更新时间: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; } }
父主题: 密钥管理类