Skip to content
This repository has been archived by the owner on Feb 7, 2023. It is now read-only.

Commit

Permalink
Update AES interfaces, fix encrypt/decrypt/finish in certain cases
Browse files Browse the repository at this point in the history
  • Loading branch information
Adam Lippai committed Jun 3, 2018
1 parent f193ecf commit b6eb05d
Show file tree
Hide file tree
Showing 11 changed files with 127 additions and 114 deletions.
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -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",
Expand Down
36 changes: 12 additions & 24 deletions src/aes/aes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand All @@ -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;

Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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];
Expand All @@ -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;
Expand Down Expand Up @@ -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];
Expand Down Expand Up @@ -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;
}
}
21 changes: 13 additions & 8 deletions src/aes/cbc.ts
Original file line number Diff line number Diff line change
@@ -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);
}
}
42 changes: 18 additions & 24 deletions src/aes/ccm.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand All @@ -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(
Expand Down Expand Up @@ -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 {
Expand Down Expand Up @@ -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;

Expand Down Expand Up @@ -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;
Expand All @@ -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;
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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 {
Expand Down
21 changes: 13 additions & 8 deletions src/aes/cfb.ts
Original file line number Diff line number Diff line change
@@ -1,26 +1,31 @@
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) {
super(key, iv, true, 'CFB');
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);
}
}
4 changes: 2 additions & 2 deletions src/aes/cmac.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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);

Expand Down Expand Up @@ -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;
}
}
21 changes: 13 additions & 8 deletions src/aes/ctr.ts
Original file line number Diff line number Diff line change
@@ -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) {
Expand All @@ -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 {
Expand Down
Loading

0 comments on commit b6eb05d

Please sign in to comment.