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转换了预期数据,却没有注意到它;自然,验证失败.

Inm小程序商店 | Vultr中文网

最佳答案

请检查基于您的简单代码,以导入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;
}

我建议比较两个代码以找出差异

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
经常看到有人要找AES-GCM-128  这个算法加解密 网上相关的文档也较少其中在telegram登录首页就在使用该算法 应该让不少哥们头疼 其实这个加密常见于浏览器内置接口window.crypto.subtle 该接口不仅支持该类型的加密 且支持非常多的算法加密如RSA DES  等等  这里就演示AES-GCM-128 这个类型 crypto-AES-GCM-128调用例子 function ___crypto__test(keyData, iv, data) {     const format = "raw",         // keyData = new Uint8Array([23, 113, 57, 6, 35, -69, -60, 98, 84, -17, -125, -49, 18, 6, -92, 32]),         algorithm = "AES-GCM",         extractable = true,         usages = ["encrypt", "decrypt"];     // iv = new Uint8Array([47, 46, 123, 78, 36, 14, 109, 50, 121, 64, 11, 38]);     window.crypto.subtle.importKey(         format,         keyData,         algorithm,         extractable, usages     ).then(key =gt; {         window.crypto.subtle.encrypt({                 name: algorithm,                 iv: iv             },             key,             data         ).then(result =gt; {             console.log(Array.from(new Uint8Array((result))))         })     }) } console.log(___crypto__test(             new Uint8Array([23, 113, 57, 6, 35, -69, -60, 98, 84, -17, -125, -49, 18, 6, -92, 32]),                 new Uint8Array([47, 46, 123, 78, 36, 14, 109, 50, 121, 64, 11, 38]),             new Uint8Array([50, 49, 48]) )) crypto主要相关接口介绍 crypto.subtle.importKey const result = crypto.subtle.importKey(     format,     keyData,     algorithm,     extractable,     usages ); format  是一个字符串,描述要导入的密钥的数据格式。可以是以下之一:----------raw:原始格式。----------pkcs8:PKCS#8格式。----------spki:SubjectPublicKeyInfo格式。----------jwk:JSON Web密钥格式。 - keyData 是ArrayBuffer,TypedArray,a DataView或JSONWebKey包含给定格式的键的对象。 - algorithm  是一个字典对象,用于定义要导入的密钥的类型并提供额外的算法特定参数。对于RSASSA-PKCS1-v1_5,  RSA-PSS或  RSA-OAEP:传递RsaHashedImportParams对象。对于ECDSA或ECDH:传递  EcKeyImportParams对象。对于HMAC:传递一个HmacImportParams对象。对于AES-CTR,AES-CBC,AES-GCM或AES-KW:传递标识算法的字符串或形式为的对象{ "name": ALGORITHM },其中ALGORITHM 是算法的名称。对于PBKDF2  :传递字符串PBKDF2。 - extractable 是Boolean表明它是否将有可能使用到导出密钥SubtleCrypto.exportKey()或SubtleCrypto.wrapKey()。 - ke

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值