diff --git a/package.json b/package.json index f24a6ad..c1ef27d 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "asmcrypto.js", - "version": "2.0.0", + "version": "2.0.1", "description": "Asm.js implementation of WebCrypto API", "homepage": "https://github.com/asmcrypto/asmcrypto.js", "main": "asmcrypto.all.js", diff --git a/src/aes/aes.ts b/src/aes/aes.ts index 811caff..54635d3 100644 --- a/src/aes/aes.ts +++ b/src/aes/aes.ts @@ -7,7 +7,6 @@ export abstract class AES { protected readonly asm: AES_asm; private readonly mode: string; protected padding: boolean; // TODO: This should be `private readonly`, hacking for AES-CFB?! - public result!: Uint8Array | null; protected pos: number = 0; protected len: number = 0; @@ -19,7 +18,6 @@ export abstract class AES { this.asm = new AES_asm(null, this.heap.buffer); // The AES object state - this.result = null; this.pos = 0; this.len = 0; @@ -54,7 +52,7 @@ export abstract class AES { this.padding = padding; } - AES_Encrypt_process(data: Uint8Array): this { + AES_Encrypt_process(data: Uint8Array): Uint8Array { if (!is_bytes(data)) throw new TypeError("data isn't of expected type"); let asm = this.asm; @@ -91,14 +89,13 @@ export abstract class AES { } } - this.result = result; this.pos = pos; this.len = len; - return this; + return result; } - AES_Encrypt_finish(): this { + AES_Encrypt_finish(): Uint8Array { let asm = this.asm; let heap = this.heap; let amode = AES_asm.ENC[this.mode]; @@ -122,23 +119,19 @@ export abstract class AES { len += plen; } - if (!this.result) throw new Error('There is no result'); - - const result = new Uint8Array(this.result.length + rlen); - result.set(this.result, 0); + const result = new Uint8Array(rlen); if (len) asm.cipher(amode, hpos + pos, len); - if (rlen) result.set(heap.subarray(pos, pos + rlen), this.result.length); + if (rlen) result.set(heap.subarray(pos, pos + rlen)); - this.result = result; this.pos = 0; this.len = 0; - return this; + return result; } - AES_Decrypt_process(data: Uint8Array): this { + AES_Decrypt_process(data: Uint8Array): Uint8Array { if (!is_bytes(data)) throw new TypeError("data isn't of expected type"); let asm = this.asm; @@ -181,14 +174,13 @@ export abstract class AES { } } - this.result = result; this.pos = pos; this.len = len; - return this; + return result; } - AES_Decrypt_finish(): this { + AES_Decrypt_finish(): Uint8Array { let asm = this.asm; let heap = this.heap; let amode = AES_asm.DEC[this.mode]; @@ -220,19 +212,15 @@ export abstract class AES { } } - if (!this.result) throw new Error('There is no result'); - - const result = new Uint8Array(rlen + this.result.length); - result.set(this.result, 0); + const result = new Uint8Array(rlen); if (rlen > 0) { - result.set(heap.subarray(pos, pos + rlen), this.result.length); + result.set(heap.subarray(pos, pos + rlen)); } - this.result = result; this.pos = 0; this.len = 0; - return this; + return result; } } diff --git a/src/aes/cbc.ts b/src/aes/cbc.ts index 95bd3b7..dfa6f4d 100644 --- a/src/aes/cbc.ts +++ b/src/aes/cbc.ts @@ -1,25 +1,30 @@ import { AES } from './aes'; +import { joinBytes } from '../other/utils'; export class AES_CBC extends AES { static encrypt(data: Uint8Array, key: Uint8Array, padding: boolean = true, iv?: Uint8Array): Uint8Array { - return new AES_CBC(key, iv, padding).encrypt(data).result as Uint8Array; + return new AES_CBC(key, iv, padding).encrypt(data); } static decrypt(data: Uint8Array, key: Uint8Array, padding: boolean = true, iv?: Uint8Array): Uint8Array { - return new AES_CBC(key, iv, padding).decrypt(data).result as Uint8Array; + return new AES_CBC(key, iv, padding).decrypt(data); } constructor(key: Uint8Array, iv?: Uint8Array, padding: boolean = true) { super(key, iv, padding, 'CBC'); } - encrypt(data: Uint8Array): this { - this.AES_Encrypt_process(data); - return this.AES_Encrypt_finish(); + encrypt(data: Uint8Array): Uint8Array { + const r1 = this.AES_Encrypt_process(data); + const r2 = this.AES_Encrypt_finish(); + + return joinBytes(r1, r2); } - decrypt(data: Uint8Array): this { - this.AES_Decrypt_process(data); - return this.AES_Decrypt_finish(); + decrypt(data: Uint8Array): Uint8Array { + const r1 = this.AES_Decrypt_process(data); + const r2 = this.AES_Decrypt_finish(); + + return joinBytes(r1, r2); } } diff --git a/src/aes/ccm.ts b/src/aes/ccm.ts index 1d67ace..078b2f8 100644 --- a/src/aes/ccm.ts +++ b/src/aes/ccm.ts @@ -36,7 +36,7 @@ export class AES_CCM extends AES { adata: Uint8Array | undefined, tagsize: number = 16, ): Uint8Array { - return new AES_CCM(key, nonce, adata, tagsize, clear.length).encrypt(clear).result as Uint8Array; + return new AES_CCM(key, nonce, adata, tagsize, clear.length).encrypt(clear); } static decrypt( cipher: Uint8Array, @@ -45,7 +45,7 @@ export class AES_CCM extends AES { adata: Uint8Array | undefined, tagsize: number = 16, ): Uint8Array { - return new AES_CCM(key, nonce, adata, tagsize, cipher.length - tagsize).decrypt(cipher).result as Uint8Array; + return new AES_CCM(key, nonce, adata, tagsize, cipher.length - tagsize).decrypt(cipher); } constructor( @@ -86,32 +86,30 @@ export class AES_CCM extends AES { this.AES_CTR_set_options(nonce, this.counter, 8 * this.lengthSize); } - encrypt(data: Uint8Array): this { + encrypt(data: Uint8Array): Uint8Array { this.dataLength = data.length || 0; - const result1 = this.AES_CCM_Encrypt_process(data).result as Uint8Array; - const result2 = this.AES_CCM_Encrypt_finish().result as Uint8Array; + const result1 = this.AES_CCM_Encrypt_process(data); + const result2 = this.AES_CCM_Encrypt_finish(); const result = new Uint8Array(result1.length + result2.length); if (result1.length) result.set(result1); if (result2.length) result.set(result2, result1.length); - this.result = result; - return this; + return result; } - decrypt(data: Uint8Array): this { + decrypt(data: Uint8Array): Uint8Array { this.dataLength = data.length || 0; - const result1 = this.AES_CCM_Decrypt_process(data).result as Uint8Array; - const result2 = this.AES_CCM_Decrypt_finish().result as Uint8Array; + const result1 = this.AES_CCM_Decrypt_process(data); + const result2 = this.AES_CCM_Decrypt_finish(); const result = new Uint8Array(result1.length + result2.length); if (result1.length) result.set(result1); if (result2.length) result.set(result2, result1.length); - this.result = result; - return this; + return result; } AES_CCM_calculate_iv(): void { @@ -166,7 +164,7 @@ export class AES_CCM extends AES { } } - AES_CCM_Encrypt_process(data: Uint8Array): this { + AES_CCM_Encrypt_process(data: Uint8Array): Uint8Array { const asm = this.asm; const heap = this.heap; @@ -208,15 +206,14 @@ export class AES_CCM extends AES { } } - this.result = result; this.counter = counter; this.pos = pos; this.len = len; - return this; + return result; } - AES_CCM_Encrypt_finish(): this { + AES_CCM_Encrypt_finish(): Uint8Array { const asm = this.asm; const heap = this.heap; const tagSize = this.tagSize; @@ -237,15 +234,14 @@ export class AES_CCM extends AES { asm.cipher(AES_asm.ENC.CTR, AES_asm.HEAP_DATA, 16); result.set(heap.subarray(0, tagSize), len); - this.result = result; this.counter = 1; this.pos = 0; this.len = 0; - return this; + return result; } - AES_CCM_Decrypt_process(data: Uint8Array): this { + AES_CCM_Decrypt_process(data: Uint8Array): Uint8Array { let dpos = 0; let dlen = data.length || 0; const asm = this.asm; @@ -284,15 +280,14 @@ export class AES_CCM extends AES { len += _heap_write(heap, 0, data, dpos, dlen); } - this.result = result; this.counter = counter; this.pos = pos; this.len = len; - return this; + return result; } - AES_CCM_Decrypt_finish(): this { + AES_CCM_Decrypt_finish(): Uint8Array { const asm = this.asm; const heap = this.heap; const tagSize = this.tagSize; @@ -320,12 +315,11 @@ export class AES_CCM extends AES { for (let j = 0; j < tagSize; ++j) acheck |= atag[j] ^ heap[j]; if (acheck) throw new SecurityError('data integrity check failed'); - this.result = result; this.counter = 1; this.pos = 0; this.len = 0; - return this; + return result; } private AES_CTR_set_options(nonce: Uint8Array, counter: number, size: number): void { diff --git a/src/aes/cfb.ts b/src/aes/cfb.ts index 1702d01..be90668 100644 --- a/src/aes/cfb.ts +++ b/src/aes/cfb.ts @@ -1,12 +1,13 @@ import { AES } from './aes'; +import { joinBytes } from '../other/utils'; export class AES_CFB extends AES { static encrypt(data: Uint8Array, key: Uint8Array, iv?: Uint8Array): Uint8Array { - return new AES_CFB(key, iv).encrypt(data).result as Uint8Array; + return new AES_CFB(key, iv).encrypt(data); } static decrypt(data: Uint8Array, key: Uint8Array, iv?: Uint8Array): Uint8Array { - return new AES_CFB(key, iv).decrypt(data).result as Uint8Array; + return new AES_CFB(key, iv).decrypt(data); } constructor(key: Uint8Array, iv?: Uint8Array) { @@ -14,13 +15,17 @@ export class AES_CFB extends AES { delete this.padding; } - encrypt(data: Uint8Array): this { - this.AES_Encrypt_process(data); - return this.AES_Encrypt_finish(); + encrypt(data: Uint8Array): Uint8Array { + const r1 = this.AES_Encrypt_process(data); + const r2 = this.AES_Encrypt_finish(); + + return joinBytes(r1, r2); } - decrypt(data: Uint8Array): this { - this.AES_Decrypt_process(data); - return this.AES_Decrypt_finish(); + decrypt(data: Uint8Array): Uint8Array { + const r1 = this.AES_Decrypt_process(data); + const r2 = this.AES_Decrypt_finish(); + + return joinBytes(r1, r2); } } diff --git a/src/aes/cmac.ts b/src/aes/cmac.ts index 67a9b62..2b76612 100644 --- a/src/aes/cmac.ts +++ b/src/aes/cmac.ts @@ -21,7 +21,7 @@ export class AES_CMAC { } constructor(key: Uint8Array) { - this.k = new AES_ECB(key).encrypt(new Uint8Array(16)).result as Uint8Array; + this.k = new AES_ECB(key).encrypt(new Uint8Array(16)); mul2(this.k); this.cbc = new AES_CBC(key, new Uint8Array(16), false); @@ -56,7 +56,7 @@ export class AES_CMAC { this.buffer[i] ^= this.k[i]; } - this.result = this.cbc.encrypt(this.buffer).result; + this.result = this.cbc.encrypt(this.buffer); return this; } } diff --git a/src/aes/ctr.ts b/src/aes/ctr.ts index 5cd3a87..061c159 100644 --- a/src/aes/ctr.ts +++ b/src/aes/ctr.ts @@ -1,13 +1,14 @@ import { AES } from './aes'; import { IllegalArgumentError } from '../other/errors'; +import { joinBytes } from '../other/utils'; export class AES_CTR extends AES { static encrypt(data: Uint8Array, key: Uint8Array, nonce: Uint8Array): Uint8Array { - return new AES_CTR(key, nonce).encrypt(data).result as Uint8Array; + return new AES_CTR(key, nonce).encrypt(data); } static decrypt(data: Uint8Array, key: Uint8Array, nonce: Uint8Array): Uint8Array { - return new AES_CTR(key, nonce).encrypt(data).result as Uint8Array; + return new AES_CTR(key, nonce).encrypt(data); } constructor(key: Uint8Array, nonce: Uint8Array) { @@ -17,14 +18,18 @@ export class AES_CTR extends AES { this.AES_CTR_set_options(nonce); } - encrypt(data: Uint8Array): this { - this.AES_Encrypt_process(data); - return this.AES_Encrypt_finish(); + encrypt(data: Uint8Array): Uint8Array { + const r1 = this.AES_Encrypt_process(data); + const r2 = this.AES_Encrypt_finish(); + + return joinBytes(r1, r2); } - decrypt(data: Uint8Array): this { - this.AES_Encrypt_process(data); - return this.AES_Encrypt_finish(); + decrypt(data: Uint8Array): Uint8Array { + const r1 = this.AES_Encrypt_process(data); + const r2 = this.AES_Encrypt_finish(); + + return joinBytes(r1, r2); } private AES_CTR_set_options(nonce: Uint8Array, counter?: number, size?: number): void { diff --git a/src/aes/ecb.ts b/src/aes/ecb.ts index 33913e0..7fc3ef8 100644 --- a/src/aes/ecb.ts +++ b/src/aes/ecb.ts @@ -1,25 +1,30 @@ import { AES } from './aes'; +import { joinBytes } from '../other/utils'; export class AES_ECB extends AES { static encrypt(data: Uint8Array, key: Uint8Array, padding: boolean = false): Uint8Array { - return new AES_ECB(key, padding).encrypt(data).result as Uint8Array; + return new AES_ECB(key, padding).encrypt(data); } static decrypt(data: Uint8Array, key: Uint8Array, padding: boolean = false): Uint8Array { - return new AES_ECB(key, padding).decrypt(data).result as Uint8Array; + return new AES_ECB(key, padding).decrypt(data); } constructor(key: Uint8Array, padding: boolean = false) { super(key, undefined, padding, 'ECB'); } - encrypt(data: Uint8Array): this { - this.AES_Encrypt_process(data); - return this.AES_Encrypt_finish(); + encrypt(data: Uint8Array): Uint8Array { + const r1 = this.AES_Encrypt_process(data); + const r2 = this.AES_Encrypt_finish(); + + return joinBytes(r1, r2); } - decrypt(data: Uint8Array): this { - this.AES_Decrypt_process(data); - return this.AES_Decrypt_finish(); + decrypt(data: Uint8Array): Uint8Array { + const r1 = this.AES_Decrypt_process(data); + const r2 = this.AES_Decrypt_finish(); + + return joinBytes(r1, r2); } } diff --git a/src/aes/gcm.ts b/src/aes/gcm.ts index f966a94..08b9dbc 100644 --- a/src/aes/gcm.ts +++ b/src/aes/gcm.ts @@ -18,7 +18,7 @@ export class AES_GCM extends AES { adata?: Uint8Array, tagsize?: number, ): Uint8Array { - return new AES_GCM(key, nonce, adata, tagsize).encrypt(cleartext).result as Uint8Array; + return new AES_GCM(key, nonce, adata, tagsize).encrypt(cleartext); } static decrypt( @@ -28,7 +28,7 @@ export class AES_GCM extends AES { adata?: Uint8Array, tagsize?: number, ): Uint8Array { - return new AES_GCM(key, nonce, adata, tagsize).decrypt(ciphertext).result as Uint8Array; + return new AES_GCM(key, nonce, adata, tagsize).decrypt(ciphertext); } constructor(key: Uint8Array, nonce: Uint8Array, adata?: Uint8Array, private readonly tagSize: number = 16) { @@ -107,7 +107,7 @@ export class AES_GCM extends AES { return this.AES_GCM_decrypt(data); } - AES_GCM_Encrypt_process(data: Uint8Array) { + AES_GCM_Encrypt_process(data: Uint8Array): Uint8Array { let dpos = 0; let dlen = data.length || 0; let asm = this.asm; @@ -145,15 +145,14 @@ export class AES_GCM extends AES { } } - this.result = result; this.counter = counter; this.pos = pos; this.len = len; - return this; + return result; } - AES_GCM_Encrypt_finish() { + AES_GCM_Encrypt_finish(): Uint8Array { let asm = this.asm; let heap = this.heap; let counter = this.counter; @@ -196,15 +195,14 @@ export class AES_GCM extends AES { asm.cipher(AES_asm.ENC.CTR, AES_asm.HEAP_DATA, 16); result.set(heap.subarray(0, tagSize), len); - this.result = result; this.counter = 1; this.pos = 0; this.len = 0; - return this; + return result; } - AES_GCM_Decrypt_process(data: Uint8Array) { + AES_GCM_Decrypt_process(data: Uint8Array): Uint8Array { let dpos = 0; let dlen = data.length || 0; let asm = this.asm; @@ -243,12 +241,11 @@ export class AES_GCM extends AES { len += _heap_write(heap, 0, data, dpos, dlen); } - this.result = result; this.counter = counter; this.pos = pos; this.len = len; - return this; + return result; } AES_GCM_Decrypt_finish() { @@ -300,36 +297,33 @@ export class AES_GCM extends AES { for (let i = 0; i < tagSize; ++i) acheck |= atag[i] ^ heap[i]; if (acheck) throw new SecurityError('data integrity check failed'); - this.result = result; this.counter = 1; this.pos = 0; this.len = 0; - return this; + return result; } - private AES_GCM_decrypt(data: Uint8Array) { - const result1 = this.AES_GCM_Decrypt_process(data).result as Uint8Array; - const result2 = this.AES_GCM_Decrypt_finish().result as Uint8Array; + private AES_GCM_decrypt(data: Uint8Array): Uint8Array { + const result1 = this.AES_GCM_Decrypt_process(data); + const result2 = this.AES_GCM_Decrypt_finish(); const result = new Uint8Array(result1.length + result2.length); if (result1.length) result.set(result1); if (result2.length) result.set(result2, result1.length); - this.result = result; - return this; + return result; } - private AES_GCM_encrypt(data: Uint8Array) { - const result1 = this.AES_GCM_Encrypt_process(data).result as Uint8Array; - const result2 = this.AES_GCM_Encrypt_finish().result as Uint8Array; + private AES_GCM_encrypt(data: Uint8Array): Uint8Array { + const result1 = this.AES_GCM_Encrypt_process(data); + const result2 = this.AES_GCM_Encrypt_finish(); const result = new Uint8Array(result1.length + result2.length); if (result1.length) result.set(result1); if (result2.length) result.set(result2, result1.length); - this.result = result; - return this; + return result; } _gcm_mac_process(data: Uint8Array) { diff --git a/src/aes/ofb.ts b/src/aes/ofb.ts index c2a0411..8a09d1d 100644 --- a/src/aes/ofb.ts +++ b/src/aes/ofb.ts @@ -1,25 +1,30 @@ import { AES } from './aes'; +import { joinBytes } from '../other/utils'; export class AES_OFB extends AES { static encrypt(data: Uint8Array, key: Uint8Array, iv?: Uint8Array): Uint8Array { - return new AES_OFB(key, iv).encrypt(data).result as Uint8Array; + return new AES_OFB(key, iv).encrypt(data); } static decrypt(data: Uint8Array, key: Uint8Array, iv?: Uint8Array): Uint8Array { - return new AES_OFB(key, iv).decrypt(data).result as Uint8Array; + return new AES_OFB(key, iv).decrypt(data); } constructor(key: Uint8Array, iv?: Uint8Array) { super(key, iv, false, 'OFB'); } - encrypt(data: Uint8Array): this { - this.AES_Encrypt_process(data); - return this.AES_Encrypt_finish(); + encrypt(data: Uint8Array): Uint8Array { + const r1 = this.AES_Encrypt_process(data); + const r2 = this.AES_Encrypt_finish(); + + return joinBytes(r1, r2); } - decrypt(data: Uint8Array): this { - this.AES_Decrypt_process(data); - return this.AES_Decrypt_finish(); + decrypt(data: Uint8Array): Uint8Array { + const r1 = this.AES_Decrypt_process(data); + const r2 = this.AES_Decrypt_finish(); + + return joinBytes(r1, r2); } } diff --git a/src/other/utils.ts b/src/other/utils.ts index a7f4820..7fe4704 100644 --- a/src/other/utils.ts +++ b/src/other/utils.ts @@ -159,3 +159,15 @@ export function _heap_write(heap: Uint8Array, hpos: number, data: Uint8Array, dp return wlen; } + +export function joinBytes(...arg: Uint8Array[]): Uint8Array { + const totalLenght = arg.reduce((sum, curr) => sum + curr.length, 0); + const ret = new Uint8Array(totalLenght); + + let cursor = 0; + for (let i = 0; i < arg.length; i++) { + ret.set(arg[i], cursor); + cursor += arg[i].length; + } + return ret; +}