Path: blob/trunk/third_party/closure/goog/crypt/pbkdf2.js
2868 views
// Copyright 2012 The Closure Library Authors. All Rights Reserved.1//2// Licensed under the Apache License, Version 2.0 (the "License");3// you may not use this file except in compliance with the License.4// You may obtain a copy of the License at5//6// http://www.apache.org/licenses/LICENSE-2.07//8// Unless required by applicable law or agreed to in writing, software9// distributed under the License is distributed on an "AS-IS" BASIS,10// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.11// See the License for the specific language governing permissions and12// limitations under the License.1314/**15* @fileoverview Implementation of PBKDF2 in JavaScript.16* @see http://en.wikipedia.org/wiki/PBKDF217*18* Currently we only support HMAC-SHA1 as the underlying hash function. To add a19* new hash function, add a static method similar to deriveKeyFromPasswordSha1()20* and implement the specific computeBlockCallback() using the hash function.21*22* Usage:23* var key = pbkdf2.deriveKeySha1(24* stringToByteArray('password'), stringToByteArray('salt'), 1000, 128);25*26*/2728goog.provide('goog.crypt.pbkdf2');2930goog.require('goog.array');31goog.require('goog.asserts');32goog.require('goog.crypt');33goog.require('goog.crypt.Hmac');34goog.require('goog.crypt.Sha1');353637/**38* Derives key from password using PBKDF2-SHA139* @param {!Array<number>} password Byte array representation of the password40* from which the key is derived.41* @param {!Array<number>} initialSalt Byte array representation of the salt.42* @param {number} iterations Number of interations when computing the key.43* @param {number} keyLength Length of the output key in bits.44* Must be multiple of 8.45* @return {!Array<number>} Byte array representation of the output key.46*/47goog.crypt.pbkdf2.deriveKeySha1 = function(48password, initialSalt, iterations, keyLength) {49// Length of the HMAC-SHA1 output in bits.50var HASH_LENGTH = 160;5152/**53* Compute each block of the key using HMAC-SHA1.54* @param {!Array<number>} index Byte array representation of the index of55* the block to be computed.56* @return {!Array<number>} Byte array representation of the output block.57*/58var computeBlock = function(index) {59// Initialize the result to be array of 0 such that its xor with the first60// block would be the first block.61var result = goog.array.repeat(0, HASH_LENGTH / 8);62// Initialize the salt of the first iteration to initialSalt || i.63var salt = initialSalt.concat(index);64var hmac = new goog.crypt.Hmac(new goog.crypt.Sha1(), password, 64);65// Compute and XOR each iteration.66for (var i = 0; i < iterations; i++) {67// The salt of the next iteration is the result of the current iteration.68salt = hmac.getHmac(salt);69result = goog.crypt.xorByteArray(result, salt);70}71return result;72};7374return goog.crypt.pbkdf2.deriveKeyFromPassword_(75computeBlock, HASH_LENGTH, keyLength);76};777879/**80* Compute each block of the key using PBKDF2.81* @param {Function} computeBlock Function to compute each block of the output82* key.83* @param {number} hashLength Length of each block in bits. This is determined84* by the specific hash function used. Must be multiple of 8.85* @param {number} keyLength Length of the output key in bits.86* Must be multiple of 8.87* @return {!Array<number>} Byte array representation of the output key.88* @private89*/90goog.crypt.pbkdf2.deriveKeyFromPassword_ = function(91computeBlock, hashLength, keyLength) {92goog.asserts.assert(keyLength % 8 == 0, 'invalid output key length');9394// Compute and concactate each block of the output key.95var numBlocks = Math.ceil(keyLength / hashLength);96goog.asserts.assert(numBlocks >= 1, 'invalid number of blocks');97var result = [];98for (var i = 1; i <= numBlocks; i++) {99var indexBytes = goog.crypt.pbkdf2.integerToByteArray_(i);100result = result.concat(computeBlock(indexBytes));101}102103// Trim the last block if needed.104var lastBlockSize = keyLength % hashLength;105if (lastBlockSize != 0) {106var desiredBytes = ((numBlocks - 1) * hashLength + lastBlockSize) / 8;107result.splice(desiredBytes, (hashLength - lastBlockSize) / 8);108}109return result;110};111112113/**114* Converts an integer number to a 32-bit big endian byte array.115* @param {number} n Integer number to be converted.116* @return {!Array<number>} Byte Array representation of the 32-bit big endian117* encoding of n.118* @private119*/120goog.crypt.pbkdf2.integerToByteArray_ = function(n) {121var result = new Array(4);122result[0] = n >> 24 & 0xFF;123result[1] = n >> 16 & 0xFF;124result[2] = n >> 8 & 0xFF;125result[3] = n & 0xFF;126return result;127};128129130