美文网首页
SM2 裸签名

SM2 裸签名

作者: jockie911 | 来源:发表于2021-08-18 17:56 被阅读0次

    最近在处理一个需求,使用国密SM2进行签名,在实际需求中有这样的一个场景:对PDF进行签名,其实是签署PDF sm3处理后的摘要,所以后端给到我们的就是sm3 hash,标准的做法是签署 signerinfo->AuthenticatedAttributeSet,而偏偏我们遇到的是直接对hash进行签名,所以不能用sm2sign_with_sm3,而BC库又不支持sm2sign算法。最后看源码找到了SM2Signer,它的内部实现其实还是sm2sign_with_sm3,所以我们可以进行修改SM2Signer

    看过源码后发现只要修改generateSignature -> eHash就可以了,这样就可以直接跳过内部做过的sm3算法

    public byte[] generateSignature(byte[] sm3Hash)
                throws CryptoException
    {
        byte[] eHash = sm3Hash;
    
        BigInteger n = ecParams.getN();
        BigInteger e = calculateE(eHash);
        BigInteger d = ((ECPrivateKeyParameters)ecKey).getD();
    
        BigInteger r, s;
    
        ECMultiplier basePointMultiplier = createBasePointMultiplier();
    
        // 5.2.1 Draft RFC:  SM2 Public Key Algorithms
        do // generate s
        {
            BigInteger k;
            do // generate r
            {
                // A3
                k = kCalculator.nextK();
    
                // A4
                ECPoint p = basePointMultiplier.multiply(ecParams.getG(), k).normalize();
    
                // A5
                r = e.add(p.getAffineXCoord().toBigInteger()).mod(n);
            }
            while (r.equals(ZERO) || r.add(k).equals(n));
    
            // A6
            BigInteger dPlus1ModN = d.add(ONE).modInverse(n);
    
            s = k.subtract(r.multiply(d)).mod(n);
            s = dPlus1ModN.multiply(s).mod(n);
        }
        while (s.equals(ZERO));
    
        // A7
        try
        {
            return derEncode(r, s);
        }
        catch (IOException ex)
        {
            throw new CryptoException("unable to encode signature: " + ex.getMessage(), ex);
        }
    }
    

    在使用的时候只需要传入sm3后的hash

    /**
     * 签名
     *
     * @param priKey  私钥
     * @param srcData 原文
     * @return DER编码后的签名值
     * @throws CryptoException
     */
    public static byte[] sign(BCECPrivateKey priKey, byte[] srcData) throws CryptoException {
        ECPrivateKeyParameters priKeyParameters = BCECUtil.convertPrivateKeyToParameters(priKey);
        BCSM2Signer signer = new BCSM2Signer();
        CipherParameters param = new ParametersWithRandom(priKeyParameters, new SecureRandom());
        signer.init(true, param);
        return signer.generateSignature(srcData);
    }
    

    签名验签同理

    public boolean verifySignature(byte[] sm3Hash,byte[] signature)
    {
        this.sm3Hash = sm3Hash;
        try
        {
            BigInteger[] rs = derDecode(signature);
            if (rs != null)
            {
                return verifySignature(rs[0], rs[1]);
            }
        }
        catch (IOException e)
        {
        }
    
        return false;
    }
    
    
    private boolean verifySignature(BigInteger r, BigInteger s)
    {
        BigInteger n = ecParams.getN();
    
        // 5.3.1 Draft RFC:  SM2 Public Key Algorithms
        // B1
        if (r.compareTo(ONE) < 0 || r.compareTo(n) >= 0)
        {
            return false;
        }
    
        // B2
        if (s.compareTo(ONE) < 0 || s.compareTo(n) >= 0)
        {
            return false;
        }
    
        // B3
        byte[] eHash = sm3Hash;
    
        // B4
        BigInteger e = calculateE(eHash);
    
        // B5
        BigInteger t = r.add(s).mod(n);
        if (t.equals(ZERO))
        {
            return false;
        }
    
        // B6
        ECPoint q = ((ECPublicKeyParameters)ecKey).getQ();
        ECPoint x1y1 = ECAlgorithms.sumOfTwoMultiplies(ecParams.getG(), s, q, t).normalize();
        if (x1y1.isInfinity())
        {
            return false;
        }
    
        // B7
        BigInteger expectedR = e.add(x1y1.getAffineXCoord().toBigInteger()).mod(n);
    
        return expectedR.equals(r);
    }   
    
    /**
     * 验签
     *
     * @param pubKey  公钥
     * @param sm3Hash 原文sm3hash
     * @param sign    DER编码的签名值
     * @return
     */
    public static boolean verify(BCECPublicKey pubKey, byte[] sm3Hash, byte[] sign) {
        ECPublicKeyParameters pubKeyParameters = BCECUtil.convertPublicKeyToParameters(pubKey);
        BCSM2Signer signer = new BCSM2Signer();
        signer.init(false, pubKeyParameters);
        return signer.verifySignature(sm3Hash,sign);
    }
    

    相关文章

      网友评论

          本文标题:SM2 裸签名

          本文链接:https://www.haomeiwen.com/subject/bftnbltx.html