Skip to content

Commit

Permalink
v0.4.4
Browse files Browse the repository at this point in the history
  • Loading branch information
Maurice-Mueller committed Apr 18, 2019
1 parent de92d28 commit c247b7f
Show file tree
Hide file tree
Showing 41 changed files with 2,155 additions and 30 deletions.
23 changes: 12 additions & 11 deletions package.json
@@ -1,6 +1,6 @@
{
"name": "@esentri/js-crypto-wrapper",
"version": "0.1.1",
"version": "0.4.4",
"description": "a wrapper around WebCryptoAPI",
"keywords": [],
"main": "dist/crypto-wrapper.umd.js",
Expand Down Expand Up @@ -46,6 +46,7 @@
}
},
"jest": {
"testURL": "http://localhost/",
"transform": {
".(ts|tsx)": "<rootDir>/node_modules/ts-jest/preprocessor.js"
},
Expand All @@ -71,26 +72,25 @@
"statements": 95
}
},
"collectCoverage": true,
"mapCoverage": true
"collectCoverage": true
},
"devDependencies": {
"@types/jest": "^22.0.0",
"@types/node": "^9.3.0",
"asmcrypto.js": "^0.22.0",
"colors": "^1.1.2",
"commitizen": "^2.9.6",
"commitizen": "^3.0.7",
"coveralls": "^3.0.0",
"cross-env": "^5.0.1",
"cz-conventional-changelog": "^2.0.0",
"elliptic": "^6.4.0",
"husky": "^0.14.0",
"jest": "^22.0.2",
"jest": "^24.7.1",
"lint-staged": "^7.0.0",
"lodash.camelcase": "^4.3.0",
"node": "9.5.0",
"node-gyp": "3.6.2",
"node-webcrypto-ossl": "^1.0.36",
"node-gyp": "^3.8.0",
"node-webcrypto-ossl": "^1.0.37",
"prompt": "^1.0.0",
"replace-in-file": "^3.0.0-beta.2",
"rimraf": "^2.6.1",
Expand All @@ -102,15 +102,16 @@
"rollup-plugin-typescript2": "^0.11.1",
"semantic-release": "^15.0.0",
"text-encoding-shim": "^1.0.0",
"ts-jest": "^22.0.0",
"ts-jest": "^24.0.2",
"ts-node": "^5.0.1",
"tslint": "^5.8.0",
"tslint-config-standard": "^7.0.0",
"typedoc": "^0.11.0",
"typescript": "^2.8.3",
"typedoc": "^0.14.2",
"typescript": "^3.4.0",
"validate-commit-msg": "^2.12.2"
},
"dependencies": {
"@esentri/de-serializer": "^0.7.1"
"@esentri/de-serializer": "^0.9.6",
"@esentri/transformer-functions": "^0.3.5"
}
}
49 changes: 49 additions & 0 deletions src/KeyPair.ts
Expand Up @@ -2,6 +2,9 @@ import {PublicKey} from './PublicKey'
import {PrivateKey} from './PrivateKey'
import {KeyPairConfig} from './config/KeyPairConfig'
import {WebCryptoConfig} from './config/WebCryptoConfig'
import {KeyPairExtracted} from './KeyPairExtracted'
import {SymmetricKey} from './SymmetricKey'
import {WrappedKey} from './WrappedKey'

export class KeyPair {
private readonly publicKey: PublicKey
Expand All @@ -12,11 +15,57 @@ export class KeyPair {
this.privateKey = new PrivateKey(cryptoKey.privateKey)
}

public extractPublicKey (): Promise<string> {
return this.publicKey.extractKey()
}

public extractPrivateKey (): Promise<string> {
return this.privateKey.extractKey()
}

public extract (): Promise<KeyPairExtracted> {
const publicKeyPromise = this.extractPublicKey()
const privateKeyPromise = this.extractPrivateKey()
return Promise.all([publicKeyPromise, privateKeyPromise])
.then(extractedKeys => {
return new KeyPairExtracted(extractedKeys[0], extractedKeys[1])
})
}

public wrapKey (symmetricKey: SymmetricKey): Promise<WrappedKey> {
return this.publicKey.wrapKey(symmetricKey)
}

public unwrapKey (wrappedKey: WrappedKey): Promise<SymmetricKey> {
return this.privateKey.unwrapKey(wrappedKey.base64, wrappedKey.config)
}

public static random (config: KeyPairConfig = WebCryptoConfig.DEFAULT.keyPairConfig)
: Promise<KeyPair> {
return window.crypto.subtle.generateKey(config.keyParams, config.extractable, config.keyUsage)
.then(keyPair => {
return new KeyPair(keyPair as CryptoKeyPair)
}) as Promise<KeyPair>
}

public static fromPrivatePublic (privateKeyBase64: string,
publicKeyBase: string,
config = WebCryptoConfig.DEFAULT.keyPairConfig)
: Promise<KeyPair> {
const privateKeyPromise = PrivateKey.fromBase64(privateKeyBase64, config)
const publicKeyPromise = PublicKey.fromBase64(publicKeyBase, config)
return new Promise<KeyPair>((resolve, reject) => {
Promise.all([privateKeyPromise, publicKeyPromise]).then(keys => {
resolve(new KeyPair({privateKey: keys[0]['key'], publicKey: keys[1]['key']}))
}).catch(error => {
console.error('error in creating a keypair: ', error)
reject(error)
})
})
}

public static fromExtracted (keyPairExtracted: KeyPairExtracted,
config = WebCryptoConfig.DEFAULT.keyPairConfig): Promise<KeyPair> {
return this.fromPrivatePublic(keyPairExtracted.privateKey, keyPairExtracted.publicKey, config)
}
}
9 changes: 9 additions & 0 deletions src/KeyPairExtracted.ts
@@ -0,0 +1,9 @@
export class KeyPairExtracted {
public publicKey: string
public privateKey: string

constructor (publicKey: string, privateKey: string) {
this.publicKey = publicKey
this.privateKey = privateKey
}
}
47 changes: 47 additions & 0 deletions src/PrivateKey.ts
@@ -1,7 +1,54 @@
import {ArrayBufferToBase64, Base64ToArrayBuffer} from '@esentri/transformer-functions'
import {KeyPairConfig, KeyPairConfigBuilder} from './config/KeyPairConfig'
import {SymmetricKey} from './SymmetricKey'
import {SymmetricKeyConfig} from './config/SymmetricKeyConfig'
import {FilterPrivateKeyUsage} from './config/KeyUsage'

export class PrivateKey {
private readonly key: CryptoKey

constructor (key: CryptoKey) {
this.key = key
}

public extractKey (): Promise<string> {
return window.crypto.subtle.exportKey('pkcs8', this.key).then(rawKey => {
return ArrayBufferToBase64(rawKey)
}) as Promise<string>
}

public keyConfig(): KeyPairConfig {
return new KeyPairConfigBuilder()
.keyUsage(this.key.usages)
.keyAlgorithm(this.key.algorithm.name!)
.extractable(this.key.extractable)
.build()
}

public unwrapKey (base64: string, config: SymmetricKeyConfig = SymmetricKeyConfig.DEFAULT)
: Promise<SymmetricKey> {
return window.crypto.subtle.unwrapKey('raw',
Base64ToArrayBuffer(base64),
this.key,
this.key.algorithm.name!,
config.keyAlgorithm,
config.extractable,
config.keyUsage)
.then((key: CryptoKey) => new SymmetricKey(key)) as Promise<SymmetricKey>
}

public static fromBase64 (base64: string, config = KeyPairConfig.DEFAULT): Promise<PrivateKey> {
return new Promise<PrivateKey>((resolve, reject) => {
(window.crypto.subtle.importKey('pkcs8',
Base64ToArrayBuffer(base64),
config.keyParams,
config.extractable,
FilterPrivateKeyUsage(config.keyUsage)) as Promise<CryptoKey>)
.then(key => resolve(new PrivateKey(key)))
.catch(error => {
console.error('couldn\'t create a private key from base64: ', error)
reject(error)
})
})
}
}
45 changes: 45 additions & 0 deletions src/PublicKey.ts
@@ -1,7 +1,52 @@
import {ArrayBufferToBase64, Base64ToArrayBuffer} from '@esentri/transformer-functions'
import {KeyPairConfig, KeyPairConfigBuilder} from './config/KeyPairConfig'
import {SymmetricKey} from './SymmetricKey'
import {WrappedKey} from './WrappedKey'
import {FilterPublicKeyUsage} from './config/KeyUsage'

export class PublicKey {
private readonly key: CryptoKey

constructor (key: CryptoKey) {
this.key = key
}

public extractKey (): Promise<string> {
return window.crypto.subtle.exportKey('spki', this.key).then(rawKey => {
return ArrayBufferToBase64(rawKey)
}) as Promise<string>
}

public keyConfig(): KeyPairConfig {
return new KeyPairConfigBuilder()
.keyUsage(this.key.usages)
.keyAlgorithm(this.key.algorithm.name!)
.extractable(this.key.extractable)
.build()
}

public wrapKey (symmetricKey: SymmetricKey): Promise<WrappedKey> {
return window.crypto.subtle
.wrapKey('raw',
symmetricKey['cryptoKey'],
this.key,
this.key.algorithm.name!)
.then(rawKey =>
new WrappedKey(ArrayBufferToBase64(rawKey), symmetricKey.keyConfig())) as Promise<WrappedKey>
}

public static fromBase64 (hexString: string, config = KeyPairConfig.DEFAULT): Promise<PublicKey> {
return new Promise<PublicKey>(((resolve, reject) => {
(window.crypto.subtle.importKey('spki',
Base64ToArrayBuffer(hexString),
config.keyParams,
config.extractable,
FilterPublicKeyUsage(config.keyUsage)) as Promise<CryptoKey>)
.then(key => resolve(new PublicKey(key)))
.catch(error => {
console.error('couldn\'t create a public key from base64: ', error)
reject(error)
})
}))
}
}
57 changes: 51 additions & 6 deletions src/SymmetricKey.ts
@@ -1,8 +1,9 @@
import {SymmetricKeyConfig} from './config/SymmetricKeyConfig'
import {SymmetricKeyConfig, SymmetricKeyConfigBuilder} from './config/SymmetricKeyConfig'
import {WebCryptoConfig} from './config/WebCryptoConfig'
import {EncryptedObject} from './EncryptedObject'
import {InitializationVector} from './InitializationVector'
import {DeSerializeParameter, SerializedType, SimpleDeserialize, SimpleSerialize} from '@esentri/de-serializer'
import {DeSerializeParameter, DeSerializeParameterBuilder, SerializedType, SimpleDeserialize, SimpleSerialize} from '@esentri/de-serializer'
import {ArrayBufferToBase64, Base64ToArrayBuffer} from '@esentri/transformer-functions'

export class SymmetricKey {

Expand All @@ -13,10 +14,13 @@ export class SymmetricKey {
}

public encrypt (encryptee: any,
parameters: Array<DeSerializeParameter> = [DeSerializeParameter.WITH_FUNCTIONS])
vector: InitializationVector = InitializationVector.random(),
parameters: DeSerializeParameter = new DeSerializeParameterBuilder()
.withFunctions(true)
.serializedType(SerializedType.ARRAY_BUFFER)
.build())
: Promise<EncryptedObject> {
return SimpleSerialize(encryptee, parameters, SerializedType.ARRAY_BUFFER).then(encryptee => {
let vector = InitializationVector.random()
return SimpleSerialize(encryptee, parameters).then(encryptee => {
return window.crypto.subtle.encrypt(
{name: this.cryptoKey.algorithm.name!, iv: vector.asArray()},
this.cryptoKey,
Expand All @@ -32,10 +36,51 @@ export class SymmetricKey {
return window.crypto.subtle
.decrypt(decryptionParameters, this.cryptoKey, content).then(decrypted => {
if (prototype == null) return decrypted
return SimpleDeserialize(decrypted, prototype, SerializedType.ARRAY_BUFFER)
return SimpleDeserialize(decrypted, prototype)
}) as Promise<any>
}

public extractKey (): Promise<string> {
return window.crypto.subtle.exportKey('raw', this.cryptoKey).then(rawKey => {
return ArrayBufferToBase64(rawKey)
}) as Promise<string>
}

public keyConfig (): SymmetricKeyConfig {
return new SymmetricKeyConfigBuilder()
.keyAlgorithm(this.cryptoKey.algorithm.name!)
.extractable(this.cryptoKey.extractable)
.keyUsage(this.cryptoKey.usages)
.length((this.cryptoKey.algorithm as any)['length'])
.build()
}

public decryptionParameters (vector: InitializationVector | Uint8Array): any {
if (vector instanceof InitializationVector) vector = vector.asArray()
return {name: this.cryptoKey.algorithm.name, iv: vector}
}

public static fromBase64 (base64: string, config = SymmetricKeyConfig.DEFAULT)
: Promise<SymmetricKey> {
return this.fromRaw(Base64ToArrayBuffer(base64), config)
}

public static fromRaw (rawKey: ArrayBuffer, config = SymmetricKeyConfig.DEFAULT)
: Promise<SymmetricKey> {
// saving the keyParams in an extra variable is necessary because of a bug in one of the test
// libraries
const keyParams = {} as any
Object.assign(keyParams, config.keyParams)
return window.crypto.subtle.importKey('raw',
rawKey,
keyParams,
config.extractable,
config.keyUsage).then(key => {
console.log('par>: ', keyParams)
return new SymmetricKey(key)
}) as Promise<SymmetricKey>
}

static random (config: SymmetricKeyConfig = WebCryptoConfig.DEFAULT.symmetricKeyConfig)
: Promise<SymmetricKey> {
return window.crypto.subtle.generateKey(config.keyParams, config.extractable, config.keyUsage)
Expand Down
11 changes: 11 additions & 0 deletions src/WrappedKey.ts
@@ -0,0 +1,11 @@
import {SymmetricKeyConfig} from './crypto-wrapper'

export class WrappedKey {
public readonly base64: string
public readonly config: SymmetricKeyConfig

constructor (base64: string, config: SymmetricKeyConfig) {
this.base64 = base64
this.config = config
}
}
4 changes: 1 addition & 3 deletions src/config/KeyPairConfig.ts
Expand Up @@ -37,15 +37,13 @@ export class KeyPairConfig {
public static readonly DEFAULT: KeyPairConfig = new KeyPairConfig()
}


export class KeyPairConfigBuilder {
private _keyAlgorithm: string = KeyAlgorithm.RSA_OAEP
private _modulusLength: number = ModulusLength._2048
private _publicExponent: Uint8Array = PublicExponent.DEFAULT
private _hashAlgorithm: string = HashAlgorithm.SHA_512
private _extractable: boolean = true
private _keyUsage: Array<string> = [KeyUsage.ENCRYPT, KeyUsage.DECRYPT, KeyUsage.WRAP_KEY,
KeyUsage.UNWRAP_KEY]
private _keyUsage: Array<string> = [KeyUsage.ENCRYPT, KeyUsage.DECRYPT]

public keyAlgorithm (value: string): KeyPairConfigBuilder {
this._keyAlgorithm = value
Expand Down
8 changes: 8 additions & 0 deletions src/config/KeyUsage.ts
Expand Up @@ -8,3 +8,11 @@ export class KeyUsage {
public static readonly WRAP_KEY: string = 'wrapKey'
public static readonly UNWRAP_KEY: string = 'unwrapKey'
}

export function FilterPrivateKeyUsage(usage: Array<string>): Array<string> {
return usage.filter(use => use === KeyUsage.UNWRAP_KEY || use === KeyUsage.DECRYPT)
}

export function FilterPublicKeyUsage(usage: Array<string>): Array<string> {
return usage.filter(use => use === KeyUsage.ENCRYPT || use === KeyUsage.WRAP_KEY)
}
2 changes: 1 addition & 1 deletion src/config/SymmetricKeyConfig.ts
Expand Up @@ -20,7 +20,7 @@ export class SymmetricKeyConfig {
this.keyParams = {name: this.keyAlgorithm, length: this.length}
}

public static DEFAULT: SymmetricKeyConfig = new SymmetricKeyConfig()
public static readonly DEFAULT: SymmetricKeyConfig = new SymmetricKeyConfig()
}

export class SymmetricKeyConfigBuilder {
Expand Down

0 comments on commit c247b7f

Please sign in to comment.