nel-neo-thinsdk
Version:
303 lines (294 loc) • 15 kB
text/typescript
///// <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();
}
}