文档首页/ 数据加密服务 DEW/ 常见问题/ 密钥管理类/ 进行SM2签名时,如何计算SM3摘要?
更新时间:2023-03-21 GMT+08:00
分享

进行SM2签名时,如何计算SM3摘要?

使用SM2密钥签名时,仅支持对消息摘要签名。

根据GBT32918国家标准,计算SM2签名值时,消息摘要不是对原始消息直接计算SM3摘要,而是对Z(A)和M的拼接值计算的摘要。其中M是待签名的原始消息,Z(A)是GBT32918中定义的用户A的杂凑值。

以JAVA为例,参考如下示例代码:
public class Sm2SignDataPreprocessing {

    private static final String ECC_A = "FFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00000000FFFFFFFFFFFFFFFC";
    private static final String ECC_B = "28E9FA9E9D9F5E344D5A9E4BCF6509A7F39789F515AB8F92DDBCBD414D940E93";
    private static final String ECC_GX = "32C4AE2C1F1981195F9904466A39C9948FE30BBFF2660BE1715A4589334C74C7";
    private static final String ECC_GY = "BC3736A2F4F6779C59BDCEE36B692153D0A9877CC62A474002DF32E52139F0A0";

    // 签名者ID,本示例使用国密标准定义的缺省值"1234567812345678"
    private static final String SM2_ID = "31323334353637383132333435363738";

    public static void main(String[] args) throws Exception {

        // SM2公钥,BASE64编码格式,仅做示例,实际使用请替换
        String sm2PubKey = "MFkwEwYHKoZIzj0CAQYIKoEcz1UBgi0DQgAEsuOq/EjQeYUD9h7lIyqi3pQ6SWL7hTXjUJWmSIZAcnj" +
                "h9c0QcdbwzaCfI8iyyPCetX0QZl5NHrBoYLYxJpvbFg==";

        byte[] pubKeyBytes = Base64.decodeBase64(sm2PubKey.getBytes(StandardCharsets.UTF_8));
        X509EncodedKeySpec keySpec = new X509EncodedKeySpec(pubKeyBytes);
        KeyFactory keyFactory = KeyFactory.getInstance("EC", new BouncyCastleProvider());
        ECPublicKey ecPublicKey = (ECPublicKey) keyFactory.generatePublic(keySpec);

        // 待签名的原始消息,仅做示例,实际使用请替换
        byte[] dataToDigest = new byte[]{1, 2, 3, 4};

        // Z(A)是GBT32918中定义的用户A的杂凑值
        byte[] zsm = getSm2Z(ecPublicKey.getQ().getAffineXCoord().getEncoded(),
                ecPublicKey.getQ().getAffineYCoord().getEncoded());

        // Z(A)和M的拼接值计算的摘要,并打印
        byte[] dataToSign = getSm3SignData(zsm, dataToDigest);
        System.out.println(Base64.encodeBase64String(dataToSign));

        // 其他语言实现或执行此示例应有如下输出:He+qiM2MmtNxlV/EB4vqkcP60XgG08z/8nWQdp/IS5c=
    }

    // 计算Z(A)
    private static byte[] getSm2Z(byte[] x, byte[] y) throws DecoderException {
        SM3Digest sm3 = new SM3Digest();
        byte[] userId = Hex.decodeHex(SM2_ID.toCharArray());
        byte[] byteEccA = Hex.decodeHex(ECC_A);
        byte[] byteEccB = Hex.decodeHex(ECC_B);
        byte[] byteEccGx = Hex.decodeHex(ECC_GX);
        byte[] byteEccGy = Hex.decodeHex(ECC_GY);
        int len = userId.length * 8;
        sm3.update((byte) (len >> 8 & 255));
        sm3.update((byte) (len & 255));
        sm3.update(userId, 0, userId.length);
        sm3.update(byteEccA, 0, byteEccA.length);
        sm3.update(byteEccB, 0, byteEccB.length);
        sm3.update(byteEccGx, 0, byteEccGx.length);
        sm3.update(byteEccGy, 0, byteEccGy.length);
        sm3.update(x, 0, x.length);
        sm3.update(y, 0, y.length);
        byte[] md = new byte[sm3.getDigestSize()];
        sm3.doFinal(md, 0);
        return md;
    }

    // 计算Z(A)和M的拼接值的摘要
    private static byte[] getSm3SignData(byte[] z, byte[] sourceData) {
        SM3Digest sm3 = new SM3Digest();
        sm3.update(z, 0, z.length);
        sm3.update(sourceData, 0, sourceData.length);
        byte[] md = new byte[sm3.getDigestSize()];
        sm3.doFinal(md, 0);
        return md;
    }

}

相关文档