3

我有以下代码来测试 WebCrypto API。它适用于 Firefox 和 Chrome,我正在尝试让它在 Safari 中运行。

 function ab2str(buf) {
      return String.fromCharCode.apply(null, new Uint16Array(buf));
    }

//converts a forge 0.6.x string of bytes to an ArrayBuffer
function str2ab(str) {
  var b = new ArrayBuffer(str.length);
  var view = new Uint8Array(b);
  for(var i = 0; i < str.length; ++i) {
    view[i] = str.charCodeAt(i);
  }
  return b;
}


function _arrayBufferToBase64( buffer ) {
    var binary = '';
    var bytes = new Uint8Array( buffer );
    var len = bytes.byteLength;
    for (var i = 0; i < len; i++) {
        binary += String.fromCharCode( bytes[ i ] );
    }
    return window.btoa( binary );
}

var pubKey;
var privKey;

var s_pubKey="MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA5tieEkcDAqAp/baSmNIdg5ezJMcWJX63+hM/DQolgKtw9Dvc0c8GRUqK2r/idZ1iXJzOjWQ3KIFIzmgTRHOKe3aPgJADdZ2vyAqu2woKtsgQ8nTcDYI86dmyfYsHFbgbSn/qeoE8WEzwyT3OoGgn54zoMuQmUmLbGaJYY2XN5bxwqxsRJSoXetBu9o1G9Wy4V1fdxwjRtaO/2FrZfkLp/P5Tc5Hk1Ev7PIPrkRhrl/7lF4JblVRG5m90aeviErvFIN0LdlqiY90UaQY3gyTsylrheTlqRq6yyzKf3dWnF78+CeAqppsOMI+WHURThNLkN56EOTX6TaBrG6f2XjxeqQIDAQAB";

var cripto= window.crypto || window.msCrypto;
var subtle= cripto.subtle || window.crypto.webkitSubtle;

subtle.generateKey(
        {
            name: "RSA-OAEP",
            modulusLength: 2048, //can be 1024, 2048, or 4096
            publicExponent: new Uint8Array([0x01, 0x00, 0x01]),
            hash: {name: "SHA-256"}, //can be "SHA-1", "SHA-256", "SHA-384", or "SHA-512"
        },
        true, //whether the key is extractable (i.e. can be used in exportKey)
        ["encrypt", "decrypt"] //must contain both "encrypt" and "decrypt"
    )
    .then(function(key){
        //returns a keypair object
        //console.log(key);
        //console.log(key.publicKey);
        //console.log(key.privateKey);
        subtle.exportKey(
                "jwk", //can be "jwk" (public or private), "spki" (public only), or "pkcs8" (private only)
                key.publicKey //can be a publicKey or privateKey, as long as extractable was true
            )
            .then(function(keydata){
                //returns the exported key data

                console.log("publicKey:"+_arrayBufferToBase64(keydata));
                subtle.exportKey(
                        "jwk", //can be "jwk" (public or private), "spki" (public only), or "pkcs8" (private only)
                        key.privateKey //can be a publicKey or privateKey, as long as extractable was true
                    )
                    .then(function(keydata){
                        //returns the exported key data

                        console.log("privateKey:"+_arrayBufferToBase64(keydata));
                    });

                subtle.importKey(                       
                        "jwk", //can be "jwk" (public or private), "spki" (public only), or "pkcs8" (private only)
                        keydata,
                        {   //these are the algorithm options
                            name: "RSA-OAEP",
                            hash: {name: "SHA-256"}, //can be "SHA-1", "SHA-256", "SHA-384", or "SHA-512"
                        },
                        false, //whether the key is extractable (i.e. can be used in exportKey)
                        ["encrypt"] //"encrypt" for public key import, "decrypt" for private key imports
                    )
                    .then(function(publicKey){
                        //returns a publicKey (or privateKey if you are importing a private key)
                        console.log(publicKey);

                        subtle.encrypt(
                                {
                                    name: "RSA-OAEP",
                                    //label: Uint8Array([...]) //optional
                                },
                                publicKey, //from generateKey or importKey above
                                str2ab("hola mundo") //ArrayBuffer of data you want to encrypt
                            )
                            .then(function(encrypted){
                                //returns an ArrayBuffer containing the encrypted data
                                //console.log(new Uint8Array(encrypted));
                                console.log("enc: "+_arrayBufferToBase64(encrypted));
                            })
                            .catch(function(err){
                                console.error(err);
                            });
                    })

            })

    })
    .catch(function(err){
        console.error(err);
    });

问题是微妙的.encrypt 显然没有执行。既不调用 console.log 也不调用 console.error。任何线索发生了什么?上一行“console.log(publicKey);” 工作正常。

4

3 回答 3

2

当前版本的 Safari、Safari 技术预览和 WebKit 不支持 RSA-OAEP-256。它们仅支持带有 SHA-1 的旧 RSA-OAEP:

https://bugs.webkit.org/show_bug.cgi?id=151308

于 2016-07-08T17:40:30.307 回答
2

目前 WebCrypto 的 Safari 实现以及 Edge 实现存在许多问题。这因浏览器之间的算法支持差异而变得复杂。

您可以通过访问: https ://peculiarventures.github.io/pv-webcrypto-tests/来探索给定浏览器支持的内容

鉴于这些差异,我们实现了这个库,它掩盖了许多差异并添加了一些算法(可选)以使它们互操作:https ://github.com/PeculiarVentures/webcrypto-liner/blob/master/BrowserSupport.md

对于 Safari,它们仅支持 RSA-OAEP 的以下内容:

  • RSA-OAEP mod:2048 pubExp:3 /w SHA1 格式:jwk
  • RSA-OAEP mod:2048 pubExp:65535 /w SHA1 格式:jwk

如果您更改:哈希:{name:“SHA-256”}

到:哈希:{名称:“SHA-1”}

我怀疑这会奏效。

于 2016-12-09T07:29:03.383 回答
1

在您调用“generateKey”之后,key.publicKey 和 key.privateKey 实际上是 CryptoKey 对象吗?在我修补 Safari(在 iPad 上)时,它们似乎只是对象......当我调用“exportKey”时,我得到一个 TypeError 被抛出

ps 没关系,我使用的是“RSASSA-PKCS1-v1_5”,而不是“RSA-OAEP”。

于 2015-08-21T02:42:11.277 回答