gpt4 book ai didi

java - 调号在 Python 中有效,但在 Java 中不行吗?

转载 作者:行者123 更新时间:2023-11-30 04:10:58 26 4
gpt4 key购买 nike

我使用 pycrypto 在 python 中生成了一个 key 对

key=RSA.generate(bit_size,os.urandom)

exportedPrivateKey = key.exportKey('PEM', None, pkcs=1).decode("utf-8")
exportedPublicKey = key.publickey().exportKey('PEM', None, pkcs=1).decode("utf-8")

我编写了一个小型实用程序,它获取消息的哈希值并对哈希值进行签名...

hash = MD5.new(json_info.encode("utf-8")).digest()
privateKey = RSA.importKey(USER_TOKEN_PRIVATE_KEY)
signature = privateKey.sign(hash,'')

然后我写了一些东西,使用公钥来验证它是否有效......我的 token 中的签名工作正常......

hash = MD5.new(packet.encode("utf-8")).digest()
publicKey = RSA.importKey(tokenPublicKey)

if publicKey.verify(hash, signature):
return json.loads(packet)
else:
return None

现在,因为我需要在 Java 和 Python 中使用它,所以我将一个类似的库移植到 java,但我开始遇到问题。也就是说,我的验证总是会失败......

我首先从导出的 PEM 创建 PublicKey 对象...

byte[] encoded = Base64.decodeBase64(USER_TOKEN_PUBLIC_KEY);

//decode the encoded RSA public key
X509EncodedKeySpec keySpec = new X509EncodedKeySpec(encoded);
KeyFactory kf = KeyFactory.getInstance("RSA");
PublicKey pubKey = kf.generatePublic(keySpec);

我能够获得签名,并且它是完全相同的签名,并且值哈希为完全相同的值(好吧,类似;java 将字节表示为有符号整数,而 python 将它们表示为无符号整数,但它们'相同的二进制表示)。但它似乎总是无法验证我的签名..这就是我用来执行此操作的方法:

byte[] hash = hasher.digest(packet.getBytes("UTF-8"));

InputStream hashStream = new ByteArrayInputStream(hash);

final Signature sign = Signature.getInstance("MD5withRSA");
sign.initVerify(pubKey);

byte[] buffer = new byte[256];
int length;
while ((length = hashStream.read (buffer)) != -1)
sign.update (buffer, 0, length);

hashStream.close();

System.out.println(sign.verify(signature.getBytes("UTF-8")));

不幸的是,这只会打印错误。

我真正看到的唯一区别是,当我在 Java 中传递它进行验证时,它要求一个 long 数组,而在 python 中,它需要一个字节序列。我最好的猜测是采用那么长的字符串表示并将其转换为一堆字节,但是失败了。我的所有其他尝试也都失败了(查看底层大整数的字节表示,查看数组的字节表示等)。我觉得我错过了一些非常简单的东西,但我一生都无法弄清楚它是什么......

对于 Python 中签名的示例,我给出:

[688304594898632574115230115201042030356261470845487427579402264460794863484312‌​120410963342371307037749493750151877472804877900061168981924606440672704577286260‌​395240971170923041153667805814235978868869872792318501209376911650132169706471509‌​89646220735762034864029622135210042186666476516651349805320771941650]

最佳答案

您正在将签名作为 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)));
}
}

[编辑2]

privateKey.sign(hash,'') 使用“原始”RSA 签名。需要使用PKCS115_SigScheme相反。

为了更安全,请尝试使用 PSS 样式签名和 higher key size 。此外,MD5 对于签名应用程序的使用已被破坏。请改用 SHA-256 或 SHA-512。

关于java - 调号在 Python 中有效,但在 Java 中不行吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/19601782/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com