Java符号/验证密钥和Javascript WebCrypto验证失败
作者:互联网
我试图
>生成签名/验证密钥(RSA)
>在Java Web应用程序上签名一个值(使用这些键)(让我们调用服务器端)
>以便Web客户端进行验证-作为RSASSA-PKCS1-v1_5 SHA-256导入的公钥(在浏览器中,使用WebCrypto API /客户端)
即使将公共符号/验证密钥成功作为客户端的JWK导入,我也无法验证签名的值(在Java服务器端进行了签名).
我想知道在我可能遇到的任何步骤(OpenSSL,Java或Javascript)中是否存在算法兼容性问题.
用于生成密钥的OpenSSL命令
openssl genrsa -out privatekey.pem 2048
openssl rsa -in privatekey.pem -pubout > publickey.pub
openssl pkcs8 -topk8 -inform PEM -outform DER -in privatekey.pem -out privatekey-pkcs8.pem
使用Java导入密钥(服务器端)
public static KeyPair generateSignKeyPair() throws ... {
byte[] privBytes = b64ToByteArray(PRIVATE_KEY_PEM_VALUE);
byte[] pubBytes = b64ToByteArray(PUBLIC_KEY_PEM_VALUE);
// private key
KeySpec keySpec = new PKCS8EncodedKeySpec(privBytes);
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
PrivateKey privateKey = keyFactory.generatePrivate(keySpec);
// public key (javaPubSignKey)
X509EncodedKeySpec X509publicKey = new X509EncodedKeySpec(pubBytes);
PublicKey publicKey = keyFactory.generatePublic(X509publicKey);
return new KeyPair(publicKey, privateKey);
}
使用Java签名值(服务器端)
public static byte[] generateSignature(PrivateKey signPrivateKey, byte[] data) throws ... {
Signature dsa = Signature.getInstance("SHA256withRSA");
dsa.initSign(signPrivateKey);
dsa.update(data);
return dsa.sign();
}
将它们发送到WebCrypto API的Web应用程序,以作为客户端/浏览器进行验证(客户端知道第一步中生成的publicKey).
// Import public sign/verify key (javaPubSignVerifyKey)
var signatureAlgorithm = {
name: 'RSASSA-PKCS1-v1_5',
modulusLength: 2048,
publicExponent: new Uint8Array([0x01, 0x00, 0x01]),
hash: {
name: 'SHA-256'
}
};
// JWK format (1)
crypto.subtle.importKey(
'jwk', javaPubSignVerifyKey, signatureAlgorithm, false, ['verify']
).then(success, error);
function success(key) {
signatureVerifyPublicKey = key;
}
注意(1):在Java方面,我使用com.nimbusds.jose.jwk.JWK将publicKey导出为JWK格式.
WebCrypto已成功导入签名密钥.但是,当涉及到验证时,它将失败(验证布尔值为false).
crypto.subtle.verify(
signatureAlgorithm,
signatureVerifyPublicKey,
signature, // bytes in Int8Array format (2)
data // bytes in Int8Array format
).then(
function (valid) {
// valid === false
}
)
注意(2):还请注意,我在WebCrypto上找到的每个示例都使用Uint8Array表示字节数组,但是由于Java生成带符号的字节数组,因此我需要使用Int8Array以便不污染签名值(也许这也是一个问题) .
编辑:作为参考,原来是另一个不相关的问题-我在Javascript中两次从base64转换了预期数据,却没有注意到它;自然,验证失败.
解决方法:
请检查基于您的简单代码,以导入RSA公钥(spki)并验证签名.我已经使用类似的Java代码生成了密钥和签名
var publicKeyB64 = "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDVdZDEs6htb3oxWstz7q+e5IwIRcptMNJiyemuoNyyjtiOy+0tEodjgo7RVoyUcGU3MysEivqvKdswQZ4KfwQCBLAR8DRzp3biAge5utZcKsQoQaC1rCEplfmzEo5ovIlBcMq5x1BxnrnlwEPRmM7MefRa+OeAOQJcstHcrJFO7QIDAQAB";
var dataB64 = "aGVsbG8=";
var signatureB64 = "aEOmUA7YC5gvF6QgH+TMg0erY5pzr83nykZGFtyGOOe+6ld+MC4/Qdb608XiNud+pBpzh0wqd6aajOtJim5XEfCH8vUPsv45aSPtukUIQTX00Oc1frIFDQI6jGJ4Q8dQYIwpqsyE2rkGwTDzt1fTTGiw54pLsJXjtL/D5hUEKL8=";
var signatureAlgorithm = {name: 'RSASSA-PKCS1-v1_5',modulusLength: 2048, publicExponent: new Uint8Array([0x01, 0x00, 0x01]),hash: { name: 'SHA-256' }};
//convert public key, data and signature to ArrayBuffer.
var publicKey = str2ab(atob(publicKeyB64));
var data = str2ab(atob(dataB64));
var signature = str2ab(atob(signatureB64));
crypto.subtle.importKey("spki", publicKey, signatureAlgorithm, false,["verify"]).
then(function(key){
console.log(key);
return crypto.subtle.verify( signatureAlgorithm, key, signature, data);
}).then( function (valid) {
console.log("Signature valid: "+valid);
}).catch(function(err) {
alert("Verification failed " + err );
});
我无法完全重现该问题.使用您链接的str2ab实用程序功能,代码可以完美运行.
//Utility function
function str2ab(str) {
var arrBuff = new ArrayBuffer(str.length);
var bytes = new Uint8Array(arrBuff);
for (var iii = 0; iii < str.length; iii++) {
bytes[iii] = str.charCodeAt(iii);
}
return bytes;
}
我建议比较两个代码以找出差异
标签:cryptography,digital-signature,webcrypto-api,javascript,java 来源: https://codeday.me/bug/20191118/2024575.html