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

Commit

Permalink
Add AES-CMAC mode. Fix #133
Browse files Browse the repository at this point in the history
  • Loading branch information
Adam Lippai committed Feb 7, 2018
1 parent 1bfbeb8 commit 3adb482
Show file tree
Hide file tree
Showing 5 changed files with 120 additions and 1 deletion.
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": "0.21.0",
"version": "0.22.0",
"description": "Asm.js implementation of WebCrypto API",
"homepage": "https://github.com/vibornoff/asmcrypto.js",
"main": "asmcrypto.js",
Expand Down
63 changes: 63 additions & 0 deletions src/aes/cmac/cmac.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
import { AES_ECB } from '../ecb/ecb';
import { AES_CBC_Encrypt } from '../cbc/cbc';
import { bytes_to_hex, hex_to_bytes } from '../../utils';

/**
* @param {Uint8Array} data
*/
function mul2(data) {
const t = data[0] & 0x80;
for (var i = 0; i < 15; i++) {
data[i] = (data[i] << 1) ^ ((data[i+1] & 0x80) ? 1 : 0);
}
data[15] = (data[15] << 1) ^ (t ? 0x87 : 0);
}

export class AES_CMAC {
/**
* @param {Uint8Array} key
*/
constructor(key) {
this.k = new AES_ECB(key).encrypt(new Uint8Array(16)).result;
mul2(this.k);
this.cbc = new AES_CBC_Encrypt(key, new Uint8Array(16), false);

this.buffer = new Uint8Array(16);
this.bufferLength = 0;
this.result = null;
}

/**
* @param {Uint8Array} data
*/
process(data) {
if (this.bufferLength + data.length > 16) {
this.cbc.process(this.buffer.subarray(0, this.bufferLength));
const offset = ((this.bufferLength + data.length - 1) & ~15) - this.bufferLength;
this.cbc.process(data.subarray(0, offset));
this.buffer.set(data.subarray(offset));
this.bufferLength = data.length - offset;
} else {
this.buffer.set(data, this.bufferLength);
this.bufferLength += data.length;
}
return this;
}

finish() {
if (this.bufferLength !== 16) {
this.buffer[this.bufferLength] = 0x80;
for (let i = this.bufferLength + 1; i < 16; i++) {
this.buffer[i] = 0;
}
mul2(this.k);
}

for (let i = 0; i < 16; i++) {
this.buffer[i] ^= this.k[i];
}

this.result = this.cbc.process(this.buffer).result;
return this;
}
}
16 changes: 16 additions & 0 deletions src/aes/cmac/exports.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import { AES_CMAC } from './cmac';

/**
* @param {Uint8Array} data
* @param {Uint8Array} key
* @returns {Uint8Array}
*/
function AES_CMAC_bytes(data, key) {
if (data === undefined) throw new SyntaxError('data required');
if (key === undefined) throw new SyntaxError('key required');
return new AES_CMAC(key).process(data).finish().result;
}

AES_CMAC.bytes = AES_CMAC_bytes;

export { AES_CMAC };
1 change: 1 addition & 0 deletions src/entry-export_all.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ export * from './errors';
export * from './aes/cbc/exports';
export * from './aes/ccm/exports';
export * from './aes/cfb/exports';
export * from './aes/cmac/exports';
export * from './aes/ctr/exports';
export * from './aes/ecb/exports';
export * from './aes/gcm/exports';
Expand Down
39 changes: 39 additions & 0 deletions test/aes.js
Original file line number Diff line number Diff line change
Expand Up @@ -967,3 +967,42 @@ testIf( asmCrypto.AES_OFB !== undefined, "asmCrypto.AES_OFB", function () {
);
}
});

testIf( asmCrypto.AES_CMAC !== undefined, "asmCrypto.AES_CMAC", function () {
// key, data, result
var cmac_vectors = [
[
asmCrypto.hex_to_bytes('2b7e151628aed2a6abf7158809cf4f3c'),
asmCrypto.hex_to_bytes(''),
asmCrypto.hex_to_bytes('bb1d6929e95937287fa37d129b756746'),
],
[
asmCrypto.hex_to_bytes('2b7e151628aed2a6abf7158809cf4f3c'),
asmCrypto.hex_to_bytes('6bc1bee22e409f96e93d7e117393172a'),
asmCrypto.hex_to_bytes('070a16b46b4d4144f79bdd9dd04a287c'),
],
[
asmCrypto.hex_to_bytes('2b7e151628aed2a6abf7158809cf4f3c'),
asmCrypto.hex_to_bytes('6bc1bee22e409f96e93d7e117393172aae2d8a571e03ac9c9eb76fac45af8e5130c81c46a35ce411'),
asmCrypto.hex_to_bytes('dfa66747de9ae63030ca32611497c827'),
],
[
asmCrypto.hex_to_bytes('2b7e151628aed2a6abf7158809cf4f3c'),
asmCrypto.hex_to_bytes('6bc1bee22e409f96e93d7e117393172aae2d8a571e03ac9c9eb76fac45af8e5130c81c46a35ce411e5fbc1191a0a52eff69f2445df4f9b17ad2b417be66c3710'),
asmCrypto.hex_to_bytes('51f0bebf7e3b9d92fc49741779363cfe'),
],
];

for ( var i = 0; i < cmac_vectors.length; ++i ) {
var key = new Uint8Array( cmac_vectors[i][0] ),
data = new Uint8Array( cmac_vectors[i][1] ),
result = new Uint8Array( cmac_vectors[i][2] );

equal(
asmCrypto.bytes_to_hex( asmCrypto.AES_CMAC.bytes( data, key ) ),
asmCrypto.bytes_to_hex(result),
"cmac vector " + i
);

}
});

0 comments on commit 3adb482

Please sign in to comment.