TFS_ANTIGUO/SIGPC/ProyectoSIGPC/hfda/scripts/aes-cbc.js

375 lines
11 KiB
JavaScript
Raw Normal View History

//*******************************************************************************
//
// Copyright 2014 Microsoft
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
//*******************************************************************************
/// #region JSCop/JsHint
/* global msrcryptoPseudoRandom */
/* global msrcryptoJwk */
/* global operations */
/* global msrcryptoUtilities */
/* global msrcryptoBlockCipher */
/* jshint -W016 */ /* allows bitwise operators */
/// <reference path="random.js" />
/// <reference path="utilities.js" />
/// <reference path="operations.js" />
/// <reference path="jwk.js" />
/// <reference path="aes.js" />
/// <dictionary>
/// Cbc,msrcrypto,res
/// </dictionary>
/// <disable>JS3092.DeclarePropertiesBeforeUse</disable>
/// #endregion JSCop/JsHint
var msrcryptoPadding = msrcryptoPadding || {};
msrcryptoPadding.pkcsv7 = function (blockSize) {
function pad(messageBlocks) {
/// <signature>
/// <summary>Apply PKCS7 padding to message</summary>
/// <param name="messageBlocks" type="Array">An array of blocks to pad</param> <
/// </signature>
var lastIndex = messageBlocks.length - 1 >= 0 ? messageBlocks.length - 1 : 0,
lastBlock = messageBlocks[lastIndex],
lastBlockLength = lastBlock.length,
createNewBlock = (lastBlockLength === blockSize);
if (createNewBlock) {
var newBlock = [], i;
for (i = 0 ; i < blockSize; i += 1) {
newBlock.push(blockSize);
}
messageBlocks.push(newBlock);
} else {
var byteToAdd = (blockSize - lastBlockLength) & 0xff;
while (lastBlock.length !== blockSize) {
lastBlock.push(byteToAdd);
}
}
}
function unpad(messageBytes) {
/// <signature>
/// <summary>Remove PKCS7 padding from the message</summary>
/// <param name="messageBytes" type="Array"></param>
/// <returns type="Boolean">True for legal padding. False if not.</returns>
/// </signature>
var verified = true;
// Verify the cipher text is an increment of block length
if (messageBytes.length % blockSize !== 0) {
verified = false;
}
// Get the last block
var lastBlock = messageBytes.slice(-blockSize);
// Get value of the last element in the block
// This will be the number of padding bytes on the end if the
// message was decrypted correctly.
var padLen = lastBlock[lastBlock.length - 1];
for (var i = 0; i < blockSize; i++) {
var isPaddingElement = (blockSize - i <= padLen);
var isCorrectValue = (lastBlock[i] === padLen);
verified = (isPaddingElement ? isCorrectValue : true) && verified;
}
var trimLen = verified ? padLen : 0;
messageBytes.length -= trimLen;
return verified;
}
return {
pad: pad,
unpad: unpad
};
};
var msrcryptoCbc = function (blockCipher) {
var blockSize = blockCipher.blockSize / 8;
var paddingScheme = msrcryptoPadding.pkcsv7(blockSize);
// Merges an array of block arrays into a single byte array
var mergeBlocks = function (/*@type(Array)*/tab) {
var res = [], i, j;
for (i = 0 ; i < tab.length; i += 1) {
var block = tab[i];
for (j = 0 ; j < block.length; j += 1) {
res.push(block[j]);
}
}
return res;
};
// Breaks an array of bytes into an array of block size arrays of bytes
function getBlocks(dataBytes) {
var blocks = [];
// Append incoming bytes to the end of the existing buffered bytes
mBuffer = mBuffer.concat(dataBytes);
var blockCount = Math.floor(mBuffer.length / blockSize);
for (var i = 0; i < blockCount; i++) {
blocks.push(mBuffer.slice(i * blockSize, (i + 1) * blockSize));
}
// Set the buffer to the remaining bytes
mBuffer = mBuffer.slice(blockCount * blockSize);
return blocks;
}
function encryptBlocks(blocks) {
var result = [],
toEncrypt;
for (var i = 0; i < blocks.length; i++) {
toEncrypt = msrcryptoUtilities.xorVectors(mIvBytes, blocks[i]);
result.push(blockCipher.encrypt(toEncrypt));
mIvBytes = result[i];
}
return result;
}
function decryptBlocks(blocks) {
var result = [],
toDecrypt,
decrypted;
for (var i = 0 ; i < blocks.length; i += 1) {
toDecrypt = blocks[i].slice(0, blocks[i].length);
decrypted = blockCipher.decrypt(toDecrypt);
result.push(msrcryptoUtilities.xorVectors(mIvBytes, decrypted));
mIvBytes = blocks[i];
}
return result;
}
function clearState() {
mBuffer = [];
mResultBuffer = [];
mIvBytes = null;
}
var mBuffer = [],
mResultBuffer = [],
mIvBytes;
return {
init: function (ivBytes) {
if (ivBytes.length !== blockSize) {
throw new Error("Invalid iv size");
}
mIvBytes = ivBytes.slice();
},
// Does a full encryption of the input
encrypt: function (plainBytes) {
/// <summary>perform the encryption of the plain text message</summary>
/// <param name="plainBytes" type="Array">the plain text to encrypt</param>
/// <returns type="Array">the encrypted message</returns>
this.processEncrypt(plainBytes);
return this.finishEncrypt();
},
// Encrypts full blocks of streamed input
processEncrypt: function (plainBytes) {
var result = encryptBlocks(getBlocks(plainBytes));
mResultBuffer = mResultBuffer.concat(mergeBlocks(result));
return;
},
// Call when done streaming input
finishEncrypt: function () {
var blocks = mBuffer.length === 1 ? [[mBuffer[0]]] : [mBuffer];
paddingScheme.pad(blocks);
var result = mResultBuffer.concat(mergeBlocks(encryptBlocks(blocks)));
clearState();
return result;
},
// Does a full decryption and returns the result
decrypt: function (/*@type(Array)*/cipherBytes) {
/// <summary>perform the decryption of the encrypted message</summary>
/// <param name="encryptedBytes" type="Array">the plain text to encrypt</param>
/// <returns type="Array">the encrypted message</returns>
this.processDecrypt(cipherBytes);
return this.finishDecrypt();
},
// Decrypts full blocks of streamed data
processDecrypt: function (cipherBytes) {
var result = decryptBlocks(getBlocks(cipherBytes));
mResultBuffer = mResultBuffer.concat(mergeBlocks(result));
return;
},
// Called to finalize streamed decryption
finishDecrypt: function () {
var result = mResultBuffer;
// Strip the padding.
var verified = paddingScheme.unpad(result);
clearState();
return result;
}
};
};
var cbcInstance = null;
if (typeof operations !== "undefined") {
msrcryptoCbc.workerEncrypt = function (p) {
var result;
if (!cbcInstance) {
cbcInstance = msrcryptoCbc(msrcryptoBlockCipher.aes(p.keyData));
cbcInstance.init(p.algorithm.iv);
}
if (p.operationSubType === "process") {
cbcInstance.processEncrypt(p.buffer);
return;
}
if (p.operationSubType === "finish") {
result = cbcInstance.finishEncrypt();
cbcInstance = null;
return result;
}
result = cbcInstance.encrypt(p.buffer);
cbcInstance = null;
return result;
};
msrcryptoCbc.workerDecrypt = function (p) {
var result;
if (!cbcInstance) {
cbcInstance = msrcryptoCbc(msrcryptoBlockCipher.aes(p.keyData));
cbcInstance.init(p.algorithm.iv);
}
if (p.operationSubType === "process") {
cbcInstance.processDecrypt(p.buffer);
return;
}
if (p.operationSubType === "finish") {
result = cbcInstance.finishDecrypt();
cbcInstance = null;
return result;
}
result = cbcInstance.decrypt(p.buffer);
cbcInstance = null;
return result;
};
msrcryptoCbc.generateKey = function (p) {
if (p.algorithm.length % 8 !== 0) {
throw new Error();
}
return {
type: "keyGeneration",
keyData: msrcryptoPseudoRandom.getBytes(Math.floor(p.algorithm.length / 8)),
keyHandle: {
algorithm: p.algorithm,
extractable: p.extractable,
keyUsage: null || p.keyUsage,
type: "secret"
}
};
};
msrcryptoCbc.importKey = function (p) {
var keyObject = msrcryptoJwk.jwkToKey(p.keyData, p.algorithm, ["k"]);
return {
type: "keyImport",
keyData: keyObject.k,
keyHandle: {
algorithm: p.algorithm,
extractable: p.extractable || keyObject.extractable,
keyUsage: null || p.keyUsage,
type: "secret"
}
};
};
msrcryptoCbc.exportKey = function (p) {
var jsonKeyStringArray = msrcryptoJwk.keyToJwk(p.keyHandle, p.keyData);
return { type: "keyExport", keyHandle: jsonKeyStringArray };
};
operations.register("importKey", "aes-cbc", msrcryptoCbc.importKey);
operations.register("exportKey", "aes-cbc", msrcryptoCbc.exportKey);
operations.register("generateKey", "aes-cbc", msrcryptoCbc.generateKey);
operations.register("encrypt", "aes-cbc", msrcryptoCbc.workerEncrypt);
operations.register("decrypt", "aes-cbc", msrcryptoCbc.workerDecrypt);
}