UNPKG

nel-neo-thinsdk

Version:
303 lines (294 loc) 15 kB
///// <reference path="RandomNumberGenerator.ts"/> interface String { base58Decode(): Uint8Array; base64UrlDecode(): Uint8Array; toAesKey(): PromiseLike<ArrayBuffer>; } interface Uint8Array { base58Encode(): string; base64UrlEncode(): string; } declare function escape(s:string): string; declare function unescape(s: string): string; namespace Neo.Cryptography { String.prototype.base58Decode = function (): Uint8Array { return Base58.decode(this); } String.prototype.base64UrlDecode = function (): Uint8Array { let str = window.atob(this.replace(/-/g, '+').replace(/_/g, '/')); let arr = new Uint8Array(str.length); for (let i = 0; i < str.length; i++) arr[i] = str.charCodeAt(i); return arr; } String.prototype.toAesKey = function (): PromiseLike<ArrayBuffer> { let utf8 = unescape(encodeURIComponent(this)); let codes = new Uint8Array(utf8.length); for (let i = 0; i < codes.length; i++) codes[i] = utf8.charCodeAt(i); return window.crypto.subtle.digest({ name: "SHA-256" }, codes).then(result => { return window.crypto.subtle.digest({ name: "SHA-256" }, result); }); } Uint8Array.prototype.base58Encode = function () { return Base58.encode(this); } Uint8Array.prototype.base64UrlEncode = function () { let str: string = String.fromCharCode.apply(null, this); str = global["btoa"](str); return str.replace(/\+/g, '-').replace(/\//g, '_').replace(/=/g, ''); } let getAlgorithmName = (algorithm: string | Algorithm) => typeof algorithm === "string" ? algorithm : algorithm.name; let w = global as any; if (global["crypto"] == null) (global as any).crypto = { subtle: null, getRandomValues: null }; if (global["crypto"].getRandomValues == null) { if (w.msCrypto) { w.crypto.getRandomValues = array => w.msCrypto.getRandomValues(array); } else { //RandomNumberGenerator.startCollectors(); //window.crypto.getRandomValues = RandomNumberGenerator.getRandomValues; } } //w.crypto.subtle = window.crypto.subtle || w.crypto.webkitSubtle; if (global["crypto"].subtle == null && w.msCrypto) { (global as any).crypto.subtle = { decrypt: (a, b, c) => new NeoPromise((resolve, reject) => { let op = w.msCrypto.subtle.decrypt(a, b, c) as any; op.oncomplete = () => resolve(op.result); op.onerror = e => reject(e); }), deriveBits: (a, b, c) => new NeoPromise((resolve, reject) => { let op = w.msCrypto.subtle.deriveBits(a, b, c) as any; op.oncomplete = () => resolve(op.result); op.onerror = e => reject(e); }), deriveKey: (a, b, c, d, e) => new NeoPromise((resolve, reject) => { let op = w.msCrypto.subtle.deriveKey(a, b, c, d, e) as any; op.oncomplete = () => resolve(op.result); op.onerror = e => reject(e); }), digest: (a, b) => new NeoPromise((resolve, reject) => { let op = w.msCrypto.subtle.digest(a, b); op.oncomplete = () => resolve(op.result); op.onerror = e => reject(e); }), encrypt: (a, b, c) => new NeoPromise((resolve, reject) => { let op = w.msCrypto.subtle.encrypt(a, b, c) as any; op.oncomplete = () => resolve(op.result); op.onerror = e => reject(e); }), exportKey: (a, b) => new NeoPromise((resolve, reject) => { let op = w.msCrypto.subtle.exportKey(a, b) as any; op.oncomplete = () => resolve(op.result); op.onerror = e => reject(e); }), generateKey: (a, b, c) => new NeoPromise((resolve, reject) => { let op = w.msCrypto.subtle.generateKey(a, b, c) as any; op.oncomplete = () => resolve(op.result); op.onerror = e => reject(e); }), importKey: (a, b, c, d, e) => new NeoPromise((resolve, reject) => { let op = w.msCrypto.subtle.importKey(a, b, c, d, e) as any; op.oncomplete = () => resolve(op.result); op.onerror = e => reject(e); }), sign: (a, b, c) => new NeoPromise((resolve, reject) => { let op = w.msCrypto.subtle.sign(a, b, c) as any; op.oncomplete = () => resolve(op.result); op.onerror = e => reject(e); }), unwrapKey: (a, b, c, d, e, f, g) => new NeoPromise((resolve, reject) => { let op = w.msCrypto.subtle.unwrapKey(a, b, c, d, e, f, g) as any; op.oncomplete = () => resolve(op.result); op.onerror = e => reject(e); }), verify: (a, b, c, d) => new NeoPromise((resolve, reject) => { let op = w.msCrypto.subtle.verify(a, b, c, d) as any; op.oncomplete = () => resolve(op.result); op.onerror = e => reject(e); }), wrapKey: (a, b, c, d) => new NeoPromise((resolve, reject) => { let op = w.msCrypto.subtle.wrapKey(a, b, c, d) as any; op.oncomplete = () => resolve(op.result); op.onerror = e => reject(e); }), }; } if (global["crypto"].subtle == null) { (global as any).crypto.subtle = { decrypt: (algorithm, key, data) => new NeoPromise((resolve, reject) => { if (typeof algorithm === "string" || algorithm.name != "AES-CBC" || !algorithm.iv || algorithm.iv.byteLength != 16 || data.byteLength % 16 != 0) { reject(new RangeError()); return; } try { let aes = new Aes((key as any).export(), (algorithm as any).iv); resolve(aes.decrypt(data)); } catch (e) { reject(e); } }), deriveBits: null, deriveKey: null, digest: (algorithm, data) => new NeoPromise((resolve, reject) => { if (getAlgorithmName(algorithm) != "SHA-256") { reject(new RangeError()); return; } try { resolve(Sha256.computeHash(data)); } catch (e) { reject(e); } }), encrypt: (algorithm, key, data) => new NeoPromise((resolve, reject) => { if (typeof algorithm === "string" || algorithm.name != "AES-CBC" || !algorithm.iv || algorithm.iv.byteLength != 16) { reject(new RangeError()); return; } try { let aes = new Aes((key as AesCryptoKey).export(), (algorithm as any).iv); resolve(aes.encrypt(data)); } catch (e) { reject(e); } }), exportKey: (format, key) => new NeoPromise((resolve, reject) => { if (format != "jwk" || !(key instanceof AesCryptoKey)) { reject(new RangeError()); return; } try { let k = key as AesCryptoKey; resolve({ alg: "A256CBC", ext: true, k: k.export().base64UrlEncode(), key_ops: k.usages, kty: "oct" }); } catch (e) { reject(e); } }), generateKey: (algorithm, extractable, keyUsages) => new NeoPromise((resolve, reject) => { if (typeof algorithm === "string" || algorithm.name != "AES-CBC" || (algorithm.length != 128 && algorithm.length != 192 && algorithm.length != 256)) { reject(new RangeError()); return; } try { resolve(AesCryptoKey.create(algorithm.length)); } catch (e) { reject(e); } }), importKey: (format, keyData, algorithm, extractable, keyUsages) => new NeoPromise((resolve, reject) => { if ((format != "raw" && format != "jwk") || getAlgorithmName(algorithm) != "AES-CBC") { reject(new RangeError()); return; } try { if (format == "jwk") keyData = (keyData as any).k.base64UrlDecode(); resolve(AesCryptoKey.import(keyData)); } catch (e) { reject(e); } }), sign: null, unwrapKey: null, verify: null, wrapKey: null, }; } function hook_ripemd160() { let digest_old = global["crypto"].subtle.digest; global["crypto"].subtle.digest = (algorithm, data) => { if (getAlgorithmName(algorithm) != "RIPEMD-160") return digest_old.call(window.crypto.subtle, algorithm, data); return new NeoPromise<ArrayBuffer>((resolve, reject) => { try { resolve(RIPEMD160.computeHash(data)); } catch (e) { reject(e); } }); }; } hook_ripemd160(); function hook_ecdsa() { let exportKey_old = global["crypto"].subtle.exportKey; global["crypto"].subtle.exportKey = (format, key) => { if (key.algorithm.name != "ECDSA") return exportKey_old.call(window.crypto.subtle, format, key); return new NeoPromise((resolve, reject) => { let k = key as ECDsaCryptoKey; if (format != "jwk" || (k.algorithm as any).namedCurve != "P-256") reject(new RangeError()); else try { if (k.type == "private") resolve({ crv: (k.algorithm as any).namedCurve, d: k.privateKey.base64UrlEncode(), ext: true, key_ops: k.usages, kty: "EC", x: k.publicKey.x.value.toUint8Array(false, 32).base64UrlEncode(), y: k.publicKey.y.value.toUint8Array(false, 32).base64UrlEncode() }); else resolve({ crv: (k.algorithm as any).namedCurve, ext: true, key_ops: k.usages, kty: "EC", x: k.publicKey.x.value.toUint8Array(false, 32).base64UrlEncode(), y: k.publicKey.y.value.toUint8Array(false, 32).base64UrlEncode() }); } catch (e) { reject(e); } }); }; let generateKey_old = window.crypto.subtle.generateKey; window.crypto.subtle.generateKey = (algorithm, extractable, keyUsages) => { if (getAlgorithmName(algorithm) != "ECDSA") return generateKey_old.call(window.crypto.subtle, algorithm, extractable, keyUsages); return new NeoPromise((resolve, reject) => { if ((algorithm as any).namedCurve != "P-256") reject(new RangeError()); else try { resolve(ECDsa.generateKey(ECCurve.secp256r1)); } catch (e) { reject(e); } }); }; let importKey_old = window.crypto.subtle.importKey; window.crypto.subtle.importKey = (format, keyData, algorithm, extractable, keyUsages) => { if (getAlgorithmName(algorithm) != "ECDSA") return importKey_old.call(window.crypto.subtle, format, keyData, algorithm, extractable, keyUsages); return new NeoPromise((resolve, reject) => { if (format != "jwk" || (algorithm as any).namedCurve != "P-256") reject(new RangeError()); else try { let k = keyData as any; let x = k.x.base64UrlDecode(); let y = k.y.base64UrlDecode(); let arr = new Uint8Array(65); arr[0] = 0x04; Array.copy(x, 0, arr, 1, 32); Array.copy(y, 0, arr, 33, 32); let pubkey = ECPoint.decodePoint(arr, ECCurve.secp256r1); if (k.d) resolve(new ECDsaCryptoKey(pubkey, k.d.base64UrlDecode())); else resolve(new ECDsaCryptoKey(pubkey)); } catch (e) { reject(e); } }); }; let sign_old = window.crypto.subtle.sign; window.crypto.subtle.sign = (algorithm, key, data) => { if (getAlgorithmName(algorithm as any) != "ECDSA") return sign_old.call(window.crypto.subtle, algorithm, key, data); return new NeoPromise((resolve, reject) => { if ((algorithm as any).hash.name != "SHA-256" || key.algorithm.name != "ECDSA") reject(new RangeError()); else try { let ecdsa = new ECDsa(key as ECDsaCryptoKey); resolve(ecdsa.sign(data)); } catch (e) { reject(e); } }); }; let verify_old = window.crypto.subtle.verify; window.crypto.subtle.verify = (algorithm, key, signature, data) => { if (getAlgorithmName(algorithm as any) != "ECDSA") return verify_old.call(window.crypto.subtle, algorithm, key, signature, data); return new NeoPromise((resolve, reject) => { if ((algorithm as any).hash.name != "SHA-256" || key.algorithm.name != "ECDSA") reject(new RangeError()); else try { let ecdsa = new ECDsa(key as ECDsaCryptoKey); resolve(ecdsa.verify(data, signature)); } catch (e) { reject(e); } }); }; } try { (global["crypto"].subtle.generateKey({ name: "ECDSA", namedCurve: "P-256" }, false, ["sign", "verify"]) as any).catch(hook_ecdsa); } catch (ex) { hook_ecdsa(); } }