Java 中使用 SHA256 算法和 Pkcs1 RSA 签名填充的哈希数字签名 (HMACSHA256) 与点网实现不匹配

问题描述 投票:0回答:1

我正在尝试使用 SHA256 算法和 Pkcs1 RSA 签名填充在 Java 中创建哈希的数字签名(使用 HMACSHA256 创建),但它不会生成与供应商在 .net 中实现的签名相同的签名。

我的Java代码:

String secretKey = "1n6pobYP5+BZHgEdFCtNibcb1eykysLMbWMV2fJD0OwfmY3TbtRlUaRWu8A7Fp0dt8O+TCIl3LABlUrW48FFUg==";

private String hmacSha256(String data, String key) throws Exception {
    Mac mac = Mac.getInstance("HmacSHA256");
    SecretKeySpec secretKeySpec = new SecretKeySpec(key.getBytes("UTF-8"), "HmacSHA256");
    mac.init(secretKeySpec);
    byte[] hmacSha256Bytes = mac.doFinal(data.getBytes("UTF-8"));
    return Base64.getEncoder().encodeToString(hmacSha256Bytes);
}

private String signHash(String hash, PrivateKey privateKey) throws Exception {
    Signature signature = Signature.getInstance("SHA256withRSA", "BC");
    signature.initSign(privateKey);
    signature.update(Base64.getDecoder().decode(hash));
    byte[] signedBytes = signature.sign();
    return Base64.getEncoder().encodeToString(signedBytes);
}

private String signMessage(String hashedMsg, PrivateKey privateKey) throws Exception {
    Signature signature = Signature.getInstance("SHA256withRSA", "BC");
    signature.initSign(privateKey);
    signature.update(hashedMsg.getBytes("UTF-8"));
    byte[] signedBytes = signature.sign();
    return Base64.getEncoder().encodeToString(signedBytes);
}

SignHash 是向已经散列的消息添加签名,而 SignMessage 是向已经散列的消息再次添加散列,然后添加签名。 SignMessage 正在根据供应商进行正确的签名,但 SignHash 正在创建不同的签名。

供应商对 SignHash 函数的 Dotnet 代码实现:

String secretKey = "1n6pobYP5+BZHgEdFCtNibcb1eykysLMbWMV2fJD0OwfmY3TbtRlUaRWu8A7Fp0dt8O+TCIl3LABlUrW48FFUg==";

public static string HashInstruction(string message, string key)
{
    using HMACSHA256 hMACSHA = new HMACSHA256(Encoding.UTF8.GetBytes(key));
    return Convert.ToBase64String(hMACSHA.ComputeHash(Encoding.UTF8.GetBytes(message)));
}

public static string SignHashWithFile(string message, string privateKeyFile)
{
    byte[] array = ReadPrivateFile(privateKeyFile);
    RSA rSA = RSA.Create();
    rSA.ImportRSAPrivateKey(array, out var _);
    byte[] hash = Convert.FromBase64String(message);
    byte[] inArray = rSA.SignHash(hash, HashAlgorithmName.SHA256, RSASignaturePadding.Pkcs1);
    return Convert.ToBase64String(inArray);
}

public static string SignDataWithFile(string message, string privateKeyFile)
{
    byte[] array = ReadPrivateFile(privateKeyFile);
    RSA rSA = RSA.Create();
    rSA.ImportRSAPrivateKey(array, out var _);
    byte[] data = Encoding.ASCII.GetBytes(message);
    byte[] inArray = rSA.SignData(data, HashAlgorithmName.SHA256, RSASignaturePadding.Pkcs1);
    return Convert.ToBase64String(inArray);
}

SignDataWithFile() 生成与signMessage() 相同的签名,但signHash() 和SignHashWithFile() 生成不同的签名。

.NET 的示例值:

哈希前的数据:'512|PUB55442201|3555101122526|20000'

哈希后的数据:'vGEWCW/XP7NPFIrY4sOo+jE4Q713RfVlKV/VV8ZQG6I='

签名(signhash):'m3CHGVvBy90CVVnPzzFYQAekN6oy/isfz+fAVyXsJ/COTZ/fCMemANy0Q+yWlh/WUkSGbS7SQrc/33m+Wy69XrctOYSZcWMZpGFGBwBrCkg+wmscBfYItBqKlqmbQr2W0CI xOJlj5fLTeWYQ0MLCrMoBB9g1sB93eECYy9G5MzNfrRQaHVVzQrvBdyphABf8GsIuOzfjTOca5jGCZq6+0i/Xnb49jpkr3bPG3JP2+HbwKbyeqzB59pQaQ1+ye1pE7w85b0Sd3WDSfyj mYDBcNUooaMzekROaR8GPvlerhr1LbXwzvhoDON3ZJhFjerSikcrrM1JeL+s0DOCSQdvsBg=='

签名(signData):'wLDprhCgUVG3V0pgU6DCZDQyoHf3VSQ7PMs9T6Ns3OM/lIz2cvACSVFJIs5W5sR7NN/jcp8k6yjQreq9SuSi9EPJsHFNlsqDjfqt78KOkqVD41PlFKRguPi9caMskRSKF/Ja1np XEweQw0MLgxGhs1sOffEzgk7Tqq4N3p2LN4mxgBtxoK3S+HfybPbHKpeSqx6Y0dVfz+Axa3v0/ChNU1+ZHA68H7+j7opdtaXTsx4dzodMvzdpfmFOpC9ye+mhmbJWBfhHDUd+AtIgLSCUZ0v +YhTLFlFY7hUEYRMqk3/tAxLw6dshXla9TSyzkJe3lijJabWGaMGqDgGC+/0puw=='

Java 的示例值:

哈希前的数据:'512|PUB55442201|3555101122526|20000'

哈希后的数据:'vGEWCW/XP7NPFIrY4sOo+jE4Q713RfVlKV/VV8ZQG6I='

签名(signhash):'W1U84sux5el9Tij8Dd9Tu2VbcXC2/BUwZFn5qeYh9M1D/ym6WjahyseTqUb6QFLuy1I9AAQN7p71NvYm1XpKKSGlJMl97cyHPijH3vj/+ydceLWm6Z4cIcJHrZsR ld9EYNfYIW7e3h7UVQRwexZaNS+PjcWDatuUWZevCGnQNzu20D3dIhdJdcZUp/J0rRO0rrWl9njXWDshiZz9mnVYx2wnoOJC6+2j2UBQOezupBzA5ZcvWaTrJhnes0l8aKhgwcdfb59ifuwhvcrFKB TxLkFVI7eMJslluHcFe2BYVjhmOQkqVfbkTYXgBqEsiQjCNdHlYsY15ZSbVDNpt9fthA=='

签名(signData):'wLDprhCgUVG3V0pgU6DCZDQyoHf3VSQ7PMs9T6Ns3OM/lIz2cvACSVFJIs5W5sR7NN/jcp8k6yjQreq9SuSi9EPJsHFNlsqDjfqt78KOkqVD41PlFKRguPi9caMskRSKF/Ja1np XEweQw0MLgxGhs1sOffEzgk7Tqq4N3p2LN4mxgBtxoK3S+HfybPbHKpeSqx6Y0dVfz+Axa3v0/ChNU1+ZHA68H7+j7opdtaXTsx4dzodMvzdpfmFOpC9ye+mhmbJWBfhHDUd+AtIgLSCUZ0v +YhTLFlFY7hUEYRMqk3/tAxLw6dshXla9TSyzkJe3lijJabWGaMGqDgGC+/0puw=='

java rsa digital-signature pkcs#1 hmacsha256
1个回答
0
投票

正如评论中已经提到的,必须调整 Java 方法

signHash()
才能产生与相应 .NET 方法相同的结果:

  • 哈希必须完成为 DigestInfo 值的 DER 编码。
  • NonewithRSA
    必须用作算法。

经过必要更改的相关方法是:

private static String signHash(String hash, PrivateKey privateKey) throws Exception {
    Signature signature = Signature.getInstance("NonewithRSA"); // apply NoneWithRSA
    System.out.println(signature.getProvider().getName());
    signature.initSign(privateKey); 
    signature.update(HexFormat.of().parseHex("3031300d060960864801650304020105000420")); // completet Hash: s. RFC8017, 9.2, Notes, 1.
    signature.update(Base64.getDecoder().decode(hash));
    byte[] signedBytes = signature.sign();
    return Base64.getEncoder().encodeToString(signedBytes);
}

请注意,签名不符合 RFC8017,因为哈希不是使用 SHA256 生成的,而是使用 HMAC/SHA256 生成的。

© www.soinside.com 2019 - 2024. All rights reserved.