node-webcrypto-ossl
Advanced tools
Comparing version 1.0.11 to 1.0.12
@@ -1,18 +0,20 @@ | ||
import * as iwc from "./iwebcrypto"; | ||
import * as native from "./native"; | ||
export class CryptoKey implements iwc.ICryptoKey { | ||
export interface CryptoKeyPair extends NativeCryptoKeyPair { | ||
privateKey: CryptoKey; | ||
publicKey: CryptoKey; | ||
} | ||
export class CryptoKey implements NativeCryptoKey { | ||
type: string; | ||
extractable: boolean; | ||
algorithm: iwc.IAlgorithmIdentifier; | ||
algorithm: Algorithm; | ||
usages: string[] = []; | ||
private native_; | ||
get native(): any{ | ||
private native_: native.AesKey | native.Key; | ||
get native(): native.AesKey | native.Key { | ||
return this.native_; | ||
} | ||
constructor(key: native.AesKey, alg: iwc.IAlgorithmIdentifier, type: string, extractable: boolean, keyUsages: string[]); | ||
constructor(key: native.Key, alg: iwc.IAlgorithmIdentifier, type: string, extractable: boolean, keyUsages: string[]); | ||
constructor(key: native.AesKey | native.Key, alg: iwc.IAlgorithmIdentifier, type: string, extractable: boolean, keyUsages: string[]) { | ||
constructor(key: native.AesKey | native.Key, alg: Algorithm, type: string, extractable: boolean, keyUsages: string[]) { | ||
this.native_ = key; | ||
@@ -27,3 +29,2 @@ | ||
} | ||
} | ||
} |
@@ -55,3 +55,3 @@ let native = require("../build/Release/nodessl.node"); | ||
type: number; | ||
/** | ||
@@ -61,3 +61,3 @@ * RSA modulus length | ||
modulusLength(): number; | ||
/** | ||
@@ -74,2 +74,7 @@ * RSA public exponent | ||
exportJwk(keyType: KeyType, callback: (err: Error, jwk: any) => void): void; | ||
/** | ||
* Export Key to JWK data | ||
* @param keyType type of exported key (PRIVATE or PUBLIC) | ||
*/ | ||
exportJwk(keyType: KeyType): any; | ||
@@ -113,4 +118,7 @@ /** | ||
*/ | ||
RsaOaepEncDec(digestName: string, data: Buffer, label: Buffer, decrypt: boolean, callback: (err: Error, raw: Buffer) => void): void; | ||
RsaOaepEncDec(digestName: string, data: Buffer, label: Buffer | null, decrypt: boolean, callback: (err: Error, raw: Buffer) => void): void; | ||
RsaPssSign(digestName: string, saltLength: number, data: Buffer, cb: (err: Error, signature: Buffer) => void): void; | ||
RsaPssVerify(digestName: string, saltLength: number, data: Buffer, signature: Buffer, cb: (err: Error, verified: boolean) => void): void; | ||
/** | ||
@@ -125,2 +133,10 @@ * derives key with ECDH | ||
/** | ||
* derives bits with ECDH | ||
* @param pubkey public key for key derivation | ||
* @param lengthBits the number of bits you want to derive | ||
* @param callback callback function (err: Error, raw: Buffer) | ||
*/ | ||
EcdhDeriveBits(pubkey: Key, lengthBits: number, callback: (err: Error, raw: Buffer) => void): void; | ||
/** | ||
* Generate RSA key pair | ||
@@ -147,2 +163,8 @@ * @param modulus modulus size of RSA key pair | ||
static importJwk(jwk: Object, keyType: KeyType, callback: (err: Error, key: Key) => void): void; | ||
/** | ||
* create Key from JWK data | ||
* @param jwk key in JWK format | ||
* @param keyType type of imported key (PRIVATE or PUBLIC) | ||
*/ | ||
static importJwk(jwk: {[key: string]: Buffer}, keyType: KeyType): any; | ||
@@ -172,5 +194,5 @@ /** | ||
encrypt(cipher: string, iv: Buffer, input: Buffer, callback: (err: Error, data: Buffer) => void): void; | ||
encryptGcm(iv: Buffer, input: Buffer, aad: Buffer, tag: number, callback: (err: Error, data: Buffer) => void): void; | ||
encryptGcm(iv: Buffer, input: Buffer, aad: Buffer | undefined, tag: number, callback: (err: Error, data: Buffer) => void): void; | ||
decrypt(cipher: string, iv: Buffer, input: Buffer, callback: (err: Error, data: Buffer) => void): void; | ||
decryptGcm(iv: Buffer, input: Buffer, aad: Buffer, tag: number, callback: (err: Error, data: Buffer) => void): void; | ||
decryptGcm(iv: Buffer, input: Buffer, aad: Buffer | undefined, tag: number, callback: (err: Error, data: Buffer) => void): void; | ||
export(callback: (err: Error, raw: Buffer) => void): void; | ||
@@ -177,0 +199,0 @@ static import(raw: Buffer, callback: (err: Error, key: AesKey) => void): void; |
@@ -1,25 +0,16 @@ | ||
/// <reference path="./promise.ts" /> | ||
// Core | ||
import * as webcrypto from "webcrypto-core"; | ||
const AlgorithmError = webcrypto.AlgorithmError; | ||
const PrepareAlgorithm = webcrypto.PrepareAlgorithm; | ||
let BaseCrypto = webcrypto.BaseCrypto; | ||
const AlgorithmNames = webcrypto.AlgorithmNames; | ||
import {CryptoKey} from "./key"; | ||
// Local | ||
import * as native from "./native"; | ||
import { CryptoKey, CryptoKeyPair } from "./key"; | ||
// import * as alg from "./alg"; | ||
import * as rsa from "./crypto/rsa"; | ||
import * as aes from "./crypto/aes"; | ||
import * as ec from "./crypto/ec"; | ||
import * as alg from "./alg"; | ||
import * as rsa from "./rsa"; | ||
import * as aes from "./aes"; | ||
import * as ec from "./ec"; | ||
import * as iwc from "./iwebcrypto"; | ||
function prepare_algorithm(alg: iwc.AlgorithmType): iwc.IAlgorithmIdentifier { | ||
let _alg: iwc.IAlgorithmIdentifier = { name: "" }; | ||
if (typeof alg === "string") { | ||
_alg = { name: alg }; | ||
} | ||
else { | ||
_alg = <iwc.IAlgorithmIdentifier>alg; | ||
} | ||
return _alg; | ||
} | ||
/** | ||
@@ -29,4 +20,4 @@ * Prepare array of data before it's using | ||
*/ | ||
function prepare_data(data: Buffer | ArrayBuffer): any { | ||
return (data instanceof ArrayBuffer || data instanceof Uint8Array) ? ab2b(data) : data; | ||
function PrepareData(data: NodeBufferSource): Buffer { | ||
return ab2b(data); | ||
} | ||
@@ -38,5 +29,4 @@ | ||
*/ | ||
function ab2b(ab: ArrayBuffer) { | ||
let buf = new Uint8Array(ab); | ||
return new Buffer(buf); | ||
function ab2b(ab: NodeBufferSource) { | ||
return new Buffer(ab as any); | ||
} | ||
@@ -48,375 +38,323 @@ | ||
*/ | ||
function b2ab(b: Buffer): ArrayBuffer { | ||
return new Uint8Array(b).buffer; | ||
} | ||
// function b2ab(b: Buffer): ArrayBuffer { | ||
// return b.buffer; | ||
// } | ||
export class SubtleCrypto implements iwc.ISubtleCrypto { | ||
export class SubtleCrypto extends webcrypto.SubtleCrypto { | ||
/** | ||
* Computes a digest | ||
* | ||
* > Note: Has difference from W3 WebcCrypto API | ||
* > - Supports Buffer | ||
* > - Supports SHA-1, SHA-224, SAH-256, SHA-384, SHA-512 algorithms | ||
* | ||
* @param {AlgorithmIdentifier} algorithm | ||
* @param {NodeSourceBuffer} data | ||
* @returns {PromiseLike<ArrayBuffer>} | ||
* | ||
* @memberOf SubtleCrypto | ||
*/ | ||
digest(algorithm: AlgorithmIdentifier, data: NodeBufferSource): PromiseLike<ArrayBuffer> { | ||
return super.digest.apply(this, arguments) | ||
.then(() => { | ||
return new Promise((resolve, reject) => { | ||
const _alg = PrepareAlgorithm(algorithm); | ||
const _data = PrepareData(data); | ||
let algName = _alg.name.toLowerCase(); | ||
switch (algName) { | ||
case "sha-1": | ||
case "sha-224": | ||
case "sha-256": | ||
case "sha-384": | ||
case "sha-512": | ||
native.Core.digest(algName.replace("-", ""), _data, (err, digest) => { | ||
if (err) | ||
reject(err); | ||
else | ||
resolve(digest.buffer); | ||
}); | ||
break; | ||
default: | ||
throw new AlgorithmError(AlgorithmError.NOT_SUPPORTED, algName); | ||
} | ||
}); | ||
}); | ||
} | ||
digest(algorithm: iwc.IAlgorithmIdentifier, data: iwc.TBuffer): Promise { | ||
let that = this; | ||
return new Promise(function(resolve, reject) { | ||
let _alg = prepare_algorithm(algorithm); | ||
let _data = prepare_data(data); | ||
generateKey(algorithm: string, extractable: boolean, keyUsages: string[]): PromiseLike<CryptoKeyPair | CryptoKey>; | ||
generateKey(algorithm: RsaHashedKeyGenParams | EcKeyGenParams | DhKeyGenParams, extractable: boolean, keyUsages: string[]): PromiseLike<CryptoKeyPair>; | ||
generateKey(algorithm: AesKeyGenParams | HmacKeyGenParams | Pbkdf2Params, extractable: boolean, keyUsages: string[]): PromiseLike<CryptoKey>; | ||
generateKey(algorithm: any, extractable: boolean, keyUsages: string[]): PromiseLike<CryptoKeyPair | CryptoKey> { | ||
return super.generateKey.apply(this, arguments) | ||
.then(() => { | ||
let _alg = PrepareAlgorithm(algorithm); | ||
let algName = _alg.name.toLowerCase(); | ||
switch (algName) { | ||
case "sha-1": | ||
case "sha-224": | ||
case "sha-256": | ||
case "sha-384": | ||
case "sha-512": | ||
native.Core.digest(algName.replace("-", ""), _data, function(err, digest) { | ||
if (err) | ||
reject(err); | ||
else | ||
resolve(new Uint8Array(digest).buffer); | ||
}); | ||
break; | ||
default: | ||
resolve(new Error("AlgorithmIdentifier: Unknown algorithm name")); | ||
} | ||
}); | ||
let AlgClass: typeof BaseCrypto; | ||
switch (_alg.name.toLowerCase()) { | ||
case AlgorithmNames.RsaSSA.toLowerCase(): | ||
AlgClass = rsa.RsaPKCS1; | ||
break; | ||
case AlgorithmNames.RsaPSS.toLowerCase(): | ||
AlgClass = rsa.RsaPSS; | ||
break; | ||
case AlgorithmNames.RsaOAEP.toLowerCase(): | ||
AlgClass = rsa.RsaOAEP; | ||
break; | ||
case AlgorithmNames.AesCBC.toLowerCase(): | ||
case AlgorithmNames.AesGCM.toLowerCase(): | ||
AlgClass = aes.AesCrypto; | ||
break; | ||
case AlgorithmNames.EcDSA.toLowerCase(): | ||
case AlgorithmNames.EcDH.toLowerCase(): | ||
AlgClass = ec.EcCrypto; | ||
break; | ||
default: | ||
throw new AlgorithmError(AlgorithmError.NOT_SUPPORTED, _alg.name); | ||
} | ||
return AlgClass.generateKey(_alg as any, extractable, keyUsages); | ||
}); | ||
} | ||
generateKey(algorithm: iwc.AlgorithmType, extractable: boolean, keyUsages: string[]): Promise { | ||
let that = this; | ||
return new Promise(function(resolve, reject) { | ||
let _alg = prepare_algorithm(algorithm); | ||
sign(algorithm: string | RsaPssParams | EcdsaParams | AesCmacParams, key: CryptoKey, data: NodeBufferSource): PromiseLike<ArrayBuffer>; | ||
sign(algorithm: any, key: CryptoKey, data: NodeBufferSource): PromiseLike<ArrayBuffer> { | ||
return super.sign.apply(this, arguments) | ||
.then(() => { | ||
let _alg = PrepareAlgorithm(algorithm as string); | ||
let _data = PrepareData(data); | ||
let AlgClass: alg.IAlgorithmBase = null; | ||
switch (_alg.name.toLowerCase()) { | ||
case rsa.RsaPKCS1.ALGORITHM_NAME.toLowerCase(): | ||
AlgClass = rsa.RsaPKCS1; | ||
break; | ||
case rsa.RsaPSS.ALGORITHM_NAME.toLowerCase(): | ||
AlgClass = rsa.RsaPSS; | ||
break; | ||
case rsa.RsaOAEP.ALGORITHM_NAME.toLowerCase(): | ||
AlgClass = rsa.RsaOAEP; | ||
break; | ||
case aes.AesGCM.ALGORITHM_NAME.toLowerCase(): | ||
AlgClass = aes.AesGCM; | ||
break; | ||
case aes.AesCBC.ALGORITHM_NAME.toLowerCase(): | ||
AlgClass = aes.AesCBC; | ||
break; | ||
case ec.Ecdsa.ALGORITHM_NAME.toLowerCase(): | ||
AlgClass = ec.Ecdsa; | ||
break; | ||
case ec.Ecdh.ALGORITHM_NAME.toLowerCase(): | ||
AlgClass = ec.Ecdh; | ||
break; | ||
default: | ||
throw new TypeError("Unsupported algorithm in use"); | ||
} | ||
AlgClass.generateKey(_alg, extractable, keyUsages, function(err, key) { | ||
if (err) | ||
reject(err); | ||
else | ||
resolve(key); | ||
let AlgClass: typeof BaseCrypto; | ||
switch (_alg.name.toLowerCase()) { | ||
case AlgorithmNames.RsaSSA.toLowerCase(): | ||
AlgClass = rsa.RsaPKCS1; | ||
break; | ||
case AlgorithmNames.RsaPSS.toLowerCase(): | ||
AlgClass = rsa.RsaPSS; | ||
break; | ||
case AlgorithmNames.EcDSA.toLowerCase(): | ||
AlgClass = ec.EcCrypto; | ||
break; | ||
default: | ||
throw new AlgorithmError(AlgorithmError.NOT_SUPPORTED, _alg.name); | ||
} | ||
return AlgClass.sign(_alg as any, key, _data); | ||
}); | ||
}); | ||
} | ||
sign(algorithm: iwc.AlgorithmType, key: CryptoKey, data: iwc.TBuffer): Promise { | ||
let that = this; | ||
let _data = prepare_data(data); | ||
verify(algorithm: string | RsaPssParams | EcdsaParams | AesCmacParams, key: CryptoKey, signature: NodeBufferSource, data: NodeBufferSource): PromiseLike<boolean>; | ||
verify(algorithm: any, key: CryptoKey, signature: NodeBufferSource, data: NodeBufferSource): PromiseLike<boolean> { | ||
return super.verify.apply(this, arguments) | ||
.then(() => { | ||
let _alg = PrepareAlgorithm(algorithm as string); | ||
let _signature = PrepareData(signature); | ||
let _data = PrepareData(data); | ||
return new Promise(function(resolve, reject) { | ||
let _alg = prepare_algorithm(algorithm); | ||
let AlgClass: alg.IAlgorithmBase = null; | ||
switch (_alg.name.toLowerCase()) { | ||
case rsa.RsaPKCS1.ALGORITHM_NAME.toLowerCase(): | ||
AlgClass = rsa.RsaPKCS1; | ||
break; | ||
case rsa.RsaPSS.ALGORITHM_NAME.toLowerCase(): | ||
AlgClass = rsa.RsaPSS; | ||
break; | ||
case ec.Ecdsa.ALGORITHM_NAME.toLowerCase(): | ||
AlgClass = ec.Ecdsa; | ||
break; | ||
default: | ||
throw new TypeError("Unsupported algorithm in use"); | ||
} | ||
AlgClass.sign(_alg, key, _data, function(err, sig) { | ||
if (err) | ||
reject(err); | ||
else | ||
resolve(new Uint8Array(sig).buffer); | ||
let AlgClass: typeof BaseCrypto; | ||
switch (_alg.name.toLowerCase()) { | ||
case AlgorithmNames.RsaSSA.toLowerCase(): | ||
AlgClass = rsa.RsaPKCS1; | ||
break; | ||
case AlgorithmNames.RsaPSS.toLowerCase(): | ||
AlgClass = rsa.RsaPSS; | ||
break; | ||
case AlgorithmNames.EcDSA.toLowerCase(): | ||
AlgClass = ec.EcCrypto; | ||
break; | ||
default: | ||
throw new AlgorithmError(AlgorithmError.NOT_SUPPORTED, _alg.name); | ||
} | ||
return AlgClass.verify(_alg as any, key, _signature, _data); | ||
}); | ||
}); | ||
} | ||
verify(algorithm: iwc.AlgorithmType, key: CryptoKey, signature: iwc.TBuffer, data: iwc.TBuffer): Promise { | ||
let that = this; | ||
let _signature = prepare_data(signature); | ||
let _data = prepare_data(data); | ||
encrypt(algorithm: string | RsaOaepParams | AesCtrParams | AesCbcParams | AesCmacParams | AesGcmParams | AesCfbParams, key: CryptoKey, data: NodeBufferSource): PromiseLike<ArrayBuffer>; | ||
encrypt(algorithm: any, key: CryptoKey, data: NodeBufferSource): PromiseLike<ArrayBuffer> { | ||
return super.encrypt.apply(this, arguments) | ||
.then(() => { | ||
let _alg = PrepareAlgorithm(algorithm); | ||
let _data = PrepareData(data); | ||
return new Promise(function(resolve, reject) { | ||
let _alg = prepare_algorithm(algorithm); | ||
let AlgClass: alg.IAlgorithmBase = null; | ||
switch (_alg.name.toLowerCase()) { | ||
case rsa.RsaPKCS1.ALGORITHM_NAME.toLowerCase(): | ||
AlgClass = rsa.RsaPKCS1; | ||
break; | ||
case rsa.RsaPSS.ALGORITHM_NAME.toLowerCase(): | ||
AlgClass = rsa.RsaPSS; | ||
break; | ||
case ec.Ecdsa.ALGORITHM_NAME.toLowerCase(): | ||
AlgClass = ec.Ecdsa; | ||
break; | ||
default: | ||
throw new TypeError("Unsupported algorithm in use"); | ||
} | ||
AlgClass.verify(_alg, key, _signature, _data, function(err, valid) { | ||
if (err) | ||
reject(err); | ||
else | ||
resolve(valid); | ||
let AlgClass: typeof BaseCrypto; | ||
switch (_alg.name.toLowerCase()) { | ||
case AlgorithmNames.RsaOAEP.toLowerCase(): | ||
AlgClass = rsa.RsaOAEP; | ||
break; | ||
case AlgorithmNames.AesCBC.toLowerCase(): | ||
case AlgorithmNames.AesGCM.toLowerCase(): | ||
AlgClass = aes.AesCrypto; | ||
break; | ||
default: | ||
throw new AlgorithmError(AlgorithmError.NOT_SUPPORTED, _alg.name); | ||
} | ||
return AlgClass.encrypt(_alg, key, _data); | ||
}); | ||
}); | ||
} | ||
encrypt(algorithm: iwc.AlgorithmType, key: CryptoKey, data: iwc.TBuffer): Promise { | ||
let that = this; | ||
let _data = prepare_data(data); | ||
decrypt(algorithm: string | RsaOaepParams | AesCtrParams | AesCbcParams | AesCmacParams | AesGcmParams | AesCfbParams, key: CryptoKey, data: NodeBufferSource): PromiseLike<ArrayBuffer>; | ||
decrypt(algorithm: any, key: CryptoKey, data: NodeBufferSource): PromiseLike<ArrayBuffer> { | ||
return super.decrypt.apply(this, arguments) | ||
.then(() => { | ||
let _alg = PrepareAlgorithm(algorithm); | ||
let _data = PrepareData(data); | ||
return new Promise(function(resolve, reject) { | ||
let _alg = prepare_algorithm(algorithm); | ||
let AlgClass: alg.IAlgorithmBase = null; | ||
switch (_alg.name.toLowerCase()) { | ||
case rsa.RsaOAEP.ALGORITHM_NAME.toLowerCase(): | ||
AlgClass = rsa.RsaOAEP; | ||
break; | ||
case aes.AesGCM.ALGORITHM_NAME.toLowerCase(): | ||
AlgClass = aes.AesGCM; | ||
break; | ||
case aes.AesCBC.ALGORITHM_NAME.toLowerCase(): | ||
AlgClass = aes.AesCBC; | ||
break; | ||
default: | ||
throw new TypeError("Unsupported algorithm in use"); | ||
} | ||
AlgClass.encrypt(_alg, key, _data, function(err, buf) { | ||
if (err) | ||
reject(err); | ||
else | ||
resolve(new Uint8Array(buf).buffer); | ||
let AlgClass: typeof BaseCrypto; | ||
switch (_alg.name.toLowerCase()) { | ||
case AlgorithmNames.RsaOAEP.toLowerCase(): | ||
AlgClass = rsa.RsaOAEP; | ||
break; | ||
case AlgorithmNames.AesCBC.toLowerCase(): | ||
case AlgorithmNames.AesGCM.toLowerCase(): | ||
AlgClass = aes.AesCrypto; | ||
break; | ||
default: | ||
throw new AlgorithmError(AlgorithmError.NOT_SUPPORTED, _alg.name); | ||
} | ||
return AlgClass.decrypt(_alg, key, _data); | ||
}); | ||
}); | ||
} | ||
decrypt(algorithm: iwc.AlgorithmType, key: CryptoKey, data: iwc.TBuffer): Promise { | ||
let that = this; | ||
let _data = prepare_data(data); | ||
return new Promise(function(resolve, reject) { | ||
let _alg = prepare_algorithm(algorithm); | ||
let AlgClass: alg.IAlgorithmBase = null; | ||
switch (_alg.name.toLowerCase()) { | ||
case rsa.RsaOAEP.ALGORITHM_NAME.toLowerCase(): | ||
AlgClass = rsa.RsaOAEP; | ||
break; | ||
case aes.AesGCM.ALGORITHM_NAME.toLowerCase(): | ||
AlgClass = aes.AesGCM; | ||
break; | ||
case aes.AesCBC.ALGORITHM_NAME.toLowerCase(): | ||
AlgClass = aes.AesCBC; | ||
break; | ||
default: | ||
throw new TypeError("Unsupported algorithm in use"); | ||
} | ||
AlgClass.decrypt(_alg, key, _data, function(err, buf) { | ||
if (err) | ||
reject(err); | ||
else | ||
resolve(new Uint8Array(buf).buffer); | ||
wrapKey(format: string, key: CryptoKey, wrappingKey: CryptoKey, wrapAlgorithm: AlgorithmIdentifier): PromiseLike<ArrayBuffer> { | ||
return super.wrapKey.apply(this, arguments) | ||
.then(() => { | ||
return this.exportKey(format as any, key) | ||
.then(exportedKey => { | ||
let _data: Buffer; | ||
if (!(exportedKey instanceof ArrayBuffer)) { | ||
_data = new Buffer(JSON.stringify(exportedKey)); | ||
} | ||
else { | ||
_data = new Buffer(exportedKey); | ||
} | ||
return this.encrypt(wrapAlgorithm, wrappingKey, _data); | ||
}); | ||
}); | ||
}); | ||
} | ||
wrapKey(format: string, key: CryptoKey, wrappingKey: CryptoKey, algorithm: iwc.IAlgorithmIdentifier): Promise { | ||
let that = this; | ||
return new Promise(function(resolve, reject) { | ||
let _alg = prepare_algorithm(algorithm); | ||
let AlgClass: alg.IAlgorithmBase = null; | ||
switch (_alg.name.toLowerCase()) { | ||
case rsa.RsaOAEP.ALGORITHM_NAME.toLowerCase(): | ||
AlgClass = rsa.RsaOAEP; | ||
break; | ||
case aes.AesGCM.ALGORITHM_NAME.toLowerCase(): | ||
AlgClass = aes.AesGCM; | ||
break; | ||
case aes.AesCBC.ALGORITHM_NAME.toLowerCase(): | ||
AlgClass = aes.AesCBC; | ||
break; | ||
default: | ||
throw new TypeError("Unsupported algorithm in use"); | ||
} | ||
AlgClass.wrapKey(key, wrappingKey, _alg, function(err, buf) { | ||
if (err) | ||
reject(err); | ||
else | ||
resolve(new Uint8Array(buf).buffer); | ||
unwrapKey(format: string, wrappedKey: NodeBufferSource, unwrappingKey: CryptoKey, unwrapAlgorithm: AlgorithmIdentifier, unwrappedKeyAlgorithm: AlgorithmIdentifier, extractable: boolean, keyUsages: string[]): PromiseLike<CryptoKey> { | ||
return super.unwrapKey.apply(this, arguments) | ||
.then(() => { | ||
return Promise.resolve() | ||
.then(() => { | ||
return this.decrypt(unwrapAlgorithm, unwrappingKey, wrappedKey); | ||
}) | ||
.then(decryptedKey => { | ||
let keyData: JsonWebKey | Buffer; | ||
if (format === "jwk") { | ||
keyData = JSON.parse(new Buffer(decryptedKey).toString()); | ||
} | ||
else { | ||
keyData = new Buffer(decryptedKey); | ||
} | ||
return this.importKey(format as any, keyData as Buffer, unwrappedKeyAlgorithm, extractable, keyUsages); | ||
}); | ||
}); | ||
}); | ||
} | ||
unwrapKey(format: string, wrappedKey: iwc.TBuffer, unwrappingKey: CryptoKey, unwrapAlgorithm: iwc.IAlgorithmIdentifier, unwrappedAlgorithm: iwc.IAlgorithmIdentifier, extractable: boolean, keyUsages: string[]): Promise { | ||
let that = this; | ||
let _wrappedKey = prepare_data(wrappedKey); | ||
deriveKey(algorithm: string | EcdhKeyDeriveParams | DhKeyDeriveParams | ConcatParams | HkdfCtrParams | Pbkdf2Params, baseKey: CryptoKey, derivedKeyType: string | AesDerivedKeyParams | HmacImportParams | ConcatParams | HkdfCtrParams | Pbkdf2Params, extractable: boolean, keyUsages: string[]): PromiseLike<CryptoKey>; | ||
deriveKey(algorithm: any, baseKey: CryptoKey, derivedKeyType: any, extractable: boolean, keyUsages: string[]): PromiseLike<CryptoKey> { | ||
return super.deriveKey.apply(this, arguments) | ||
.then(() => { | ||
let _algorithm = PrepareAlgorithm(algorithm); | ||
let _derivedKeyType = PrepareAlgorithm(derivedKeyType); | ||
return new Promise(function(resolve, reject) { | ||
let _alg1 = prepare_algorithm(unwrapAlgorithm); | ||
let _alg2 = prepare_algorithm(unwrappedAlgorithm); | ||
let AlgClass: alg.IAlgorithmBase = null; | ||
switch (_alg1.name.toLowerCase()) { | ||
case rsa.RsaOAEP.ALGORITHM_NAME.toLowerCase(): | ||
AlgClass = rsa.RsaOAEP; | ||
break; | ||
case aes.AesGCM.ALGORITHM_NAME.toLowerCase(): | ||
AlgClass = aes.AesGCM; | ||
break; | ||
case aes.AesCBC.ALGORITHM_NAME.toLowerCase(): | ||
AlgClass = aes.AesCBC; | ||
break; | ||
default: | ||
throw new TypeError("Unsupported algorithm in use"); | ||
} | ||
AlgClass.unwrapKey(_wrappedKey, unwrappingKey, _alg1, _alg2, extractable, keyUsages, function(err, key) { | ||
if (err) | ||
reject(err); | ||
else | ||
resolve(key); | ||
let AlgClass: typeof BaseCrypto; | ||
switch (_algorithm.name.toLowerCase()) { | ||
case AlgorithmNames.EcDH.toLowerCase(): | ||
AlgClass = ec.EcCrypto; | ||
break; | ||
default: | ||
throw new AlgorithmError(AlgorithmError.NOT_SUPPORTED, _algorithm.name); | ||
} | ||
return AlgClass.deriveKey(_algorithm as any, baseKey, _derivedKeyType, extractable, keyUsages); | ||
}); | ||
}); | ||
} | ||
deriveKey(algorithm: iwc.IAlgorithmIdentifier, baseKey: CryptoKey, derivedKeyType: iwc.IAlgorithmIdentifier, extractable: boolean, keyUsages: string[]): Promise { | ||
let that = this; | ||
deriveBits(algorithm: string | EcdhKeyDeriveParams | DhKeyDeriveParams | ConcatParams | HkdfCtrParams | Pbkdf2Params, baseKey: CryptoKey, length: number): PromiseLike<ArrayBuffer>; | ||
deriveBits(algorithm: any, baseKey: CryptoKey, length: number): PromiseLike<ArrayBuffer> { | ||
return super.deriveBits.apply(this, arguments) | ||
.then(() => { | ||
let _algorithm = PrepareAlgorithm(algorithm); | ||
return new Promise(function(resolve, reject) { | ||
let _alg1 = prepare_algorithm(algorithm); | ||
let _alg2 = prepare_algorithm(derivedKeyType); | ||
let AlgClass: alg.IAlgorithmBase = null; | ||
switch (_alg1.name.toLowerCase()) { | ||
case ec.Ecdh.ALGORITHM_NAME.toLowerCase(): | ||
AlgClass = ec.Ecdh; | ||
break; | ||
default: | ||
throw new TypeError("Unsupported algorithm in use"); | ||
} | ||
AlgClass.deriveKey(algorithm, baseKey, derivedKeyType, extractable, keyUsages, function(err, key) { | ||
if (err) | ||
reject(err); | ||
else | ||
resolve(key); | ||
let AlgClass: typeof BaseCrypto; | ||
switch (_algorithm.name.toLowerCase()) { | ||
case AlgorithmNames.EcDH.toLowerCase(): | ||
AlgClass = ec.EcCrypto; | ||
break; | ||
default: | ||
throw new AlgorithmError(AlgorithmError.NOT_SUPPORTED, _algorithm.name); | ||
} | ||
return AlgClass.deriveBits(_algorithm as any, baseKey, length); | ||
}); | ||
}); | ||
} | ||
exportKey(format: string, key: CryptoKey): Promise { | ||
let that = this; | ||
return new Promise(function(resolve, reject) { | ||
let KeyClass; | ||
switch (key.algorithm.name) { | ||
case rsa.RsaPKCS1.ALGORITHM_NAME: | ||
KeyClass = rsa.RsaPKCS1; | ||
break; | ||
case rsa.RsaOAEP.ALGORITHM_NAME: | ||
KeyClass = rsa.RsaOAEP; | ||
break; | ||
case aes.AesCBC.ALGORITHM_NAME: | ||
KeyClass = aes.AesCBC; | ||
break; | ||
case aes.AesGCM.ALGORITHM_NAME: | ||
KeyClass = aes.AesGCM; | ||
break; | ||
case ec.Ecdsa.ALGORITHM_NAME: | ||
KeyClass = ec.Ecdsa; | ||
break; | ||
case ec.Ecdh.ALGORITHM_NAME: | ||
KeyClass = ec.Ecdh; | ||
break; | ||
default: | ||
throw new Error(`ExportKey: Unsupported algorithm ${key.algorithm.name}`); | ||
} | ||
KeyClass.exportKey(format.toLocaleLowerCase(), key, function(err, data) { | ||
if (err) | ||
reject(err); | ||
else | ||
if (Buffer.isBuffer(data)) { | ||
let ubuf = new Uint8Array(<any>data); | ||
resolve(ubuf.buffer); | ||
} | ||
else | ||
resolve(data); | ||
exportKey(format: "jwk", key: CryptoKey): PromiseLike<JsonWebKey>; | ||
exportKey(format: "raw" | "pkcs8" | "spki", key: CryptoKey): PromiseLike<ArrayBuffer>; | ||
exportKey(format: string, key: CryptoKey): PromiseLike<JsonWebKey | ArrayBuffer>; | ||
exportKey(format: string, key: CryptoKey): PromiseLike<JsonWebKey | ArrayBuffer> { | ||
return super.exportKey.apply(this, arguments) | ||
.then(() => { | ||
let AlgClass: typeof BaseCrypto; | ||
switch (key.algorithm.name.toLowerCase()) { | ||
case AlgorithmNames.RsaSSA.toLowerCase(): | ||
AlgClass = rsa.RsaPKCS1; | ||
break; | ||
case AlgorithmNames.RsaPSS.toLowerCase(): | ||
AlgClass = rsa.RsaPSS; | ||
break; | ||
case AlgorithmNames.RsaOAEP.toLowerCase(): | ||
AlgClass = rsa.RsaOAEP; | ||
break; | ||
case AlgorithmNames.AesCBC.toLowerCase(): | ||
case AlgorithmNames.AesGCM.toLowerCase(): | ||
AlgClass = aes.AesCrypto; | ||
break; | ||
case AlgorithmNames.EcDSA.toLowerCase(): | ||
case AlgorithmNames.EcDH.toLowerCase(): | ||
AlgClass = ec.EcCrypto; | ||
break; | ||
default: | ||
throw new AlgorithmError(AlgorithmError.NOT_SUPPORTED, key.algorithm.name); | ||
} | ||
return AlgClass.exportKey(format, key); | ||
}); | ||
}); | ||
} | ||
importKey( | ||
format: string, | ||
keyData: iwc.TBuffer, | ||
algorithm: iwc.IAlgorithmIdentifier, | ||
extractable: boolean, | ||
keyUsages: string[] | ||
): Promise { | ||
return new Promise(function(resolve, reject) { | ||
let _alg = prepare_algorithm(algorithm); | ||
let _data = prepare_data(keyData); | ||
importKey(format: "jwk", keyData: JsonWebKey, algorithm: string | RsaHashedImportParams | EcKeyImportParams | HmacImportParams | DhImportKeyParams, extractable: boolean, keyUsages: string[]): PromiseLike<CryptoKey>; | ||
importKey(format: "raw" | "pkcs8" | "spki", keyData: NodeBufferSource, algorithm: string | RsaHashedImportParams | EcKeyImportParams | HmacImportParams | DhImportKeyParams, extractable: boolean, keyUsages: string[]): PromiseLike<CryptoKey>; | ||
importKey(format: string, keyData: JsonWebKey | NodeBufferSource, algorithm: string | RsaHashedImportParams | EcKeyImportParams | HmacImportParams | DhImportKeyParams, extractable: boolean, keyUsages: string[]): PromiseLike<CryptoKey>; | ||
importKey(format: string, keyData: JsonWebKey | NodeBufferSource, algorithm: any, extractable: boolean, keyUsages: string[]): PromiseLike<CryptoKey> { | ||
return super.importKey.apply(this, arguments) | ||
.then(() => { | ||
let _alg = PrepareAlgorithm(algorithm as string); | ||
let AlgClass: alg.IAlgorithmBase = null; | ||
switch (_alg.name.toLowerCase()) { | ||
case rsa.RsaPKCS1.ALGORITHM_NAME.toLowerCase(): | ||
AlgClass = rsa.RsaPKCS1; | ||
break; | ||
case rsa.RsaOAEP.ALGORITHM_NAME.toLowerCase(): | ||
AlgClass = rsa.RsaOAEP; | ||
break; | ||
case ec.Ecdsa.ALGORITHM_NAME.toLowerCase(): | ||
AlgClass = ec.Ecdsa; | ||
break; | ||
case ec.Ecdh.ALGORITHM_NAME.toLowerCase(): | ||
AlgClass = ec.Ecdh; | ||
break; | ||
case aes.AesCBC.ALGORITHM_NAME.toLowerCase(): | ||
AlgClass = aes.AesCBC; | ||
break; | ||
case aes.AesGCM.ALGORITHM_NAME.toLowerCase(): | ||
AlgClass = aes.AesGCM; | ||
break; | ||
default: | ||
throw new TypeError("Unsupported algorithm in use"); | ||
} | ||
if (format.toLocaleLowerCase() === "jwk") { | ||
if (Buffer.isBuffer(keyData)) { | ||
throw new Error("ImportKey: keydData must be Object"); | ||
let _data = keyData; | ||
if (format !== "jwk") { | ||
_data = PrepareData(_data as NodeBufferSource); | ||
} | ||
// copy input object | ||
let cpy = {}; | ||
for (let i in _data) { | ||
cpy[i] = _data[i]; | ||
let AlgClass: typeof BaseCrypto; | ||
switch (_alg.name.toLowerCase()) { | ||
case AlgorithmNames.RsaSSA.toLowerCase(): | ||
AlgClass = rsa.RsaPKCS1; | ||
break; | ||
case AlgorithmNames.RsaPSS.toLowerCase(): | ||
AlgClass = rsa.RsaPSS; | ||
break; | ||
case AlgorithmNames.RsaOAEP.toLowerCase(): | ||
AlgClass = rsa.RsaOAEP; | ||
break; | ||
case AlgorithmNames.AesCBC.toLowerCase(): | ||
case AlgorithmNames.AesGCM.toLowerCase(): | ||
AlgClass = aes.AesCrypto; | ||
break; | ||
case AlgorithmNames.EcDSA.toLowerCase(): | ||
case AlgorithmNames.EcDH.toLowerCase(): | ||
AlgClass = ec.EcCrypto; | ||
break; | ||
default: | ||
throw new AlgorithmError(AlgorithmError.NOT_SUPPORTED, _alg.name); | ||
} | ||
_data = <any>cpy; | ||
} | ||
AlgClass.importKey(format.toLocaleLowerCase(), _data, _alg, extractable, keyUsages, function(err, key) { | ||
if (err) | ||
reject(err); | ||
else | ||
resolve(key); | ||
return AlgClass.importKey(format, _data, _alg, extractable, keyUsages); | ||
}); | ||
}); | ||
} | ||
} |
@@ -1,12 +0,29 @@ | ||
import * as iwc from "./iwebcrypto"; | ||
// Core | ||
import * as webcrypto from "webcrypto-core"; | ||
// Local | ||
import * as subtle from "./subtle"; | ||
import * as crypto from "crypto"; | ||
import {KeyStorage} from "./key_storage"; | ||
// Fix btoa and atob for NodeJS | ||
let _global = global as any; | ||
_global.btoa = (data: string) => new Buffer(data, "binary").toString("base64"); | ||
_global.atob = (data: string) => new Buffer(data, "base64").toString("binary"); | ||
const ERR_RANDOM_VALUE_LENGTH = "Failed to execute 'getRandomValues' on 'Crypto': The ArrayBufferView's byte length (%1) exceeds the number of bytes of entropy available via this API (65536)."; | ||
export interface WebCryptoOptions { | ||
directory?: string; | ||
} | ||
/** | ||
* PKCS11 with WebCrypto Interface | ||
* OpenSSL with WebCrypto Interface | ||
*/ | ||
export default class WebCrypto implements iwc.IWebCrypto { | ||
class WebCrypto implements NativeCrypto { | ||
keyStorage: KeyStorage; | ||
public subtle: iwc.ISubtleCrypto = null; | ||
subtle: SubtleCrypto; | ||
@@ -17,4 +34,14 @@ /** | ||
*/ | ||
getRandomValues(array): any { | ||
return crypto.randomBytes(array.byteLength); | ||
// Based on: https://github.com/KenanY/get-random-values | ||
getRandomValues(array: NodeBufferSource): NodeBufferSource; | ||
getRandomValues(array: ArrayBufferView): ArrayBufferView; | ||
getRandomValues(array: NodeBufferSource): NodeBufferSource { | ||
if (array.byteLength > 65536) { | ||
let error = new webcrypto.WebCryptoError(ERR_RANDOM_VALUE_LENGTH, array.byteLength); | ||
error.code = 22; | ||
throw error; | ||
} | ||
let bytes = crypto.randomBytes(array.byteLength); | ||
(array as Uint8Array).set(bytes); | ||
return array; | ||
} | ||
@@ -25,5 +52,8 @@ | ||
*/ | ||
constructor() { | ||
constructor(options?: WebCryptoOptions) { | ||
this.subtle = new subtle.SubtleCrypto(); | ||
if (options && options.directory) | ||
this.keyStorage = new KeyStorage(options.directory); | ||
} | ||
} | ||
} | ||
module.exports = WebCrypto; |
{ | ||
"name": "node-webcrypto-ossl", | ||
"version": "1.0.11", | ||
"description": "", | ||
"version": "1.0.12", | ||
"repository": { | ||
"type": "git", | ||
"url": "https://github.com/PeculiarVentures/node-webcrypto-ossl.git" | ||
}, | ||
"description": "A WebCrypto Polyfill for Node in TypeScript built on OpenSSL", | ||
"main": "buildjs/webcrypto.js", | ||
"types": "index.d.ts", | ||
"scripts": { | ||
"clean": "rm -rf build/ buildjs/ coverage/ .nyc_output/ npm-debug.log npm-debug.log.*", | ||
"prepublish": "npm run build", | ||
"postinstall": "npm run build", | ||
"pretest": "npm run build:source", | ||
"test": "mocha", | ||
"install": "tsd install && tsc && node-gyp rebuild" | ||
"build": "npm run build:es5", | ||
"build:es5": "tsc", | ||
"build:source": "tsc --sourceMap", | ||
"build:es2015": "tsc --module es2015 --target es2015", | ||
"pub": "npm version patch && npm publish && git push", | ||
"sync": "git ac && git pull --rebase && git push", | ||
"coverage": "nyc npm test", | ||
"precoveragehtml": "npm run coverage", | ||
"coveragehtml": "nyc report -r html", | ||
"watch": "watch 'npm run coveragehtml' lib/ src/ test/", | ||
"live": "live-server -q --port=4005 --ignorePattern='(js|css|png)$' coverage", | ||
"predev": "if [ ! -f coverage/index.html ]; then mkdir coverage; cp .waiting.html coverage/index.html; fi", | ||
"dev": "npm-run-all -p --silent watch live", | ||
"coveralls": "nyc report --reporter=text-lcov | coveralls" | ||
}, | ||
@@ -13,16 +35,26 @@ "author": "PeculiarVentures", | ||
"keywords": [ | ||
"crypto", | ||
"openssl", | ||
"webcrypto", | ||
"rsa", | ||
"aes", | ||
"ec", | ||
"jwk", | ||
"polyfill" | ||
"crypto", | ||
"openssl", | ||
"webcrypto", | ||
"rsa", | ||
"aes", | ||
"ec", | ||
"jwk", | ||
"polyfill" | ||
], | ||
"dependencies": { | ||
"base64url": "^1.0.5", | ||
"mocha": "^2.3.4", | ||
"nan": "2.1.0" | ||
"@types/node": "^6.0.45", | ||
"@types/mkdirp": "^0.3.29", | ||
"mkdirp": "^0.5.1", | ||
"nan": "^2.4.0", | ||
"webcrypto-core": "git+https://github.com/PeculiarVentures/webcrypto-core#types" | ||
}, | ||
"devDependencies": { | ||
"live-server": "^1", | ||
"mocha": "^3", | ||
"npm-run-all": "^3", | ||
"nyc": "^8", | ||
"typescript": "^2.0.3", | ||
"watch": "^0" | ||
} | ||
} |
# node-webcrypto-ossl | ||
[![license](https://img.shields.io/badge/license-MIT-green.svg?style=flat)](https://raw.githubusercontent.com/PeculiarVentures/node-webcrypto-ossl/master/LICENSE) | ||
[![License](https://img.shields.io/badge/license-MIT-green.svg?style=flat)](https://raw.githubusercontent.com/PeculiarVentures/node-webcrypto-ossl/master/LICENSE) | ||
[![Build Status](https://travis-ci.org/PeculiarVentures/node-webcrypto-ossl.svg?branch=master)](https://travis-ci.org/PeculiarVentures/node-webcrypto-ossl) | ||
[![Coverage Status](https://coveralls.io/repos/github/PeculiarVentures/node-webcrypto-ossl/badge.svg?branch=master)](https://coveralls.io/github/PeculiarVentures/node-webcrypto-ossl?branch=master) | ||
[![NPM version](https://badge.fury.io/js/node-webcrypto-ossl.png)](http://badge.fury.io/js/node-webcrypto-ossl) | ||
@@ -35,11 +38,2 @@ We wanted to be able to write Javascript that used crypto on both the client and the server but we did not want to rely on Javascript implementations of crypto. The only native cryptography availible in browser is [Web Crypto](caniuse.com/#search=cryptography), this resulted in us creating a `node-webcrypto-ossl` a native polyfil for WebCrypto based on Openssl. | ||
### Install Dependencies | ||
``` | ||
npm install node-gyp -g | ||
npm install typescript -g | ||
npm install tsd -g | ||
npm install mocha -g | ||
``` | ||
### Install | ||
@@ -57,2 +51,45 @@ | ||
## KeyStorage | ||
To use KeyStorage you shoud init WebCrypto with `directory` option. If `directory` option is missing then `keyStorage` is `null` | ||
```javascript | ||
var WebCrypto = require("node-webcrypto-ossl"); | ||
var webcrypto = new WebCrypto({ | ||
directory: "key_storage" | ||
}) | ||
``` | ||
KeyStorage implements interface of [W3 Storage](https://developer.mozilla.org/en-US/docs/Web/API/Storage) | ||
```javascript | ||
var keyStorage = webcrypto.keyStorage; | ||
// generating RSA key | ||
webcrypto.subtle.generateKey({ | ||
name: "RSASSA-PKCS1-v1_5", | ||
modulusLength: 1024, | ||
publicExponent: new Uint8Array([1, 0, 1]), | ||
hash: { | ||
name: "SHA-1" | ||
} | ||
}, | ||
false, | ||
["sign", "verify"] | ||
) | ||
.then(function(keyPairs){ | ||
/** | ||
* saving private RSA key to KeyStorage | ||
* creates file ./key_storage/prvRSA-1024.json | ||
*/ | ||
keyStorage.setItem("prvRSA-1024", keyPairs.privateKey); | ||
}) | ||
``` | ||
To get key from KeyStorage | ||
```javascript | ||
var rsaKey = webcrypto.getItem("prvRSA-1024"); | ||
``` | ||
## Threat Model | ||
@@ -68,3 +105,3 @@ | ||
TODO: ADD THREATS FROM HANCOCK SERVICE COMPROMISE | ||
TODO: ADD THREATS FROM NODE-WEBCRYPTO-OSSL DEFECT | ||
@@ -81,3 +118,3 @@ ### Threats From Weak Cryptography | ||
## Bug Reporting | ||
Please report bugs either as pull requests or as issues in the issue tracker. Backwater has a full disclosure vulnerability policy. Please do NOT attempt to report any security vulnerability in this code privately to anybody. | ||
Please report bugs either as pull requests or as issues in the issue tracker. node-webcrypto-ossl has a full disclosure vulnerability policy. Please do NOT attempt to report any security vulnerability in this code privately to anybody. | ||
@@ -87,5 +124,5 @@ | ||
- [node-webcrypto-p11](https://github.com/PeculiarVentures/node-webcrypto-p11) | ||
- [MSR WebCrypto Polyfill](http://research.microsoft.com/en-us/downloads/29f9385d-da4c-479a-b2ea-2a7bb335d727/) | ||
- [webcrypto-liner](https://github.com/PeculiarVentures/webcrypto-liner) | ||
- [WebCrypto Examples](https://github.com/diafygi/webcrypto-examples) | ||
- [OpenSSL](https://github.com/openssl/openssl) | ||
- [WebCrypto Examples](https://github.com/diafygi/webcrypto-examples) | ||
- [OpenSSL AES GCM encrypt/decrypt](https://wiki.openssl.org/index.php/EVP_Authenticated_Encryption_and_Decryption) |
398
test/aes.js
var assert = require('assert'); | ||
var webcrypto = require('./config'); | ||
var keys = []; | ||
describe("WebCrypto Aes", function () { | ||
var TEST_MESSAGE = new Buffer("12345678901234561234567890123456"); | ||
var TEST_MESSAGE = new Buffer("1234567890123456"); | ||
var KEYS = [ | ||
{ alg: "AES-CBC", usages: ["encrypt", "decrypt", "wrapKey", "unwrapKey"] }, | ||
{ alg: "AES-GCM", usages: ["encrypt", "decrypt", "wrapKey", "unwrapKey"] }, | ||
]; | ||
before(function (done) { | ||
done(); | ||
}) | ||
context("Generate key", () => { | ||
it("Aes CBC", function (done) { | ||
var key = null; | ||
var iv = webcrypto.getRandomValues(new Uint8Array(16)); | ||
webcrypto.subtle.generateKey({ | ||
name: "AES-CBC", | ||
length: 256, //can be 128, 192, or 256 | ||
}, | ||
false, //whether the key is extractable (i.e. can be used in exportKey) | ||
["encrypt", "decrypt"] //can "encrypt", "decrypt", "wrapKey", or "unwrapKey" | ||
) | ||
.then(function (k) { | ||
assert.equal(k.key !== null, true, "Has no key value"); | ||
key = k; | ||
// Algs | ||
KEYS.forEach(key => { | ||
// length | ||
[128, 192, 256].forEach(length => { | ||
var keyName = `${key.alg} l:${length}`; | ||
var keyTemplate = { | ||
name: keyName, | ||
key: null, | ||
usages: key.usages, | ||
}; | ||
keys.push(keyTemplate); | ||
it(keyName, done => { | ||
var alg = { | ||
name: key.alg, | ||
length: length | ||
}; | ||
webcrypto.subtle.generateKey(alg, true, key.usages) | ||
.then(aesKey => { | ||
assert.equal(!!aesKey, true, "Aes key is empty"); | ||
keyTemplate.key = aesKey; | ||
}) | ||
.then(done, done); | ||
}); | ||
}); | ||
}) | ||
return webcrypto.subtle.encrypt( | ||
{ | ||
name: "AES-CBC", | ||
}); | ||
//Don't re-use initialization vectors! | ||
//Always generate a new iv every time your encrypt! | ||
iv: iv | ||
}, | ||
key, //from generateKey or importKey above | ||
TEST_MESSAGE //ArrayBuffer of data you want to encrypt | ||
) | ||
}) | ||
.then(function (enc) { | ||
assert.equal(enc !== null, true, "Has no encrypted value"); | ||
assert.notEqual(enc.length, 0, "Has empty encrypted value"); | ||
return webcrypto.subtle.decrypt( | ||
{ | ||
name: "AES-CBC", | ||
iv: iv //The initialization vector you used to encrypt | ||
}, | ||
key, //from generateKey or importKey above | ||
enc //ArrayBuffer of the data | ||
); | ||
}) | ||
.then(function (dec) { | ||
var s = ""; | ||
var buf = new Uint8Array(dec); | ||
for (var i = 0; i < buf.length; i++) { | ||
s += String.fromCharCode(buf[i]); | ||
} | ||
assert.equal(s, TEST_MESSAGE.toString(), "AES-CBC encrypt/decrypt is not valid") | ||
}) | ||
.then(done, done); | ||
}) | ||
context("Encrypt/Decrypt", () => { | ||
it("Aes CBC JWK export/import", function (done) { | ||
var key = null; | ||
var _jwk; | ||
webcrypto.subtle.generateKey({ | ||
name: "AES-CBC", | ||
length: 256, //can be 128, 192, or 256 | ||
}, | ||
false, //whether the key is extractable (i.e. can be used in exportKey) | ||
["encrypt", "decrypt"] //can "encrypt", "decrypt", "wrapKey", or "unwrapKey" | ||
) | ||
.then(function (k) { | ||
assert.equal(k.key !== null, true, "Has no key value"); | ||
key = k; | ||
context("AES-CBC", () => { | ||
return webcrypto.subtle.exportKey("jwk", key); | ||
}) | ||
.then(function (jwk) { | ||
assert.equal(jwk != null, true, "Has no JWK secretKey"); | ||
assert.equal(jwk.k !== null, true, "Wrong JWK key param"); | ||
assert.equal(jwk.key_ops.length === 4, true, "Wrong JWK key usages amount"); | ||
assert.equal(jwk.alg === "A256CBC", true, "Wrong JWK key algorithm"); | ||
assert.equal(jwk.kty === "oct", true, "Wrong JWK key type"); | ||
assert.equal(jwk.ext, true, "Wrong JWK key extractable"); | ||
_jwk = jwk; | ||
return webcrypto.subtle.importKey( | ||
"jwk", | ||
jwk, | ||
{ | ||
name: "AES-CBC" | ||
}, | ||
true, | ||
["encrypt", "decrypt"] | ||
); | ||
}) | ||
.then(function (k) { | ||
assert.equal(k.type === "secret", true, "Key is not Secret"); | ||
assert.equal(k.algorithm.name === "AES-CBC", true, "Key is not AES-CBC"); | ||
key = k; | ||
return webcrypto.subtle.exportKey("jwk", k) | ||
}) | ||
.then(function (jwk) { | ||
assert.equal(jwk != null, true, "Has no JWK secretKey"); | ||
assert.equal(jwk.k === _jwk.k, true, "Wrong JWK key param"); | ||
}) | ||
.then(done, done); | ||
}) | ||
// Filter CBC | ||
keys.filter(key => /AES-CBC/.test(key.name)) | ||
.forEach(key => { | ||
[new Uint8Array(16), new Uint8Array(16)].forEach(iv => { | ||
it(`iv:${iv.length}\t${key.name}`, done => { | ||
var alg = { name: "AES-CBC", iv: iv }; | ||
webcrypto.subtle.encrypt(alg, key.key, TEST_MESSAGE) | ||
.then(enc => { | ||
assert(!!enc, true, "Encrypted message is empty"); | ||
return webcrypto.subtle.decrypt(alg, key.key, enc); | ||
}) | ||
.then(dec => { | ||
assert(new Buffer(dec).toString(), TEST_MESSAGE.toString(), "Decrypted message is wrong"); | ||
}) | ||
.then(done, done); | ||
}); | ||
}); | ||
}); | ||
}); | ||
it("Aes GCM", function (done) { | ||
var key = null; | ||
var iv = webcrypto.getRandomValues(new Uint8Array(12)); | ||
webcrypto.subtle.generateKey({ | ||
name: "AES-GCM", | ||
length: 256, //can be 128, 192, or 256 | ||
}, | ||
false, //whether the key is extractable (i.e. can be used in exportKey) | ||
["encrypt", "decrypt"] //can "encrypt", "decrypt", "wrapKey", or "unwrapKey" | ||
) | ||
.then(function (k) { | ||
assert.equal(k.key !== null, true, "Has no key value"); | ||
key = k; | ||
context("AES-GCM", () => { | ||
// Filter GCM | ||
keys.filter(key => /AES-GCM/.test(key.name)) | ||
.forEach(key => { | ||
// IV | ||
[new Uint8Array(16)].forEach(iv => { | ||
// AAD | ||
[new Uint8Array([1, 2, 3, 4, 5]), null].forEach(aad => { | ||
// Tag | ||
[32, 64, 96, 104, 112, 120, 128].forEach(tag => { | ||
it(`aad:${aad ? "+" : "-"} t:${tag}\t${key.name}`, done => { | ||
var alg = { name: "AES-GCM", iv: iv, aad: aad, tagLength: tag }; | ||
webcrypto.subtle.encrypt(alg, key.key, TEST_MESSAGE) | ||
.then(enc => { | ||
assert(!!enc, true, "Encrypted message is empty"); | ||
return webcrypto.subtle.decrypt(alg, key.key, enc); | ||
}) | ||
.then(dec => { | ||
assert(new Buffer(dec).toString(), TEST_MESSAGE.toString(), "Decrypted message is wrong"); | ||
}) | ||
.then(done, done); | ||
}); | ||
}); | ||
}); | ||
}); | ||
}); | ||
}); | ||
return webcrypto.subtle.encrypt( | ||
{ | ||
name: "AES-GCM", | ||
}); | ||
//Don't re-use initialization vectors! | ||
//Always generate a new iv every time your encrypt! | ||
iv: iv, | ||
//Additional authentication data (optional) | ||
additionalData: new Uint8Array([1, 2, 3, 4, 5, 6, 7, 8]).buffer, | ||
context("", () => { | ||
//Tag length (optional) | ||
tagLength: 128, //can be 32, 64, 96, 104, 112, 120 or 128 (default) | ||
}, | ||
key, //from generateKey or importKey above | ||
TEST_MESSAGE //ArrayBuffer of data you want to encrypt | ||
) | ||
}) | ||
.then(function (enc) { | ||
assert.equal(enc !== null, true, "Has no encrypted value"); | ||
assert.notEqual(enc.length, 0, "Has empty encrypted value"); | ||
return webcrypto.subtle.decrypt( | ||
{ | ||
name: "AES-GCM", | ||
iv: iv, //The initialization vector you used to encrypt | ||
//Additional authentication data (optional) | ||
additionalData: new Uint8Array([1, 2, 3, 4, 5, 6, 7, 8]).buffer, | ||
context("AES-CBC", () => { | ||
//Tag length (optional) | ||
tagLength: 128, //can be 32, 64, 96, 104, 112, 120 or 128 (default) | ||
}, | ||
key, //from generateKey or importKey above | ||
enc //ArrayBuffer of the data | ||
); | ||
}) | ||
.then(function (dec) { | ||
var s = ""; | ||
var buf = new Uint8Array(dec); | ||
for (var i = 0; i < buf.length; i++) { | ||
s += String.fromCharCode(buf[i]); | ||
} | ||
assert.equal(s, TEST_MESSAGE.toString(), "AES-GCM encrypt/decrypt is not valid") | ||
}) | ||
.then(done, done); | ||
}) | ||
// Filter CBC | ||
keys.filter(key => /AES-CBC/.test(key.name)) | ||
.forEach(key => { | ||
[new Uint8Array(16), new Uint8Array(16)].forEach(iv => { | ||
it(`iv:${iv.length}\t${key.name}`, done => { | ||
var alg = { name: "AES-CBC", iv: iv }; | ||
webcrypto.subtle.encrypt(alg, key.key, TEST_MESSAGE) | ||
.then(enc => { | ||
assert(!!enc, true, "Encrypted message is empty"); | ||
return webcrypto.subtle.decrypt(alg, key.key, enc); | ||
}) | ||
.then(dec => { | ||
assert(new Buffer(dec).toString(), TEST_MESSAGE.toString(), "Decrypted message is wrong"); | ||
}) | ||
.then(done, done); | ||
}); | ||
}); | ||
}); | ||
}); | ||
it("Aes GCM JWK export/import", function (done) { | ||
var key = null; | ||
var _jwk; | ||
webcrypto.subtle.generateKey({ | ||
name: "AES-GCM", | ||
length: 256, //can be 128, 192, or 256 | ||
}, | ||
false, //whether the key is extractable (i.e. can be used in exportKey) | ||
["encrypt", "decrypt"] //can "encrypt", "decrypt", "wrapKey", or "unwrapKey" | ||
) | ||
.then(function (k) { | ||
assert.equal(k.key !== null, true, "Has no key value"); | ||
key = k; | ||
context("AES-GCM", () => { | ||
// Filter GCM | ||
keys.filter(key => /AES-GCM/.test(key.name)) | ||
.forEach(key => { | ||
// IV | ||
[new Uint8Array(16)].forEach(iv => { | ||
// AAD | ||
[new Uint8Array([1, 2, 3, 4, 5]), null].forEach(aad => { | ||
// Tag | ||
[32, 64, 96, 104, 112, 120, 128].forEach(tag => { | ||
it(`aad:${aad ? "+" : "-"} t:${tag}\t${key.name}`, done => { | ||
var alg = { name: "AES-GCM", iv: iv, aad: aad, tagLength: tag }; | ||
webcrypto.subtle.encrypt(alg, key.key, TEST_MESSAGE) | ||
.then(enc => { | ||
assert(!!enc, true, "Encrypted message is empty"); | ||
return webcrypto.subtle.decrypt(alg, key.key, enc); | ||
}) | ||
.then(dec => { | ||
assert(new Buffer(dec).toString(), TEST_MESSAGE.toString(), "Decrypted message is wrong"); | ||
}) | ||
.then(done, done); | ||
}); | ||
}); | ||
}); | ||
}); | ||
}); | ||
}); | ||
return webcrypto.subtle.exportKey("jwk", key); | ||
}) | ||
.then(function (jwk) { | ||
assert.equal(jwk != null, true, "Has no JWK secretKey"); | ||
assert.equal(jwk.k !== null, true, "Wrong JWK key param"); | ||
assert.equal(jwk.key_ops.length === 4, true, "Wrong JWK key usages amount"); | ||
assert.equal(jwk.alg === "A256GCM", true, "Wrong JWK key algorithm"); | ||
assert.equal(jwk.kty === "oct", true, "Wrong JWK key type"); | ||
assert.equal(jwk.ext, true, "Wrong JWK key extractable"); | ||
_jwk = jwk; | ||
return webcrypto.subtle.importKey( | ||
"jwk", | ||
jwk, | ||
{ | ||
name: "AES-GCM" | ||
}, | ||
true, | ||
["encrypt", "decrypt"] | ||
); | ||
}) | ||
.then(function (k) { | ||
assert.equal(k.type === "secret", true, "Key is not Secret"); | ||
assert.equal(k.algorithm.name === "AES-GCM", true, "Key is not AES-CBC"); | ||
key = k; | ||
return webcrypto.subtle.exportKey("jwk", k) | ||
}) | ||
.then(function (jwk) { | ||
assert.equal(jwk != null, true, "Has no JWK secretKey"); | ||
assert.equal(jwk.k === _jwk.k, true, "Wrong JWK key param"); | ||
}) | ||
.then(done, done); | ||
}) | ||
}); | ||
context("Export/Import", () => { | ||
// Keys | ||
keys.forEach(key => { | ||
// Format | ||
["jwk", "raw"].forEach(format => { | ||
it(`${format}\t${key.name}`, done => { | ||
webcrypto.subtle.exportKey(format, key.key) | ||
.then(jwk => { | ||
assert.equal(!!jwk, true, "Has no jwk value"); | ||
if (format === "jwk") | ||
assert.equal(!!jwk.k, true, "Has no k value"); | ||
else | ||
assert.equal(!!jwk.byteLength, true, "Wrong raw length"); | ||
return webcrypto.subtle.importKey(format, jwk, key.key.algorithm, true, key.key.usages); | ||
}) | ||
.then(k => { | ||
assert.equal(!!k, true, "Imported key is empty") | ||
assert.equal(!!k.native_, true, "Has no native key value"); | ||
}) | ||
.then(done, done); | ||
}); | ||
}); | ||
}); | ||
}); | ||
context("Wrap/Unwrap", () => { | ||
context("AES-CBC", () => { | ||
// AES keys | ||
keys.filter(key => /AES-CBC/.test(key.name)).forEach(key => { | ||
["jwk", "raw"].forEach(format => { | ||
it(`format:${format} ${key.name}`, done => { | ||
var _alg = { name: "AES-CBC", iv: new Uint8Array(16) } | ||
webcrypto.subtle.wrapKey(format, key.key, key.key, _alg) | ||
.then(wrappedKey => { | ||
assert.equal(!!wrappedKey, true, "Wrapped key is empty"); | ||
return webcrypto.subtle.unwrapKey(format, wrappedKey, key.key, _alg, key.key.algorithm, true, ["encrypt", "decrypt"]); | ||
}) | ||
.then(key => { | ||
assert.equal(!!key, true, "Unwrapped key is empty"); | ||
}) | ||
.then(done, done); | ||
}) | ||
}); | ||
}); | ||
}); | ||
context("AES-GCM", () => { | ||
// AES keys | ||
keys.filter(key => /AES-GCM/.test(key.name)).forEach(key => { | ||
["jwk", "raw"].forEach(format => { | ||
it(`format:${format} ${key.name}`, done => { | ||
var _alg = { name: "AES-GCM", iv: new Uint8Array(16) } | ||
webcrypto.subtle.wrapKey(format, key.key, key.key, _alg) | ||
.then(wrappedKey => { | ||
assert.equal(!!wrappedKey, true, "Wrapped key is empty"); | ||
return webcrypto.subtle.unwrapKey(format, wrappedKey, key.key, _alg, key.key.algorithm, true, ["encrypt", "decrypt"]); | ||
}) | ||
.then(key => { | ||
assert.equal(!!key, true, "Unwrapped key is empty"); | ||
}) | ||
.then(done, done); | ||
}) | ||
}); | ||
}); | ||
}); | ||
}); | ||
}) |
@@ -1,3 +0,3 @@ | ||
var WebCrypto = require("../buildjs/webcrypto.js").default; | ||
var WebCrypto = require("../buildjs/webcrypto.js"); | ||
module.exports = new WebCrypto() | ||
module.exports = new WebCrypto({directory: "test_storage"}) |
599
test/ec.js
@@ -0,482 +1,147 @@ | ||
"use strict"; | ||
var assert = require('assert'); | ||
var crypto = require('crypto'); | ||
var webcrypto = require('./config'); | ||
var ecdsa_pkey_json_256 = '{"crv":"P-256","d":"yc_pdEqHhjMAk8w3Yq0yVmnlKYV1jBBo6ThVc5iJSqU","ext":true,"key_ops":["sign"],"kty":"EC","x":"e8iiCqQRobJkDVodjY8h6xxz812IU5wQD8OKthVjkxk","y":"3HHkboj5WFUjf-3P-UtxzIDnj71cfppEE0X-lDtIYXM"}'; | ||
var ecdsa_pubkey_json_256 = '{"crv":"P-256","ext":true,"key_ops":["verify"],"kty":"EC","x":"e8iiCqQRobJkDVodjY8h6xxz812IU5wQD8OKthVjkxk","y":"3HHkboj5WFUjf-3P-UtxzIDnj71cfppEE0X-lDtIYXM"}'; | ||
var ecdsa_signature_sha256 = "2hWEkyEDu1L8oM5Ty2hrz5fce1k3x7zbkBpTawW6sMZb4hhTmlT3GjMqWDs3i1zyE1b/miQMEoVhtc5+U7NTvA=="; | ||
//"MEUCIFoUVs/MlxKIge49fAsF3L/FJCyYJNc/Kqr/WnPZ2n7tAiEA0zNTXGFPRGVxBiNo+xWgjM6N/hMccnT+SmTBf8azhhQ=" | ||
describe("WebCrypto EC", () => { | ||
var ecdsa_pkey_json_384 = '{"crv":"P-384","d":"zWcBN2j49GfQioUrq1Im0Wph_UXExXPmsEUuY2oW-5EEaQAkL6L3HsBiWD6qwrRC","ext":true,"key_ops":["sign"],"kty":"EC","x":"lICjaouipTzjecKGqGtGsk7P7f5MkLWGmFl5MstedIkCttr9ow3fq77Dbb4aEWzS","y":"1dU_-FMuvl97crcufR11_p8BVu7LvcmjyO65gwDvSXGUtflwR101iOLMhvL2W490"}'; | ||
var ecdsa_pubkey_json_384 = '{"crv":"P-384","ext":true,"key_ops":["verify"],"kty":"EC","x":"lICjaouipTzjecKGqGtGsk7P7f5MkLWGmFl5MstedIkCttr9ow3fq77Dbb4aEWzS","y":"1dU_-FMuvl97crcufR11_p8BVu7LvcmjyO65gwDvSXGUtflwR101iOLMhvL2W490"}'; | ||
var ecdsa_signature_384_sha256 = "d4DC1hqV0FstrRDv30v/MorVEGgwXufDeFJtP5la5ZWDJdLtIwrV/FHJLHS0VaKA/pSrcACnbywN787BfJcTIwtcZ2WKcQuITeNTLMuip/zxf4Rek/HzVT9qwE0Xef0k"; | ||
var TEST_MESSAGE = new Buffer("1234567890123456"); | ||
var KEYS = [ | ||
{ alg: "ECDSA", usages: ["sign", "verify"] }, | ||
{ alg: "ECDH", usages: ["deriveKey", "deriveBits"] }, | ||
]; | ||
var DIGEST = ["SHA-1", "SHA-256", "SHA-384", "SHA-512"]; | ||
var NAMED_CURVES = ["P-256", "P-384", "P-521"]; | ||
function testDeriveKey(webcrypto, namedCurve, algName, keySize, done) { | ||
var promise = new Promise(function (resolve, reject) { | ||
var key = null; | ||
webcrypto.subtle.generateKey( | ||
{ | ||
name: "ECDH", | ||
namedCurve: namedCurve, //can be "P-256", "P-384", or "P-521" | ||
}, | ||
false, //whether the key is extractable (i.e. can be used in exportKey) | ||
["deriveKey"] //can be any combination of "deriveKey" | ||
) | ||
.then(function (k) { | ||
assert.equal(k.privateKey !== null, true, "Has no private key"); | ||
assert.equal(k.publicKey !== null, true, "Has no public key"); | ||
key = k; | ||
return webcrypto.subtle.deriveKey( | ||
{ | ||
name: "ECDH", | ||
namedCurve: namedCurve, //can be "P-256", "P-384", or "P-521" | ||
public: k.publicKey, //an ECDH public key from generateKey or importKey | ||
}, | ||
k.privateKey, //your ECDH private key from generateKey or importKey | ||
{ //the key type you want to create based on the derived bits | ||
name: algName, //can be any AES algorithm ("AES-CTR", "AES-CBC", "AES-CMAC", "AES-GCM", "AES-CFB", "AES-KW", "ECDH", "DH", or "HMAC") | ||
//the generateKey parameters for that type of algorithm | ||
length: keySize, //can be 128, 192, or 256 | ||
}, | ||
false, //whether the derived key is extractable (i.e. can be used in exportKey) | ||
["encrypt", "decrypt"] //limited to the options in that algorithm's importKey | ||
) | ||
}) | ||
.then(function (key) { | ||
assert.equal(key != null, true, "Has no derived Key value"); | ||
assert.equal(key.type === "secret", true, "Derived key is not Secret"); | ||
}) | ||
.then(resolve, reject); | ||
}) | ||
promise = promise.then(done, done); | ||
} | ||
var keys = []; | ||
describe("WebCrypto ECDSA sign/verify", function () { | ||
before(function (done) { | ||
done(); | ||
}) | ||
context("Generate key", () => { | ||
// Algs | ||
KEYS.forEach(key => { | ||
// namedCurve | ||
NAMED_CURVES.forEach(namedCurve => { | ||
var keyName = `${key.alg} crv:${namedCurve}` | ||
var keyTemplate = { | ||
name: keyName, | ||
privateKey: null, | ||
publicKey: null, | ||
usages: key.usages, | ||
} | ||
keys.push(keyTemplate); | ||
it(keyName, done => { | ||
var alg = { | ||
name: key.alg, | ||
namedCurve: namedCurve | ||
}; | ||
webcrypto.subtle.generateKey(alg, true, key.usages) | ||
.then(keyPair => { | ||
assert.equal(!!(keyPair.privateKey || keyPair.publicKey), true, "KeyPair is empty"); | ||
// save keays for next tests | ||
keyTemplate.privateKey = keyPair.privateKey; | ||
keyTemplate.publicKey = keyPair.publicKey; | ||
return Promise.resolve(); | ||
}) | ||
.then(done, done); | ||
}); | ||
}); | ||
}); | ||
}); | ||
var TEST_MESSAGE = new Buffer("This is test message for crypto functions"); | ||
context("Sign/Verify", () => { | ||
it("Ecdsa", function (done) { | ||
keys.filter(key => key.usages.some(usage => usage === "sign")) | ||
.forEach(key => { | ||
// Hash | ||
DIGEST.forEach(hash => { | ||
it(`${hash}\t${key.name}`, done => { | ||
var alg = { name: key.privateKey.algorithm.name, hash: { name: hash } }; | ||
webcrypto.subtle.sign(alg, key.privateKey, TEST_MESSAGE) | ||
.then(sig => { | ||
assert.equal(!!sig, true, "Has no signature value"); | ||
assert.notEqual(sig.length, 0, "Has empty signature value"); | ||
return webcrypto.subtle.verify(alg, key.publicKey, sig, TEST_MESSAGE) | ||
}) | ||
.then(v => assert.equal(v, true, "Signature is not valid")) | ||
.then(done, done); | ||
}); | ||
}); | ||
}); | ||
}); | ||
var key = null; | ||
webcrypto.subtle.generateKey( | ||
{ | ||
name: "ECDSA", | ||
namedCurve: "P-256", //can be "P-256", "P-384", or "P-521" | ||
}, | ||
false, //whether the key is extractable (i.e. can be used in exportKey) | ||
["sign", "verify"] //can be any combination of "sign" and "verify" | ||
) | ||
.then(function (k) { | ||
assert.equal(k.privateKey !== null, true, "Has no private key"); | ||
assert.equal(k.publicKey !== null, true, "Has no public key"); | ||
key = k; | ||
return webcrypto.subtle.sign( | ||
{ | ||
name: "ECDSA", | ||
hash: { name: "SHA-256" }, //can be "SHA-1", "SHA-256", "SHA-384", or "SHA-512" | ||
}, | ||
key.privateKey, | ||
TEST_MESSAGE) | ||
}) | ||
.then(function (sig) { | ||
assert.equal(sig !== null, true, "Has no signature value"); | ||
assert.notEqual(sig.length, 0, "Has empty signature value"); | ||
return webcrypto.subtle.verify( | ||
{ | ||
name: "ECDSA", | ||
hash: { name: "SHA-256" }, //can be "SHA-1", "SHA-256", "SHA-384", or "SHA-512" | ||
}, | ||
key.publicKey, | ||
sig, | ||
TEST_MESSAGE | ||
) | ||
}) | ||
.then(function (v) { | ||
assert.equal(v, true, "Ecdsa signature is not valid"); | ||
}) | ||
.then(done, done); | ||
}) | ||
context("Derive key", () => { | ||
it("Ecdsa export/import PKCS8", function (done) { | ||
keys.filter(key => key.usages.some(usage => usage === "deriveKey")) | ||
.forEach(key => { | ||
// AES alg | ||
["AES-CBC", "AES-GCM"].forEach(aesAlg => { | ||
// AES length | ||
[128, 192, 256].forEach(aesLength => { | ||
it(`${aesAlg}-${aesLength}\t${key.name}`, done => { | ||
var alg = { | ||
name: key.privateKey.algorithm.name, | ||
public: key.publicKey | ||
}; | ||
webcrypto.subtle.deriveKey(alg, key.privateKey, { name: aesAlg, length: aesLength }, true, ["encrypt"]) | ||
.then(aesKey => { | ||
assert.equal(!!aesKey, true, "Has no derived key"); | ||
assert.equal(aesKey.algorithm.length, aesLength, "Has wrong derived key length"); | ||
assert.equal(aesKey.usages.length, 1, "Has wrong key usages length"); | ||
assert.equal(aesKey.usages[0], "encrypt", "Has wrong key usage"); | ||
}) | ||
.then(done, done); | ||
}); | ||
}); | ||
}); | ||
}); | ||
}); | ||
var key = null; | ||
webcrypto.subtle.generateKey( | ||
{ | ||
name: "ECDSA", | ||
namedCurve: "P-256", //can be "P-256", "P-384", or "P-521" | ||
}, | ||
false, //whether the key is extractable (i.e. can be used in exportKey) | ||
["sign", "verify"] //can be any combination of "sign" and "verify" | ||
) | ||
.then(function (k) { | ||
key = k; | ||
return webcrypto.subtle.exportKey( | ||
"pkcs8", | ||
key.privateKey | ||
); | ||
}) | ||
.then(function (pkcs8) { | ||
assert.equal(pkcs8 instanceof ArrayBuffer, true, "pkcs8 is not ArrayBuffer"); | ||
return webcrypto.subtle.importKey( | ||
"pkcs8", | ||
pkcs8, | ||
{ | ||
name: "ECDSA", | ||
namedCurve: "P-256", //can be "P-256", "P-384", or "P-521" | ||
}, | ||
true, //whether the key is extractable (i.e. can be used in exportKey) | ||
["sign"] //can be any combination of "sign" and "verify" | ||
) | ||
}) | ||
.then(function (k) { | ||
assert.equal(k.type === "private", true, "Key is not Private"); | ||
assert.equal(k.algorithm.name === "ECDSA", true, "Key is not ECDSA"); | ||
assert.equal(k.algorithm.namedCurve, "P-256", "Key has wrong named curve"); | ||
assert.equal(k.type, "private", "Key is not private"); | ||
assert.equal(k.extractable, true, "Key has wrong extractable property"); | ||
assert.equal(k.usages.length, 1, "Key has wrong key usages property"); | ||
assert.equal(k.usages[0], "sign", "Key has wrong key usages property"); | ||
}) | ||
.then(done, done); | ||
}) | ||
context("Derive bits", () => { | ||
it("Ecdsa export/import SPKI", function (done) { | ||
keys.filter(key => key.usages.some(usage => usage === "deriveBits")) | ||
.forEach(key => { | ||
// length | ||
[56, 96, 128, 192, 256].forEach(bitsLength => { | ||
it(`bits:${bitsLength} \t${key.name}`, done => { | ||
var alg = { | ||
name: key.privateKey.algorithm.name, | ||
public: key.publicKey | ||
}; | ||
webcrypto.subtle.deriveBits(alg, key.privateKey, bitsLength) | ||
.then(bits => { | ||
assert.equal(!!bits, true, "Has no derived bits"); | ||
assert.equal(bits.byteLength, bitsLength / 8, "Has wrong derived bits length"); | ||
}) | ||
.then(done, done); | ||
}); | ||
}); | ||
}); | ||
}); | ||
var key = null; | ||
webcrypto.subtle.generateKey( | ||
{ | ||
name: "ECDSA", | ||
namedCurve: "P-256", //can be "P-256", "P-384", or "P-521" | ||
}, | ||
false, //whether the key is extractable (i.e. can be used in exportKey) | ||
["sign", "verify"] //can be any combination of "sign" and "verify" | ||
) | ||
.then(function (k) { | ||
key = k; | ||
return webcrypto.subtle.exportKey( | ||
"spki", | ||
key.publicKey | ||
); | ||
}) | ||
.then(function (spki) { | ||
assert.equal(spki instanceof ArrayBuffer, true, "spki is not ArrayBuffer"); | ||
return webcrypto.subtle.importKey( | ||
"spki", | ||
spki, | ||
{ | ||
name: "ECDSA", | ||
namedCurve: "P-256", | ||
}, | ||
false, | ||
["verify"] | ||
) | ||
}) | ||
.then(function (k) { | ||
assert.equal(k.type === "public", true, "Key is not Public"); | ||
assert.equal(k.algorithm.name === "ECDSA", true, "Key is not ECDSA"); | ||
assert.equal(k.algorithm.namedCurve, "P-256", "Key has wrong named curve"); | ||
assert.equal(k.type, "public", "Key is not public"); | ||
assert.equal(k.extractable, false, "Key has wrong extractable property"); | ||
assert.equal(k.usages.length, 1, "Key has wrong key usages property"); | ||
assert.equal(k.usages[0], "verify", "Key has wrong key usages property"); | ||
}) | ||
.then(done, done); | ||
}) | ||
context("Export/Import", () => { | ||
it("Ecdsa JWK export/import", function (done) { | ||
var _jwk; | ||
var key = null; | ||
webcrypto.subtle.generateKey( | ||
{ | ||
name: "ECDSA", | ||
namedCurve: "P-256", //can be "P-256", "P-384", or "P-521" | ||
}, | ||
false, //whether the key is extractable (i.e. can be used in exportKey) | ||
["sign", "verify"] //can be any combination of "sign" and "verify" | ||
) | ||
.then(function (k) { | ||
assert.equal(k.privateKey !== null, true, "Has no private key"); | ||
assert.equal(k.publicKey !== null, true, "Has no public key"); | ||
key = k; | ||
return webcrypto.subtle.exportKey( | ||
"jwk", | ||
key.privateKey | ||
); | ||
}) | ||
.then(function (jwk) { | ||
assert.equal(jwk.x !== null, true, "Wrong EC key param"); | ||
assert.equal(jwk.y !== null, true, "Wrong EC key param"); | ||
assert.equal(jwk.d !== null, true, "Wrong EC key param"); | ||
assert.equal(jwk.crv !== null, true, "Wrong EC key param"); | ||
_jwk = jwk; | ||
return webcrypto.subtle.importKey( | ||
"jwk", | ||
jwk, | ||
{ | ||
name: "ECDSA", | ||
namedCurve: "P-256" | ||
}, | ||
false, | ||
["sign"] | ||
); | ||
}) | ||
.then(function (k) { | ||
assert.equal(k.type === "private", true, "Key is not Private"); | ||
assert.equal(k.algorithm.name === "ECDSA", true, "Key is not ECDSA"); | ||
return webcrypto.subtle.exportKey("jwk", k) | ||
}) | ||
.then(function (jwk) { | ||
assert.equal(jwk.x === _jwk.x, true, "Wrong EC key param"); | ||
assert.equal(jwk.y === _jwk.y, true, "Wrong EC key param"); | ||
assert.equal(jwk.d === _jwk.d, true, "Wrong EC key param"); | ||
return webcrypto.subtle.sign( | ||
{ | ||
name: "ECDSA", | ||
hash: { name: "SHA-256" } //can be "SHA-1", "SHA-256", "SHA-384", or "SHA-512" | ||
}, | ||
key.privateKey, | ||
TEST_MESSAGE) | ||
}) | ||
.then(function (sig) { | ||
assert.equal(sig !== null, true, "Has no signature value"); | ||
assert.notEqual(sig.length, 0, "Has empty signature value"); | ||
return webcrypto.subtle.verify( | ||
{ | ||
name: "ECDSA", | ||
hash: { name: "SHA-256" } | ||
}, | ||
key.publicKey, //from generateKey or importKey above | ||
sig, //ArrayBuffer of the signature | ||
TEST_MESSAGE //ArrayBuffer of the data | ||
) | ||
}) | ||
.then(function (v) { | ||
assert.equal(v, true, "Signature is not valid") | ||
}) | ||
.then(done, done); | ||
}) | ||
// Keys | ||
keys.forEach(key => { | ||
// Format | ||
["jwk", "spki", "pkcs8"].forEach(format => { | ||
it(`${format}\t${key.name}`, done => { | ||
var promise = Promise.resolve(); | ||
// Check public and private keys | ||
[key.privateKey, key.publicKey].forEach(_key => { | ||
if ((format === "spki" && _key.type === "public") || (format === "pkcs8" && _key.type === "private") || format === "jwk") | ||
promise = promise.then(() => { | ||
return webcrypto.subtle.exportKey(format, _key) | ||
.then(jwk => { | ||
assert.equal(!!jwk, true, "Has no jwk value"); | ||
// TODO assert JWK params | ||
return webcrypto.subtle.importKey(format, jwk, _key.algorithm, true, _key.usages); | ||
}) | ||
}) | ||
.then(k => assert.equal(!!k, true, "Imported key is empty")) | ||
// TODO assert imported key params | ||
}); | ||
promise.then(done, done); | ||
}); | ||
}); | ||
}); | ||
}); | ||
it("Ecdh derive AES-CBC 128", function (done) { | ||
testDeriveKey(webcrypto, "P-256", "AES-CBC", 128, done) | ||
}) | ||
it("Ecdh derive AES-CBC 256", function (done) { | ||
testDeriveKey(webcrypto, "P-256", "AES-CBC", 256, done) | ||
}) | ||
it("Ecdh derive AES-GCM 128", function (done) { | ||
testDeriveKey(webcrypto, "P-256", "AES-GCM", 128, done) | ||
}) | ||
it("Ecdh derive AES-GCM 256", function (done) { | ||
testDeriveKey(webcrypto, "P-256", "AES-GCM", 256, done) | ||
}) | ||
it("Ecdh export/import PKCS8", function (done) { | ||
var key = null; | ||
webcrypto.subtle.generateKey( | ||
{ | ||
name: "ECDH", | ||
namedCurve: "P-256", | ||
}, | ||
false, | ||
["decrypt", "encrypt"] | ||
) | ||
.then(function (k) { | ||
key = k; | ||
return webcrypto.subtle.exportKey( | ||
"pkcs8", | ||
key.privateKey | ||
); | ||
}) | ||
.then(function (pkcs8) { | ||
assert.equal(pkcs8 instanceof ArrayBuffer, true, "pkcs8 is not ArrayBuffer"); | ||
return webcrypto.subtle.importKey( | ||
"pkcs8", | ||
pkcs8, | ||
{ | ||
name: "ECDH", | ||
namedCurve: "P-256", | ||
}, | ||
false, | ||
["decrypt"] | ||
) | ||
}) | ||
.then(function (k) { | ||
assert.equal(k.type === "private", true, "Key is not Private"); | ||
assert.equal(k.algorithm.name === "ECDH", true, "Key is not ECDH"); | ||
}) | ||
.then(done, done); | ||
}) | ||
it("Ecdsa export/import SPKI", function (done) { | ||
var key = null; | ||
webcrypto.subtle.generateKey( | ||
{ | ||
name: "ECDH", | ||
namedCurve: "P-256", | ||
}, | ||
false, | ||
["decrypt", "encrypt"] | ||
) | ||
.then(function (k) { | ||
key = k; | ||
return webcrypto.subtle.exportKey( | ||
"spki", | ||
key.publicKey | ||
); | ||
}) | ||
.then(function (spki) { | ||
assert.equal(spki instanceof ArrayBuffer, true, "spki is not ArrayBuffer"); | ||
return webcrypto.subtle.importKey( | ||
"spki", | ||
spki, | ||
{ | ||
name: "ECDH", | ||
namedCurve: "P-256", | ||
}, | ||
false, | ||
["encrypt"] | ||
) | ||
}) | ||
.then(function (k) { | ||
assert.equal(k.type === "public", true, "Key is not Public"); | ||
assert.equal(k.algorithm.name === "ECDH", true, "Key is not ECDH"); | ||
}) | ||
.then(done, done); | ||
}) | ||
it("Ecdsa test signature from Chrome crypto", function (done) { | ||
var key, sig; | ||
webcrypto.subtle.importKey( | ||
"jwk", //can be "jwk" (public or private), "spki" (public only), or "pkcs8" (private only) | ||
JSON.parse(ecdsa_pubkey_json_384) | ||
, | ||
{ //these are the algorithm options | ||
name: "ECDSA", | ||
namedCurve: "P-384", //can be "P-256", "P-384", or "P-521" | ||
}, | ||
true, //whether the key is extractable (i.e. can be used in exportKey) | ||
["verify"] //"verify" for public key import, "sign" for private key imports | ||
) | ||
.then(function (k) { | ||
key = k; | ||
return webcrypto.subtle.exportKey( | ||
"jwk", | ||
key | ||
); | ||
}) | ||
.then(function () { | ||
sig = new Buffer(ecdsa_signature_384_sha256, "base64"); | ||
return webcrypto.subtle.verify( | ||
{ | ||
name: "ECDSA", | ||
hash: { name: "SHA-256" } | ||
}, | ||
key, //from generateKey or importKey above | ||
sig, | ||
TEST_MESSAGE //ArrayBuffer of the data | ||
) | ||
}) | ||
.then(function (v) { | ||
assert.equal(v, true, "Signature is not valid") | ||
}) | ||
.then(done, done); | ||
}) | ||
function test_sign(namedCurve, hash, done){ | ||
var keys = null; | ||
webcrypto.subtle.generateKey( | ||
{ | ||
name: "ECDSA", | ||
namedCurve: namedCurve, //can be "P-256", "P-384", or "P-521" | ||
}, | ||
false, //whether the key is extractable (i.e. can be used in exportKey) | ||
["sign", "verify"] //can be any combination of "sign" and "verify" | ||
) | ||
.then(function (k) { | ||
assert.equal(k.privateKey !== null, true, "Has no private key"); | ||
assert.equal(k.publicKey !== null, true, "Has no public key"); | ||
keys = k; | ||
return webcrypto.subtle.sign( | ||
{ | ||
name: "ECDSA", | ||
hash: { name: hash }, //can be "SHA-1", "SHA-256", "SHA-384", or "SHA-512" | ||
}, | ||
keys.privateKey, | ||
TEST_MESSAGE) | ||
}) | ||
.then(function (sig) { | ||
assert.equal(sig !== null, true, "Has no signature value"); | ||
assert.notEqual(sig.length, 0, "Has empty signature value"); | ||
return webcrypto.subtle.verify( | ||
{ | ||
name: "ECDSA", | ||
hash: { name: hash }, //can be "SHA-1", "SHA-256", "SHA-384", or "SHA-512" | ||
}, | ||
keys.publicKey, | ||
sig, | ||
TEST_MESSAGE | ||
) | ||
}) | ||
.then(function (v) { | ||
assert.equal(v, true, "Ecdsa signature is not valid"); | ||
}) | ||
.then(done, done); | ||
} | ||
it("Ecdsa sign/verify P-256 SHA-1", function (done) { | ||
test_sign("P-256", "SHA-1", done); | ||
}) | ||
it("Ecdsa sign/verify P-256 SHA-256", function (done) { | ||
test_sign("P-256", "SHA-256", done); | ||
}) | ||
it("Ecdsa sign/verify P-256 SHA-384", function (done) { | ||
test_sign("P-256", "SHA-384", done); | ||
}) | ||
it("Ecdsa sign/verify P-256 SHA-512", function (done) { | ||
test_sign("P-256", "SHA-512", done); | ||
}) | ||
it("Ecdsa sign/verify P-384 SHA-1", function (done) { | ||
test_sign("P-384", "SHA-1", done); | ||
}) | ||
it("Ecdsa sign/verify P-384 SHA-256", function (done) { | ||
test_sign("P-384", "SHA-256", done); | ||
}) | ||
it("Ecdsa sign/verify P-384 SHA-384", function (done) { | ||
test_sign("P-384", "SHA-384", done); | ||
}) | ||
it("Ecdsa sign/verify P-384 SHA-512", function (done) { | ||
test_sign("P-384", "SHA-512", done); | ||
}) | ||
it("Ecdsa sign/verify P-521 SHA-1", function (done) { | ||
test_sign("P-521", "SHA-1", done); | ||
}) | ||
it("Ecdsa sign/verify P-521 SHA-256", function (done) { | ||
test_sign("P-521", "SHA-256", done); | ||
}) | ||
it("Ecdsa sign/verify P-521 SHA-384", function (done) { | ||
test_sign("P-521", "SHA-384", done); | ||
}) | ||
it("Ecdsa sign/verify P-521 SHA-512", function (done) { | ||
test_sign("P-521", "SHA-512", done); | ||
}) | ||
}) | ||
}); |
@@ -5,3 +5,3 @@ var assert = require('assert'); | ||
describe("native", function () { | ||
var TEST_MESSAGE = new Buffer("Hello world"); | ||
@@ -306,4 +306,4 @@ | ||
}) | ||
function test_encrypt_gcm(keySize, aad, tag, done){ | ||
function test_encrypt_gcm(keySize, aad, tag, done) { | ||
var msg = new Buffer("Hello world"); | ||
@@ -322,7 +322,7 @@ native.AesKey.generate(keySize, function (err, key) { | ||
} | ||
it("AES GCM encrypt 192 AAD, tag(16)", function (done) { | ||
test_encrypt_gcm(24, new Buffer("1234567890123456"), 16, done); | ||
}) | ||
it("AES GCM encrypt 192 no AAD, tag(4)", function (done) { | ||
@@ -335,9 +335,9 @@ test_encrypt_gcm(24, new Buffer(""), 4, done); | ||
}) | ||
it("AES GCM encrypt 256 no AAD, tag(13)", function (done) { | ||
test_encrypt_gcm(32, new Buffer(""), 13, done); | ||
}) | ||
function test_digest(md, mdlen, done){ | ||
native.Core.digest(md, TEST_MESSAGE, function(err, digest){ | ||
function test_digest(md, mdlen, done) { | ||
native.Core.digest(md, TEST_MESSAGE, function (err, digest) { | ||
assert.equal(!err, true, err); | ||
@@ -348,17 +348,17 @@ assert.equal(digest.length, mdlen, "Wrong digest length"); | ||
} | ||
it("digest sha1", function (done) { | ||
test_digest("sha1", 20, done); | ||
}) | ||
it("digest sha256", function (done) { | ||
test_digest("sha256", 32, done); | ||
}) | ||
it("digest sha512", function (done) { | ||
test_digest("sha512", 64, done); | ||
}) | ||
it("digest wrong name", function (done) { | ||
native.Core.digest("wrong name", TEST_MESSAGE, function(err, digest){ | ||
native.Core.digest("wrong name", TEST_MESSAGE, function (err, digest) { | ||
assert.equal(err != null, true, "Error is NULL"); | ||
@@ -369,2 +369,85 @@ done() | ||
it("native RSA Key export/import jwk sync", function (done) { | ||
native.Key.generateRsa(1024, native.RsaPublicExponent.RSA_3, function (err, key) { | ||
assert.equal(err == null, true, "error on key generation"); | ||
// export key PRIVATE | ||
var jwk = key.exportJwk(native.KeyType.PRIVATE); | ||
assert.equal(!!jwk, true, "Can not export jwk"); | ||
// import key PRIVATE | ||
var new_key = native.Key.importJwk(jwk, native.KeyType.PRIVATE); | ||
assert.equal(!!new_key, true, "Can not import jwk"); | ||
// export key PUBLIC | ||
var jwk = key.exportJwk(native.KeyType.PUBLIC); | ||
assert.equal(!!jwk, true, "Can not export jwk"); | ||
// import key PUBLIC | ||
var new_key = native.Key.importJwk(jwk, native.KeyType.PUBLIC); | ||
assert.equal(!!new_key, true, "Can not import jwk"); | ||
done(); | ||
}) | ||
}); | ||
it("native EC Key export/import jwk sync", function (done) { | ||
native.Key.generateEc(native.EcNamedCurves.secp256k1, function (err, key) { | ||
assert.equal(err == null, true, "error on key generation"); | ||
// export key PRIVATE | ||
var jwk = key.exportJwk(native.KeyType.PRIVATE); | ||
assert.equal(!!jwk, true, "Can not export jwk"); | ||
// import key PRIVATE | ||
var new_key = native.Key.importJwk(jwk, native.KeyType.PRIVATE); | ||
assert.equal(!!new_key, true, "Can not import jwk"); | ||
// export key PUBLIC | ||
var jwk = key.exportJwk(native.KeyType.PUBLIC); | ||
assert.equal(!!jwk, true, "Can not export jwk"); | ||
// import key PUBLIC | ||
var new_key = native.Key.importJwk(jwk, native.KeyType.PUBLIC); | ||
assert.equal(!!new_key, true, "Can not import jwk"); | ||
done(); | ||
}) | ||
}); | ||
it("EC deriveBits P-256 256", function (done) { | ||
native.Key.generateEc(native.EcNamedCurves.secp256k1, function (err, key) { | ||
assert(key != null, true, "Error on key generation"); | ||
key.EcdhDeriveBits(key, 256, function (err, bits) { | ||
if (!err) | ||
assert.equal(bits.length, 256 / 8); | ||
done(err); | ||
}); | ||
}) | ||
}); | ||
it("EC deriveBits P-256 128", function (done) { | ||
native.Key.generateEc(native.EcNamedCurves.secp256k1, function (err, key) { | ||
assert(key != null, true, "Error on key generation"); | ||
key.EcdhDeriveBits(key, 128, function (err, bits) { | ||
if (!err) | ||
assert.equal(bits.length, 128 / 8); | ||
done(err); | ||
}); | ||
}) | ||
}); | ||
it("EC deriveBits P-256 512, error", function (done) { | ||
native.Key.generateEc(native.EcNamedCurves.secp256k1, function (err, key) { | ||
assert(key != null, true, "Error on key generation"); | ||
key.EcdhDeriveBits(key, 512, function (err, bits) { | ||
assert.equal(!!err, true, "Should be error"); | ||
done(); | ||
}); | ||
}) | ||
}); | ||
it("EC deriveBits P-521 528, error", function (done) { | ||
native.Key.generateEc(native.EcNamedCurves.secp521r1, function (err, key) { | ||
assert(key != null, true, "Error on key generation"); | ||
key.EcdhDeriveBits(key, 528, function (err, bits) { | ||
if (!err) | ||
assert.equal(bits.length, 528 / 8); | ||
done(err); | ||
}); | ||
}) | ||
}); | ||
}) |
586
test/rsa.js
@@ -0,431 +1,183 @@ | ||
"use strict"; | ||
var assert = require('assert'); | ||
var webcrypto = require('./config'); | ||
describe("WebCrypto RSA", function () { | ||
describe("WebCrypto RSA", () => { | ||
var TEST_MESSAGE = new Buffer("This is test message for crypto functions"); | ||
var TEST_MESSAGE = new Buffer("1234567890123456"); | ||
var KEYS = [ | ||
{ alg: "RSASSA-PKCS1-v1_5", usages: ["sign", "verify"] }, | ||
{ alg: "RSA-PSS", usages: ["sign", "verify"] }, | ||
{ alg: "RSA-OAEP", usages: ["encrypt", "decrypt", "wrapKey", "unwrapKey"] }, | ||
]; | ||
var DIGEST = ["SHA-1", "SHA-256", "SHA-384", "SHA-512"]; | ||
var PUBLIC_EXPONENT = [new Uint8Array([3]), new Uint8Array([1, 0, 1])]; | ||
var MODULUS_LENGTH = [1024, 2048, /*4096*/]; | ||
before(function (done) { | ||
done(); | ||
}) | ||
var keys = []; | ||
it("RSA PKCS1 1.5 sign/verify", function (done) { | ||
var key = null; | ||
webcrypto.subtle.generateKey({ | ||
name: "RSASSA-PKCS1-v1_5", | ||
modulusLength: 1024, | ||
publicExponent: new Uint8Array([1, 0, 1]), | ||
hash: { | ||
name: "SHA-1" | ||
} | ||
}, | ||
false, | ||
["sign", "verify"] | ||
) | ||
.then(function (k) { | ||
assert.equal(k.privateKey !== null, true, "Has no private key"); | ||
assert.equal(k.publicKey !== null, true, "Has no public key"); | ||
key = k; | ||
return webcrypto.subtle.sign({ name: "RSASSA-PKCS1-v1_5" }, key.privateKey, TEST_MESSAGE) | ||
}) | ||
.then(function (sig) { | ||
assert.equal(sig !== null, true, "Has no signature value"); | ||
assert.notEqual(sig.length, 0, "Has empty signature value"); | ||
return webcrypto.subtle.verify({ name: "RSASSA-PKCS1-v1_5" }, key.publicKey, sig, TEST_MESSAGE) | ||
}) | ||
.then(function (v) { | ||
assert.equal(v, true, "Rsa PKCS1 signature is not valid") | ||
}) | ||
.then(done, done); | ||
}) | ||
it("RSA PKCS1 export/import JWK", function (done) { | ||
var key = null; | ||
var _jwk; | ||
webcrypto.subtle.generateKey({ | ||
name: "RSASSA-PKCS1-v1_5", | ||
modulusLength: 1024, | ||
publicExponent: new Uint8Array([3]), | ||
hash: { | ||
name: "SHA-1" | ||
} | ||
}, | ||
false, | ||
["sign", "verify"] | ||
) | ||
.then(function (k) { | ||
assert.equal(k.privateKey != null, true, "Has no private key"); | ||
assert.equal(k.publicKey != null, true, "Has no public key"); | ||
key = k; | ||
return webcrypto.subtle.exportKey("jwk", key.publicKey) | ||
}) | ||
.then(function (jwk) { | ||
assert.equal(jwk != null, true, "Has no JWK publicKey"); | ||
return webcrypto.subtle.importKey( | ||
"jwk", | ||
jwk, | ||
{ | ||
name: "RSASSA-PKCS1-v1_5", | ||
hash: { | ||
name: "SHA-1" | ||
context("Generate key", () => { | ||
// Algs | ||
KEYS.forEach(key => { | ||
// Digest | ||
DIGEST.forEach(digest => { | ||
// publicExponent | ||
PUBLIC_EXPONENT.forEach(pubExp => { | ||
// modulusLength | ||
MODULUS_LENGTH.forEach(modLen => { | ||
var keyName = `${key.alg} ${digest} e:${pubExp.length === 1 ? 3 : 65535} n:${modLen}` | ||
var keyTemplate = { | ||
name: keyName, | ||
privateKey: null, | ||
publicKey: null, | ||
usages: key.usages, | ||
} | ||
}, | ||
false, | ||
["verify"] | ||
); | ||
}) | ||
.then(function (k) { | ||
assert.equal(k.type === "public", true, "Key is not Public"); | ||
assert.equal(k.algorithm.name === "RSASSA-PKCS1-v1_5", true, "Key is not RSASSA-PKCS1-v1_5"); | ||
return webcrypto.subtle.exportKey("jwk", key.privateKey) | ||
}) | ||
.then(function (jwk) { | ||
assert.equal(jwk != null, true, "Has no JWK privateKey"); | ||
assert.equal(jwk.e !== null, true, "Wrong JWK key param"); | ||
assert.equal(jwk.n !== null, true, "Wrong JWK key param"); | ||
assert.equal(jwk.d !== null, true, "Wrong JWK key param"); | ||
assert.equal(jwk.p !== null, true, "Wrong JWK key param"); | ||
assert.equal(jwk.q !== null, true, "Wrong JWK key param"); | ||
assert.equal(jwk.dp !== null, true, "Wrong JWK key param"); | ||
assert.equal(jwk.dq !== null, true, "Wrong JWK key param"); | ||
assert.equal(jwk.qi !== null, true, "Wrong JWK key param"); | ||
assert.equal(jwk.alg !== null, true, "Wrong JWK key param"); | ||
assert.equal(jwk.key_ops !== null, true, "Wrong JWK key param"); | ||
_jwk = jwk; | ||
return webcrypto.subtle.importKey( | ||
"jwk", | ||
jwk, | ||
{ | ||
name: "RSASSA-PKCS1-v1_5", | ||
hash: { | ||
name: "SHA-1" | ||
} | ||
}, | ||
true, | ||
["sign"] | ||
); | ||
}) | ||
.then(function (k) { | ||
assert.equal(k.type === "private", true, "Key is not Private"); | ||
assert.equal(k.algorithm.name === "RSASSA-PKCS1-v1_5", true, "Key is not RSASSA-PKCS1-v1_5"); | ||
key = k; | ||
return webcrypto.subtle.exportKey("jwk", k) | ||
}) | ||
.then(function (jwk) { | ||
assert.equal(jwk != null, true, "Has no JWK privateKey"); | ||
assert.equal(jwk.n === _jwk.n, true, "RSA has wrong key parameter"); | ||
assert.equal(jwk.e === _jwk.e, true, "RSA has wrong key parameter"); | ||
assert.equal(jwk.d === _jwk.d, true, "RSA has wrong key parameter"); | ||
assert.equal(jwk.p === _jwk.p, true, "RSA has wrong key parameter"); | ||
assert.equal(jwk.q === _jwk.q, true, "RSA has wrong key parameter"); | ||
assert.equal(jwk.dp === _jwk.dp, true, "RSA has wrong key parameter"); | ||
assert.equal(jwk.dq === _jwk.dq, true, "RSA has wrong key parameter"); | ||
assert.equal(jwk.qi === _jwk.qi, true, "RSA has wrong key parameter"); | ||
return webcrypto.subtle.sign({ name: "RSASSA-PKCS1-v1_5" }, key, TEST_MESSAGE) | ||
}) | ||
.then(function (sig) { | ||
assert.equal(sig !== null, true, "Has no signature value"); | ||
}) | ||
.then(done, done); | ||
}) | ||
keys.push(keyTemplate); | ||
it(keyName, done => { | ||
var alg = { | ||
name: key.alg, | ||
hash: { name: digest }, | ||
modulusLength: modLen, | ||
publicExponent: pubExp | ||
}; | ||
webcrypto.subtle.generateKey(alg, true, key.usages) | ||
.then(keyPair => { | ||
assert.equal(!!(keyPair.privateKey || keyPair.publicKey), true, "KeyPair is empty"); | ||
// save keays for next tests | ||
keyTemplate.privateKey = keyPair.privateKey; | ||
keyTemplate.publicKey = keyPair.publicKey; | ||
return Promise.resolve(); | ||
}) | ||
.then(done, done); | ||
}).timeout(modLen === 2048 ? 4000 : 2000); | ||
}); | ||
}); | ||
}); | ||
}); | ||
}); | ||
it("RSA OAEP export/import JWK", function (done) { | ||
var key = null; | ||
var _jwk; | ||
webcrypto.subtle.generateKey({ | ||
name: "RSA-OAEP", | ||
modulusLength: 1024, | ||
publicExponent: new Uint8Array([1, 0, 1]), | ||
hash: { | ||
name: "SHA-256" | ||
} | ||
}, | ||
false, | ||
["encrypt", "decrypt"] | ||
) | ||
.then(function (k) { | ||
assert.equal(k.privateKey != null, true, "Has no private key"); | ||
assert.equal(k.publicKey != null, true, "Has no public key"); | ||
key = k; | ||
return webcrypto.subtle.exportKey("jwk", key.publicKey) | ||
}) | ||
.then(function (jwk) { | ||
assert.equal(jwk != null, true, "Has no JWK publicKey"); | ||
return webcrypto.subtle.importKey( | ||
"jwk", | ||
jwk, | ||
{ | ||
name: "RSA-OAEP", | ||
hash: { | ||
name: "SHA-256" | ||
} | ||
}, | ||
false, | ||
["encrypt"] | ||
); | ||
}) | ||
.then(function (k) { | ||
assert.equal(k.type === "public", true, "Key is not Public"); | ||
assert.equal(k.algorithm.name === "RSA-OAEP", true, "Key is not RSA-OAEP"); | ||
return webcrypto.subtle.exportKey("jwk", key.privateKey) | ||
}) | ||
.then(function (jwk) { | ||
assert.equal(jwk != null, true, "Has no JWK privateKey"); | ||
_jwk = jwk; | ||
return webcrypto.subtle.importKey( | ||
"jwk", | ||
jwk, | ||
{ | ||
name: "RSA-OAEP", | ||
hash: { | ||
name: "SHA-256" | ||
} | ||
}, | ||
true, | ||
["decrypt"] | ||
); | ||
}) | ||
.then(function (k) { | ||
assert.equal(k.type === "private", true, "Key is not Private"); | ||
assert.equal(k.algorithm.name === "RSA-OAEP", true, "Key is not RSA-OAEP"); | ||
return webcrypto.subtle.exportKey("jwk", k) | ||
}) | ||
.then(function (jwk) { | ||
assert.equal(jwk != null, true, "Has no JWK privateKey"); | ||
assert.equal(jwk.n === _jwk.n, true, "RSA has wrong key parameter"); | ||
assert.equal(jwk.e === _jwk.e, true, "RSA has wrong key parameter"); | ||
assert.equal(jwk.d === _jwk.d, true, "RSA has wrong key parameter"); | ||
assert.equal(jwk.p === _jwk.p, true, "RSA has wrong key parameter"); | ||
assert.equal(jwk.q === _jwk.q, true, "RSA has wrong key parameter"); | ||
assert.equal(jwk.dp === _jwk.dp, true, "RSA has wrong key parameter"); | ||
assert.equal(jwk.dq === _jwk.dq, true, "RSA has wrong key parameter"); | ||
assert.equal(jwk.qi === _jwk.qi, true, "RSA has wrong key parameter"); | ||
}) | ||
.then(done, done); | ||
}) | ||
context("Sign/Verify", () => { | ||
it("RSA OAEP encrypt/decrypt", function (done) { | ||
var key = null; | ||
webcrypto.subtle.generateKey({ | ||
name: "RSA-OAEP", | ||
modulusLength: 1024, | ||
publicExponent: new Uint8Array([1, 0, 1]), | ||
hash: { | ||
name: "SHA-1" | ||
} | ||
}, | ||
false, | ||
["encrypt", "decrypt"] | ||
) | ||
.then(function (k) { | ||
assert.equal(k.privateKey !== null, true, "Has no private key"); | ||
assert.equal(k.publicKey !== null, true, "Has no public key"); | ||
key = k; | ||
return webcrypto.subtle.encrypt({ name: "RSA-OAEP" }, key.publicKey, TEST_MESSAGE) | ||
}) | ||
.then(function (enc) { | ||
assert.equal(enc !== null, true, "Has no encrypted value"); | ||
assert.notEqual(enc.length, 0, "Has empty encrypted value"); | ||
return webcrypto.subtle.decrypt({ name: "RSA-OAEP" }, key.privateKey, enc); | ||
}) | ||
.then(function (dec) { | ||
var str = ""; | ||
var buf = new Uint8Array(dec); | ||
for (var i = 0; i < buf.length; i++) | ||
str += String.fromCharCode(buf[i]); | ||
assert.equal(str, TEST_MESSAGE.toString(), "Rsa OAEP encrypt/decrypt is not valid") | ||
}) | ||
.then(done, done); | ||
}) | ||
keys.filter(key => key.usages.some(usage => usage === "sign")) | ||
.forEach(key => { | ||
it(key.name, done => { | ||
// TODO: Add label | ||
webcrypto.subtle.sign({ name: key.privateKey.algorithm.name }, key.privateKey, TEST_MESSAGE) | ||
.then(sig => { | ||
assert.equal(!!sig, true, "Has no signature value"); | ||
assert.notEqual(sig.length, 0, "Has empty signature value"); | ||
return webcrypto.subtle.verify({ name: key.publicKey.algorithm.name }, key.publicKey, sig, TEST_MESSAGE) | ||
}) | ||
.then(v => assert.equal(v, true, "Signature is not valid")) | ||
.then(done, done); | ||
}); | ||
}); | ||
}); | ||
it("RSA OAEP wrap/unwrap", function (done) { | ||
var key = null; | ||
var skey = null; | ||
webcrypto.subtle.generateKey({ | ||
name: "RSA-OAEP", | ||
modulusLength: 1024, | ||
publicExponent: new Uint8Array([1, 0, 1]), | ||
hash: { | ||
name: "SHA-1" | ||
} | ||
}, | ||
false, | ||
["wrapKey", "unwrapKey"] | ||
) | ||
.then(function (k) { | ||
assert.equal(k.privateKey !== null, true, "Has no private key"); | ||
assert.equal(k.publicKey !== null, true, "Has no public key"); | ||
key = k; | ||
return webcrypto.subtle.generateKey({ | ||
name: "AES-CBC", | ||
length: 128, //can be 128, 192, or 256 | ||
}, | ||
true, //whether the key is extractable (i.e. can be used in exportKey) | ||
["encrypt", "decrypt"]); | ||
}) | ||
.then(function (sk) { | ||
skey = sk; | ||
assert.equal(skey.key !== null, true, "Has no secret key"); | ||
return webcrypto.subtle.wrapKey( | ||
"raw", | ||
skey, | ||
key.publicKey, | ||
{ | ||
name: "RSA-OAEP", | ||
hash: { name: "SHA-1" } | ||
}) | ||
}) | ||
.then(function (dec) { | ||
return webcrypto.subtle.unwrapKey( | ||
"raw", //the import format, must be "raw" (only available sometimes) | ||
dec, //the key you want to unwrap | ||
key.privateKey, //the private key with "unwrapKey" usage flag | ||
{ //these are the wrapping key's algorithm options | ||
name: "RSA-OAEP", | ||
modulusLength: 1024, | ||
publicExponent: new Uint8Array([0x01, 0x00, 0x01]), | ||
hash: { name: "SHA-1" }, | ||
}, | ||
{ //this what you want the wrapped key to become (same as when wrapping) | ||
name: "AES-CBC", | ||
length: 128 | ||
}, | ||
false, //whether the key is extractable (i.e. can be used in exportKey) | ||
["encrypt", "decrypt"] //the usages you want the unwrapped key to have | ||
) | ||
}) | ||
.then(function (sk) { | ||
assert.equal(sk.key !== null, true, "Has no secret key"); | ||
}) | ||
.then(done, done); | ||
}) | ||
context("Encrypt/Decrypt", () => { | ||
// Select keys for encrypt | ||
keys.filter(key => key.usages.some(usage => usage === "encrypt")) | ||
.forEach(key => { | ||
// Label | ||
[null, new Uint8Array([1, 2, 3, 4, 5, 6, 7, 8])].forEach(label => { | ||
it(`${label ? "label\t" : "no label"}\t${key.name}`, done => { | ||
webcrypto.subtle.encrypt({ name: key.privateKey.algorithm.name, label: label }, key.publicKey, TEST_MESSAGE) | ||
.catch(e => { | ||
if (e.message.indexOf("RSA_padding_add_PKCS1_OAEP_mgf1") > -1) | ||
return Promise.reject(); | ||
return Promise.reject(e); | ||
}) | ||
.then(enc => { | ||
assert.equal(!!enc, true, "Has no encrpted value"); | ||
assert.notEqual(enc.length, 0, "Has empty encrypted value"); | ||
return webcrypto.subtle.decrypt({ name: key.publicKey.algorithm.name, label: label }, key.privateKey, enc) | ||
}) | ||
.then(dec => { | ||
assert.equal(new Buffer(dec).toString(), TEST_MESSAGE.toString(), "Decrypted message is not valid") | ||
}) | ||
.then(done, done); | ||
}); | ||
}); | ||
}); | ||
}); | ||
it("RSA OAEP encrypt/decrypt with label", function (done) { | ||
var key = null; | ||
var label = null; | ||
webcrypto.subtle.generateKey({ | ||
name: "RSA-OAEP", | ||
modulusLength: 1024, | ||
publicExponent: new Uint8Array([1, 0, 1]), | ||
hash: { | ||
name: "SHA-1" | ||
} | ||
}, | ||
false, | ||
["encrypt", "decrypt"] | ||
) | ||
.then(function (k) { | ||
assert.equal(k.privateKey !== null, true, "Has no private key"); | ||
assert.equal(k.publicKey !== null, true, "Has no public key"); | ||
key = k; | ||
return webcrypto.subtle.exportKey("jwk", k.privateKey); | ||
}) | ||
.then(function (jwk) { | ||
label = webcrypto.getRandomValues(new Uint8Array(4)); | ||
return webcrypto.subtle.encrypt({ name: "RSA-OAEP", label: label }, key.publicKey, TEST_MESSAGE) | ||
}) | ||
.then(function (enc) { | ||
assert.equal(enc !== null, true, "Has no encrypted value"); | ||
assert.notEqual(enc.length, 0, "Has empty encrypted value"); | ||
return webcrypto.subtle.decrypt({ name: "RSA-OAEP", label: label }, key.privateKey, enc); | ||
}) | ||
.then(function (dec) { | ||
var str = ""; | ||
var buf = new Uint8Array(dec); | ||
for (var i = 0; i < buf.length; i++) | ||
str += String.fromCharCode(buf[i]); | ||
assert.equal(str, TEST_MESSAGE.toString(), "Rsa OAEP encrypt/decrypt is not valid") | ||
}) | ||
.then(done, done); | ||
}) | ||
context("Export/Import", () => { | ||
it("RSA OAEP import/export SPKI", function (done) { | ||
var key = null; | ||
var label = null; | ||
// Geberate RSA key | ||
webcrypto.subtle.generateKey({ | ||
name: "RSA-OAEP", | ||
modulusLength: 1024, | ||
publicExponent: new Uint8Array([1, 0, 1]), | ||
hash: { | ||
name: "SHA-1" | ||
} | ||
}, | ||
false, | ||
["encrypt", "decrypt"] | ||
) | ||
.then(function (k) { | ||
assert.equal(k.privateKey !== null, true, "Has no private key"); | ||
assert.equal(k.publicKey !== null, true, "Has no public key"); | ||
key = k; | ||
return webcrypto.subtle.exportKey("spki", k.publicKey); | ||
}) | ||
.then(function (spki) { | ||
assert.equal(spki instanceof ArrayBuffer, true, "Is empty exported RSA key"); | ||
return webcrypto.subtle.importKey("spki", spki, { | ||
name: "RSA-OAEP", | ||
hash: { | ||
name: "SHA-1" | ||
} | ||
}, | ||
true, | ||
["encrypt"]) | ||
}) | ||
.then(function (key) { | ||
assert.equal(!!key, true, "Key is empty"); | ||
assert.equal(key.algorithm.name, "RSA-OAEP", "Wrong algorithm name"); | ||
assert.equal(key.extractable, true, "Wrong extractable param"); | ||
assert.equal(key.usages.length, 1, "Wrong key usages length"); | ||
assert.equal(key.usages[0], "encrypt", "Wrong key usages value"); | ||
assert.equal(key.algorithm.modulusLength, 1024, "Wrong modulus length value"); | ||
assert.equal(key.algorithm.publicExponent.length, 3, "Wrong public exponent value"); | ||
assert.equal(key.type, "public", "Wrong key type"); | ||
}) | ||
.then(done, done); | ||
}) | ||
// Keys | ||
keys.forEach(key => { | ||
// Format | ||
["jwk", "spki", "pkcs8"].forEach(format => { | ||
it(`${format}\t${key.name}`, done => { | ||
var promise = Promise.resolve(); | ||
// Check public and private keys | ||
[key.privateKey, key.publicKey].forEach(_key => { | ||
if ((format === "spki" && _key.type === "public") || (format === "pkcs8" && _key.type === "private") || format === "jwk") | ||
promise = promise.then(() => { | ||
return webcrypto.subtle.exportKey(format, _key) | ||
.then(jwk => { | ||
assert.equal(!!jwk, true, "Has no jwk value"); | ||
// TODO assert JWK params | ||
return webcrypto.subtle.importKey(format, jwk, _key.algorithm, true, _key.usages); | ||
}) | ||
}) | ||
.then(k => assert.equal(!!k, true, "Imported key is empty")) | ||
// TODO assert imported key params | ||
}); | ||
promise.then(done, done); | ||
}); | ||
}); | ||
}); | ||
}); | ||
it("RSA OAEP import/export PKCS8", function (done) { | ||
var key = null; | ||
var label = null; | ||
// Geberate RSA key | ||
webcrypto.subtle.generateKey({ | ||
name: "RSA-OAEP", | ||
modulusLength: 2048, | ||
publicExponent: new Uint8Array([3]), | ||
hash: { | ||
name: "SHA-1" | ||
} | ||
}, | ||
false, | ||
["encrypt", "decrypt"] | ||
) | ||
.then(function (k) { | ||
assert.equal(k.privateKey !== null, true, "Has no private key"); | ||
assert.equal(k.publicKey !== null, true, "Has no public key"); | ||
key = k; | ||
return webcrypto.subtle.exportKey("pkcs8", k.privateKey); | ||
}) | ||
.then(function (pkcs8) { | ||
assert.equal(pkcs8 instanceof ArrayBuffer, true, "Is empty exported RSA key"); | ||
return webcrypto.subtle.importKey("pkcs8", pkcs8, { | ||
name: "RSA-OAEP", | ||
hash: { | ||
name: "SHA-1" | ||
} | ||
}, | ||
false, | ||
["decrypt"]) | ||
}) | ||
.then(function (key) { | ||
assert.equal(!!key, true, "Key is empty"); | ||
assert.equal(key.algorithm.name, "RSA-OAEP", "Wrong algorithm name"); | ||
assert.equal(key.extractable, false, "Wrong extractable param"); | ||
assert.equal(key.usages.length, 1, "Wrong key usages length"); | ||
assert.equal(key.usages[0], "decrypt", "Wrong key usages value"); | ||
assert.equal(key.algorithm.modulusLength, 2048, "Wrong modulus length value"); | ||
assert.equal(key.algorithm.publicExponent.length, 1, "Wrong public exponent value"); | ||
assert.equal(key.type, "private", "Wrong key type"); | ||
}) | ||
.then(done, done); | ||
}) | ||
context("Wrap/Unwrap", () => { | ||
var aesKeys = [{}, {}, {}]; | ||
before(done => { | ||
var promise = Promise.resolve(); | ||
[128, 192, 256].forEach((length, index) => { | ||
var keyTemplate = aesKeys[index]; | ||
promise.then(() => { | ||
return webcrypto.subtle.generateKey({ name: "AES-CBC", length: length }, true, ["encrypt", "decrypt"]) | ||
.then(key => { | ||
keyTemplate.key = key; | ||
// return Promise.resolve(); | ||
}); | ||
}); | ||
}); | ||
promise.then(done, done); | ||
}); | ||
// Keys | ||
keys.filter(key => key.usages.some(usage => "wrapKey" === usage)) | ||
.forEach(key => { | ||
// AES keys | ||
aesKeys.forEach(aes => { | ||
// Format | ||
["raw"].forEach(format => { | ||
[null, new Uint8Array([1, 2, 3, 4, 5, 6, 7, 8])].forEach(label => { | ||
it(`${label ? "label\t" : "no label"}\t${key.name}`, done => { | ||
var _alg = { name: key.publicKey.algorithm.name, label: label }; | ||
webcrypto.subtle.wrapKey(format, aes.key, key.publicKey, _alg) | ||
.catch(e => { | ||
if (e.message.indexOf("RSA_padding_add_PKCS1_OAEP_mgf1") > -1) | ||
return Promise.reject(); | ||
return Promise.reject(e); | ||
}) | ||
.then(enc => { | ||
assert.equal(!!enc, true, "Has no encrypted value"); | ||
return webcrypto.subtle.unwrapKey(format, enc, key.privateKey, _alg, aes.key.algorithm, true, aes.key.usages); | ||
}) | ||
.then(key => { | ||
assert.equal(!!key, true, "Has no unwrapped key"); | ||
}) | ||
.then(done, done); | ||
}); | ||
}); | ||
}); | ||
}); | ||
}); | ||
}); | ||
}) |
{ | ||
"compilerOptions": { | ||
"target": "es5", | ||
"lib": [ | ||
"es5", | ||
"es2015.promise", | ||
"dom" | ||
], | ||
"noUnusedLocals": true, | ||
"strictNullChecks": true, | ||
"module": "commonjs", | ||
"rootDir": "lib", | ||
"moduleResolution": "node", | ||
"outDir": "buildjs", | ||
"declaration": true, | ||
"sourceMap": true | ||
"removeComments": true, | ||
"declaration": false, | ||
"sourceMap": false, | ||
"noImplicitAny": true | ||
}, | ||
"exclude": [ | ||
"node_modules", "buildjs" | ||
"node_modules", | ||
"test" | ||
] | ||
} |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Git dependency
Supply chain riskContains a dependency which resolves to a remote git URL. Dependencies fetched from git URLs are not immutable and can be used to inject untrusted code or reduce the likelihood of a reproducible install.
Found 1 instance in 1 package
Install scripts
Supply chain riskInstall scripts are run when the package is installed. The majority of malware in npm is hidden in install scripts.
Found 1 instance in 1 package
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
Manifest confusion
Supply chain riskThis package has inconsistent metadata. This could be malicious or caused by an error when publishing the package.
Found 1 instance in 1 package
Filesystem access
Supply chain riskAccesses the file system, and could potentially read sensitive data.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Long strings
Supply chain riskContains long string literals, which may be a sign of obfuscated or packed code.
Found 1 instance in 1 package
No repository
Supply chain riskPackage does not have a linked source code repository. Without this field, a package will have no reference to the location of the source code use to generate the package.
Found 1 instance in 1 package
357889
88
124
1
5
6
2780
2
3
+ Added@types/mkdirp@^0.3.29
+ Added@types/node@^6.0.45
+ Addedmkdirp@^0.5.1
+ Addedwebcrypto-core@git+https://github.com/PeculiarVentures/webcrypto-core#types
+ Added@types/mkdirp@0.3.29(transitive)
+ Added@types/node@6.14.13(transitive)
+ Addedmkdirp@0.5.6(transitive)
+ Addednan@2.22.0(transitive)
- Removedbase64url@^1.0.5
- Removedmocha@^2.3.4
- Removedbase64url@1.0.6(transitive)
- Removedcamelcase@1.2.1(transitive)
- Removedcamelcase-keys@1.0.0(transitive)
- Removedcommander@0.6.12.3.0(transitive)
- Removedconcat-stream@1.4.11(transitive)
- Removedcore-util-is@1.0.3(transitive)
- Removeddebug@2.2.0(transitive)
- Removeddiff@1.4.0(transitive)
- Removedescape-string-regexp@1.0.2(transitive)
- Removedget-stdin@4.0.1(transitive)
- Removedglob@3.2.11(transitive)
- Removedgrowl@1.9.2(transitive)
- Removedindent-string@1.2.2(transitive)
- Removedinherits@2.0.4(transitive)
- Removedis-finite@1.1.0(transitive)
- Removedisarray@0.0.1(transitive)
- Removedjade@0.26.3(transitive)
- Removedlru-cache@2.7.3(transitive)
- Removedmap-obj@1.0.1(transitive)
- Removedmeow@2.0.0(transitive)
- Removedminimatch@0.3.0(transitive)
- Removedminimist@0.0.8(transitive)
- Removedmkdirp@0.3.00.5.1(transitive)
- Removedmocha@2.5.3(transitive)
- Removedms@0.7.1(transitive)
- Removednan@2.1.0(transitive)
- Removedobject-assign@1.0.0(transitive)
- Removedreadable-stream@1.1.14(transitive)
- Removedrepeating@1.1.3(transitive)
- Removedsigmund@1.0.1(transitive)
- Removedstring_decoder@0.10.31(transitive)
- Removedsupports-color@1.2.0(transitive)
- Removedto-iso-string@0.0.2(transitive)
- Removedtypedarray@0.0.7(transitive)
Updatednan@^2.4.0