Java签名/验证密钥和Javascript WebCrypto验证失败

Java签名/验证密钥和Javascript WebCrypto验证失败,javascript,java,cryptography,digital-signature,webcrypto-api,Javascript,Java,Cryptography,Digital Signature,Webcrypto Api,我正在努力 生成签名/验证密钥(RSA) 在Java web应用程序(让我们调用服务器端)上签署一个值(使用这些键) 为了让web客户端验证-公钥作为RSASSA-PKCS1-v1_5+SHA-256,导入(在浏览器中,使用/client-side) 我在验证签名值(在Java服务器端签名)时遇到问题,即使公共签名/验证密钥在客户端作为JWK成功导入 我想知道在我可能遇到的任何步骤(OpenSSL、Java或Javascript)中是否存在算法兼容性问题 用于生成密钥的OpenSSL命令 ope

我正在努力

  • 生成签名/验证密钥(RSA)
  • 在Java web应用程序(让我们调用服务器端)上签署一个值(使用这些键)
  • 为了让web客户端验证-公钥作为
    RSASSA-PKCS1-v1_5
    +
    SHA-256
    ,导入(在浏览器中,使用/client-side)
  • 我在验证签名值(在Java服务器端签名)时遇到问题,即使公共签名/验证密钥在客户端作为JWK成功导入

    我想知道在我可能遇到的任何步骤(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导入密钥(服务器端)

    使用Java对值进行签名(服务器端)

    将它们发送到WebCryptoAPI的web应用程序,以作为客户端/浏览器进行验证(客户端知道在第一步中生成的公钥)

    注意(1):在Java方面,我使用
    com.nimbusds.jose.jwk.jwk
    将公钥导出为jwk格式

    WebCrypto已成功导入签名密钥。但是当涉及到验证时,它失败了(验证布尔值为
    false

    注意(2):还要注意,我在WebCrypto上找到的每个示例都使用
    Uint8Array
    来表示字节数组,但是由于Java生成signed字节数组,我需要使用
    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;
    }
    
    //实用函数
    功能str2ab(str){
    var arrBuff=新阵列缓冲区(str.length);
    var bytes=新的Uint8Array(arrBuff);
    对于(变量iii=0;iii

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

    java
    byte[]
    存储0..255的值。我认为您需要使用
    Uint8Array
    ArrayBuffer
    。您能否尝试使用此处介绍的
    stringToArrayBuffer
    函数来表示
    数据
    签名
    ?谢谢,仍然不起作用。也许我需要改变实现的基本原理:考虑在Java中导入X509证书,并使用
    pki.js
    +
    asn1.js
    在Javascript中提取公钥(证书),以便WebCrypto进行验证(),我想公钥没有问题,因为在导入JWK时它引发了一个异常。但是,为了确保这一点,您可以在导入
    spki
    时以
    spki
    格式导入它(二进制RSA密钥转换为ArrayBuffer),在Java中使用
    Base64.encode(pubKey.getEncoded())
    生成,在Javascript中使用
    str2ab(atob(spkiBase64))
    导入。症状相同:验证失败。Hi@pedrofb,感谢您的反馈-这是另一个不相关的问题:我在Javascript中两次转换base64的预期数据,但没有注意到它;核查自然失败。作为参考,使用
    Uint8Array
    并没有引起我最初怀疑的任何问题。此外,我使用的
    str2ab
    ab2str
    方法就像您可能在使用
    Uint16Array
    时遇到问题一样。我已经使用您提供的
    str2ab
    函数检查了代码,而且效果很好。事实上,函数的内容与我在
    stringToArrayBuffer
    中使用的代码相同。我认为前面的
    str2ab
    的问题是
    Uint16Array
    。我已经用正确的链接更新了anwser
    // 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;
    }
    
    crypto.subtle.verify(
          signatureAlgorithm,
          signatureVerifyPublicKey,
          signature,               // bytes in Int8Array format (2)
          data                     // bytes in Int8Array format
        ).then(
           function (valid) {
               // valid === false
           }
        )
    
    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 );
    });
    
    //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;
    }