在Java中采用BouncyCastle的Jar(bcprov-jdk15on-1.58.jar)对授权数据进行签名。因为项目的历史原因,没用采用更高版本jar包。签名后,把授权数据和签名发给C#的应用进行验签。由于Java端的签名结果是由64字节组成的hex字符串,是直接拼接r||s的字节数组,没用经过asn1编码的。在C#应用端通过NuGet引入BouncyCastle.Crypto的版本为1.9.0.0。该库中的对象SM2Signer自带的验签方法VerifySignature的参数是需要带asn1编码的签名hex字符串。因此,需要把从Java中传来的签名字符串先进行asn1编码后,在传给验签函数VerifySignature进行验签。asn1编码互转的方法如下:
/**
* BC的SM3withSM2验签需要的rs是asn1格式的,这个方法将直接拼接r||s的字节数组转化成asn1格式
* @param sign in plain byte array
* @return rs result asn1格式
*/
public static byte[] RsByteArrayToAsn1(byte[] sign)
{
if (sign.Length != 32 * 2) throw new ArgumentException("err rs. ");
BigInteger r = new BigInteger(1, Arrays.CopyOfRange(sign, 0, 32));
BigInteger s = new BigInteger(1, Arrays.CopyOfRange(sign, 32, 32 * 2));
Asn1EncodableVector v = new Asn1EncodableVector();
v.Add(new DerInteger(r));
v.Add(new DerInteger(s));
try
{
return new DerSequence(v).GetEncoded("DER");
}
catch (IOException e)
{
log.Error("RsPlainByteArrayToAsn1 error: " + e.Message, e);
return null;
}
}
/**
* BC的SM3withSM2签名得到的结果的rs是asn1格式的,这个方法转化成直接拼接r||s
* @param rsDer rs asn1 格式
* @return sign result in plain byte array
*/
public static byte[] RsAsn1ToByteArray(byte[] rsDer)
{
Asn1Sequence seq = Asn1Sequence.GetInstance(rsDer);
byte[] r = BigIntToFixexLengthBytes(DerInteger.GetInstance(seq[0]).Value);
byte[] s = BigIntToFixexLengthBytes(DerInteger.GetInstance(seq[1]).Value);
byte[] result = new byte[32 * 2];
Buffer.BlockCopy(r, 0, result, 0, r.Length);
Buffer.BlockCopy(s, 0, result, 32, s.Length);
return result;
}