我正在尝试:
我想知道是否在任何步骤(OpenSSL、Java或JavaScript)中存在任何算法兼容性问题。以下是用于生成密钥的OpenSSL命令:
将它们发送到 WebCrypto API 的 Web 应用程序以作为客户端/浏览器进行验证(客户端知道在第一步生成的 publicKey)。
注意(1):在Java端,我使用
签名密钥已成功导入WebCrypto。但是在验证时失败了(验证布尔值为
注意(2):还要注意到,我在WebCrypto上找到的每个示例都使用
- 生成签名/验证密钥(RSA)
- 在Java Web应用程序上使用这些密钥对一个值进行签名(我们称之为服务器端)
- 以便Web客户端验证-公钥导入为
RSASSA-PKCS1-v1_5
+SHA-256
,(在浏览器中使用WebCrypto API/客户端)
我想知道是否在任何步骤(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转换了两次,而没有注意到它;自然会导致验证失败。
byte[]
存储来自0..255的值。我认为您需要使用Uint8Array
和ArrayBuffer
。您可以尝试使用此处记录的stringToArrayBuffer
函数(https://dev59.com/vVoV5IYBdhLWcg3wnf7r#37407739)来表示`data`和`signature`。 - pedrofbpki.js
+asn1.js
从中(证书)提取公钥,在JavaScript中使用WebCrypto进行验证(示例在这里)。 - nunospki
格式(将二进制RSA密钥转换为ArrayBuffer)进行导入。 - pedrofbBase64.encode(pubKey.getEncoded())
生成spki
,并在Javascript中使用str2ab(atob(spkiBase64))
导入时,出现的症状是相同的:验证失败。 - nuno