UNPKG

node-aes-cmac

Version:

A pure Node.js implementation of the AES-CMAC algorithm (NIST 800-38B / RFC 4493).

86 lines (68 loc) 2.44 kB
var crypto = require('crypto'); var bufferTools = require('./buffer-tools.js'); var const_Zero = new Buffer('00000000000000000000000000000000', 'hex'); var const_Rb = new Buffer('00000000000000000000000000000087', 'hex'); var const_blockSize = 16; exports.generateSubkeys = function (key) { var l = aes(key, const_Zero); var subkey1 = bufferTools.bitShiftLeft(l); if (l[0] & 0x80) { subkey1 = bufferTools.xor(subkey1, const_Rb); } var subkey2 = bufferTools.bitShiftLeft(subkey1); if (subkey1[0] & 0x80) { subkey2 = bufferTools.xor(subkey2, const_Rb); } return { subkey1: subkey1, subkey2: subkey2 }; }; function aes(key, message) { var keyLengthToCipher = { 16: 'aes128', 24: 'aes192', 32: 'aes256' }; if (!keyLengthToCipher[key.length]) { throw new Error('Keys must be 128, 192, or 256 bits in length.'); } var cipher = crypto.createCipheriv(keyLengthToCipher[key.length], key, const_Zero); var result = cipher.update(message); cipher.final(); return result; } exports.aesCmac = function (key, message) { var subkeys = exports.generateSubkeys(key); var blockCount = Math.ceil(message.length / const_blockSize); var lastBlockCompleteFlag, lastBlock, lastBlockIndex; if (blockCount === 0) { blockCount = 1; lastBlockCompleteFlag = false } else { lastBlockCompleteFlag = (message.length % const_blockSize === 0); } lastBlockIndex = blockCount -1; if (lastBlockCompleteFlag) { lastBlock = bufferTools.xor(getMessageBlock(message, lastBlockIndex), subkeys.subkey1); } else { lastBlock = bufferTools.xor(getPaddedMessageBlock(message, lastBlockIndex), subkeys.subkey2); } var x = new Buffer('00000000000000000000000000000000', 'hex'); var y; for (var index = 0; index < lastBlockIndex; index++) { y = bufferTools.xor(x, getMessageBlock(message, index)); x = aes(key, y); } y = bufferTools.xor(lastBlock, x); return aes(key, y); }; function getMessageBlock(message, blockIndex) { var block = new Buffer(const_blockSize); var start = blockIndex * const_blockSize; var end = start + const_blockSize; message.copy(block, 0, start, end); return block; } function getPaddedMessageBlock(message, blockIndex) { var block = new Buffer(const_blockSize); var start = blockIndex * const_blockSize; var end = message.length; block.fill(0); message.copy(block, 0, start, end); block[end - start] = 0x80; return block; }