mirror of
https://github.com/darkwire/darkwire.io.git
synced 2025-08-01 06:37:08 +00:00
For webkit support, I removed the public/private signing keys and replaced them with a symmetric HMAC signing key. It achieves the same thing and besides adding webkit support, is also a bit cleaner. Webkit handles key export is a non-standard way, so with this shim we have to export and import public keys in “spki” format. Webkit also requires slightly different options to be passed in for some operations.
597 lines
22 KiB
JavaScript
597 lines
22 KiB
JavaScript
/**
|
|
* @file Web Cryptography API shim
|
|
* @author Artem S Vybornov <vybornov@gmail.com>
|
|
* @license MIT
|
|
*/
|
|
!function ( global ) {
|
|
'use strict';
|
|
|
|
if ( typeof Promise !== 'function' )
|
|
throw "Promise support required";
|
|
|
|
var _crypto = global.crypto || global.msCrypto;
|
|
if ( !_crypto ) return;
|
|
|
|
var _subtle = _crypto.subtle || _crypto.webkitSubtle;
|
|
if ( !_subtle ) return;
|
|
|
|
var _Crypto = global.Crypto || _crypto.constructor || Object,
|
|
_SubtleCrypto = global.SubtleCrypto || _subtle.constructor || Object,
|
|
_CryptoKey = global.CryptoKey || global.Key || Object;
|
|
|
|
var isIE = !!global.msCrypto,
|
|
isWebkit = !!_crypto.webkitSubtle;
|
|
if ( !isIE && !isWebkit ) return;
|
|
|
|
function s2a ( s ) {
|
|
return btoa(s).replace(/\=+$/, '').replace(/\+/g, '-').replace(/\//g, '_');
|
|
}
|
|
|
|
function a2s ( s ) {
|
|
s += '===', s = s.slice( 0, -s.length % 4 );
|
|
return atob( s.replace(/-/g, '+').replace(/_/g, '/') );
|
|
}
|
|
|
|
function s2b ( s ) {
|
|
var b = new Uint8Array(s.length);
|
|
for ( var i = 0; i < s.length; i++ ) b[i] = s.charCodeAt(i);
|
|
return b;
|
|
}
|
|
|
|
function b2s ( b ) {
|
|
if ( b instanceof ArrayBuffer ) b = new Uint8Array(b);
|
|
return String.fromCharCode.apply( String, b );
|
|
}
|
|
|
|
function alg ( a ) {
|
|
var r = { 'name': (a.name || a || '').toUpperCase().replace('V','v') };
|
|
switch ( r.name ) {
|
|
case 'SHA-1':
|
|
case 'SHA-256':
|
|
case 'SHA-384':
|
|
case 'SHA-512':
|
|
break;
|
|
case 'AES-CBC':
|
|
case 'AES-GCM':
|
|
case 'AES-KW':
|
|
if ( a.length ) r['length'] = a.length;
|
|
break;
|
|
case 'HMAC':
|
|
if ( a.hash ) r['hash'] = alg(a.hash);
|
|
if ( a.length ) r['length'] = a.length;
|
|
break;
|
|
case 'RSAES-PKCS1-v1_5':
|
|
if ( a.publicExponent ) r['publicExponent'] = new Uint8Array(a.publicExponent);
|
|
if ( a.modulusLength ) r['modulusLength'] = a.modulusLength;
|
|
break;
|
|
case 'RSASSA-PKCS1-v1_5':
|
|
case 'RSA-OAEP':
|
|
if ( a.hash ) r['hash'] = alg(a.hash);
|
|
if ( a.publicExponent ) r['publicExponent'] = new Uint8Array(a.publicExponent);
|
|
if ( a.modulusLength ) r['modulusLength'] = a.modulusLength;
|
|
break;
|
|
default:
|
|
throw new SyntaxError("Bad algorithm name");
|
|
}
|
|
return r;
|
|
};
|
|
|
|
function jwkAlg ( a ) {
|
|
return {
|
|
'HMAC': {
|
|
'SHA-1': 'HS1',
|
|
'SHA-256': 'HS256',
|
|
'SHA-384': 'HS384',
|
|
'SHA-512': 'HS512',
|
|
},
|
|
'RSASSA-PKCS1-v1_5': {
|
|
'SHA-1': 'RS1',
|
|
'SHA-256': 'RS256',
|
|
'SHA-384': 'RS384',
|
|
'SHA-512': 'RS512',
|
|
},
|
|
'RSAES-PKCS1-v1_5': {
|
|
'': 'RSA1_5',
|
|
},
|
|
'RSA-OAEP': {
|
|
'SHA-1': 'RSA-OAEP',
|
|
'SHA-256': 'RSA-OAEP-256',
|
|
},
|
|
'AES-KW': {
|
|
'128': 'A128KW',
|
|
'192': 'A192KW',
|
|
'256': 'A256KW',
|
|
},
|
|
'AES-GCM': {
|
|
'128': 'A128GCM',
|
|
'192': 'A192GCM',
|
|
'256': 'A256GCM',
|
|
},
|
|
'AES-CBC': {
|
|
'128': 'A128CBC',
|
|
'192': 'A192CBC',
|
|
'256': 'A256CBC',
|
|
},
|
|
}[a.name][ ( a.hash || {} ).name || a.length || '' ];
|
|
}
|
|
|
|
function b2jwk ( k ) {
|
|
if ( k instanceof ArrayBuffer || k instanceof Uint8Array ) k = JSON.parse( decodeURIComponent( escape( b2s(k) ) ) );
|
|
var jwk = { 'kty': k.kty, 'alg': k.alg, 'ext': k.ext || k.extractable };
|
|
switch ( jwk.kty ) {
|
|
case 'oct':
|
|
jwk.k = k.k;
|
|
case 'RSA':
|
|
[ 'n', 'e', 'd', 'p', 'q', 'dp', 'dq', 'qi', 'oth' ].forEach( function ( x ) { if ( x in k ) jwk[x] = k[x] } );
|
|
break;
|
|
default:
|
|
throw new TypeError("Unsupported key type");
|
|
}
|
|
return jwk;
|
|
}
|
|
|
|
function jwk2b ( k ) {
|
|
var jwk = b2jwk(k);
|
|
if ( isIE ) jwk['extractable'] = jwk.ext, delete jwk.ext;
|
|
return s2b( unescape( encodeURIComponent( JSON.stringify(jwk) ) ) ).buffer;
|
|
}
|
|
|
|
function pkcs2jwk ( k ) {
|
|
var info = b2der(k), prv = false;
|
|
if ( info.length > 2 ) prv = true, info.shift(); // remove version from PKCS#8 PrivateKeyInfo structure
|
|
var jwk = { 'ext': true };
|
|
switch ( info[0][0] ) {
|
|
case '1.2.840.113549.1.1.1':
|
|
var rsaComp = [ 'n', 'e', 'd', 'p', 'q', 'dp', 'dq', 'qi' ],
|
|
rsaKey = b2der( info[1] );
|
|
if ( prv ) rsaKey.shift(); // remove version from PKCS#1 RSAPrivateKey structure
|
|
for ( var i = 0; i < rsaKey.length; i++ ) {
|
|
if ( !rsaKey[i][0] ) rsaKey[i] = rsaKey[i].subarray(1);
|
|
jwk[ rsaComp[i] ] = s2a( b2s( rsaKey[i] ) );
|
|
}
|
|
jwk['kty'] = 'RSA';
|
|
break;
|
|
default:
|
|
throw new TypeError("Unsupported key type");
|
|
}
|
|
return jwk;
|
|
}
|
|
|
|
function jwk2pkcs ( k ) {
|
|
var key, info = [ [ '', null ] ], prv = false;
|
|
switch ( k.kty ) {
|
|
case 'RSA':
|
|
var rsaComp = [ 'n', 'e', 'd', 'p', 'q', 'dp', 'dq', 'qi' ],
|
|
rsaKey = [];
|
|
for ( var i = 0; i < rsaComp.length; i++ ) {
|
|
if ( !( rsaComp[i] in k ) ) break;
|
|
var b = rsaKey[i] = s2b( a2s( k[ rsaComp[i] ] ) );
|
|
if ( b[0] & 0x80 ) rsaKey[i] = new Uint8Array(b.length + 1), rsaKey[i].set( b, 1 );
|
|
}
|
|
if ( rsaKey.length > 2 ) prv = true, rsaKey.unshift( new Uint8Array([0]) ); // add version to PKCS#1 RSAPrivateKey structure
|
|
info[0][0] = '1.2.840.113549.1.1.1';
|
|
key = rsaKey;
|
|
break;
|
|
default:
|
|
throw new TypeError("Unsupported key type");
|
|
}
|
|
info.push( new Uint8Array( der2b(key) ).buffer );
|
|
if ( !prv ) info[1] = { 'tag': 0x03, 'value': info[1] };
|
|
else info.unshift( new Uint8Array([0]) ); // add version to PKCS#8 PrivateKeyInfo structure
|
|
return new Uint8Array( der2b(info) ).buffer;
|
|
}
|
|
|
|
var oid2str = { 'KoZIhvcNAQEB': '1.2.840.113549.1.1.1' },
|
|
str2oid = { '1.2.840.113549.1.1.1': 'KoZIhvcNAQEB' };
|
|
|
|
function b2der ( buf, ctx ) {
|
|
if ( buf instanceof ArrayBuffer ) buf = new Uint8Array(buf);
|
|
if ( !ctx ) ctx = { pos: 0, end: buf.length };
|
|
|
|
if ( ctx.end - ctx.pos < 2 || ctx.end > buf.length ) throw new RangeError("Malformed DER");
|
|
|
|
var tag = buf[ctx.pos++],
|
|
len = buf[ctx.pos++];
|
|
|
|
if ( len >= 0x80 ) {
|
|
len &= 0x7f;
|
|
if ( ctx.end - ctx.pos < len ) throw new RangeError("Malformed DER");
|
|
for ( var xlen = 0; len--; ) xlen <<= 8, xlen |= buf[ctx.pos++];
|
|
len = xlen;
|
|
}
|
|
|
|
if ( ctx.end - ctx.pos < len ) throw new RangeError("Malformed DER");
|
|
|
|
var rv;
|
|
|
|
switch ( tag ) {
|
|
case 0x02: // Universal Primitive INTEGER
|
|
rv = buf.subarray( ctx.pos, ctx.pos += len );
|
|
break;
|
|
case 0x03: // Universal Primitive BIT STRING
|
|
if ( buf[ctx.pos++] ) throw new Error( "Unsupported bit string" );
|
|
len--;
|
|
case 0x04: // Universal Primitive OCTET STRING
|
|
rv = new Uint8Array( buf.subarray( ctx.pos, ctx.pos += len ) ).buffer;
|
|
break;
|
|
case 0x05: // Universal Primitive NULL
|
|
rv = null;
|
|
break;
|
|
case 0x06: // Universal Primitive OBJECT IDENTIFIER
|
|
var oid = btoa( b2s( buf.subarray( ctx.pos, ctx.pos += len ) ) );
|
|
if ( !( oid in oid2str ) ) throw new Error( "Unsupported OBJECT ID " + oid );
|
|
rv = oid2str[oid];
|
|
break;
|
|
case 0x30: // Universal Constructed SEQUENCE
|
|
rv = [];
|
|
for ( var end = ctx.pos + len; ctx.pos < end; ) rv.push( b2der( buf, ctx ) );
|
|
break;
|
|
default:
|
|
throw new Error( "Unsupported DER tag 0x" + tag.toString(16) );
|
|
}
|
|
|
|
return rv;
|
|
}
|
|
|
|
function der2b ( val, buf ) {
|
|
if ( !buf ) buf = [];
|
|
|
|
var tag = 0, len = 0,
|
|
pos = buf.length + 2;
|
|
|
|
buf.push( 0, 0 ); // placeholder
|
|
|
|
if ( val instanceof Uint8Array ) { // Universal Primitive INTEGER
|
|
tag = 0x02, len = val.length;
|
|
for ( var i = 0; i < len; i++ ) buf.push( val[i] );
|
|
}
|
|
else if ( val instanceof ArrayBuffer ) { // Universal Primitive OCTET STRING
|
|
tag = 0x04, len = val.byteLength, val = new Uint8Array(val);
|
|
for ( var i = 0; i < len; i++ ) buf.push( val[i] );
|
|
}
|
|
else if ( val === null ) { // Universal Primitive NULL
|
|
tag = 0x05, len = 0;
|
|
}
|
|
else if ( typeof val === 'string' && val in str2oid ) { // Universal Primitive OBJECT IDENTIFIER
|
|
var oid = s2b( atob( str2oid[val] ) );
|
|
tag = 0x06, len = oid.length;
|
|
for ( var i = 0; i < len; i++ ) buf.push( oid[i] );
|
|
}
|
|
else if ( val instanceof Array ) { // Universal Constructed SEQUENCE
|
|
for ( var i = 0; i < val.length; i++ ) der2b( val[i], buf );
|
|
tag = 0x30, len = buf.length - pos;
|
|
}
|
|
else if ( typeof val === 'object' && val.tag === 0x03 && val.value instanceof ArrayBuffer ) { // Tag hint
|
|
val = new Uint8Array(val.value), tag = 0x03, len = val.byteLength;
|
|
buf.push(0); for ( var i = 0; i < len; i++ ) buf.push( val[i] );
|
|
len++;
|
|
}
|
|
else {
|
|
throw new Error( "Unsupported DER value " + val );
|
|
}
|
|
|
|
if ( len >= 0x80 ) {
|
|
var xlen = len, len = 4;
|
|
buf.splice( pos, 0, (xlen >> 24) & 0xff, (xlen >> 16) & 0xff, (xlen >> 8) & 0xff, xlen & 0xff );
|
|
while ( len > 1 && !(xlen >> 24) ) xlen <<= 8, len--;
|
|
if ( len < 4 ) buf.splice( pos, 4 - len );
|
|
len |= 0x80;
|
|
}
|
|
|
|
buf.splice( pos - 2, 2, tag, len );
|
|
|
|
return buf;
|
|
}
|
|
|
|
function CryptoKey ( key, alg, ext, use ) {
|
|
Object.defineProperties( this, {
|
|
_key: {
|
|
value: key
|
|
},
|
|
type: {
|
|
value: key.type,
|
|
enumerable: true,
|
|
},
|
|
extractable: {
|
|
value: (ext === undefined) ? key.extractable : ext,
|
|
enumerable: true,
|
|
},
|
|
algorithm: {
|
|
value: (alg === undefined) ? key.algorithm : alg,
|
|
enumerable: true,
|
|
},
|
|
usages: {
|
|
value: (use === undefined) ? key.usages : use,
|
|
enumerable: true,
|
|
},
|
|
});
|
|
}
|
|
|
|
function isPubKeyUse ( u ) {
|
|
return u === 'verify' || u === 'encrypt' || u === 'wrapKey';
|
|
}
|
|
|
|
function isPrvKeyUse ( u ) {
|
|
return u === 'sign' || u === 'decrypt' || u === 'unwrapKey';
|
|
}
|
|
|
|
[ 'generateKey', 'importKey', 'unwrapKey' ]
|
|
.forEach( function ( m ) {
|
|
var _fn = _subtle[m];
|
|
|
|
_subtle[m] = function ( a, b, c ) {
|
|
var args = [].slice.call(arguments),
|
|
ka, kx, ku;
|
|
|
|
switch ( m ) {
|
|
case 'generateKey':
|
|
ka = alg(a), kx = b, ku = c;
|
|
break;
|
|
case 'importKey':
|
|
ka = alg(c), kx = args[3], ku = args[4];
|
|
if ( a === 'jwk' ) {
|
|
b = b2jwk(b);
|
|
if ( !b.alg ) b.alg = jwkAlg(ka);
|
|
if ( !b.key_ops ) b.key_ops = ( b.kty !== 'oct' ) ? ( 'd' in b ) ? ku.filter(isPrvKeyUse) : ku.filter(isPubKeyUse) : ku.slice();
|
|
args[1] = jwk2b(b);
|
|
}
|
|
break;
|
|
case 'unwrapKey':
|
|
ka = args[4], kx = args[5], ku = args[6];
|
|
args[2] = c._key;
|
|
break;
|
|
}
|
|
|
|
if ( m === 'generateKey' && ka.name === 'HMAC' && ka.hash ) {
|
|
ka.length = ka.length || { 'SHA-1': 512, 'SHA-256': 512, 'SHA-384': 1024, 'SHA-512': 1024 }[ka.hash.name];
|
|
return _subtle.importKey( 'raw', _crypto.getRandomValues( new Uint8Array( (ka.length+7)>>3 ) ), ka, kx, ku );
|
|
}
|
|
|
|
if ( isWebkit && m === 'generateKey' && ka.name === 'RSASSA-PKCS1-v1_5' && ( !ka.modulusLength || ka.modulusLength >= 2048 ) ) {
|
|
a = alg(a), a.name = 'RSAES-PKCS1-v1_5', delete a.hash;
|
|
return _subtle.generateKey( a, true, [ 'encrypt', 'decrypt' ] )
|
|
.then( function ( k ) {
|
|
return Promise.all([
|
|
_subtle.exportKey( 'jwk', k.publicKey ),
|
|
_subtle.exportKey( 'jwk', k.privateKey ),
|
|
]);
|
|
})
|
|
.then( function ( keys ) {
|
|
keys[0].alg = keys[1].alg = jwkAlg(ka);
|
|
keys[0].key_ops = ku.filter(isPubKeyUse), keys[1].key_ops = ku.filter(isPrvKeyUse);
|
|
return Promise.all([
|
|
_subtle.importKey( 'jwk', keys[0], ka, kx, keys[0].key_ops ),
|
|
_subtle.importKey( 'jwk', keys[1], ka, kx, keys[1].key_ops ),
|
|
]);
|
|
})
|
|
.then( function ( keys ) {
|
|
return {
|
|
publicKey: keys[0],
|
|
privateKey: keys[1],
|
|
};
|
|
});
|
|
}
|
|
|
|
if ( ( isWebkit || ( isIE && ( ka.hash || {} ).name === 'SHA-1' ) )
|
|
&& m === 'importKey' && a === 'jwk' && ka.name === 'HMAC' && b.kty === 'oct' ) {
|
|
return _subtle.importKey( 'raw', s2b( a2s(b.k) ), c, args[3], args[4] );
|
|
}
|
|
|
|
if ( isWebkit && m === 'importKey' && ( a === 'spki' || a === 'pkcs8' ) ) {
|
|
return _subtle.importKey( 'jwk', pkcs2jwk(b), c, args[3], args[4] );
|
|
}
|
|
|
|
if ( isIE && m === 'unwrapKey' ) {
|
|
return _subtle.decrypt( args[3], c, b )
|
|
.then( function ( k ) {
|
|
return _subtle.importKey( a, k, args[4], args[5], args[6] );
|
|
});
|
|
}
|
|
|
|
var op;
|
|
try {
|
|
op = _fn.apply( _subtle, args );
|
|
}
|
|
catch ( e ) {
|
|
return Promise.reject(e);
|
|
}
|
|
|
|
if ( isIE ) {
|
|
op = new Promise( function ( res, rej ) {
|
|
op.onabort =
|
|
op.onerror = function ( e ) { rej(e) };
|
|
op.oncomplete = function ( r ) { res(r.target.result) };
|
|
});
|
|
}
|
|
|
|
op = op.then( function ( k ) {
|
|
if ( ka.name === 'HMAC' ) {
|
|
if ( !ka.length ) ka.length = 8 * k.algorithm.length;
|
|
}
|
|
if ( ka.name.search('RSA') == 0 ) {
|
|
if ( !ka.modulusLength ) ka.modulusLength = (k.publicKey || k).algorithm.modulusLength;
|
|
if ( !ka.publicExponent ) ka.publicExponent = (k.publicKey || k).algorithm.publicExponent;
|
|
}
|
|
if ( k.publicKey && k.privateKey ) {
|
|
k = {
|
|
publicKey: new CryptoKey( k.publicKey, ka, kx, ku.filter(isPubKeyUse) ),
|
|
privateKey: new CryptoKey( k.privateKey, ka, kx, ku.filter(isPrvKeyUse) ),
|
|
};
|
|
}
|
|
else {
|
|
k = new CryptoKey( k, ka, kx, ku );
|
|
}
|
|
return k;
|
|
});
|
|
|
|
return op;
|
|
}
|
|
});
|
|
|
|
[ 'exportKey', 'wrapKey' ]
|
|
.forEach( function ( m ) {
|
|
var _fn = _subtle[m];
|
|
|
|
_subtle[m] = function ( a, b, c ) {
|
|
var args = [].slice.call(arguments);
|
|
|
|
switch ( m ) {
|
|
case 'exportKey':
|
|
args[1] = b._key;
|
|
break;
|
|
case 'wrapKey':
|
|
args[1] = b._key, args[2] = c._key;
|
|
break;
|
|
}
|
|
|
|
if ( ( isWebkit || ( isIE && ( b.algorithm.hash || {} ).name === 'SHA-1' ) )
|
|
&& m === 'exportKey' && a === 'jwk' && b.algorithm.name === 'HMAC' ) {
|
|
args[0] = 'raw';
|
|
}
|
|
|
|
if ( isWebkit && m === 'exportKey' && ( a === 'spki' || a === 'pkcs8' ) ) {
|
|
args[0] = 'jwk';
|
|
}
|
|
|
|
if ( isIE && m === 'wrapKey' ) {
|
|
return _subtle.exportKey( a, b )
|
|
.then( function ( k ) {
|
|
if ( a === 'jwk' ) k = s2b( unescape( encodeURIComponent( JSON.stringify( b2jwk(k) ) ) ) );
|
|
return _subtle.encrypt( args[3], c, k );
|
|
});
|
|
}
|
|
|
|
var op;
|
|
try {
|
|
op = _fn.apply( _subtle, args );
|
|
}
|
|
catch ( e ) {
|
|
return Promise.reject(e);
|
|
}
|
|
|
|
if ( isIE ) {
|
|
op = new Promise( function ( res, rej ) {
|
|
op.onabort =
|
|
op.onerror = function ( e ) { rej(e) };
|
|
op.oncomplete = function ( r ) { res(r.target.result) };
|
|
});
|
|
}
|
|
|
|
if ( m === 'exportKey' && a === 'jwk' ) {
|
|
op = op.then( function ( k ) {
|
|
if ( ( isWebkit || ( isIE && ( b.algorithm.hash || {} ).name === 'SHA-1' ) )
|
|
&& b.algorithm.name === 'HMAC') {
|
|
return { 'kty': 'oct', 'alg': jwkAlg(b.algorithm), 'key_ops': b.usages.slice(), 'ext': true, 'k': s2a( b2s(k) ) };
|
|
}
|
|
k = b2jwk(k);
|
|
if ( !k.alg ) k['alg'] = jwkAlg(b.algorithm);
|
|
if ( !k.key_ops ) k['key_ops'] = ( b.type === 'public' ) ? b.usages.filter(isPubKeyUse) : ( b.type === 'private' ) ? b.usages.filter(isPrvKeyUse) : b.usages.slice();
|
|
return k;
|
|
});
|
|
}
|
|
|
|
if ( isWebkit && m === 'exportKey' && ( a === 'spki' || a === 'pkcs8' ) ) {
|
|
op = op.then( function ( k ) {
|
|
k = jwk2pkcs( b2jwk(k) );
|
|
return k;
|
|
});
|
|
}
|
|
|
|
return op;
|
|
}
|
|
});
|
|
|
|
[ 'encrypt', 'decrypt', 'sign', 'verify' ]
|
|
.forEach( function ( m ) {
|
|
var _fn = _subtle[m];
|
|
|
|
_subtle[m] = function ( a, b, c, d ) {
|
|
if ( isIE && ( !c.byteLength || ( d && !d.byteLength ) ) )
|
|
throw new Error("Empy input is not allowed");
|
|
|
|
var args = [].slice.call(arguments),
|
|
ka = alg(a);
|
|
|
|
if ( isIE && m === 'decrypt' && ka.name === 'AES-GCM' ) {
|
|
var tl = a.tagLength >> 3;
|
|
args[2] = (c.buffer || c).slice( 0, c.byteLength - tl ),
|
|
a.tag = (c.buffer || c).slice( c.byteLength - tl );
|
|
}
|
|
|
|
args[1] = b._key;
|
|
|
|
var op;
|
|
try {
|
|
op = _fn.apply( _subtle, args );
|
|
}
|
|
catch ( e ) {
|
|
return Promise.reject(e);
|
|
}
|
|
|
|
if ( isIE ) {
|
|
op = new Promise( function ( res, rej ) {
|
|
op.onabort =
|
|
op.onerror = function ( e ) {
|
|
rej(e);
|
|
};
|
|
|
|
op.oncomplete = function ( r ) {
|
|
var r = r.target.result;
|
|
|
|
if ( m === 'encrypt' && r instanceof AesGcmEncryptResult ) {
|
|
var c = r.ciphertext, t = r.tag;
|
|
r = new Uint8Array( c.byteLength + t.byteLength );
|
|
r.set( new Uint8Array(c), 0 );
|
|
r.set( new Uint8Array(t), c.byteLength );
|
|
r = r.buffer;
|
|
}
|
|
|
|
res(r);
|
|
};
|
|
});
|
|
}
|
|
|
|
return op;
|
|
}
|
|
});
|
|
|
|
if ( isIE ) {
|
|
var _digest = _subtle.digest;
|
|
|
|
_subtle['digest'] = function ( a, b ) {
|
|
if ( !b.byteLength )
|
|
throw new Error("Empy input is not allowed");
|
|
|
|
var op;
|
|
try {
|
|
op = _digest.call( _subtle, a, b );
|
|
}
|
|
catch ( e ) {
|
|
return Promise.reject(e);
|
|
}
|
|
|
|
op = new Promise( function ( res, rej ) {
|
|
op.onabort =
|
|
op.onerror = function ( e ) { rej(e) };
|
|
op.oncomplete = function ( r ) { res(r.target.result) };
|
|
});
|
|
|
|
return op;
|
|
};
|
|
|
|
global.crypto = Object.create( _crypto, {
|
|
getRandomValues: { value: function ( a ) { return _crypto.getRandomValues(a) } },
|
|
subtle: { value: _subtle },
|
|
});
|
|
|
|
global.CryptoKey = CryptoKey;
|
|
}
|
|
|
|
if ( isWebkit ) {
|
|
_crypto.subtle = _subtle;
|
|
|
|
global.Crypto = _Crypto;
|
|
global.SubtleCrypto = _SubtleCrypto;
|
|
global.CryptoKey = CryptoKey;
|
|
}
|
|
}(this); |