用户在使用Python的pycrypto库生成RSA密钥对并进行签名验证时,发现签名验证在Python中是有效的,但在Java中却总是失败。通过对比Python和Java中的代码,用户发现Python中使用的是字节序列,而Java中使用的是长整型数组。用户尝试将签名转换为字符串并将其转换为字节数组,但仍然无法验证签名。
2、解决方案
- [解决方案一]
- 在Java中,将签名作为Java字符串处理,并使用UTF-8编码的字符串作为签名值是不正确的。签名可以是任何编码,包括无法编码成可打印字符串的字节,因此这不可能是正确的。
- 签名看起来像一个1024位签名,表示为方括号中的一个数字。因此,可以使用以下代码进行转换:
import java.math.BigInteger;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class SignatureFromPython {
private static final Pattern PAT = Pattern.compile("\[(\d+)\]");
private static byte[] i2osp(final BigInteger i, final int bitSize) {
if (i == null || i.signum() == -1) {
throw new IllegalArgumentException(
"input parameter should not be null or negative");
}
if (bitSize < Byte.SIZE) {
throw new IllegalArgumentException(
"bitSize parameter should not be negative and a multiple of 8");
}
final int byteSize = (bitSize - 1) / Byte.SIZE + 1;
final byte[] signedBigEndian = i.toByteArray();
final int signedBigEndianLength = signedBigEndian.length;
if (signedBigEndianLength == byteSize) {
return signedBigEndian;
}
final byte[] leftPadded = new byte[byteSize];
if (signedBigEndianLength == byteSize + 1) {
System.arraycopy(signedBigEndian, 1, leftPadded, 0, byteSize);
} else if (signedBigEndianLength < byteSize) {
System.arraycopy(signedBigEndian, 0, leftPadded, byteSize
- signedBigEndianLength, signedBigEndianLength);
} else {
throw new IllegalArgumentException(
"Integer i is too large to fit into " + bitSize + " bits");
}
return leftPadded;
}
public static String toHex(final byte[] data) {
final StringBuilder hex = new StringBuilder(data.length * 2);
for (int i = 0; i < data.length; i++) {
hex.append(String.format("%02X", data[i]));
}
return hex.toString();
}
public static void main(String[] args) {
String sigString = "[68830459489863257411523011520104203035626147084548742757940226446079486348431212041096334237130703774949375015187747280487790006116898192460644067270457728626039524097117092304115366780581423597886886987279231850120937691165013216970647150989646220735762034864029622135210042186666476516651349805320771941650]";
Matcher sigMatcher = PAT.matcher(sigString);
if (!sigMatcher.matches()) {
throw new IllegalArgumentException("Whatever");
}
BigInteger sigBI = new BigInteger(sigMatcher.group(1));
// requires bouncy castle libraries
System.out.println(toHex(i2osp(sigBI, 1024)));
}
}
- [解决方案二]
- privateKey.sign(hash,'') 使用“原始”RSA签名。需要使用PKCS115_SigScheme代替。
- 为了更加安全,请尝试使用PSS样式签名和更高的密钥大小。此外,MD5的使用对于签名应用程序来说是不可靠的。改用SHA-256或SHA-512。