Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

node-webcrypto-ossl

Package Overview
Dependencies
Maintainers
2
Versions
60
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

node-webcrypto-ossl - npm Package Compare versions

Comparing version 1.0.11 to 1.0.12

.nyc_output/13b4505eba988299e8f38e1463545cf2.json

21

lib/key.ts

@@ -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)
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"})

@@ -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);
});
})
});
})

@@ -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

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc