Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Doesn't work in Safari #44

Open
borisreitman opened this issue Dec 19, 2017 · 10 comments
Open

Doesn't work in Safari #44

borisreitman opened this issue Dec 19, 2017 · 10 comments
Assignees

Comments

@borisreitman
Copy link

I cloned the project, installed webpack, and ran webpack that generated files in dist/ directory.
However, when I try to run the example in examples/src/index.html on Safari, I get an error.

The first error I get is "unable to delete property" on line 3719:

3710 Object.defineProperty(exports, "__esModule", { value: true });
3711 var index_1 = __webpack_require__(6);
3712 var w = self;
3713 // Object.freeze(Math);
3714 // Object.freeze(Math.random);
3715 // Object.freeze((Math as any).imul);
3716 if (index_1.nativeCrypto) {
3717     Object.freeze(index_1.nativeCrypto.getRandomValues);
3718 }
3719 delete self.crypto;
3720 w.crypto = new index_1.Crypto();
3721 Object.freeze(w.crypto);
3722 exports.crypto = w.crypto;
3723 

When I actually try to use the sample, I get the error:

undefined is not an object (evaluating 'crypto.subtle.generateKey')

Safari version: Version 9.1.3 (11601.7.8) on a MacBook Pro, OSX version 10.11.6 (15G1004)

@rmhrisk
Copy link
Contributor

rmhrisk commented Dec 20, 2017

Sounds like you didn't follow the steps in https://github.com/PeculiarVentures/webcrypto-liner#installation

Specifically if your going to run in a browser that doesn't support ES6 you need to be sure to convert to ES2015

@borisreitman
Copy link
Author

Ok, I now followed the steps, the error now occurs on a different line, but the error is the same "Unable to delete property".

2413    n.nativeCrypto && Object.freeze(n.nativeCrypto.getRandomValues), delete self.crypto, a.crypto = new n.Crypto, Object.freeze(a.crypto), r.crypto = a.crypto

Basically, if I would try to manually do: delete window.crypto I get the same error. It appears that this property is read-only in Safari. Doing the same in Google Chrome works and gives no errors.

@borisreitman
Copy link
Author

borisreitman commented Dec 20, 2017

I tried this fix, and got past that error,

diff --git a/src/shim.ts b/src/shim.ts
index d136bde..06b6dc2 100644
--- a/src/shim.ts
+++ b/src/shim.ts
@@ -10,8 +10,12 @@ if (nativeCrypto) {
     Object.freeze(nativeCrypto.getRandomValues);
 }
 
-delete (self as any).crypto;
-w.crypto = new Crypto();
+try {
+  delete (self as any).crypto;
+  w.crypto = new Crypto();
+} catch(e){
+  w.crypto.subtle = new Crypto().subtle;
+}
 Object.freeze(w.crypto);
 
 export const crypto = w.crypto;

However, when I try to use the sample to "Sign", I get error from App.sign() call, that I tracked down to this line in file subtle.ts:

                if (!key.key) {
                    throw new LinerError("Cannot export native CryptoKey from JS implementation");
                }

@rmhrisk
Copy link
Contributor

rmhrisk commented Dec 20, 2017

Works in Safari without code modification as we use it in several projects, ill have @microshine take a look when he gets online.

@borisreitman
Copy link
Author

borisreitman commented Dec 20, 2017 via email

@rmhrisk
Copy link
Contributor

rmhrisk commented Dec 20, 2017

Boris,

I am not too familiar with cordova/phonegap but I understand you end up with JS also using this should work.

Ryan

@microshine
Copy link
Contributor

microshine commented Dec 20, 2017

@borisreitman Could you try https://github.com/PeculiarVentures/webcrypto-liner/blob/master/dist/webcrypto-liner.lib.js? This variant of webcrypto-liner doesn't delete native crypto object. This script uses global liner variable which has own crypto object. We use webcrypto-liner.lib.js for Web Worker, because some browsers don't allow to remove native crypto

Example

<script src="https://peculiarventures.github.io/pv-webcrypto-tests/src/asmcrypto.js"></script>
<script src="webcrypto-liner.lib.js"></script>
liner.crypto.subtle.generateKey({name: "AES-GCM", length: 256}, false, ["encrypt"]).then((k) => {
  console.log(k);
})

@borisreitman
Copy link
Author

Yes, this version worked fine.

Quick question: does liner work in a browser that has no native window.crypto at all ?

@microshine
Copy link
Contributor

microshine commented Dec 20, 2017

@borisreitman Yes, it does.
You can use this script to do it. webcrypto-liner needs getRandomValues for key generation. So if you don't have crypto object you must implement your own getRandomValues

Example

function getRandomArbitrary(min, max)
{
    return self.Math.random() * (max - min) + min;
}

function getRandomValues(buffer)
{
    // TODO: seed random
    const buf = new Uint8Array(buffer.buffer);
    let i = 0;
	
    while(i < buf.length)
        buf[i++] = getRandomArbitrary(0, 255);
	
    return buffer;
}

if(!self.crypto) {
    self.crypto = { getRandomValues: getRandomValues };
    Object.freeze(self.crypto);
}

@borisreitman
Copy link
Author

borisreitman commented Dec 20, 2017

For anyone else who may benefit from reading this thread, here's a tip on where to get native random numbers in Cordova.

var crypto = new AeroGear.Crypto();
crypto.getRandomValue();

https://github.com/aerogear/aerogear-cordova-crypto

EDIT: I just checked that both Android Webview and iOS Safari (and probably the iOS Webview) have window.crypto.getRandomValues() and the whole window.crypto.subtle suite. Someone has reported on StackOverflow that Android has no subtle, but it was his error. It's there, as long as user is using https:// to browse a website. And, it is there in the Cordova webview.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants