SM2 裸簽名

最近在處理一個需求,使用國密SM2進(jìn)行簽名,在實際需求中有這樣的一個場景:對PDF進(jìn)行簽名,其實是簽署PDF sm3處理后的摘要,所以后端給到我們的就是sm3 hash,標(biāo)準(zhǔn)的做法是簽署 signerinfo->AuthenticatedAttributeSet,而偏偏我們遇到的是直接對hash進(jìn)行簽名,所以不能用sm2sign_with_sm3,而BC庫又不支持sm2sign算法。最后看源碼找到了SM2Signer,它的內(nèi)部實現(xiàn)其實還是sm2sign_with_sm3,所以我們可以進(jìn)行修改SM2Signer

看過源碼后發(fā)現(xiàn)只要修改generateSignature -> eHash就可以了,這樣就可以直接跳過內(nèi)部做過的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);
}
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容