// Copyright 2012 The Closure Library Authors. All Rights Reserved. // // 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. /** * @fileoverview Implementation of CBC mode for block ciphers. See * http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation * #Cipher-block_chaining_.28CBC.29. for description. * * @author nnaze@google.com (Nathan Naze) */ goog.provide('goog.crypt.Cbc'); goog.require('goog.array'); goog.require('goog.asserts'); goog.require('goog.crypt'); goog.require('goog.crypt.BlockCipher'); /** * Implements the CBC mode for block ciphers. See * http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation * #Cipher-block_chaining_.28CBC.29 * * @param {!goog.crypt.BlockCipher} cipher The block cipher to use. * @constructor * @final * @struct */ goog.crypt.Cbc = function(cipher) { /** * Block cipher. * @type {!goog.crypt.BlockCipher} * @private */ this.cipher_ = cipher; }; /** * Encrypt a message. * * @param {!Array|!Uint8Array} plainText Message to encrypt. An array of * bytes. The length should be a multiple of the block size. * @param {!Array|!Uint8Array} initialVector Initial vector for the CBC * mode. An array of bytes with the same length as the block size. * @return {!Array} Encrypted message. */ goog.crypt.Cbc.prototype.encrypt = function(plainText, initialVector) { goog.asserts.assert( plainText.length % this.cipher_.BLOCK_SIZE == 0, 'Data\'s length must be multiple of block size.'); goog.asserts.assert( initialVector.length == this.cipher_.BLOCK_SIZE, 'Initial vector must be size of one block.'); // Implementation of // http://en.wikipedia.org/wiki/File:Cbc_encryption.png var cipherText = []; var vector = initialVector; // Generate each block of the encrypted cypher text. for (var blockStartIndex = 0; blockStartIndex < plainText.length; blockStartIndex += this.cipher_.BLOCK_SIZE) { // Takes one block from the input message. var plainTextBlock = goog.array.slice( plainText, blockStartIndex, blockStartIndex + this.cipher_.BLOCK_SIZE); var input = goog.crypt.xorByteArray(plainTextBlock, vector); var resultBlock = this.cipher_.encrypt(input); goog.array.extend(cipherText, resultBlock); vector = resultBlock; } return cipherText; }; /** * Decrypt a message. * * @param {!Array|!Uint8Array} cipherText Message to decrypt. An array * of bytes. The length should be a multiple of the block size. * @param {!Array|!Uint8Array} initialVector Initial vector for the CBC * mode. An array of bytes with the same length as the block size. * @return {!Array} Decrypted message. */ goog.crypt.Cbc.prototype.decrypt = function(cipherText, initialVector) { goog.asserts.assert( cipherText.length % this.cipher_.BLOCK_SIZE == 0, 'Data\'s length must be multiple of block size.'); goog.asserts.assert( initialVector.length == this.cipher_.BLOCK_SIZE, 'Initial vector must be size of one block.'); // Implementation of // http://en.wikipedia.org/wiki/File:Cbc_decryption.png var plainText = []; var blockStartIndex = 0; var vector = initialVector; // Generate each block of the decrypted plain text. while (blockStartIndex < cipherText.length) { // Takes one block. var cipherTextBlock = goog.array.slice( cipherText, blockStartIndex, blockStartIndex + this.cipher_.BLOCK_SIZE); var resultBlock = this.cipher_.decrypt(cipherTextBlock); var plainTextBlock = goog.crypt.xorByteArray(vector, resultBlock); goog.array.extend(plainText, plainTextBlock); vector = cipherTextBlock; blockStartIndex += this.cipher_.BLOCK_SIZE; } return plainText; };