123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128 |
- // 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 PBKDF2 in JavaScript.
- * @see http://en.wikipedia.org/wiki/PBKDF2
- *
- * Currently we only support HMAC-SHA1 as the underlying hash function. To add a
- * new hash function, add a static method similar to deriveKeyFromPasswordSha1()
- * and implement the specific computeBlockCallback() using the hash function.
- *
- * Usage:
- * var key = pbkdf2.deriveKeySha1(
- * stringToByteArray('password'), stringToByteArray('salt'), 1000, 128);
- *
- */
- goog.provide('goog.crypt.pbkdf2');
- goog.require('goog.array');
- goog.require('goog.asserts');
- goog.require('goog.crypt');
- goog.require('goog.crypt.Hmac');
- goog.require('goog.crypt.Sha1');
- /**
- * Derives key from password using PBKDF2-SHA1
- * @param {!Array<number>} password Byte array representation of the password
- * from which the key is derived.
- * @param {!Array<number>} initialSalt Byte array representation of the salt.
- * @param {number} iterations Number of interations when computing the key.
- * @param {number} keyLength Length of the output key in bits.
- * Must be multiple of 8.
- * @return {!Array<number>} Byte array representation of the output key.
- */
- goog.crypt.pbkdf2.deriveKeySha1 = function(
- password, initialSalt, iterations, keyLength) {
- // Length of the HMAC-SHA1 output in bits.
- var HASH_LENGTH = 160;
- /**
- * Compute each block of the key using HMAC-SHA1.
- * @param {!Array<number>} index Byte array representation of the index of
- * the block to be computed.
- * @return {!Array<number>} Byte array representation of the output block.
- */
- var computeBlock = function(index) {
- // Initialize the result to be array of 0 such that its xor with the first
- // block would be the first block.
- var result = goog.array.repeat(0, HASH_LENGTH / 8);
- // Initialize the salt of the first iteration to initialSalt || i.
- var salt = initialSalt.concat(index);
- var hmac = new goog.crypt.Hmac(new goog.crypt.Sha1(), password, 64);
- // Compute and XOR each iteration.
- for (var i = 0; i < iterations; i++) {
- // The salt of the next iteration is the result of the current iteration.
- salt = hmac.getHmac(salt);
- result = goog.crypt.xorByteArray(result, salt);
- }
- return result;
- };
- return goog.crypt.pbkdf2.deriveKeyFromPassword_(
- computeBlock, HASH_LENGTH, keyLength);
- };
- /**
- * Compute each block of the key using PBKDF2.
- * @param {Function} computeBlock Function to compute each block of the output
- * key.
- * @param {number} hashLength Length of each block in bits. This is determined
- * by the specific hash function used. Must be multiple of 8.
- * @param {number} keyLength Length of the output key in bits.
- * Must be multiple of 8.
- * @return {!Array<number>} Byte array representation of the output key.
- * @private
- */
- goog.crypt.pbkdf2.deriveKeyFromPassword_ = function(
- computeBlock, hashLength, keyLength) {
- goog.asserts.assert(keyLength % 8 == 0, 'invalid output key length');
- // Compute and concactate each block of the output key.
- var numBlocks = Math.ceil(keyLength / hashLength);
- goog.asserts.assert(numBlocks >= 1, 'invalid number of blocks');
- var result = [];
- for (var i = 1; i <= numBlocks; i++) {
- var indexBytes = goog.crypt.pbkdf2.integerToByteArray_(i);
- result = result.concat(computeBlock(indexBytes));
- }
- // Trim the last block if needed.
- var lastBlockSize = keyLength % hashLength;
- if (lastBlockSize != 0) {
- var desiredBytes = ((numBlocks - 1) * hashLength + lastBlockSize) / 8;
- result.splice(desiredBytes, (hashLength - lastBlockSize) / 8);
- }
- return result;
- };
- /**
- * Converts an integer number to a 32-bit big endian byte array.
- * @param {number} n Integer number to be converted.
- * @return {!Array<number>} Byte Array representation of the 32-bit big endian
- * encoding of n.
- * @private
- */
- goog.crypt.pbkdf2.integerToByteArray_ = function(n) {
- var result = new Array(4);
- result[0] = n >> 24 & 0xFF;
- result[1] = n >> 16 & 0xFF;
- result[2] = n >> 8 & 0xFF;
- result[3] = n & 0xFF;
- return result;
- };
|