Path: blob/trunk/third_party/closure/goog/crypt/arc4.js
2868 views
// Copyright 2005 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 ARC4 streamcipher implementation. A description of the16* algorithm can be found at:17* http://www.mozilla.org/projects/security/pki/nss/draft-kaukonen-cipher-arcfour-03.txt.18*19* Usage:20* <code>21* var arc4 = new goog.crypt.Arc4();22* arc4.setKey(key);23* arc4.discard(1536);24* arc4.crypt(bytes);25* </code>26*27* Note: For converting between strings and byte arrays, goog.crypt.base64 may28* be useful.29*30*/3132goog.provide('goog.crypt.Arc4');3334goog.require('goog.asserts');35363738/**39* ARC4 streamcipher implementation.40* @constructor41* @final42* @struct43*/44goog.crypt.Arc4 = function() {45/**46* A permutation of all 256 possible bytes.47* @type {Array<number>}48* @private49*/50this.state_ = [];5152/**53* 8 bit index pointer into this.state_.54* @type {number}55* @private56*/57this.index1_ = 0;5859/**60* 8 bit index pointer into this.state_.61* @type {number}62* @private63*/64this.index2_ = 0;65};666768/**69* Initialize the cipher for use with new key.70* @param {Array<number>} key A byte array containing the key.71* @param {number=} opt_length Indicates # of bytes to take from the key.72*/73goog.crypt.Arc4.prototype.setKey = function(key, opt_length) {74goog.asserts.assertArray(key, 'Key parameter must be a byte array');7576if (!opt_length) {77opt_length = key.length;78}7980var state = this.state_;8182for (var i = 0; i < 256; ++i) {83state[i] = i;84}8586var j = 0;87for (var i = 0; i < 256; ++i) {88j = (j + state[i] + key[i % opt_length]) & 255;8990var tmp = state[i];91state[i] = state[j];92state[j] = tmp;93}9495this.index1_ = 0;96this.index2_ = 0;97};9899100/**101* Discards n bytes of the keystream.102* These days 1536 is considered a decent amount to drop to get the key state103* warmed-up enough for secure usage. This is not done in the constructor to104* preserve efficiency for use cases that do not need this.105* NOTE: Discard is identical to crypt without actually xoring any data. It's106* unfortunate to have this code duplicated, but this was done for performance107* reasons. Alternatives which were attempted:108* 1. Create a temp array of the correct length and pass it to crypt. This109* works but needlessly allocates an array. But more importantly this110* requires choosing an array type (Array or Uint8Array) in discard, and111* choosing a different type than will be passed to crypt by the client112* code hurts the javascript engines ability to optimize crypt (7x hit in113* v8).114* 2. Make data option in crypt so discard can pass null, this has a huge115* perf hit for crypt.116* @param {number} length Number of bytes to disregard from the stream.117*/118goog.crypt.Arc4.prototype.discard = function(length) {119var i = this.index1_;120var j = this.index2_;121var state = this.state_;122123for (var n = 0; n < length; ++n) {124i = (i + 1) & 255;125j = (j + state[i]) & 255;126127var tmp = state[i];128state[i] = state[j];129state[j] = tmp;130}131132this.index1_ = i;133this.index2_ = j;134};135136137/**138* En- or decrypt (same operation for streamciphers like ARC4)139* @param {Array<number>|Uint8Array} data The data to be xor-ed in place.140* @param {number=} opt_length The number of bytes to crypt.141*/142goog.crypt.Arc4.prototype.crypt = function(data, opt_length) {143if (!opt_length) {144opt_length = data.length;145}146var i = this.index1_;147var j = this.index2_;148var state = this.state_;149150for (var n = 0; n < opt_length; ++n) {151i = (i + 1) & 255;152j = (j + state[i]) & 255;153154var tmp = state[i];155state[i] = state[j];156state[j] = tmp;157158data[n] ^= state[(state[i] + state[j]) & 255];159}160161this.index1_ = i;162this.index2_ = j;163};164165166