使用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;
}
}