Adding mapbox-gl branch
This commit is contained in:
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,24 @@
|
||||
<!doctype html>
|
||||
<html>
|
||||
<!--
|
||||
Copyright 2012 The Closure Library Authors. All Rights Reserved.
|
||||
|
||||
Use of this source code is governed by the Apache License, Version 2.0.
|
||||
See the COPYING file for details.
|
||||
-->
|
||||
<!--
|
||||
Unit test for goog.crypt.Aes
|
||||
-->
|
||||
<head>
|
||||
<title>
|
||||
goog.crypt.Aes unit test
|
||||
</title>
|
||||
<script src="../base.js">
|
||||
</script>
|
||||
<script>
|
||||
goog.require('goog.crypt.AesTest');
|
||||
</script>
|
||||
</head>
|
||||
<body>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,586 @@
|
||||
// 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.
|
||||
|
||||
goog.provide('goog.crypt.AesTest');
|
||||
goog.setTestOnly('goog.crypt.AesTest');
|
||||
|
||||
goog.require('goog.crypt');
|
||||
goog.require('goog.crypt.Aes');
|
||||
goog.require('goog.testing.jsunit');
|
||||
goog.crypt.Aes.ENABLE_TEST_MODE = true;
|
||||
|
||||
/*
|
||||
* Unit test for goog.crypt.Aes using the test vectors from the spec:
|
||||
* http://csrc.nist.gov/publications/fips/fips197/fips-197.pdf
|
||||
*/
|
||||
|
||||
var testData = null;
|
||||
|
||||
function test128() {
|
||||
doTest('000102030405060708090a0b0c0d0e0f',
|
||||
'00112233445566778899aabbccddeeff',
|
||||
v128,
|
||||
true /* encrypt */);
|
||||
}
|
||||
|
||||
function test192() {
|
||||
doTest('000102030405060708090a0b0c0d0e0f1011121314151617',
|
||||
'00112233445566778899aabbccddeeff',
|
||||
v192,
|
||||
true /* encrypt */);
|
||||
}
|
||||
|
||||
function test256() {
|
||||
doTest('000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f',
|
||||
'00112233445566778899aabbccddeeff',
|
||||
v256,
|
||||
true /* encrypt */);
|
||||
}
|
||||
|
||||
function test128d() {
|
||||
doTest('000102030405060708090a0b0c0d0e0f',
|
||||
'69c4e0d86a7b0430d8cdb78070b4c55a',
|
||||
v128d,
|
||||
false /* decrypt */);
|
||||
}
|
||||
|
||||
function test192d() {
|
||||
doTest('000102030405060708090a0b0c0d0e0f1011121314151617',
|
||||
'dda97ca4864cdfe06eaf70a0ec0d7191',
|
||||
v192d,
|
||||
false /* decrypt */);
|
||||
}
|
||||
|
||||
function test256d() {
|
||||
doTest('000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f',
|
||||
'8ea2b7ca516745bfeafc49904b496089',
|
||||
v256d,
|
||||
false /* decrypt */);
|
||||
}
|
||||
|
||||
function doTest(key, input, values, dir) {
|
||||
testData = values;
|
||||
var keyArray = goog.crypt.hexToByteArray(key);
|
||||
var aes = new goog.crypt.Aes(keyArray);
|
||||
|
||||
aes.testKeySchedule_ = onTestKeySchedule;
|
||||
aes.testStartRound_ = onTestStartRound;
|
||||
aes.testAfterSubBytes_ = onTestAfterSubBytes;
|
||||
aes.testAfterShiftRows_ = onTestAfterShiftRows;
|
||||
aes.testAfterMixColumns_ = onTestAfterMixColumns;
|
||||
aes.testAfterAddRoundKey_ = onTestAfterAddRoundKey;
|
||||
|
||||
var inputArr = goog.crypt.hexToByteArray(input);
|
||||
var keyArr = goog.crypt.hexToByteArray(key);
|
||||
var outputArr = [];
|
||||
|
||||
var outputArr;
|
||||
if (dir) {
|
||||
outputArr = aes.encrypt(inputArr);
|
||||
} else {
|
||||
outputArr = aes.decrypt(inputArr);
|
||||
}
|
||||
|
||||
assertEquals('Incorrect output for test ' + testData.name,
|
||||
testData[testData.length - 1].output,
|
||||
encodeHex(outputArr));
|
||||
}
|
||||
|
||||
function onTestKeySchedule(roundNum, keySchedule, keyScheduleIndex) {
|
||||
assertEquals(
|
||||
'Incorrect key for round ' + roundNum,
|
||||
testData[roundNum].k_sch, encodeKey(keySchedule, keyScheduleIndex));
|
||||
}
|
||||
|
||||
function onTestStartRound(roundNum, state) {
|
||||
assertEquals('Incorrect state for test ' + testData.name +
|
||||
' at start round ' + roundNum,
|
||||
testData[roundNum].start, encodeState(state));
|
||||
}
|
||||
|
||||
function onTestAfterSubBytes(roundNum, state) {
|
||||
assertEquals('Incorrect state for test ' + testData.name +
|
||||
' after sub bytes in round ' + roundNum,
|
||||
testData[roundNum].s_box, encodeState(state));
|
||||
}
|
||||
|
||||
function onTestAfterShiftRows(roundNum, state) {
|
||||
assertEquals('Incorrect state for test ' + testData.name +
|
||||
' after shift rows in round ' + roundNum,
|
||||
testData[roundNum].s_row, encodeState(state));
|
||||
}
|
||||
|
||||
function onTestAfterMixColumns(roundNum, state) {
|
||||
assertEquals('Incorrect state for test ' + testData.name +
|
||||
' after mix columns in round ' + roundNum,
|
||||
testData[roundNum].m_col, encodeState(state));
|
||||
}
|
||||
|
||||
function onTestAfterAddRoundKey(roundNum, state) {
|
||||
assertEquals('Incorrect state for test ' + testData.name +
|
||||
' after adding round key in round ' + roundNum,
|
||||
testData[roundNum].k_add, encodeState(state));
|
||||
}
|
||||
|
||||
function encodeHex(arr) {
|
||||
var str = [];
|
||||
|
||||
for (var i = 0; i < arr.length; i++) {
|
||||
str.push(encodeByte(arr[i]));
|
||||
}
|
||||
|
||||
return str.join('');
|
||||
}
|
||||
|
||||
function encodeState(state) {
|
||||
var s = [];
|
||||
|
||||
for (var c = 0; c < 4; c++) {
|
||||
for (var r = 0; r < 4; r++) {
|
||||
s.push(encodeByte(state[r][c]));
|
||||
}
|
||||
}
|
||||
|
||||
return s.join('');
|
||||
}
|
||||
|
||||
function encodeKey(key, round) {
|
||||
var s = [];
|
||||
|
||||
for (var r = round * 4; r < (round * 4 + 4); r++) {
|
||||
for (var c = 0; c < 4; c++) {
|
||||
s.push(encodeByte(key[r][c]));
|
||||
}
|
||||
}
|
||||
|
||||
return s.join('');
|
||||
}
|
||||
|
||||
function encodeByte(val) {
|
||||
val = Number(val).toString(16);
|
||||
|
||||
if (val.length == 1) {
|
||||
val = '0' + val;
|
||||
}
|
||||
|
||||
return val;
|
||||
}
|
||||
|
||||
var v128 = [];
|
||||
(function v128_init() {
|
||||
for (var i = 0; i <= 10; i++) v128[i] = {};
|
||||
v128.name = '128';
|
||||
v128[0].input = '00112233445566778899aabbccddeeff';
|
||||
v128[0].k_sch = '000102030405060708090a0b0c0d0e0f';
|
||||
v128[1].start = '00102030405060708090a0b0c0d0e0f0';
|
||||
v128[1].s_box = '63cab7040953d051cd60e0e7ba70e18c';
|
||||
v128[1].s_row = '6353e08c0960e104cd70b751bacad0e7';
|
||||
v128[1].m_col = '5f72641557f5bc92f7be3b291db9f91a';
|
||||
v128[1].k_sch = 'd6aa74fdd2af72fadaa678f1d6ab76fe';
|
||||
v128[2].start = '89d810e8855ace682d1843d8cb128fe4';
|
||||
v128[2].s_box = 'a761ca9b97be8b45d8ad1a611fc97369';
|
||||
v128[2].s_row = 'a7be1a6997ad739bd8c9ca451f618b61';
|
||||
v128[2].m_col = 'ff87968431d86a51645151fa773ad009';
|
||||
v128[2].k_sch = 'b692cf0b643dbdf1be9bc5006830b3fe';
|
||||
v128[3].start = '4915598f55e5d7a0daca94fa1f0a63f7';
|
||||
v128[3].s_box = '3b59cb73fcd90ee05774222dc067fb68';
|
||||
v128[3].s_row = '3bd92268fc74fb735767cbe0c0590e2d';
|
||||
v128[3].m_col = '4c9c1e66f771f0762c3f868e534df256';
|
||||
v128[3].k_sch = 'b6ff744ed2c2c9bf6c590cbf0469bf41';
|
||||
v128[4].start = 'fa636a2825b339c940668a3157244d17';
|
||||
v128[4].s_box = '2dfb02343f6d12dd09337ec75b36e3f0';
|
||||
v128[4].s_row = '2d6d7ef03f33e334093602dd5bfb12c7';
|
||||
v128[4].m_col = '6385b79ffc538df997be478e7547d691';
|
||||
v128[4].k_sch = '47f7f7bc95353e03f96c32bcfd058dfd';
|
||||
v128[5].start = '247240236966b3fa6ed2753288425b6c';
|
||||
v128[5].s_box = '36400926f9336d2d9fb59d23c42c3950';
|
||||
v128[5].s_row = '36339d50f9b539269f2c092dc4406d23';
|
||||
v128[5].m_col = 'f4bcd45432e554d075f1d6c51dd03b3c';
|
||||
v128[5].k_sch = '3caaa3e8a99f9deb50f3af57adf622aa';
|
||||
v128[6].start = 'c81677bc9b7ac93b25027992b0261996';
|
||||
v128[6].s_box = 'e847f56514dadde23f77b64fe7f7d490';
|
||||
v128[6].s_row = 'e8dab6901477d4653ff7f5e2e747dd4f';
|
||||
v128[6].m_col = '9816ee7400f87f556b2c049c8e5ad036';
|
||||
v128[6].k_sch = '5e390f7df7a69296a7553dc10aa31f6b';
|
||||
v128[7].start = 'c62fe109f75eedc3cc79395d84f9cf5d';
|
||||
v128[7].s_box = 'b415f8016858552e4bb6124c5f998a4c';
|
||||
v128[7].s_row = 'b458124c68b68a014b99f82e5f15554c';
|
||||
v128[7].m_col = 'c57e1c159a9bd286f05f4be098c63439';
|
||||
v128[7].k_sch = '14f9701ae35fe28c440adf4d4ea9c026';
|
||||
v128[8].start = 'd1876c0f79c4300ab45594add66ff41f';
|
||||
v128[8].s_box = '3e175076b61c04678dfc2295f6a8bfc0';
|
||||
v128[8].s_row = '3e1c22c0b6fcbf768da85067f6170495';
|
||||
v128[8].m_col = 'baa03de7a1f9b56ed5512cba5f414d23';
|
||||
v128[8].k_sch = '47438735a41c65b9e016baf4aebf7ad2';
|
||||
v128[9].start = 'fde3bad205e5d0d73547964ef1fe37f1';
|
||||
v128[9].s_box = '5411f4b56bd9700e96a0902fa1bb9aa1';
|
||||
v128[9].s_row = '54d990a16ba09ab596bbf40ea111702f';
|
||||
v128[9].m_col = 'e9f74eec023020f61bf2ccf2353c21c7';
|
||||
v128[9].k_sch = '549932d1f08557681093ed9cbe2c974e';
|
||||
v128[10].start = 'bd6e7c3df2b5779e0b61216e8b10b689';
|
||||
v128[10].s_box = '7a9f102789d5f50b2beffd9f3dca4ea7';
|
||||
v128[10].s_row = '7ad5fda789ef4e272bca100b3d9ff59f';
|
||||
v128[10].k_sch = '13111d7fe3944a17f307a78b4d2b30c5';
|
||||
v128[10].output = '69c4e0d86a7b0430d8cdb78070b4c55a';
|
||||
})();
|
||||
|
||||
var v128d = [];
|
||||
(function v128d_init() {
|
||||
for (var i = 0; i <= 10; i++) v128d[i] = {};
|
||||
v128d.name = '128d';
|
||||
v128d[0].input = '69c4e0d86a7b0430d8cdb78070b4c55a';
|
||||
v128d[0].k_sch = '13111d7fe3944a17f307a78b4d2b30c5';
|
||||
v128d[1].start = '7ad5fda789ef4e272bca100b3d9ff59f';
|
||||
v128d[1].s_row = '7a9f102789d5f50b2beffd9f3dca4ea7';
|
||||
v128d[1].s_box = 'bd6e7c3df2b5779e0b61216e8b10b689';
|
||||
v128d[1].k_sch = '549932d1f08557681093ed9cbe2c974e';
|
||||
v128d[1].k_add = 'e9f74eec023020f61bf2ccf2353c21c7';
|
||||
v128d[2].start = '54d990a16ba09ab596bbf40ea111702f';
|
||||
v128d[2].s_row = '5411f4b56bd9700e96a0902fa1bb9aa1';
|
||||
v128d[2].s_box = 'fde3bad205e5d0d73547964ef1fe37f1';
|
||||
v128d[2].k_sch = '47438735a41c65b9e016baf4aebf7ad2';
|
||||
v128d[2].k_add = 'baa03de7a1f9b56ed5512cba5f414d23';
|
||||
v128d[3].start = '3e1c22c0b6fcbf768da85067f6170495';
|
||||
v128d[3].s_row = '3e175076b61c04678dfc2295f6a8bfc0';
|
||||
v128d[3].s_box = 'd1876c0f79c4300ab45594add66ff41f';
|
||||
v128d[3].k_sch = '14f9701ae35fe28c440adf4d4ea9c026';
|
||||
v128d[3].k_add = 'c57e1c159a9bd286f05f4be098c63439';
|
||||
v128d[4].start = 'b458124c68b68a014b99f82e5f15554c';
|
||||
v128d[4].s_row = 'b415f8016858552e4bb6124c5f998a4c';
|
||||
v128d[4].s_box = 'c62fe109f75eedc3cc79395d84f9cf5d';
|
||||
v128d[4].k_sch = '5e390f7df7a69296a7553dc10aa31f6b';
|
||||
v128d[4].k_add = '9816ee7400f87f556b2c049c8e5ad036';
|
||||
v128d[5].start = 'e8dab6901477d4653ff7f5e2e747dd4f';
|
||||
v128d[5].s_row = 'e847f56514dadde23f77b64fe7f7d490';
|
||||
v128d[5].s_box = 'c81677bc9b7ac93b25027992b0261996';
|
||||
v128d[5].k_sch = '3caaa3e8a99f9deb50f3af57adf622aa';
|
||||
v128d[5].k_add = 'f4bcd45432e554d075f1d6c51dd03b3c';
|
||||
v128d[6].start = '36339d50f9b539269f2c092dc4406d23';
|
||||
v128d[6].s_row = '36400926f9336d2d9fb59d23c42c3950';
|
||||
v128d[6].s_box = '247240236966b3fa6ed2753288425b6c';
|
||||
v128d[6].k_sch = '47f7f7bc95353e03f96c32bcfd058dfd';
|
||||
v128d[6].k_add = '6385b79ffc538df997be478e7547d691';
|
||||
v128d[7].start = '2d6d7ef03f33e334093602dd5bfb12c7';
|
||||
v128d[7].s_row = '2dfb02343f6d12dd09337ec75b36e3f0';
|
||||
v128d[7].s_box = 'fa636a2825b339c940668a3157244d17';
|
||||
v128d[7].k_sch = 'b6ff744ed2c2c9bf6c590cbf0469bf41';
|
||||
v128d[7].k_add = '4c9c1e66f771f0762c3f868e534df256';
|
||||
v128d[8].start = '3bd92268fc74fb735767cbe0c0590e2d';
|
||||
v128d[8].s_row = '3b59cb73fcd90ee05774222dc067fb68';
|
||||
v128d[8].s_box = '4915598f55e5d7a0daca94fa1f0a63f7';
|
||||
v128d[8].k_sch = 'b692cf0b643dbdf1be9bc5006830b3fe';
|
||||
v128d[8].k_add = 'ff87968431d86a51645151fa773ad009';
|
||||
v128d[9].start = 'a7be1a6997ad739bd8c9ca451f618b61';
|
||||
v128d[9].s_row = 'a761ca9b97be8b45d8ad1a611fc97369';
|
||||
v128d[9].s_box = '89d810e8855ace682d1843d8cb128fe4';
|
||||
v128d[9].k_sch = 'd6aa74fdd2af72fadaa678f1d6ab76fe';
|
||||
v128d[9].k_add = '5f72641557f5bc92f7be3b291db9f91a';
|
||||
v128d[10].start = '6353e08c0960e104cd70b751bacad0e7';
|
||||
v128d[10].s_row = '63cab7040953d051cd60e0e7ba70e18c';
|
||||
v128d[10].s_box = '00102030405060708090a0b0c0d0e0f0';
|
||||
v128d[10].k_sch = '000102030405060708090a0b0c0d0e0f';
|
||||
v128d[10].output = '00112233445566778899aabbccddeeff';
|
||||
})();
|
||||
|
||||
var v192 = [];
|
||||
(function v192_init() {
|
||||
for (var i = 0; i <= 12; i++) v192[i] = {};
|
||||
v192.name = '192';
|
||||
v192[0].input = '00112233445566778899aabbccddeeff';
|
||||
v192[0].k_sch = '000102030405060708090a0b0c0d0e0f';
|
||||
v192[1].start = '00102030405060708090a0b0c0d0e0f0';
|
||||
v192[1].s_box = '63cab7040953d051cd60e0e7ba70e18c';
|
||||
v192[1].s_row = '6353e08c0960e104cd70b751bacad0e7';
|
||||
v192[1].m_col = '5f72641557f5bc92f7be3b291db9f91a';
|
||||
v192[1].k_sch = '10111213141516175846f2f95c43f4fe';
|
||||
v192[2].start = '4f63760643e0aa85aff8c9d041fa0de4';
|
||||
v192[2].s_box = '84fb386f1ae1ac977941dd70832dd769';
|
||||
v192[2].s_row = '84e1dd691a41d76f792d389783fbac70';
|
||||
v192[2].m_col = '9f487f794f955f662afc86abd7f1ab29';
|
||||
v192[2].k_sch = '544afef55847f0fa4856e2e95c43f4fe';
|
||||
v192[3].start = 'cb02818c17d2af9c62aa64428bb25fd7';
|
||||
v192[3].s_box = '1f770c64f0b579deaaac432c3d37cf0e';
|
||||
v192[3].s_row = '1fb5430ef0accf64aa370cde3d77792c';
|
||||
v192[3].m_col = 'b7a53ecbbf9d75a0c40efc79b674cc11';
|
||||
v192[3].k_sch = '40f949b31cbabd4d48f043b810b7b342';
|
||||
v192[4].start = 'f75c7778a327c8ed8cfebfc1a6c37f53';
|
||||
v192[4].s_box = '684af5bc0acce85564bb0878242ed2ed';
|
||||
v192[4].s_row = '68cc08ed0abbd2bc642ef555244ae878';
|
||||
v192[4].m_col = '7a1e98bdacb6d1141a6944dd06eb2d3e';
|
||||
v192[4].k_sch = '58e151ab04a2a5557effb5416245080c';
|
||||
v192[5].start = '22ffc916a81474416496f19c64ae2532';
|
||||
v192[5].s_box = '9316dd47c2fa92834390a1de43e43f23';
|
||||
v192[5].s_row = '93faa123c2903f4743e4dd83431692de';
|
||||
v192[5].m_col = 'aaa755b34cffe57cef6f98e1f01c13e6';
|
||||
v192[5].k_sch = '2ab54bb43a02f8f662e3a95d66410c08';
|
||||
v192[6].start = '80121e0776fd1d8a8d8c31bc965d1fee';
|
||||
v192[6].s_box = 'cdc972c53854a47e5d64c765904cc028';
|
||||
v192[6].s_row = 'cd54c7283864c0c55d4c727e90c9a465';
|
||||
v192[6].m_col = '921f748fd96e937d622d7725ba8ba50c';
|
||||
v192[6].k_sch = 'f501857297448d7ebdf1c6ca87f33e3c';
|
||||
v192[7].start = '671ef1fd4e2a1e03dfdcb1ef3d789b30';
|
||||
v192[7].s_box = '8572a1542fe5727b9e86c8df27bc1404';
|
||||
v192[7].s_row = '85e5c8042f8614549ebca17b277272df';
|
||||
v192[7].m_col = 'e913e7b18f507d4b227ef652758acbcc';
|
||||
v192[7].k_sch = 'e510976183519b6934157c9ea351f1e0';
|
||||
v192[8].start = '0c0370d00c01e622166b8accd6db3a2c';
|
||||
v192[8].s_box = 'fe7b5170fe7c8e93477f7e4bf6b98071';
|
||||
v192[8].s_row = 'fe7c7e71fe7f807047b95193f67b8e4b';
|
||||
v192[8].m_col = '6cf5edf996eb0a069c4ef21cbfc25762';
|
||||
v192[8].k_sch = '1ea0372a995309167c439e77ff12051e';
|
||||
v192[9].start = '7255dad30fb80310e00d6c6b40d0527c';
|
||||
v192[9].s_box = '40fc5766766c7bcae1d7507f09700010';
|
||||
v192[9].s_row = '406c501076d70066e17057ca09fc7b7f';
|
||||
v192[9].m_col = '7478bcdce8a50b81d4327a9009188262';
|
||||
v192[9].k_sch = 'dd7e0e887e2fff68608fc842f9dcc154';
|
||||
v192[10].start = 'a906b254968af4e9b4bdb2d2f0c44336';
|
||||
v192[10].s_box = 'd36f3720907ebf1e8d7a37b58c1c1a05';
|
||||
v192[10].s_row = 'd37e3705907a1a208d1c371e8c6fbfb5';
|
||||
v192[10].m_col = '0d73cc2d8f6abe8b0cf2dd9bb83d422e';
|
||||
v192[10].k_sch = '859f5f237a8d5a3dc0c02952beefd63a';
|
||||
v192[11].start = '88ec930ef5e7e4b6cc32f4c906d29414';
|
||||
v192[11].s_box = 'c4cedcabe694694e4b23bfdd6fb522fa';
|
||||
v192[11].s_row = 'c494bffae62322ab4bb5dc4e6fce69dd';
|
||||
v192[11].m_col = '71d720933b6d677dc00b8f28238e0fb7';
|
||||
v192[11].k_sch = 'de601e7827bcdf2ca223800fd8aeda32';
|
||||
v192[12].start = 'afb73eeb1cd1b85162280f27fb20d585';
|
||||
v192[12].s_box = '79a9b2e99c3e6cd1aa3476cc0fb70397';
|
||||
v192[12].s_row = '793e76979c3403e9aab7b2d10fa96ccc';
|
||||
v192[12].k_sch = 'a4970a331a78dc09c418c271e3a41d5d';
|
||||
v192[12].output = 'dda97ca4864cdfe06eaf70a0ec0d7191';
|
||||
})();
|
||||
|
||||
var v192d = [];
|
||||
(function v192d_init() {
|
||||
for (var i = 0; i <= 12; i++) v192d[i] = {};
|
||||
v192d.name = '192d';
|
||||
v192d[0].input = 'dda97ca4864cdfe06eaf70a0ec0d7191';
|
||||
v192d[0].k_sch = 'a4970a331a78dc09c418c271e3a41d5d';
|
||||
v192d[1].start = '793e76979c3403e9aab7b2d10fa96ccc';
|
||||
v192d[1].s_row = '79a9b2e99c3e6cd1aa3476cc0fb70397';
|
||||
v192d[1].s_box = 'afb73eeb1cd1b85162280f27fb20d585';
|
||||
v192d[1].k_sch = 'de601e7827bcdf2ca223800fd8aeda32';
|
||||
v192d[1].k_add = '71d720933b6d677dc00b8f28238e0fb7';
|
||||
v192d[2].start = 'c494bffae62322ab4bb5dc4e6fce69dd';
|
||||
v192d[2].s_row = 'c4cedcabe694694e4b23bfdd6fb522fa';
|
||||
v192d[2].s_box = '88ec930ef5e7e4b6cc32f4c906d29414';
|
||||
v192d[2].k_sch = '859f5f237a8d5a3dc0c02952beefd63a';
|
||||
v192d[2].k_add = '0d73cc2d8f6abe8b0cf2dd9bb83d422e';
|
||||
v192d[3].start = 'd37e3705907a1a208d1c371e8c6fbfb5';
|
||||
v192d[3].s_row = 'd36f3720907ebf1e8d7a37b58c1c1a05';
|
||||
v192d[3].s_box = 'a906b254968af4e9b4bdb2d2f0c44336';
|
||||
v192d[3].k_sch = 'dd7e0e887e2fff68608fc842f9dcc154';
|
||||
v192d[3].k_add = '7478bcdce8a50b81d4327a9009188262';
|
||||
v192d[4].start = '406c501076d70066e17057ca09fc7b7f';
|
||||
v192d[4].s_row = '40fc5766766c7bcae1d7507f09700010';
|
||||
v192d[4].s_box = '7255dad30fb80310e00d6c6b40d0527c';
|
||||
v192d[4].k_sch = '1ea0372a995309167c439e77ff12051e';
|
||||
v192d[4].k_add = '6cf5edf996eb0a069c4ef21cbfc25762';
|
||||
v192d[5].start = 'fe7c7e71fe7f807047b95193f67b8e4b';
|
||||
v192d[5].s_row = 'fe7b5170fe7c8e93477f7e4bf6b98071';
|
||||
v192d[5].s_box = '0c0370d00c01e622166b8accd6db3a2c';
|
||||
v192d[5].k_sch = 'e510976183519b6934157c9ea351f1e0';
|
||||
v192d[5].k_add = 'e913e7b18f507d4b227ef652758acbcc';
|
||||
v192d[6].start = '85e5c8042f8614549ebca17b277272df';
|
||||
v192d[6].s_row = '8572a1542fe5727b9e86c8df27bc1404';
|
||||
v192d[6].s_box = '671ef1fd4e2a1e03dfdcb1ef3d789b30';
|
||||
v192d[6].k_sch = 'f501857297448d7ebdf1c6ca87f33e3c';
|
||||
v192d[6].k_add = '921f748fd96e937d622d7725ba8ba50c';
|
||||
v192d[7].start = 'cd54c7283864c0c55d4c727e90c9a465';
|
||||
v192d[7].s_row = 'cdc972c53854a47e5d64c765904cc028';
|
||||
v192d[7].s_box = '80121e0776fd1d8a8d8c31bc965d1fee';
|
||||
v192d[7].k_sch = '2ab54bb43a02f8f662e3a95d66410c08';
|
||||
v192d[7].k_add = 'aaa755b34cffe57cef6f98e1f01c13e6';
|
||||
v192d[8].start = '93faa123c2903f4743e4dd83431692de';
|
||||
v192d[8].s_row = '9316dd47c2fa92834390a1de43e43f23';
|
||||
v192d[8].s_box = '22ffc916a81474416496f19c64ae2532';
|
||||
v192d[8].k_sch = '58e151ab04a2a5557effb5416245080c';
|
||||
v192d[8].k_add = '7a1e98bdacb6d1141a6944dd06eb2d3e';
|
||||
v192d[9].start = '68cc08ed0abbd2bc642ef555244ae878';
|
||||
v192d[9].s_row = '684af5bc0acce85564bb0878242ed2ed';
|
||||
v192d[9].s_box = 'f75c7778a327c8ed8cfebfc1a6c37f53';
|
||||
v192d[9].k_sch = '40f949b31cbabd4d48f043b810b7b342';
|
||||
v192d[9].k_add = 'b7a53ecbbf9d75a0c40efc79b674cc11';
|
||||
v192d[10].start = '1fb5430ef0accf64aa370cde3d77792c';
|
||||
v192d[10].s_row = '1f770c64f0b579deaaac432c3d37cf0e';
|
||||
v192d[10].s_box = 'cb02818c17d2af9c62aa64428bb25fd7';
|
||||
v192d[10].k_sch = '544afef55847f0fa4856e2e95c43f4fe';
|
||||
v192d[10].k_add = '9f487f794f955f662afc86abd7f1ab29';
|
||||
v192d[11].start = '84e1dd691a41d76f792d389783fbac70';
|
||||
v192d[11].s_row = '84fb386f1ae1ac977941dd70832dd769';
|
||||
v192d[11].s_box = '4f63760643e0aa85aff8c9d041fa0de4';
|
||||
v192d[11].k_sch = '10111213141516175846f2f95c43f4fe';
|
||||
v192d[11].k_add = '5f72641557f5bc92f7be3b291db9f91a';
|
||||
v192d[12].start = '6353e08c0960e104cd70b751bacad0e7';
|
||||
v192d[12].s_row = '63cab7040953d051cd60e0e7ba70e18c';
|
||||
v192d[12].s_box = '00102030405060708090a0b0c0d0e0f0';
|
||||
v192d[12].k_sch = '000102030405060708090a0b0c0d0e0f';
|
||||
v192d[12].output = '00112233445566778899aabbccddeeff';
|
||||
})();
|
||||
|
||||
var v256 = [];
|
||||
(function v256_init() {
|
||||
for (var i = 0; i <= 14; i++) v256[i] = {};
|
||||
v256.name = '256';
|
||||
v256[0].input = '00112233445566778899aabbccddeeff';
|
||||
v256[0].k_sch = '000102030405060708090a0b0c0d0e0f';
|
||||
v256[1].start = '00102030405060708090a0b0c0d0e0f0';
|
||||
v256[1].s_box = '63cab7040953d051cd60e0e7ba70e18c';
|
||||
v256[1].s_row = '6353e08c0960e104cd70b751bacad0e7';
|
||||
v256[1].m_col = '5f72641557f5bc92f7be3b291db9f91a';
|
||||
v256[1].k_sch = '101112131415161718191a1b1c1d1e1f';
|
||||
v256[2].start = '4f63760643e0aa85efa7213201a4e705';
|
||||
v256[2].s_box = '84fb386f1ae1ac97df5cfd237c49946b';
|
||||
v256[2].s_row = '84e1fd6b1a5c946fdf4938977cfbac23';
|
||||
v256[2].m_col = 'bd2a395d2b6ac438d192443e615da195';
|
||||
v256[2].k_sch = 'a573c29fa176c498a97fce93a572c09c';
|
||||
v256[3].start = '1859fbc28a1c00a078ed8aadc42f6109';
|
||||
v256[3].s_box = 'adcb0f257e9c63e0bc557e951c15ef01';
|
||||
v256[3].s_row = 'ad9c7e017e55ef25bc150fe01ccb6395';
|
||||
v256[3].m_col = '810dce0cc9db8172b3678c1e88a1b5bd';
|
||||
v256[3].k_sch = '1651a8cd0244beda1a5da4c10640bade';
|
||||
v256[4].start = '975c66c1cb9f3fa8a93a28df8ee10f63';
|
||||
v256[4].s_box = '884a33781fdb75c2d380349e19f876fb';
|
||||
v256[4].s_row = '88db34fb1f807678d3f833c2194a759e';
|
||||
v256[4].m_col = 'b2822d81abe6fb275faf103a078c0033';
|
||||
v256[4].k_sch = 'ae87dff00ff11b68a68ed5fb03fc1567';
|
||||
v256[5].start = '1c05f271a417e04ff921c5c104701554';
|
||||
v256[5].s_box = '9c6b89a349f0e18499fda678f2515920';
|
||||
v256[5].s_row = '9cf0a62049fd59a399518984f26be178';
|
||||
v256[5].m_col = 'aeb65ba974e0f822d73f567bdb64c877';
|
||||
v256[5].k_sch = '6de1f1486fa54f9275f8eb5373b8518d';
|
||||
v256[6].start = 'c357aae11b45b7b0a2c7bd28a8dc99fa';
|
||||
v256[6].s_box = '2e5bacf8af6ea9e73ac67a34c286ee2d';
|
||||
v256[6].s_row = '2e6e7a2dafc6eef83a86ace7c25ba934';
|
||||
v256[6].m_col = 'b951c33c02e9bd29ae25cdb1efa08cc7';
|
||||
v256[6].k_sch = 'c656827fc9a799176f294cec6cd5598b';
|
||||
v256[7].start = '7f074143cb4e243ec10c815d8375d54c';
|
||||
v256[7].s_box = 'd2c5831a1f2f36b278fe0c4cec9d0329';
|
||||
v256[7].s_row = 'd22f0c291ffe031a789d83b2ecc5364c';
|
||||
v256[7].m_col = 'ebb19e1c3ee7c9e87d7535e9ed6b9144';
|
||||
v256[7].k_sch = '3de23a75524775e727bf9eb45407cf39';
|
||||
v256[8].start = 'd653a4696ca0bc0f5acaab5db96c5e7d';
|
||||
v256[8].s_box = 'f6ed49f950e06576be74624c565058ff';
|
||||
v256[8].s_row = 'f6e062ff507458f9be50497656ed654c';
|
||||
v256[8].m_col = '5174c8669da98435a8b3e62ca974a5ea';
|
||||
v256[8].k_sch = '0bdc905fc27b0948ad5245a4c1871c2f';
|
||||
v256[9].start = '5aa858395fd28d7d05e1a38868f3b9c5';
|
||||
v256[9].s_box = 'bec26a12cfb55dff6bf80ac4450d56a6';
|
||||
v256[9].s_row = 'beb50aa6cff856126b0d6aff45c25dc4';
|
||||
v256[9].m_col = '0f77ee31d2ccadc05430a83f4ef96ac3';
|
||||
v256[9].k_sch = '45f5a66017b2d387300d4d33640a820a';
|
||||
v256[10].start = '4a824851c57e7e47643de50c2af3e8c9';
|
||||
v256[10].s_box = 'd61352d1a6f3f3a04327d9fee50d9bdd';
|
||||
v256[10].s_row = 'd6f3d9dda6279bd1430d52a0e513f3fe';
|
||||
v256[10].m_col = 'bd86f0ea748fc4f4630f11c1e9331233';
|
||||
v256[10].k_sch = '7ccff71cbeb4fe5413e6bbf0d261a7df';
|
||||
v256[11].start = 'c14907f6ca3b3aa070e9aa313b52b5ec';
|
||||
v256[11].s_box = '783bc54274e280e0511eacc7e200d5ce';
|
||||
v256[11].s_row = '78e2acce741ed5425100c5e0e23b80c7';
|
||||
v256[11].m_col = 'af8690415d6e1dd387e5fbedd5c89013';
|
||||
v256[11].k_sch = 'f01afafee7a82979d7a5644ab3afe640';
|
||||
v256[12].start = '5f9c6abfbac634aa50409fa766677653';
|
||||
v256[12].s_box = 'cfde0208f4b418ac5309db5c338538ed';
|
||||
v256[12].s_row = 'cfb4dbedf4093808538502ac33de185c';
|
||||
v256[12].m_col = '7427fae4d8a695269ce83d315be0392b';
|
||||
v256[12].k_sch = '2541fe719bf500258813bbd55a721c0a';
|
||||
v256[13].start = '516604954353950314fb86e401922521';
|
||||
v256[13].s_box = 'd133f22a1aed2a7bfa0f44697c4f3ffd';
|
||||
v256[13].s_row = 'd1ed44fd1a0f3f2afa4ff27b7c332a69';
|
||||
v256[13].m_col = '2c21a820306f154ab712c75eee0da04f';
|
||||
v256[13].k_sch = '4e5a6699a9f24fe07e572baacdf8cdea';
|
||||
v256[14].start = '627bceb9999d5aaac945ecf423f56da5';
|
||||
v256[14].s_box = 'aa218b56ee5ebeacdd6ecebf26e63c06';
|
||||
v256[14].s_row = 'aa5ece06ee6e3c56dde68bac2621bebf';
|
||||
v256[14].k_sch = '24fc79ccbf0979e9371ac23c6d68de36';
|
||||
v256[14].output = '8ea2b7ca516745bfeafc49904b496089';
|
||||
})();
|
||||
|
||||
var v256d = [];
|
||||
(function v256d_init() {
|
||||
for (var i = 0; i <= 14; i++) v256d[i] = {};
|
||||
v256d.name = '256d';
|
||||
v256d[0].input = '8ea2b7ca516745bfeafc49904b496089';
|
||||
v256d[0].k_sch = '24fc79ccbf0979e9371ac23c6d68de36';
|
||||
v256d[1].start = 'aa5ece06ee6e3c56dde68bac2621bebf';
|
||||
v256d[1].s_row = 'aa218b56ee5ebeacdd6ecebf26e63c06';
|
||||
v256d[1].s_box = '627bceb9999d5aaac945ecf423f56da5';
|
||||
v256d[1].k_sch = '4e5a6699a9f24fe07e572baacdf8cdea';
|
||||
v256d[1].k_add = '2c21a820306f154ab712c75eee0da04f';
|
||||
v256d[2].start = 'd1ed44fd1a0f3f2afa4ff27b7c332a69';
|
||||
v256d[2].s_row = 'd133f22a1aed2a7bfa0f44697c4f3ffd';
|
||||
v256d[2].s_box = '516604954353950314fb86e401922521';
|
||||
v256d[2].k_sch = '2541fe719bf500258813bbd55a721c0a';
|
||||
v256d[2].k_add = '7427fae4d8a695269ce83d315be0392b';
|
||||
v256d[3].start = 'cfb4dbedf4093808538502ac33de185c';
|
||||
v256d[3].s_row = 'cfde0208f4b418ac5309db5c338538ed';
|
||||
v256d[3].s_box = '5f9c6abfbac634aa50409fa766677653';
|
||||
v256d[3].k_sch = 'f01afafee7a82979d7a5644ab3afe640';
|
||||
v256d[3].k_add = 'af8690415d6e1dd387e5fbedd5c89013';
|
||||
v256d[4].start = '78e2acce741ed5425100c5e0e23b80c7';
|
||||
v256d[4].s_row = '783bc54274e280e0511eacc7e200d5ce';
|
||||
v256d[4].s_box = 'c14907f6ca3b3aa070e9aa313b52b5ec';
|
||||
v256d[4].k_sch = '7ccff71cbeb4fe5413e6bbf0d261a7df';
|
||||
v256d[4].k_add = 'bd86f0ea748fc4f4630f11c1e9331233';
|
||||
v256d[5].start = 'd6f3d9dda6279bd1430d52a0e513f3fe';
|
||||
v256d[5].s_row = 'd61352d1a6f3f3a04327d9fee50d9bdd';
|
||||
v256d[5].s_box = '4a824851c57e7e47643de50c2af3e8c9';
|
||||
v256d[5].k_sch = '45f5a66017b2d387300d4d33640a820a';
|
||||
v256d[5].k_add = '0f77ee31d2ccadc05430a83f4ef96ac3';
|
||||
v256d[6].start = 'beb50aa6cff856126b0d6aff45c25dc4';
|
||||
v256d[6].s_row = 'bec26a12cfb55dff6bf80ac4450d56a6';
|
||||
v256d[6].s_box = '5aa858395fd28d7d05e1a38868f3b9c5';
|
||||
v256d[6].k_sch = '0bdc905fc27b0948ad5245a4c1871c2f';
|
||||
v256d[6].k_add = '5174c8669da98435a8b3e62ca974a5ea';
|
||||
v256d[7].start = 'f6e062ff507458f9be50497656ed654c';
|
||||
v256d[7].s_row = 'f6ed49f950e06576be74624c565058ff';
|
||||
v256d[7].s_box = 'd653a4696ca0bc0f5acaab5db96c5e7d';
|
||||
v256d[7].k_sch = '3de23a75524775e727bf9eb45407cf39';
|
||||
v256d[7].k_add = 'ebb19e1c3ee7c9e87d7535e9ed6b9144';
|
||||
v256d[8].start = 'd22f0c291ffe031a789d83b2ecc5364c';
|
||||
v256d[8].s_row = 'd2c5831a1f2f36b278fe0c4cec9d0329';
|
||||
v256d[8].s_box = '7f074143cb4e243ec10c815d8375d54c';
|
||||
v256d[8].k_sch = 'c656827fc9a799176f294cec6cd5598b';
|
||||
v256d[8].k_add = 'b951c33c02e9bd29ae25cdb1efa08cc7';
|
||||
v256d[9].start = '2e6e7a2dafc6eef83a86ace7c25ba934';
|
||||
v256d[9].s_row = '2e5bacf8af6ea9e73ac67a34c286ee2d';
|
||||
v256d[9].s_box = 'c357aae11b45b7b0a2c7bd28a8dc99fa';
|
||||
v256d[9].k_sch = '6de1f1486fa54f9275f8eb5373b8518d';
|
||||
v256d[9].k_add = 'aeb65ba974e0f822d73f567bdb64c877';
|
||||
v256d[10].start = '9cf0a62049fd59a399518984f26be178';
|
||||
v256d[10].s_row = '9c6b89a349f0e18499fda678f2515920';
|
||||
v256d[10].s_box = '1c05f271a417e04ff921c5c104701554';
|
||||
v256d[10].k_sch = 'ae87dff00ff11b68a68ed5fb03fc1567';
|
||||
v256d[10].k_add = 'b2822d81abe6fb275faf103a078c0033';
|
||||
v256d[11].start = '88db34fb1f807678d3f833c2194a759e';
|
||||
v256d[11].s_row = '884a33781fdb75c2d380349e19f876fb';
|
||||
v256d[11].s_box = '975c66c1cb9f3fa8a93a28df8ee10f63';
|
||||
v256d[11].k_sch = '1651a8cd0244beda1a5da4c10640bade';
|
||||
v256d[11].k_add = '810dce0cc9db8172b3678c1e88a1b5bd';
|
||||
v256d[12].start = 'ad9c7e017e55ef25bc150fe01ccb6395';
|
||||
v256d[12].s_row = 'adcb0f257e9c63e0bc557e951c15ef01';
|
||||
v256d[12].s_box = '1859fbc28a1c00a078ed8aadc42f6109';
|
||||
v256d[12].k_sch = 'a573c29fa176c498a97fce93a572c09c';
|
||||
v256d[12].k_add = 'bd2a395d2b6ac438d192443e615da195';
|
||||
v256d[13].start = '84e1fd6b1a5c946fdf4938977cfbac23';
|
||||
v256d[13].s_row = '84fb386f1ae1ac97df5cfd237c49946b';
|
||||
v256d[13].s_box = '4f63760643e0aa85efa7213201a4e705';
|
||||
v256d[13].k_sch = '101112131415161718191a1b1c1d1e1f';
|
||||
v256d[13].k_add = '5f72641557f5bc92f7be3b291db9f91a';
|
||||
v256d[14].start = '6353e08c0960e104cd70b751bacad0e7';
|
||||
v256d[14].s_row = '63cab7040953d051cd60e0e7ba70e18c';
|
||||
v256d[14].s_box = '00102030405060708090a0b0c0d0e0f0';
|
||||
v256d[14].k_sch = '000102030405060708090a0b0c0d0e0f';
|
||||
v256d[14].output = '00112233445566778899aabbccddeeff';
|
||||
})();
|
||||
@@ -0,0 +1,164 @@
|
||||
// Copyright 2005 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 ARC4 streamcipher implementation. A description of the
|
||||
* algorithm can be found at:
|
||||
* http://www.mozilla.org/projects/security/pki/nss/draft-kaukonen-cipher-arcfour-03.txt.
|
||||
*
|
||||
* Usage:
|
||||
* <code>
|
||||
* var arc4 = new goog.crypt.Arc4();
|
||||
* arc4.setKey(key);
|
||||
* arc4.discard(1536);
|
||||
* arc4.crypt(bytes);
|
||||
* </code>
|
||||
*
|
||||
* Note: For converting between strings and byte arrays, goog.crypt.base64 may
|
||||
* be useful.
|
||||
*
|
||||
*/
|
||||
|
||||
goog.provide('goog.crypt.Arc4');
|
||||
|
||||
goog.require('goog.asserts');
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* ARC4 streamcipher implementation.
|
||||
* @constructor
|
||||
* @final
|
||||
* @struct
|
||||
*/
|
||||
goog.crypt.Arc4 = function() {
|
||||
/**
|
||||
* A permutation of all 256 possible bytes.
|
||||
* @type {Array<number>}
|
||||
* @private
|
||||
*/
|
||||
this.state_ = [];
|
||||
|
||||
/**
|
||||
* 8 bit index pointer into this.state_.
|
||||
* @type {number}
|
||||
* @private
|
||||
*/
|
||||
this.index1_ = 0;
|
||||
|
||||
/**
|
||||
* 8 bit index pointer into this.state_.
|
||||
* @type {number}
|
||||
* @private
|
||||
*/
|
||||
this.index2_ = 0;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Initialize the cipher for use with new key.
|
||||
* @param {Array<number>} key A byte array containing the key.
|
||||
* @param {number=} opt_length Indicates # of bytes to take from the key.
|
||||
*/
|
||||
goog.crypt.Arc4.prototype.setKey = function(key, opt_length) {
|
||||
goog.asserts.assertArray(key, 'Key parameter must be a byte array');
|
||||
|
||||
if (!opt_length) {
|
||||
opt_length = key.length;
|
||||
}
|
||||
|
||||
var state = this.state_;
|
||||
|
||||
for (var i = 0; i < 256; ++i) {
|
||||
state[i] = i;
|
||||
}
|
||||
|
||||
var j = 0;
|
||||
for (var i = 0; i < 256; ++i) {
|
||||
j = (j + state[i] + key[i % opt_length]) & 255;
|
||||
|
||||
var tmp = state[i];
|
||||
state[i] = state[j];
|
||||
state[j] = tmp;
|
||||
}
|
||||
|
||||
this.index1_ = 0;
|
||||
this.index2_ = 0;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Discards n bytes of the keystream.
|
||||
* These days 1536 is considered a decent amount to drop to get the key state
|
||||
* warmed-up enough for secure usage. This is not done in the constructor to
|
||||
* preserve efficiency for use cases that do not need this.
|
||||
* NOTE: Discard is identical to crypt without actually xoring any data. It's
|
||||
* unfortunate to have this code duplicated, but this was done for performance
|
||||
* reasons. Alternatives which were attempted:
|
||||
* 1. Create a temp array of the correct length and pass it to crypt. This
|
||||
* works but needlessly allocates an array. But more importantly this
|
||||
* requires choosing an array type (Array or Uint8Array) in discard, and
|
||||
* choosing a different type than will be passed to crypt by the client
|
||||
* code hurts the javascript engines ability to optimize crypt (7x hit in
|
||||
* v8).
|
||||
* 2. Make data option in crypt so discard can pass null, this has a huge
|
||||
* perf hit for crypt.
|
||||
* @param {number} length Number of bytes to disregard from the stream.
|
||||
*/
|
||||
goog.crypt.Arc4.prototype.discard = function(length) {
|
||||
var i = this.index1_;
|
||||
var j = this.index2_;
|
||||
var state = this.state_;
|
||||
|
||||
for (var n = 0; n < length; ++n) {
|
||||
i = (i + 1) & 255;
|
||||
j = (j + state[i]) & 255;
|
||||
|
||||
var tmp = state[i];
|
||||
state[i] = state[j];
|
||||
state[j] = tmp;
|
||||
}
|
||||
|
||||
this.index1_ = i;
|
||||
this.index2_ = j;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* En- or decrypt (same operation for streamciphers like ARC4)
|
||||
* @param {Array<number>|Uint8Array} data The data to be xor-ed in place.
|
||||
* @param {number=} opt_length The number of bytes to crypt.
|
||||
*/
|
||||
goog.crypt.Arc4.prototype.crypt = function(data, opt_length) {
|
||||
if (!opt_length) {
|
||||
opt_length = data.length;
|
||||
}
|
||||
var i = this.index1_;
|
||||
var j = this.index2_;
|
||||
var state = this.state_;
|
||||
|
||||
for (var n = 0; n < opt_length; ++n) {
|
||||
i = (i + 1) & 255;
|
||||
j = (j + state[i]) & 255;
|
||||
|
||||
var tmp = state[i];
|
||||
state[i] = state[j];
|
||||
state[j] = tmp;
|
||||
|
||||
data[n] ^= state[(state[i] + state[j]) & 255];
|
||||
}
|
||||
|
||||
this.index1_ = i;
|
||||
this.index2_ = j;
|
||||
};
|
||||
@@ -0,0 +1,22 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<!--
|
||||
Copyright 2010 The Closure Library Authors. All Rights Reserved.
|
||||
|
||||
Use of this source code is governed by the Apache License, Version 2.0.
|
||||
See the COPYING file for details.
|
||||
-->
|
||||
<head>
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
|
||||
<title>
|
||||
Closure Unit Tests - goog.crypt.arc4
|
||||
</title>
|
||||
<script src="../base.js">
|
||||
</script>
|
||||
<script>
|
||||
goog.require('goog.crypt.Arc4Test');
|
||||
</script>
|
||||
</head>
|
||||
<body>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,59 @@
|
||||
// Copyright 2010 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.
|
||||
|
||||
goog.provide('goog.crypt.Arc4Test');
|
||||
goog.setTestOnly('goog.crypt.Arc4Test');
|
||||
|
||||
goog.require('goog.array');
|
||||
goog.require('goog.crypt.Arc4');
|
||||
goog.require('goog.testing.jsunit');
|
||||
|
||||
function testEncryptionDecryption() {
|
||||
var key = [0x25, 0x26, 0x27, 0x28];
|
||||
var startArray = [0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67];
|
||||
var byteArray = [0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67];
|
||||
|
||||
var arc4 = new goog.crypt.Arc4();
|
||||
arc4.setKey(key);
|
||||
arc4.crypt(byteArray);
|
||||
|
||||
assertArrayEquals(byteArray, [0x51, 0xBB, 0xDD, 0x95, 0x9B, 0x42, 0x34]);
|
||||
|
||||
// The same key and crypt call should unencrypt the data back to its original
|
||||
// state
|
||||
arc4 = new goog.crypt.Arc4();
|
||||
arc4.setKey(key);
|
||||
arc4.crypt(byteArray);
|
||||
assertArrayEquals(byteArray, startArray);
|
||||
}
|
||||
|
||||
function testDiscard() {
|
||||
var key = [0x25, 0x26, 0x27, 0x28];
|
||||
var data = [0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67];
|
||||
|
||||
var arc4 = new goog.crypt.Arc4();
|
||||
arc4.setKey(key);
|
||||
arc4.discard(256);
|
||||
var withDiscard = goog.array.clone(data);
|
||||
arc4.crypt(withDiscard);
|
||||
|
||||
// First encrypting a dummy array should give the same result as
|
||||
// discarding.
|
||||
arc4 = new goog.crypt.Arc4();
|
||||
arc4.setKey(key);
|
||||
var withCrypt = goog.array.clone(data);
|
||||
arc4.crypt(new Array(256));
|
||||
arc4.crypt(withCrypt);
|
||||
assertArrayEquals(withDiscard, withCrypt);
|
||||
}
|
||||
@@ -0,0 +1,286 @@
|
||||
// Copyright 2007 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 Base64 en/decoding. Not much to say here except that we
|
||||
* work with decoded values in arrays of bytes. By "byte" I mean a number
|
||||
* in [0, 255].
|
||||
*
|
||||
* @author doughtie@google.com (Gavin Doughtie)
|
||||
*/
|
||||
|
||||
goog.provide('goog.crypt.base64');
|
||||
goog.require('goog.crypt');
|
||||
goog.require('goog.userAgent');
|
||||
|
||||
// Static lookup maps, lazily populated by init_()
|
||||
|
||||
|
||||
/**
|
||||
* Maps bytes to characters.
|
||||
* @type {Object}
|
||||
* @private
|
||||
*/
|
||||
goog.crypt.base64.byteToCharMap_ = null;
|
||||
|
||||
|
||||
/**
|
||||
* Maps characters to bytes.
|
||||
* @type {Object}
|
||||
* @private
|
||||
*/
|
||||
goog.crypt.base64.charToByteMap_ = null;
|
||||
|
||||
|
||||
/**
|
||||
* Maps bytes to websafe characters.
|
||||
* @type {Object}
|
||||
* @private
|
||||
*/
|
||||
goog.crypt.base64.byteToCharMapWebSafe_ = null;
|
||||
|
||||
|
||||
/**
|
||||
* Maps websafe characters to bytes.
|
||||
* @type {Object}
|
||||
* @private
|
||||
*/
|
||||
goog.crypt.base64.charToByteMapWebSafe_ = null;
|
||||
|
||||
|
||||
/**
|
||||
* Our default alphabet, shared between
|
||||
* ENCODED_VALS and ENCODED_VALS_WEBSAFE
|
||||
* @type {string}
|
||||
*/
|
||||
goog.crypt.base64.ENCODED_VALS_BASE =
|
||||
'ABCDEFGHIJKLMNOPQRSTUVWXYZ' +
|
||||
'abcdefghijklmnopqrstuvwxyz' +
|
||||
'0123456789';
|
||||
|
||||
|
||||
/**
|
||||
* Our default alphabet. Value 64 (=) is special; it means "nothing."
|
||||
* @type {string}
|
||||
*/
|
||||
goog.crypt.base64.ENCODED_VALS =
|
||||
goog.crypt.base64.ENCODED_VALS_BASE + '+/=';
|
||||
|
||||
|
||||
/**
|
||||
* Our websafe alphabet.
|
||||
* @type {string}
|
||||
*/
|
||||
goog.crypt.base64.ENCODED_VALS_WEBSAFE =
|
||||
goog.crypt.base64.ENCODED_VALS_BASE + '-_.';
|
||||
|
||||
|
||||
/**
|
||||
* Whether this browser supports the atob and btoa functions. This extension
|
||||
* started at Mozilla but is now implemented by many browsers. We use the
|
||||
* ASSUME_* variables to avoid pulling in the full useragent detection library
|
||||
* but still allowing the standard per-browser compilations.
|
||||
*
|
||||
* @type {boolean}
|
||||
*/
|
||||
goog.crypt.base64.HAS_NATIVE_SUPPORT = goog.userAgent.GECKO ||
|
||||
goog.userAgent.WEBKIT ||
|
||||
goog.userAgent.OPERA ||
|
||||
typeof(goog.global.atob) == 'function';
|
||||
|
||||
|
||||
/**
|
||||
* Base64-encode an array of bytes.
|
||||
*
|
||||
* @param {Array<number>|Uint8Array} input An array of bytes (numbers with
|
||||
* value in [0, 255]) to encode.
|
||||
* @param {boolean=} opt_webSafe Boolean indicating we should use the
|
||||
* alternative alphabet.
|
||||
* @return {string} The base64 encoded string.
|
||||
*/
|
||||
goog.crypt.base64.encodeByteArray = function(input, opt_webSafe) {
|
||||
if (!goog.isArrayLike(input)) {
|
||||
throw Error('encodeByteArray takes an array as a parameter');
|
||||
}
|
||||
|
||||
goog.crypt.base64.init_();
|
||||
|
||||
var byteToCharMap = opt_webSafe ?
|
||||
goog.crypt.base64.byteToCharMapWebSafe_ :
|
||||
goog.crypt.base64.byteToCharMap_;
|
||||
|
||||
var output = [];
|
||||
|
||||
for (var i = 0; i < input.length; i += 3) {
|
||||
var byte1 = input[i];
|
||||
var haveByte2 = i + 1 < input.length;
|
||||
var byte2 = haveByte2 ? input[i + 1] : 0;
|
||||
var haveByte3 = i + 2 < input.length;
|
||||
var byte3 = haveByte3 ? input[i + 2] : 0;
|
||||
|
||||
var outByte1 = byte1 >> 2;
|
||||
var outByte2 = ((byte1 & 0x03) << 4) | (byte2 >> 4);
|
||||
var outByte3 = ((byte2 & 0x0F) << 2) | (byte3 >> 6);
|
||||
var outByte4 = byte3 & 0x3F;
|
||||
|
||||
if (!haveByte3) {
|
||||
outByte4 = 64;
|
||||
|
||||
if (!haveByte2) {
|
||||
outByte3 = 64;
|
||||
}
|
||||
}
|
||||
|
||||
output.push(byteToCharMap[outByte1],
|
||||
byteToCharMap[outByte2],
|
||||
byteToCharMap[outByte3],
|
||||
byteToCharMap[outByte4]);
|
||||
}
|
||||
|
||||
return output.join('');
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Base64-encode a string.
|
||||
*
|
||||
* @param {string} input A string to encode.
|
||||
* @param {boolean=} opt_webSafe If true, we should use the
|
||||
* alternative alphabet.
|
||||
* @return {string} The base64 encoded string.
|
||||
*/
|
||||
goog.crypt.base64.encodeString = function(input, opt_webSafe) {
|
||||
// Shortcut for Mozilla browsers that implement
|
||||
// a native base64 encoder in the form of "btoa/atob"
|
||||
if (goog.crypt.base64.HAS_NATIVE_SUPPORT && !opt_webSafe) {
|
||||
return goog.global.btoa(input);
|
||||
}
|
||||
return goog.crypt.base64.encodeByteArray(
|
||||
goog.crypt.stringToByteArray(input), opt_webSafe);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Base64-decode a string.
|
||||
*
|
||||
* @param {string} input to decode.
|
||||
* @param {boolean=} opt_webSafe True if we should use the
|
||||
* alternative alphabet.
|
||||
* @return {string} string representing the decoded value.
|
||||
*/
|
||||
goog.crypt.base64.decodeString = function(input, opt_webSafe) {
|
||||
// Shortcut for Mozilla browsers that implement
|
||||
// a native base64 encoder in the form of "btoa/atob"
|
||||
if (goog.crypt.base64.HAS_NATIVE_SUPPORT && !opt_webSafe) {
|
||||
return goog.global.atob(input);
|
||||
}
|
||||
return goog.crypt.byteArrayToString(
|
||||
goog.crypt.base64.decodeStringToByteArray(input, opt_webSafe));
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Base64-decode a string.
|
||||
*
|
||||
* In base-64 decoding, groups of four characters are converted into three
|
||||
* bytes. If the encoder did not apply padding, the input length may not
|
||||
* be a multiple of 4.
|
||||
*
|
||||
* In this case, the last group will have fewer than 4 characters, and
|
||||
* padding will be inferred. If the group has one or two characters, it decodes
|
||||
* to one byte. If the group has three characters, it decodes to two bytes.
|
||||
*
|
||||
* @param {string} input Input to decode.
|
||||
* @param {boolean=} opt_webSafe True if we should use the web-safe alphabet.
|
||||
* @return {!Array<number>} bytes representing the decoded value.
|
||||
*/
|
||||
goog.crypt.base64.decodeStringToByteArray = function(input, opt_webSafe) {
|
||||
goog.crypt.base64.init_();
|
||||
|
||||
var charToByteMap = opt_webSafe ?
|
||||
goog.crypt.base64.charToByteMapWebSafe_ :
|
||||
goog.crypt.base64.charToByteMap_;
|
||||
|
||||
var output = [];
|
||||
|
||||
for (var i = 0; i < input.length; ) {
|
||||
var byte1 = charToByteMap[input.charAt(i++)];
|
||||
|
||||
var haveByte2 = i < input.length;
|
||||
var byte2 = haveByte2 ? charToByteMap[input.charAt(i)] : 0;
|
||||
++i;
|
||||
|
||||
var haveByte3 = i < input.length;
|
||||
var byte3 = haveByte3 ? charToByteMap[input.charAt(i)] : 64;
|
||||
++i;
|
||||
|
||||
var haveByte4 = i < input.length;
|
||||
var byte4 = haveByte4 ? charToByteMap[input.charAt(i)] : 64;
|
||||
++i;
|
||||
|
||||
if (byte1 == null || byte2 == null ||
|
||||
byte3 == null || byte4 == null) {
|
||||
throw Error();
|
||||
}
|
||||
|
||||
var outByte1 = (byte1 << 2) | (byte2 >> 4);
|
||||
output.push(outByte1);
|
||||
|
||||
if (byte3 != 64) {
|
||||
var outByte2 = ((byte2 << 4) & 0xF0) | (byte3 >> 2);
|
||||
output.push(outByte2);
|
||||
|
||||
if (byte4 != 64) {
|
||||
var outByte3 = ((byte3 << 6) & 0xC0) | byte4;
|
||||
output.push(outByte3);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return output;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Lazy static initialization function. Called before
|
||||
* accessing any of the static map variables.
|
||||
* @private
|
||||
*/
|
||||
goog.crypt.base64.init_ = function() {
|
||||
if (!goog.crypt.base64.byteToCharMap_) {
|
||||
goog.crypt.base64.byteToCharMap_ = {};
|
||||
goog.crypt.base64.charToByteMap_ = {};
|
||||
goog.crypt.base64.byteToCharMapWebSafe_ = {};
|
||||
goog.crypt.base64.charToByteMapWebSafe_ = {};
|
||||
|
||||
// We want quick mappings back and forth, so we precompute two maps.
|
||||
for (var i = 0; i < goog.crypt.base64.ENCODED_VALS.length; i++) {
|
||||
goog.crypt.base64.byteToCharMap_[i] =
|
||||
goog.crypt.base64.ENCODED_VALS.charAt(i);
|
||||
goog.crypt.base64.charToByteMap_[goog.crypt.base64.byteToCharMap_[i]] = i;
|
||||
goog.crypt.base64.byteToCharMapWebSafe_[i] =
|
||||
goog.crypt.base64.ENCODED_VALS_WEBSAFE.charAt(i);
|
||||
goog.crypt.base64.charToByteMapWebSafe_[
|
||||
goog.crypt.base64.byteToCharMapWebSafe_[i]] = i;
|
||||
|
||||
// Be forgiving when decoding and correctly decode both encodings.
|
||||
if (i >= goog.crypt.base64.ENCODED_VALS_BASE.length) {
|
||||
goog.crypt.base64.charToByteMap_[
|
||||
goog.crypt.base64.ENCODED_VALS_WEBSAFE.charAt(i)] = i;
|
||||
goog.crypt.base64.charToByteMapWebSafe_[
|
||||
goog.crypt.base64.ENCODED_VALS.charAt(i)] = i;
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,22 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<!--
|
||||
Copyright 2007 The Closure Library Authors. All Rights Reserved.
|
||||
|
||||
Use of this source code is governed by the Apache License, Version 2.0.
|
||||
See the COPYING file for details.
|
||||
-->
|
||||
<head>
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
|
||||
<title>
|
||||
Closure Unit Tests - goog.crypt.base64
|
||||
</title>
|
||||
<script src="../base.js">
|
||||
</script>
|
||||
<script>
|
||||
goog.require('goog.crypt.base64Test');
|
||||
</script>
|
||||
</head>
|
||||
<body>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,156 @@
|
||||
// Copyright 2007 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.
|
||||
|
||||
goog.provide('goog.crypt.base64Test');
|
||||
goog.setTestOnly('goog.crypt.base64Test');
|
||||
|
||||
goog.require('goog.crypt');
|
||||
goog.require('goog.crypt.base64');
|
||||
goog.require('goog.testing.jsunit');
|
||||
|
||||
// Static test data
|
||||
var tests = [
|
||||
'', '',
|
||||
'f', 'Zg==',
|
||||
'fo', 'Zm8=',
|
||||
'foo', 'Zm9v',
|
||||
'foob', 'Zm9vYg==',
|
||||
'fooba', 'Zm9vYmE=',
|
||||
'foobar', 'Zm9vYmFy',
|
||||
|
||||
// Testing non-ascii characters (1-10 in chinese)
|
||||
'\xe4\xb8\x80\xe4\xba\x8c\xe4\xb8\x89\xe5\x9b\x9b\xe4\xba\x94\xe5' +
|
||||
'\x85\xad\xe4\xb8\x83\xe5\x85\xab\xe4\xb9\x9d\xe5\x8d\x81',
|
||||
'5LiA5LqM5LiJ5Zub5LqU5YWt5LiD5YWr5Lmd5Y2B'];
|
||||
|
||||
function testByteArrayEncoding() {
|
||||
// Let's see if it's sane by feeding it some well-known values. Index i
|
||||
// has the input and index i+1 has the expected value.
|
||||
for (var i = 0; i < tests.length; i += 2) {
|
||||
var enc = goog.crypt.base64.encodeByteArray(
|
||||
goog.crypt.stringToByteArray(tests[i]));
|
||||
assertEquals(tests[i + 1], enc);
|
||||
var dec = goog.crypt.byteArrayToString(
|
||||
goog.crypt.base64.decodeStringToByteArray(enc));
|
||||
assertEquals(tests[i], dec);
|
||||
|
||||
// Check that websafe decoding accepts non-websafe codes.
|
||||
dec = goog.crypt.byteArrayToString(
|
||||
goog.crypt.base64.decodeStringToByteArray(enc, true /* websafe */));
|
||||
assertEquals(tests[i], dec);
|
||||
|
||||
// Re-encode as websafe.
|
||||
enc = goog.crypt.base64.encodeByteArray(
|
||||
goog.crypt.stringToByteArray(tests[i], true /* websafe */));
|
||||
|
||||
// Check that non-websafe decoding accepts websafe codes.
|
||||
dec = goog.crypt.byteArrayToString(
|
||||
goog.crypt.base64.decodeStringToByteArray(enc));
|
||||
assertEquals(tests[i], dec);
|
||||
|
||||
// Check that websafe decoding accepts websafe codes.
|
||||
dec = goog.crypt.byteArrayToString(
|
||||
goog.crypt.base64.decodeStringToByteArray(enc, true /* websafe */));
|
||||
assertEquals(tests[i], dec);
|
||||
}
|
||||
}
|
||||
|
||||
function testOddLengthByteArrayEncoding() {
|
||||
var buffer = [0, 0, 0];
|
||||
var encodedBuffer = goog.crypt.base64.encodeByteArray(buffer);
|
||||
assertEquals('AAAA', encodedBuffer);
|
||||
|
||||
var decodedBuffer = goog.crypt.base64.decodeStringToByteArray(encodedBuffer);
|
||||
assertEquals(decodedBuffer.length, buffer.length);
|
||||
for (i = 0; i < buffer.length; i++) {
|
||||
assertEquals(buffer[i], decodedBuffer[i]);
|
||||
}
|
||||
}
|
||||
|
||||
// Tests that decoding a string where the length is not a multiple of 4 does
|
||||
// not produce spurious trailing zeroes. This is a regression test for
|
||||
// cl/65120705, which fixes a bug that was introduced when support for
|
||||
// non-padded base64 encoding was added in cl/20209336.
|
||||
function testOddLengthByteArrayDecoding() {
|
||||
// The base-64 encoding of the bytes [97, 98, 99, 100], with no padding.
|
||||
// The padded version would be "YWJjZA==" (length 8), or "YWJjZA.." if
|
||||
// web-safe.
|
||||
var encodedBuffer = 'YWJjZA';
|
||||
var decodedBuffer1 = goog.crypt.base64.decodeStringToByteArray(encodedBuffer);
|
||||
assertEquals(4, decodedBuffer1.length);
|
||||
// Note that byteArrayToString ignores any trailing zeroes because
|
||||
// String.fromCharCode(0) is ''.
|
||||
assertEquals('abcd', goog.crypt.byteArrayToString(decodedBuffer1));
|
||||
|
||||
// Repeat the test in web-safe decoding mode.
|
||||
var decodedBuffer2 = goog.crypt.base64.decodeStringToByteArray(encodedBuffer,
|
||||
true /* web-safe */);
|
||||
assertEquals(4, decodedBuffer2.length);
|
||||
assertEquals('abcd', goog.crypt.byteArrayToString(decodedBuffer2));
|
||||
}
|
||||
|
||||
function testShortcutPathEncoding() {
|
||||
// Test the higher-level API (tests the btoa/atob shortcut path)
|
||||
for (var i = 0; i < tests.length; i += 2) {
|
||||
var enc = goog.crypt.base64.encodeString(tests[i]);
|
||||
assertEquals(tests[i + 1], enc);
|
||||
var dec = goog.crypt.base64.decodeString(enc);
|
||||
assertEquals(tests[i], dec);
|
||||
}
|
||||
}
|
||||
|
||||
function testMultipleIterations() {
|
||||
// Now run it through its paces
|
||||
|
||||
var numIterations = 100;
|
||||
for (var i = 0; i < numIterations; i++) {
|
||||
|
||||
var input = [];
|
||||
for (var j = 0; j < i; j++)
|
||||
input[j] = j % 256;
|
||||
|
||||
var encoded = goog.crypt.base64.encodeByteArray(input);
|
||||
var decoded = goog.crypt.base64.decodeStringToByteArray(encoded);
|
||||
assertEquals('Decoded length not equal to input length?',
|
||||
input.length, decoded.length);
|
||||
|
||||
for (var j = 0; j < i; j++)
|
||||
assertEquals('Values differ at position ' + j, input[j], decoded[j]);
|
||||
}
|
||||
}
|
||||
|
||||
function testWebSafeEncoding() {
|
||||
// Test non-websafe / websafe difference
|
||||
var test = '>>>???>>>???=/+';
|
||||
var enc = goog.crypt.base64.encodeByteArray(
|
||||
goog.crypt.stringToByteArray(test));
|
||||
assertEquals('Non-websafe broken?', 'Pj4+Pz8/Pj4+Pz8/PS8r', enc);
|
||||
enc = goog.crypt.base64.encodeString(test);
|
||||
assertEquals('Non-websafe broken?', 'Pj4+Pz8/Pj4+Pz8/PS8r', enc);
|
||||
enc = goog.crypt.base64.encodeByteArray(
|
||||
goog.crypt.stringToByteArray(test), true /* websafe */);
|
||||
assertEquals('Websafe encoding broken', 'Pj4-Pz8_Pj4-Pz8_PS8r', enc);
|
||||
enc = goog.crypt.base64.encodeString(test, true);
|
||||
assertEquals('Non-websafe broken?', 'Pj4-Pz8_Pj4-Pz8_PS8r', enc);
|
||||
var dec = goog.crypt.byteArrayToString(
|
||||
goog.crypt.base64.decodeStringToByteArray(enc, true /* websafe */));
|
||||
assertEquals('Websafe decoding broken', test, dec);
|
||||
dec = goog.crypt.base64.decodeString(enc, true /* websafe */);
|
||||
assertEquals('Websafe decoding broken', test, dec);
|
||||
|
||||
// Test parsing malformed characters
|
||||
assertThrows('Didn\'t throw on malformed input', function() {
|
||||
goog.crypt.base64.decodeStringToByteArray('foooooo)oooo', true /*websafe*/);
|
||||
});
|
||||
}
|
||||
@@ -0,0 +1,242 @@
|
||||
// Copyright 2007 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 Numeric base conversion library. Works for arbitrary bases and
|
||||
* arbitrary length numbers.
|
||||
*
|
||||
* For base-64 conversion use base64.js because it is optimized for the specific
|
||||
* conversion to base-64 while this module is generic. Base-64 is defined here
|
||||
* mostly for demonstration purpose.
|
||||
*
|
||||
* TODO: Make base64 and baseN classes that have common interface. (Perhaps...)
|
||||
*
|
||||
*/
|
||||
|
||||
goog.provide('goog.crypt.baseN');
|
||||
|
||||
|
||||
/**
|
||||
* Base-2, i.e. '01'.
|
||||
* @type {string}
|
||||
*/
|
||||
goog.crypt.baseN.BASE_BINARY = '01';
|
||||
|
||||
|
||||
/**
|
||||
* Base-8, i.e. '01234567'.
|
||||
* @type {string}
|
||||
*/
|
||||
goog.crypt.baseN.BASE_OCTAL = '01234567';
|
||||
|
||||
|
||||
/**
|
||||
* Base-10, i.e. '0123456789'.
|
||||
* @type {string}
|
||||
*/
|
||||
goog.crypt.baseN.BASE_DECIMAL = '0123456789';
|
||||
|
||||
|
||||
/**
|
||||
* Base-16 using lower case, i.e. '0123456789abcdef'.
|
||||
* @type {string}
|
||||
*/
|
||||
goog.crypt.baseN.BASE_LOWERCASE_HEXADECIMAL = '0123456789abcdef';
|
||||
|
||||
|
||||
/**
|
||||
* Base-16 using upper case, i.e. '0123456789ABCDEF'.
|
||||
* @type {string}
|
||||
*/
|
||||
goog.crypt.baseN.BASE_UPPERCASE_HEXADECIMAL = '0123456789ABCDEF';
|
||||
|
||||
|
||||
/**
|
||||
* The more-known version of the BASE-64 encoding. Uses + and / characters.
|
||||
* @type {string}
|
||||
*/
|
||||
goog.crypt.baseN.BASE_64 =
|
||||
'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/';
|
||||
|
||||
|
||||
/**
|
||||
* URL-safe version of the BASE-64 encoding.
|
||||
* @type {string}
|
||||
*/
|
||||
goog.crypt.baseN.BASE_64_URL_SAFE =
|
||||
'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_';
|
||||
|
||||
|
||||
/**
|
||||
* Converts a number from one numeric base to another.
|
||||
*
|
||||
* The bases are represented as strings, which list allowed digits. Each digit
|
||||
* should be unique. The bases can either be user defined, or any of
|
||||
* goog.crypt.baseN.BASE_xxx.
|
||||
*
|
||||
* The number is in human-readable format, most significant digit first, and is
|
||||
* a non-negative integer. Base designators such as $, 0x, d, b or h (at end)
|
||||
* will be interpreted as digits, so avoid them. Leading zeros will be trimmed.
|
||||
*
|
||||
* Note: for huge bases the result may be inaccurate because of overflowing
|
||||
* 64-bit doubles used by JavaScript for integer calculus. This may happen
|
||||
* if the product of the number of digits in the input and output bases comes
|
||||
* close to 10^16, which is VERY unlikely (100M digits in each base), but
|
||||
* may be possible in the future unicode world. (Unicode 3.2 has less than 100K
|
||||
* characters. However, it reserves some more, close to 1M.)
|
||||
*
|
||||
* @param {string} number The number to convert.
|
||||
* @param {string} inputBase The numeric base the number is in (all digits).
|
||||
* @param {string} outputBase Requested numeric base.
|
||||
* @return {string} The converted number.
|
||||
*/
|
||||
goog.crypt.baseN.recodeString = function(number, inputBase, outputBase) {
|
||||
if (outputBase == '') {
|
||||
throw Error('Empty output base');
|
||||
}
|
||||
|
||||
// Check if number is 0 (special case when we don't want to return '').
|
||||
var isZero = true;
|
||||
for (var i = 0, n = number.length; i < n; i++) {
|
||||
if (number.charAt(i) != inputBase.charAt(0)) {
|
||||
isZero = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (isZero) {
|
||||
return outputBase.charAt(0);
|
||||
}
|
||||
|
||||
var numberDigits = goog.crypt.baseN.stringToArray_(number, inputBase);
|
||||
|
||||
var inputBaseSize = inputBase.length;
|
||||
var outputBaseSize = outputBase.length;
|
||||
|
||||
// result = 0.
|
||||
var result = [];
|
||||
|
||||
// For all digits of number, starting with the most significant ...
|
||||
for (var i = numberDigits.length - 1; i >= 0; i--) {
|
||||
|
||||
// result *= number.base.
|
||||
var carry = 0;
|
||||
for (var j = 0, n = result.length; j < n; j++) {
|
||||
var digit = result[j];
|
||||
// This may overflow for huge bases. See function comment.
|
||||
digit = digit * inputBaseSize + carry;
|
||||
if (digit >= outputBaseSize) {
|
||||
var remainder = digit % outputBaseSize;
|
||||
carry = (digit - remainder) / outputBaseSize;
|
||||
digit = remainder;
|
||||
} else {
|
||||
carry = 0;
|
||||
}
|
||||
result[j] = digit;
|
||||
}
|
||||
while (carry) {
|
||||
var remainder = carry % outputBaseSize;
|
||||
result.push(remainder);
|
||||
carry = (carry - remainder) / outputBaseSize;
|
||||
}
|
||||
|
||||
// result += number[i].
|
||||
carry = numberDigits[i];
|
||||
var j = 0;
|
||||
while (carry) {
|
||||
if (j >= result.length) {
|
||||
// Extend result with a leading zero which will be overwritten below.
|
||||
result.push(0);
|
||||
}
|
||||
var digit = result[j];
|
||||
digit += carry;
|
||||
if (digit >= outputBaseSize) {
|
||||
var remainder = digit % outputBaseSize;
|
||||
carry = (digit - remainder) / outputBaseSize;
|
||||
digit = remainder;
|
||||
} else {
|
||||
carry = 0;
|
||||
}
|
||||
result[j] = digit;
|
||||
j++;
|
||||
}
|
||||
}
|
||||
|
||||
return goog.crypt.baseN.arrayToString_(result, outputBase);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Converts a string representation of a number to an array of digit values.
|
||||
*
|
||||
* More precisely, the digit values are indices into the number base, which
|
||||
* is represented as a string, which can either be user defined or one of the
|
||||
* BASE_xxx constants.
|
||||
*
|
||||
* Throws an Error if the number contains a digit not found in the base.
|
||||
*
|
||||
* @param {string} number The string to convert, most significant digit first.
|
||||
* @param {string} base Digits in the base.
|
||||
* @return {!Array<number>} Array of digit values, least significant digit
|
||||
* first.
|
||||
* @private
|
||||
*/
|
||||
goog.crypt.baseN.stringToArray_ = function(number, base) {
|
||||
var index = {};
|
||||
for (var i = 0, n = base.length; i < n; i++) {
|
||||
index[base.charAt(i)] = i;
|
||||
}
|
||||
var result = [];
|
||||
for (var i = number.length - 1; i >= 0; i--) {
|
||||
var character = number.charAt(i);
|
||||
var digit = index[character];
|
||||
if (typeof digit == 'undefined') {
|
||||
throw Error('Number ' + number +
|
||||
' contains a character not found in base ' +
|
||||
base + ', which is ' + character);
|
||||
}
|
||||
result.push(digit);
|
||||
}
|
||||
return result;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Converts an array representation of a number to a string.
|
||||
*
|
||||
* More precisely, the elements of the input array are indices into the base,
|
||||
* which is represented as a string, which can either be user defined or one of
|
||||
* the BASE_xxx constants.
|
||||
*
|
||||
* Throws an Error if the number contains a digit which is outside the range
|
||||
* 0 ... base.length - 1.
|
||||
*
|
||||
* @param {Array<number>} number Array of digit values, least significant
|
||||
* first.
|
||||
* @param {string} base Digits in the base.
|
||||
* @return {string} Number as a string, most significant digit first.
|
||||
* @private
|
||||
*/
|
||||
goog.crypt.baseN.arrayToString_ = function(number, base) {
|
||||
var n = number.length;
|
||||
var chars = [];
|
||||
var baseSize = base.length;
|
||||
for (var i = n - 1; i >= 0; i--) {
|
||||
var digit = number[i];
|
||||
if (digit >= baseSize || digit < 0) {
|
||||
throw Error('Number ' + number + ' contains an invalid digit: ' + digit);
|
||||
}
|
||||
chars.push(base.charAt(digit));
|
||||
}
|
||||
return chars.join('');
|
||||
};
|
||||
@@ -0,0 +1,22 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<!--
|
||||
Copyright 2007 The Closure Library Authors. All Rights Reserved.
|
||||
|
||||
Use of this source code is governed by the Apache License, Version 2.0.
|
||||
See the COPYING file for details.
|
||||
-->
|
||||
<head>
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
|
||||
<title>
|
||||
Closure Unit Tests - goog.crypt.baseN
|
||||
</title>
|
||||
<script src="../base.js">
|
||||
</script>
|
||||
<script>
|
||||
goog.require('goog.crypt.baseNTest');
|
||||
</script>
|
||||
</head>
|
||||
<body>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,165 @@
|
||||
// Copyright 2007 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 Tests for arbitrary base conversion library baseconversion.js.
|
||||
*/
|
||||
|
||||
goog.provide('goog.crypt.baseNTest');
|
||||
goog.setTestOnly('goog.crypt.baseNTest');
|
||||
|
||||
goog.require('goog.crypt.baseN');
|
||||
goog.require('goog.testing.jsunit');
|
||||
|
||||
function testDecToHex() {
|
||||
verifyConversion(goog.crypt.baseN.BASE_DECIMAL, '0',
|
||||
goog.crypt.baseN.BASE_LOWERCASE_HEXADECIMAL, '0');
|
||||
verifyConversion(goog.crypt.baseN.BASE_DECIMAL, '9',
|
||||
goog.crypt.baseN.BASE_UPPERCASE_HEXADECIMAL, '9');
|
||||
verifyConversion(goog.crypt.baseN.BASE_DECIMAL, '13',
|
||||
goog.crypt.baseN.BASE_LOWERCASE_HEXADECIMAL, 'd');
|
||||
verifyConversion(goog.crypt.baseN.BASE_DECIMAL, '255',
|
||||
goog.crypt.baseN.BASE_UPPERCASE_HEXADECIMAL, 'FF');
|
||||
verifyConversion(goog.crypt.baseN.BASE_DECIMAL,
|
||||
'53425987345897',
|
||||
goog.crypt.baseN.BASE_LOWERCASE_HEXADECIMAL,
|
||||
'309734ff5de9');
|
||||
verifyConversion(goog.crypt.baseN.BASE_DECIMAL,
|
||||
'987080888',
|
||||
goog.crypt.baseN.BASE_UPPERCASE_HEXADECIMAL,
|
||||
'3AD5A8B8');
|
||||
verifyConversion(goog.crypt.baseN.BASE_DECIMAL,
|
||||
'009341587237',
|
||||
goog.crypt.baseN.BASE_LOWERCASE_HEXADECIMAL,
|
||||
'22ccd4f25');
|
||||
}
|
||||
|
||||
function testBinToDec() {
|
||||
verifyConversion(
|
||||
goog.crypt.baseN.BASE_BINARY,
|
||||
'11101010101000100010010000010010010000111101000100110111000000100001' +
|
||||
'01100100111110110010000010110100111101000010010100001011111011111100' +
|
||||
'00000010000010000101010101000000000101100000000100011111011101111001' +
|
||||
'10000001000000000100101110001001001101101001101111010101111100010001' +
|
||||
'11011100000110111000000100111011100100010010011001111011001111001011' +
|
||||
'10001000101111001010011101101100110110011110010000011100101011110010' +
|
||||
'11010001001111110011000000001001011011111011010000110011010000010111' +
|
||||
'10111100000001100010111100000100000000110001011101011110100000011010' +
|
||||
'0110000100011111',
|
||||
goog.crypt.baseN.BASE_DECIMAL,
|
||||
'34589745906769047354795784390596748934723904739085568907689045723489' +
|
||||
'05745789789078907890789023447892365623589745678902348976234598723459' +
|
||||
'087523496723486089723459078349087');
|
||||
}
|
||||
|
||||
function testDecToBin() {
|
||||
verifyConversion(
|
||||
goog.crypt.baseN.BASE_DECIMAL,
|
||||
'00342589674590347859734908573490568347534805468907960579056785605496' +
|
||||
'83475873465859072390486756098742380573908572390463805745656623475234' +
|
||||
'82345670247851902784123897349486238502378940637925807378946358964328' +
|
||||
'57906148572346857346409823758034763928401296023947234784623765456367' +
|
||||
'764623627623574',
|
||||
goog.crypt.baseN.BASE_BINARY,
|
||||
'10010011011100101010001111100111001100110000110111111110010110101000' +
|
||||
'01010110110010000111000001100110100101010000101001100001011000101111' +
|
||||
'01011101111100101101010010000111011110011110010101111001110010100100' +
|
||||
'10111110000101111011010000000111111011110010011110101011100101000001' +
|
||||
'00011000101010011001101000011101001010001101011110101001011011100101' +
|
||||
'11100000101000010010101001011001100100101110111101010000011010001010' +
|
||||
'01011100100111110001100111100100011001001001100011011100100111011111' +
|
||||
'01000100101001000100110001011010010000011010111101111111111111110100' +
|
||||
'01100101001111001111100110101000001100100000111111100101110010111011' +
|
||||
'10110110001100100011101010110110100001001000101011001001100011010110' +
|
||||
'10110100000110000110010111110100000100110110010010010101111001001111' +
|
||||
'11100100000010101111110100011010011101011010001101110011100110111111' +
|
||||
'11000100001111010000000101011011000010010000000100111111010110111100' +
|
||||
'00101111010011011010011010010001000101100001111001110010010110');
|
||||
}
|
||||
|
||||
function test7To9() {
|
||||
verifyConversion(
|
||||
'0123456', // Base 7.
|
||||
'60625646056660665666066534602566346056634560665606666656465634265434' +
|
||||
'66563465664566346406366534664656650660665623456663456654360665',
|
||||
'012345678', // Base 9.
|
||||
'11451222686557606458341381287142358175337801548087003804852781764284' +
|
||||
'273762357630423116743334671762638240652740158536');
|
||||
}
|
||||
|
||||
function testZeros() {
|
||||
verifyConversion(goog.crypt.baseN.BASE_DECIMAL, '0',
|
||||
goog.crypt.baseN.BASE_LOWERCASE_HEXADECIMAL, '0');
|
||||
verifyConversion(goog.crypt.baseN.BASE_DECIMAL, '000',
|
||||
goog.crypt.baseN.BASE_LOWERCASE_HEXADECIMAL, '0');
|
||||
verifyConversion(goog.crypt.baseN.BASE_DECIMAL, '0000007',
|
||||
goog.crypt.baseN.BASE_LOWERCASE_HEXADECIMAL, '7');
|
||||
}
|
||||
|
||||
function testArbitraryBases() {
|
||||
verifyConversion('X9(', // Base 3.
|
||||
'9(XX((9X(XX9(9X9(X9(',
|
||||
'a:*o9', // Base 5.
|
||||
':oa**:9o9**9oo');
|
||||
}
|
||||
|
||||
function testEmptyBases() {
|
||||
var e = assertThrows(function() {
|
||||
goog.crypt.baseN.recodeString('1230', '', '0123');
|
||||
});
|
||||
assertEquals('Exception message', 'Number 1230 contains a character ' +
|
||||
'not found in base , which is 0', e.message);
|
||||
|
||||
e = assertThrows(function() {
|
||||
goog.crypt.baseN.recodeString('1230', '0123', '');
|
||||
});
|
||||
assertEquals('Exception message', 'Empty output base', e.message);
|
||||
}
|
||||
|
||||
function testInvalidDigits() {
|
||||
var e = assertThrows(function() {
|
||||
goog.crypt.baseN.recodeString('123x456', '01234567', '01234567');
|
||||
});
|
||||
assertEquals('Exception message', 'Number 123x456 contains a character ' +
|
||||
'not found in base 01234567, which is x', e.message);
|
||||
}
|
||||
|
||||
function makeHugeBase() {
|
||||
// Number of digits in the base.
|
||||
// Tests break if this is set to 200'000. The reason for that is
|
||||
// String.fromCharCode(196609) == String.fromCharCode(1).
|
||||
var baseSize = 20000;
|
||||
var tab = [];
|
||||
for (var i = 0; i < baseSize; i++) {
|
||||
tab.push(String.fromCharCode(i));
|
||||
}
|
||||
return tab.join('');
|
||||
}
|
||||
|
||||
function testHugeInputBase() {
|
||||
verifyConversion(makeHugeBase(), String.fromCharCode(12345),
|
||||
goog.crypt.baseN.BASE_DECIMAL, '12345');
|
||||
}
|
||||
|
||||
function testHugeOutputBase() {
|
||||
verifyConversion(goog.crypt.baseN.BASE_DECIMAL, '12345',
|
||||
makeHugeBase(), String.fromCharCode(12345));
|
||||
}
|
||||
|
||||
function verifyConversion(inputBase, inputNumber, outputBase, outputNumber) {
|
||||
assertEquals(outputNumber,
|
||||
goog.crypt.baseN.recodeString(inputNumber,
|
||||
inputBase,
|
||||
outputBase));
|
||||
}
|
||||
@@ -0,0 +1,283 @@
|
||||
// Copyright 2011 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 Asynchronous hash computer for the Blob interface.
|
||||
*
|
||||
* The Blob interface, part of the HTML5 File API, is supported on Chrome 7+,
|
||||
* Firefox 4.0 and Opera 11. No Blob interface implementation is expected on
|
||||
* Internet Explorer 10. Chrome 11, Firefox 5.0 and the subsequent release of
|
||||
* Opera are supposed to use vendor prefixes due to evolving API, see
|
||||
* http://dev.w3.org/2006/webapi/FileAPI/ for details.
|
||||
*
|
||||
* This implementation currently uses upcoming Chrome and Firefox prefixes,
|
||||
* plus the original Blob.slice specification, as implemented on Chrome 10
|
||||
* and Firefox 4.0.
|
||||
*
|
||||
*/
|
||||
|
||||
goog.provide('goog.crypt.BlobHasher');
|
||||
goog.provide('goog.crypt.BlobHasher.EventType');
|
||||
|
||||
goog.require('goog.asserts');
|
||||
goog.require('goog.events.EventTarget');
|
||||
goog.require('goog.fs');
|
||||
goog.require('goog.log');
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Construct the hash computer.
|
||||
*
|
||||
* @param {!goog.crypt.Hash} hashFn The hash function to use.
|
||||
* @param {number=} opt_blockSize Processing block size.
|
||||
* @constructor
|
||||
* @extends {goog.events.EventTarget}
|
||||
* @final
|
||||
*/
|
||||
goog.crypt.BlobHasher = function(hashFn, opt_blockSize) {
|
||||
goog.crypt.BlobHasher.base(this, 'constructor');
|
||||
|
||||
/**
|
||||
* The actual hash function.
|
||||
* @type {!goog.crypt.Hash}
|
||||
* @private
|
||||
*/
|
||||
this.hashFn_ = hashFn;
|
||||
|
||||
/**
|
||||
* The blob being processed or null if no blob is being processed.
|
||||
* @type {Blob}
|
||||
* @private
|
||||
*/
|
||||
this.blob_ = null;
|
||||
|
||||
/**
|
||||
* Computed hash value.
|
||||
* @type {Array<number>}
|
||||
* @private
|
||||
*/
|
||||
this.hashVal_ = null;
|
||||
|
||||
/**
|
||||
* Number of bytes already processed.
|
||||
* @type {number}
|
||||
* @private
|
||||
*/
|
||||
this.bytesProcessed_ = 0;
|
||||
|
||||
/**
|
||||
* The number of bytes to hash or Infinity for no limit.
|
||||
* @type {number}
|
||||
* @private
|
||||
*/
|
||||
this.hashingLimit_ = Infinity;
|
||||
|
||||
/**
|
||||
* Processing block size.
|
||||
* @type {number}
|
||||
* @private
|
||||
*/
|
||||
this.blockSize_ = opt_blockSize || 5000000;
|
||||
|
||||
/**
|
||||
* File reader object. Will be null if no chunk is currently being read.
|
||||
* @type {FileReader}
|
||||
* @private
|
||||
*/
|
||||
this.fileReader_ = null;
|
||||
|
||||
/**
|
||||
* The logger used by this object.
|
||||
* @type {goog.log.Logger}
|
||||
* @private
|
||||
*/
|
||||
this.logger_ = goog.log.getLogger('goog.crypt.BlobHasher');
|
||||
};
|
||||
goog.inherits(goog.crypt.BlobHasher, goog.events.EventTarget);
|
||||
|
||||
|
||||
/**
|
||||
* Event names for hash computation events
|
||||
* @enum {string}
|
||||
*/
|
||||
goog.crypt.BlobHasher.EventType = {
|
||||
STARTED: 'started',
|
||||
PROGRESS: 'progress',
|
||||
THROTTLED: 'throttled',
|
||||
COMPLETE: 'complete',
|
||||
ABORT: 'abort',
|
||||
ERROR: 'error'
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Start the hash computation.
|
||||
* @param {!Blob} blob The blob of data to compute the hash for.
|
||||
*/
|
||||
goog.crypt.BlobHasher.prototype.hash = function(blob) {
|
||||
this.abort();
|
||||
this.hashFn_.reset();
|
||||
this.blob_ = blob;
|
||||
this.hashVal_ = null;
|
||||
this.bytesProcessed_ = 0;
|
||||
this.dispatchEvent(goog.crypt.BlobHasher.EventType.STARTED);
|
||||
|
||||
this.processNextBlock_();
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Sets the maximum number of bytes to hash or Infinity for no limit. Can be
|
||||
* called before hash() to throttle the hash computation. The hash computation
|
||||
* can then be continued by repeatedly calling setHashingLimit() with greater
|
||||
* byte offsets. This is useful if you don't need the hash until some time in
|
||||
* the future, for example when uploading a file and you don't need the hash
|
||||
* until the transfer is complete.
|
||||
* @param {number} byteOffset The byte offset to compute the hash up to.
|
||||
* Should be a non-negative integer or Infinity for no limit. Negative
|
||||
* values are not allowed.
|
||||
*/
|
||||
goog.crypt.BlobHasher.prototype.setHashingLimit = function(byteOffset) {
|
||||
goog.asserts.assert(byteOffset >= 0, 'Hashing limit must be non-negative.');
|
||||
this.hashingLimit_ = byteOffset;
|
||||
|
||||
// Resume processing if a blob is currently being hashed, but no block read
|
||||
// is currently in progress.
|
||||
if (this.blob_ && !this.fileReader_) {
|
||||
this.processNextBlock_();
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Abort hash computation.
|
||||
*/
|
||||
goog.crypt.BlobHasher.prototype.abort = function() {
|
||||
if (this.fileReader_) {
|
||||
this.fileReader_.abort();
|
||||
this.fileReader_ = null;
|
||||
}
|
||||
|
||||
if (this.blob_) {
|
||||
this.blob_ = null;
|
||||
this.dispatchEvent(goog.crypt.BlobHasher.EventType.ABORT);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @return {number} Number of bytes processed so far.
|
||||
*/
|
||||
goog.crypt.BlobHasher.prototype.getBytesProcessed = function() {
|
||||
return this.bytesProcessed_;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @return {Array<number>} The computed hash value or null if not ready.
|
||||
*/
|
||||
goog.crypt.BlobHasher.prototype.getHash = function() {
|
||||
return this.hashVal_;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Helper function setting up the processing for the next block, or finalizing
|
||||
* the computation if all blocks were processed.
|
||||
* @private
|
||||
*/
|
||||
goog.crypt.BlobHasher.prototype.processNextBlock_ = function() {
|
||||
goog.asserts.assert(this.blob_, 'A hash computation must be in progress.');
|
||||
|
||||
if (this.bytesProcessed_ < this.blob_.size) {
|
||||
|
||||
if (this.hashingLimit_ <= this.bytesProcessed_) {
|
||||
// Throttle limit reached. Wait until we are allowed to hash more bytes.
|
||||
this.dispatchEvent(goog.crypt.BlobHasher.EventType.THROTTLED);
|
||||
return;
|
||||
}
|
||||
|
||||
// We have to reset the FileReader every time, otherwise it fails on
|
||||
// Chrome, including the latest Chrome 12 beta.
|
||||
// http://code.google.com/p/chromium/issues/detail?id=82346
|
||||
this.fileReader_ = new FileReader();
|
||||
this.fileReader_.onload = goog.bind(this.onLoad_, this);
|
||||
this.fileReader_.onerror = goog.bind(this.onError_, this);
|
||||
|
||||
var endOffset = Math.min(this.hashingLimit_, this.blob_.size);
|
||||
var size = Math.min(endOffset - this.bytesProcessed_, this.blockSize_);
|
||||
var chunk = goog.fs.sliceBlob(this.blob_, this.bytesProcessed_,
|
||||
this.bytesProcessed_ + size);
|
||||
if (!chunk || chunk.size != size) {
|
||||
goog.log.error(this.logger_, 'Failed slicing the blob');
|
||||
this.onError_();
|
||||
return;
|
||||
}
|
||||
|
||||
if (this.fileReader_.readAsArrayBuffer) {
|
||||
this.fileReader_.readAsArrayBuffer(chunk);
|
||||
} else if (this.fileReader_.readAsBinaryString) {
|
||||
this.fileReader_.readAsBinaryString(chunk);
|
||||
} else {
|
||||
goog.log.error(this.logger_, 'Failed calling the chunk reader');
|
||||
this.onError_();
|
||||
}
|
||||
} else {
|
||||
this.hashVal_ = this.hashFn_.digest();
|
||||
this.blob_ = null;
|
||||
this.dispatchEvent(goog.crypt.BlobHasher.EventType.COMPLETE);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Handle processing block loaded.
|
||||
* @private
|
||||
*/
|
||||
goog.crypt.BlobHasher.prototype.onLoad_ = function() {
|
||||
goog.log.info(this.logger_, 'Successfully loaded a chunk');
|
||||
|
||||
var array = null;
|
||||
if (this.fileReader_.result instanceof Array ||
|
||||
goog.isString(this.fileReader_.result)) {
|
||||
array = this.fileReader_.result;
|
||||
} else if (goog.global['ArrayBuffer'] && goog.global['Uint8Array'] &&
|
||||
this.fileReader_.result instanceof ArrayBuffer) {
|
||||
array = new Uint8Array(this.fileReader_.result);
|
||||
}
|
||||
if (!array) {
|
||||
goog.log.error(this.logger_, 'Failed reading the chunk');
|
||||
this.onError_();
|
||||
return;
|
||||
}
|
||||
|
||||
this.hashFn_.update(array);
|
||||
this.bytesProcessed_ += array.length;
|
||||
this.fileReader_ = null;
|
||||
this.dispatchEvent(goog.crypt.BlobHasher.EventType.PROGRESS);
|
||||
|
||||
this.processNextBlock_();
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Handles error.
|
||||
* @private
|
||||
*/
|
||||
goog.crypt.BlobHasher.prototype.onError_ = function() {
|
||||
this.fileReader_ = null;
|
||||
this.blob_ = null;
|
||||
this.dispatchEvent(goog.crypt.BlobHasher.EventType.ERROR);
|
||||
};
|
||||
@@ -0,0 +1,23 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<!--
|
||||
Copyright 2011 The Closure Library Authors. All Rights Reserved.
|
||||
|
||||
Use of this source code is governed by the Apache License, Version 2.0.
|
||||
See the COPYING file for details.
|
||||
|
||||
-->
|
||||
<head>
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
|
||||
<title>
|
||||
Closure Unit Tests - goog.crypt.BlobHasher
|
||||
</title>
|
||||
<script src="../base.js">
|
||||
</script>
|
||||
<script>
|
||||
goog.require('goog.crypt.BlobHasherTest');
|
||||
</script>
|
||||
</head>
|
||||
<body>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,382 @@
|
||||
// Copyright 2011 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.
|
||||
|
||||
goog.provide('goog.crypt.BlobHasherTest');
|
||||
goog.setTestOnly('goog.crypt.BlobHasherTest');
|
||||
|
||||
goog.require('goog.crypt');
|
||||
goog.require('goog.crypt.BlobHasher');
|
||||
goog.require('goog.crypt.Md5');
|
||||
goog.require('goog.events');
|
||||
goog.require('goog.testing.PropertyReplacer');
|
||||
goog.require('goog.testing.jsunit');
|
||||
|
||||
// A browser-independent mock of goog.fs.sliceBlob. The actual implementation
|
||||
// calls the underlying slice method differently based on browser version.
|
||||
// This mock does not support negative opt_end.
|
||||
var fsSliceBlobMock = function(blob, start, opt_end) {
|
||||
if (!goog.isNumber(opt_end)) {
|
||||
opt_end = blob.size;
|
||||
}
|
||||
return blob.slice(start, opt_end);
|
||||
};
|
||||
|
||||
// Mock out the Blob using a string.
|
||||
BlobMock = function(string) {
|
||||
this.data = string;
|
||||
this.size = this.data.length;
|
||||
};
|
||||
|
||||
BlobMock.prototype.slice = function(start, end) {
|
||||
return new BlobMock(this.data.substr(start, end - start));
|
||||
};
|
||||
|
||||
|
||||
// Mock out the FileReader to have control over the flow.
|
||||
FileReaderMock = function() {
|
||||
this.array_ = [];
|
||||
this.result = null;
|
||||
this.readyState = this.EMPTY;
|
||||
|
||||
this.onload = null;
|
||||
this.onabort = null;
|
||||
this.onerror = null;
|
||||
};
|
||||
|
||||
FileReaderMock.prototype.EMPTY = 0;
|
||||
FileReaderMock.prototype.LOADING = 1;
|
||||
FileReaderMock.prototype.DONE = 2;
|
||||
|
||||
FileReaderMock.prototype.mockLoad = function() {
|
||||
this.readyState = this.DONE;
|
||||
this.result = this.array_;
|
||||
if (this.onload) {
|
||||
this.onload.call();
|
||||
}
|
||||
};
|
||||
|
||||
FileReaderMock.prototype.abort = function() {
|
||||
this.readyState = this.DONE;
|
||||
if (this.onabort) {
|
||||
this.onabort.call();
|
||||
}
|
||||
};
|
||||
|
||||
FileReaderMock.prototype.mockError = function() {
|
||||
this.readyState = this.DONE;
|
||||
if (this.onerror) {
|
||||
this.onerror.call();
|
||||
}
|
||||
};
|
||||
|
||||
FileReaderMock.prototype.readAsArrayBuffer = function(blobMock) {
|
||||
this.readyState = this.LOADING;
|
||||
this.array_ = [];
|
||||
for (var i = 0; i < blobMock.size; ++i) {
|
||||
this.array_[i] = blobMock.data.charCodeAt(i);
|
||||
}
|
||||
};
|
||||
|
||||
FileReaderMock.prototype.isLoading = function() {
|
||||
return this.readyState == this.LOADING;
|
||||
};
|
||||
|
||||
var stubs = new goog.testing.PropertyReplacer();
|
||||
function setUp() {
|
||||
stubs.set(goog.global, 'FileReader', FileReaderMock);
|
||||
stubs.set(goog.fs, 'sliceBlob', fsSliceBlobMock);
|
||||
}
|
||||
|
||||
function tearDown() {
|
||||
stubs.reset();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Makes the blobHasher read chunks from the blob and hash it. The number of
|
||||
* reads shall not exceed a pre-determined number (typically blob size / chunk
|
||||
* size) for computing hash. This function fails fast (after maxReads is
|
||||
* reached), assuming that the hasher failed to generate hashes. This prevents
|
||||
* the test suite from going into infinite loop.
|
||||
* @param {!goog.crypt.BlobHasher} blobHasher Hasher in action.
|
||||
* @param {number} maxReads Max number of read attempts.
|
||||
*/
|
||||
function readFromBlob(blobHasher, maxReads) {
|
||||
var counter = 0;
|
||||
while (blobHasher.fileReader_ && blobHasher.fileReader_.isLoading() &&
|
||||
counter <= maxReads) {
|
||||
blobHasher.fileReader_.mockLoad();
|
||||
counter++;
|
||||
}
|
||||
assertTrue(counter <= maxReads);
|
||||
return counter;
|
||||
}
|
||||
|
||||
function testBasicOperations() {
|
||||
if (!window.Blob) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Test hashing with one chunk.
|
||||
var hashFn = new goog.crypt.Md5();
|
||||
var blobHasher = new goog.crypt.BlobHasher(hashFn);
|
||||
var blob = new BlobMock('The quick brown fox jumps over the lazy dog');
|
||||
blobHasher.hash(blob);
|
||||
readFromBlob(blobHasher, 1);
|
||||
assertEquals('9e107d9d372bb6826bd81d3542a419d6',
|
||||
goog.crypt.byteArrayToHex(blobHasher.getHash()));
|
||||
|
||||
// Test hashing with multiple chunks.
|
||||
blobHasher = new goog.crypt.BlobHasher(hashFn, 7);
|
||||
blobHasher.hash(blob);
|
||||
readFromBlob(blobHasher, Math.ceil(blob.size / 7));
|
||||
assertEquals('9e107d9d372bb6826bd81d3542a419d6',
|
||||
goog.crypt.byteArrayToHex(blobHasher.getHash()));
|
||||
|
||||
// Test hashing with no chunks.
|
||||
blob = new BlobMock('');
|
||||
blobHasher.hash(blob);
|
||||
readFromBlob(blobHasher, 1);
|
||||
assertEquals('d41d8cd98f00b204e9800998ecf8427e',
|
||||
goog.crypt.byteArrayToHex(blobHasher.getHash()));
|
||||
|
||||
}
|
||||
|
||||
function testNormalFlow() {
|
||||
if (!window.Blob) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Test the flow with one chunk.
|
||||
var hashFn = new goog.crypt.Md5();
|
||||
var blobHasher = new goog.crypt.BlobHasher(hashFn, 13);
|
||||
var blob = new BlobMock('short');
|
||||
var startedEvents = 0;
|
||||
var progressEvents = 0;
|
||||
var completeEvents = 0;
|
||||
goog.events.listen(blobHasher, goog.crypt.BlobHasher.EventType.STARTED,
|
||||
function() { ++startedEvents; });
|
||||
goog.events.listen(blobHasher, goog.crypt.BlobHasher.EventType.PROGRESS,
|
||||
function() { ++progressEvents; });
|
||||
goog.events.listen(blobHasher, goog.crypt.BlobHasher.EventType.COMPLETE,
|
||||
function() { ++completeEvents; });
|
||||
blobHasher.hash(blob);
|
||||
assertEquals(1, startedEvents);
|
||||
assertEquals(0, progressEvents);
|
||||
assertEquals(0, completeEvents);
|
||||
readFromBlob(blobHasher, 1);
|
||||
assertEquals(1, startedEvents);
|
||||
assertEquals(1, progressEvents);
|
||||
assertEquals(1, completeEvents);
|
||||
|
||||
// Test the flow with multiple chunks.
|
||||
blob = new BlobMock('The quick brown fox jumps over the lazy dog');
|
||||
startedEvents = 0;
|
||||
progressEvents = 0;
|
||||
completeEvents = 0;
|
||||
var progressLoops = 0;
|
||||
blobHasher.hash(blob);
|
||||
assertEquals(1, startedEvents);
|
||||
assertEquals(0, progressEvents);
|
||||
assertEquals(0, completeEvents);
|
||||
progressLoops = readFromBlob(blobHasher, Math.ceil(blob.size / 13));
|
||||
assertEquals(1, startedEvents);
|
||||
assertEquals(progressLoops, progressEvents);
|
||||
assertEquals(1, completeEvents);
|
||||
}
|
||||
|
||||
function testAbortsAndErrors() {
|
||||
if (!window.Blob) {
|
||||
return;
|
||||
}
|
||||
|
||||
var hashFn = new goog.crypt.Md5();
|
||||
var blobHasher = new goog.crypt.BlobHasher(hashFn, 13);
|
||||
var blob = new BlobMock('The quick brown fox jumps over the lazy dog');
|
||||
var abortEvents = 0;
|
||||
var errorEvents = 0;
|
||||
var completeEvents = 0;
|
||||
goog.events.listen(blobHasher, goog.crypt.BlobHasher.EventType.ABORT,
|
||||
function() { ++abortEvents; });
|
||||
goog.events.listen(blobHasher, goog.crypt.BlobHasher.EventType.ERROR,
|
||||
function() { ++errorEvents; });
|
||||
goog.events.listen(blobHasher, goog.crypt.BlobHasher.EventType.COMPLETE,
|
||||
function() { ++completeEvents; });
|
||||
|
||||
// Immediate abort.
|
||||
blobHasher.hash(blob);
|
||||
assertEquals(0, abortEvents);
|
||||
assertEquals(0, errorEvents);
|
||||
assertEquals(0, completeEvents);
|
||||
blobHasher.abort();
|
||||
blobHasher.abort();
|
||||
assertEquals(1, abortEvents);
|
||||
assertEquals(0, errorEvents);
|
||||
assertEquals(0, completeEvents);
|
||||
abortEvents = 0;
|
||||
|
||||
// Delayed abort.
|
||||
blobHasher.hash(blob);
|
||||
blobHasher.fileReader_.mockLoad();
|
||||
assertEquals(0, abortEvents);
|
||||
assertEquals(0, errorEvents);
|
||||
assertEquals(0, completeEvents);
|
||||
blobHasher.abort();
|
||||
blobHasher.abort();
|
||||
assertEquals(1, abortEvents);
|
||||
assertEquals(0, errorEvents);
|
||||
assertEquals(0, completeEvents);
|
||||
abortEvents = 0;
|
||||
|
||||
// Immediate error.
|
||||
blobHasher.hash(blob);
|
||||
blobHasher.fileReader_.mockError();
|
||||
assertEquals(0, abortEvents);
|
||||
assertEquals(1, errorEvents);
|
||||
assertEquals(0, completeEvents);
|
||||
errorEvents = 0;
|
||||
|
||||
// Delayed error.
|
||||
blobHasher.hash(blob);
|
||||
blobHasher.fileReader_.mockLoad();
|
||||
blobHasher.fileReader_.mockError();
|
||||
assertEquals(0, abortEvents);
|
||||
assertEquals(1, errorEvents);
|
||||
assertEquals(0, completeEvents);
|
||||
abortEvents = 0;
|
||||
|
||||
}
|
||||
|
||||
function testBasicThrottling() {
|
||||
if (!window.Blob) {
|
||||
return;
|
||||
}
|
||||
|
||||
var hashFn = new goog.crypt.Md5();
|
||||
var blobHasher = new goog.crypt.BlobHasher(hashFn, 5);
|
||||
var blob = new BlobMock('The quick brown fox jumps over the lazy dog');
|
||||
var throttledEvents = 0;
|
||||
var completeEvents = 0;
|
||||
goog.events.listen(blobHasher, goog.crypt.BlobHasher.EventType.THROTTLED,
|
||||
function() { ++throttledEvents; });
|
||||
goog.events.listen(blobHasher, goog.crypt.BlobHasher.EventType.COMPLETE,
|
||||
function() { ++completeEvents; });
|
||||
|
||||
// Start a throttled hash. No chunks should be processed yet.
|
||||
blobHasher.setHashingLimit(0);
|
||||
assertEquals(0, throttledEvents);
|
||||
blobHasher.hash(blob);
|
||||
assertEquals(1, throttledEvents);
|
||||
assertEquals(0, blobHasher.getBytesProcessed());
|
||||
assertNull(blobHasher.fileReader_);
|
||||
|
||||
// One chunk should be processed.
|
||||
blobHasher.setHashingLimit(4);
|
||||
assertEquals(1, throttledEvents);
|
||||
assertEquals(1, readFromBlob(blobHasher, 1));
|
||||
assertEquals(2, throttledEvents);
|
||||
assertEquals(4, blobHasher.getBytesProcessed());
|
||||
|
||||
// One more chunk should be processed.
|
||||
blobHasher.setHashingLimit(5);
|
||||
assertEquals(2, throttledEvents);
|
||||
assertEquals(1, readFromBlob(blobHasher, 1));
|
||||
assertEquals(3, throttledEvents);
|
||||
assertEquals(5, blobHasher.getBytesProcessed());
|
||||
|
||||
// Two more chunks should be processed.
|
||||
blobHasher.setHashingLimit(15);
|
||||
assertEquals(3, throttledEvents);
|
||||
assertEquals(2, readFromBlob(blobHasher, 2));
|
||||
assertEquals(4, throttledEvents);
|
||||
assertEquals(15, blobHasher.getBytesProcessed());
|
||||
|
||||
// The entire blob should be processed.
|
||||
blobHasher.setHashingLimit(Infinity);
|
||||
var expectedChunks = Math.ceil(blob.size / 5) - 3;
|
||||
assertEquals(expectedChunks, readFromBlob(blobHasher, expectedChunks));
|
||||
assertEquals(4, throttledEvents);
|
||||
assertEquals(1, completeEvents);
|
||||
assertEquals('9e107d9d372bb6826bd81d3542a419d6',
|
||||
goog.crypt.byteArrayToHex(blobHasher.getHash()));
|
||||
}
|
||||
|
||||
function testLengthZeroThrottling() {
|
||||
if (!window.Blob) {
|
||||
return;
|
||||
}
|
||||
|
||||
var hashFn = new goog.crypt.Md5();
|
||||
var blobHasher = new goog.crypt.BlobHasher(hashFn);
|
||||
var throttledEvents = 0;
|
||||
var completeEvents = 0;
|
||||
goog.events.listen(blobHasher, goog.crypt.BlobHasher.EventType.THROTTLED,
|
||||
function() { ++throttledEvents; });
|
||||
goog.events.listen(blobHasher, goog.crypt.BlobHasher.EventType.COMPLETE,
|
||||
function() { ++completeEvents; });
|
||||
|
||||
// Test throttling with length 0 blob.
|
||||
var blob = new BlobMock('');
|
||||
blobHasher.setHashingLimit(0);
|
||||
blobHasher.hash(blob);
|
||||
assertEquals(0, throttledEvents);
|
||||
assertEquals(1, completeEvents);
|
||||
assertEquals('d41d8cd98f00b204e9800998ecf8427e',
|
||||
goog.crypt.byteArrayToHex(blobHasher.getHash()));
|
||||
}
|
||||
|
||||
function testAbortsAndErrorsWhileThrottling() {
|
||||
if (!window.Blob) {
|
||||
return;
|
||||
}
|
||||
|
||||
var hashFn = new goog.crypt.Md5();
|
||||
var blobHasher = new goog.crypt.BlobHasher(hashFn, 5);
|
||||
var blob = new BlobMock('The quick brown fox jumps over the lazy dog');
|
||||
var abortEvents = 0;
|
||||
var errorEvents = 0;
|
||||
var throttledEvents = 0;
|
||||
var completeEvents = 0;
|
||||
goog.events.listen(blobHasher, goog.crypt.BlobHasher.EventType.ABORT,
|
||||
function() { ++abortEvents; });
|
||||
goog.events.listen(blobHasher, goog.crypt.BlobHasher.EventType.ERROR,
|
||||
function() { ++errorEvents; });
|
||||
goog.events.listen(blobHasher, goog.crypt.BlobHasher.EventType.THROTTLED,
|
||||
function() { ++throttledEvents; });
|
||||
goog.events.listen(blobHasher, goog.crypt.BlobHasher.EventType.COMPLETE,
|
||||
function() { ++completeEvents; });
|
||||
|
||||
// Test that processing cannot be continued after abort.
|
||||
blobHasher.setHashingLimit(0);
|
||||
blobHasher.hash(blob);
|
||||
assertEquals(1, throttledEvents);
|
||||
blobHasher.abort();
|
||||
assertEquals(1, abortEvents);
|
||||
blobHasher.setHashingLimit(10);
|
||||
assertNull(blobHasher.fileReader_);
|
||||
assertEquals(1, throttledEvents);
|
||||
assertEquals(0, completeEvents);
|
||||
assertNull(blobHasher.getHash());
|
||||
|
||||
// Test that processing cannot be continued after error.
|
||||
blobHasher.hash(blob);
|
||||
assertEquals(1, throttledEvents);
|
||||
blobHasher.fileReader_.mockError();
|
||||
assertEquals(1, errorEvents);
|
||||
blobHasher.setHashingLimit(100);
|
||||
assertNull(blobHasher.fileReader_);
|
||||
assertEquals(1, throttledEvents);
|
||||
assertEquals(0, completeEvents);
|
||||
assertNull(blobHasher.getHash());
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
// 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 Interface definition of a block cipher. A block cipher is a
|
||||
* pair of algorithms that implement encryption and decryption of input bytes.
|
||||
*
|
||||
* @see http://en.wikipedia.org/wiki/Block_cipher
|
||||
*
|
||||
* @author nnaze@google.com (Nathan Naze)
|
||||
*/
|
||||
|
||||
goog.provide('goog.crypt.BlockCipher');
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Interface definition for a block cipher.
|
||||
* @interface
|
||||
*/
|
||||
goog.crypt.BlockCipher = function() {};
|
||||
|
||||
|
||||
/**
|
||||
* Encrypt a plaintext block. The implementation may expect (and assert)
|
||||
* a particular block length.
|
||||
* @param {!Array<number>} input Plaintext array of input bytes.
|
||||
* @return {!Array<number>} Encrypted ciphertext array of bytes. Should be the
|
||||
* same length as input.
|
||||
*/
|
||||
goog.crypt.BlockCipher.prototype.encrypt;
|
||||
|
||||
|
||||
/**
|
||||
* Decrypt a plaintext block. The implementation may expect (and assert)
|
||||
* a particular block length.
|
||||
* @param {!Array<number>} input Ciphertext. Array of input bytes.
|
||||
* @return {!Array<number>} Decrypted plaintext array of bytes. Should be the
|
||||
* same length as input.
|
||||
*/
|
||||
goog.crypt.BlockCipher.prototype.decrypt;
|
||||
@@ -0,0 +1,25 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<!--
|
||||
Copyright 2014 The Closure Library Authors. All Rights Reserved.
|
||||
|
||||
Use of this source code is governed by the Apache License, Version 2.0.
|
||||
See the COPYING file for details.
|
||||
-->
|
||||
<head>
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||
<title>Closure Performance Tests - byteArrayToString</title>
|
||||
<link rel="stylesheet" type="text/css"
|
||||
href="../testing/performancetable.css"/>
|
||||
<script src="../base.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<h1>Closure Performance Tests - byteArrayToString</h1>
|
||||
<div id="perfTable"></div>
|
||||
<hr>
|
||||
<script>
|
||||
goog.require('goog.crypt.byteArrayToStringPerf');
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@@ -0,0 +1,124 @@
|
||||
// Copyright 2014 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 Performance test for different implementations of
|
||||
* byteArrayToString.
|
||||
*/
|
||||
|
||||
|
||||
goog.provide('goog.crypt.byteArrayToStringPerf');
|
||||
|
||||
goog.require('goog.array');
|
||||
goog.require('goog.dom');
|
||||
goog.require('goog.testing.PerformanceTable');
|
||||
|
||||
goog.setTestOnly('goog.crypt.byteArrayToStringPerf');
|
||||
|
||||
|
||||
var table = new goog.testing.PerformanceTable(
|
||||
goog.dom.getElement('perfTable'));
|
||||
|
||||
|
||||
var BYTES_LENGTH = Math.pow(2, 20);
|
||||
var CHUNK_SIZE = 8192;
|
||||
|
||||
function getBytes() {
|
||||
var bytes = [];
|
||||
for (var i = 0; i < BYTES_LENGTH; i++) {
|
||||
bytes.push('A'.charCodeAt(0));
|
||||
}
|
||||
return bytes;
|
||||
}
|
||||
|
||||
function copyAndSpliceByteArray(bytes) {
|
||||
|
||||
// Copy the passed byte array since we're going to destroy it.
|
||||
var remainingBytes = goog.array.clone(bytes);
|
||||
var strings = [];
|
||||
|
||||
// Convert each chunk to a string.
|
||||
while (remainingBytes.length) {
|
||||
var chunk = goog.array.splice(remainingBytes, 0, CHUNK_SIZE);
|
||||
strings.push(String.fromCharCode.apply(null, chunk));
|
||||
}
|
||||
return strings.join('');
|
||||
}
|
||||
|
||||
function sliceByteArrayConcat(bytes) {
|
||||
var str = '';
|
||||
for (var i = 0; i < bytes.length; i += CHUNK_SIZE) {
|
||||
var chunk = goog.array.slice(bytes, i, i + CHUNK_SIZE);
|
||||
str += String.fromCharCode.apply(null, chunk);
|
||||
}
|
||||
return str;
|
||||
}
|
||||
|
||||
|
||||
function sliceByteArrayJoin(bytes) {
|
||||
var strings = [];
|
||||
for (var i = 0; i < bytes.length; i += CHUNK_SIZE) {
|
||||
var chunk = goog.array.slice(bytes, i, i + CHUNK_SIZE);
|
||||
strings.push(String.fromCharCode.apply(null, chunk));
|
||||
}
|
||||
return strings.join('');
|
||||
}
|
||||
|
||||
function mapByteArray(bytes) {
|
||||
var strings = goog.array.map(bytes, String.fromCharCode);
|
||||
return strings.join('');
|
||||
}
|
||||
|
||||
function forLoopByteArrayConcat(bytes) {
|
||||
var str = '';
|
||||
for (var i = 0; i < bytes.length; i++) {
|
||||
str += String.fromCharCode(bytes[i]);
|
||||
}
|
||||
return str;
|
||||
}
|
||||
|
||||
function forLoopByteArrayJoin(bytes) {
|
||||
var strs = [];
|
||||
for (var i = 0; i < bytes.length; i++) {
|
||||
strs.push(String.fromCharCode(bytes[i]));
|
||||
}
|
||||
return strs.join('');
|
||||
}
|
||||
|
||||
|
||||
function run() {
|
||||
var bytes = getBytes();
|
||||
table.run(goog.partial(copyAndSpliceByteArray, getBytes()),
|
||||
'Copy array and splice out chunks.');
|
||||
|
||||
table.run(goog.partial(sliceByteArrayConcat, getBytes()),
|
||||
'Slice out copies of the byte array, concatenating results');
|
||||
|
||||
table.run(goog.partial(sliceByteArrayJoin, getBytes()),
|
||||
'Slice out copies of the byte array, joining results');
|
||||
|
||||
table.run(goog.partial(forLoopByteArrayConcat, getBytes()),
|
||||
'Use for loop with concat.');
|
||||
|
||||
table.run(goog.partial(forLoopByteArrayJoin, getBytes()),
|
||||
'Use for loop with join.');
|
||||
|
||||
// Purposefully commented out. This ends up being tremendously expensive.
|
||||
// table.run(goog.partial(mapByteArray, getBytes()),
|
||||
// 'Use goog.array.map and fromCharCode.');
|
||||
|
||||
}
|
||||
|
||||
run();
|
||||
|
||||
@@ -0,0 +1,153 @@
|
||||
// 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');
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* 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.
|
||||
* @param {number=} opt_blockSize The block size of the cipher in bytes.
|
||||
* Defaults to 16 bytes.
|
||||
* @constructor
|
||||
* @final
|
||||
* @struct
|
||||
*/
|
||||
goog.crypt.Cbc = function(cipher, opt_blockSize) {
|
||||
|
||||
/**
|
||||
* Block cipher.
|
||||
* @type {!goog.crypt.BlockCipher}
|
||||
* @private
|
||||
*/
|
||||
this.cipher_ = cipher;
|
||||
|
||||
/**
|
||||
* Block size in bytes.
|
||||
* @type {number}
|
||||
* @private
|
||||
*/
|
||||
this.blockSize_ = opt_blockSize || 16;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Encrypt a message.
|
||||
*
|
||||
* @param {!Array<number>} plainText Message to encrypt. An array of bytes.
|
||||
* The length should be a multiple of the block size.
|
||||
* @param {!Array<number>} initialVector Initial vector for the CBC mode.
|
||||
* An array of bytes with the same length as the block size.
|
||||
* @return {!Array<number>} Encrypted message.
|
||||
*/
|
||||
goog.crypt.Cbc.prototype.encrypt = function(plainText, initialVector) {
|
||||
|
||||
goog.asserts.assert(
|
||||
plainText.length % this.blockSize_ == 0,
|
||||
'Data\'s length must be multiple of block size.');
|
||||
|
||||
goog.asserts.assert(
|
||||
initialVector.length == this.blockSize_,
|
||||
'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.blockSize_) {
|
||||
|
||||
// Takes one block from the input message.
|
||||
var plainTextBlock = goog.array.slice(
|
||||
plainText,
|
||||
blockStartIndex,
|
||||
blockStartIndex + this.blockSize_);
|
||||
|
||||
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<number>} cipherText Message to decrypt. An array of bytes.
|
||||
* The length should be a multiple of the block size.
|
||||
* @param {!Array<number>} initialVector Initial vector for the CBC mode.
|
||||
* An array of bytes with the same length as the block size.
|
||||
* @return {!Array<number>} Decrypted message.
|
||||
*/
|
||||
goog.crypt.Cbc.prototype.decrypt = function(cipherText, initialVector) {
|
||||
|
||||
goog.asserts.assert(
|
||||
cipherText.length % this.blockSize_ == 0,
|
||||
'Data\'s length must be multiple of block size.');
|
||||
|
||||
goog.asserts.assert(
|
||||
initialVector.length == this.blockSize_,
|
||||
'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.blockSize_);
|
||||
|
||||
var resultBlock = this.cipher_.decrypt(cipherTextBlock);
|
||||
var plainTextBlock = goog.crypt.xorByteArray(vector, resultBlock);
|
||||
|
||||
goog.array.extend(plainText, plainTextBlock);
|
||||
vector = cipherTextBlock;
|
||||
|
||||
blockStartIndex += this.blockSize_;
|
||||
}
|
||||
|
||||
return plainText;
|
||||
};
|
||||
@@ -0,0 +1,18 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<!--
|
||||
Copyright 2012 The Closure Library Authors. All Rights Reserved.
|
||||
|
||||
Use of this source code is governed by the Apache License, Version 2.0.
|
||||
See the COPYING file for details.
|
||||
-->
|
||||
<head>
|
||||
<title>Closure Unit Tests - goog.crypt.Cbc</title>
|
||||
<script src="../base.js"></script>
|
||||
<script>
|
||||
goog.require('goog.crypt.CbcTest');
|
||||
</script>
|
||||
</head>
|
||||
<body>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,100 @@
|
||||
// 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 Unit tests for CBC mode for block ciphers.
|
||||
*
|
||||
* @author nnaze@google.com (Nathan Naze)
|
||||
*/
|
||||
|
||||
/** @suppress {extraProvide} */
|
||||
goog.provide('goog.crypt.CbcTest');
|
||||
|
||||
goog.require('goog.crypt');
|
||||
goog.require('goog.crypt.Aes');
|
||||
goog.require('goog.crypt.Cbc');
|
||||
goog.require('goog.testing.jsunit');
|
||||
|
||||
goog.setTestOnly('goog.crypt.CbcTest');
|
||||
|
||||
function stringToBytes(s) {
|
||||
var bytes = new Array(s.length);
|
||||
for (var i = 0; i < s.length; ++i)
|
||||
bytes[i] = s.charCodeAt(i) & 255;
|
||||
return bytes;
|
||||
}
|
||||
|
||||
function runCbcAesTest(keyBytes, initialVectorBytes, plainTextBytes,
|
||||
cipherTextBytes) {
|
||||
|
||||
var aes = new goog.crypt.Aes(keyBytes);
|
||||
var cbc = new goog.crypt.Cbc(aes);
|
||||
|
||||
var encryptedBytes = cbc.encrypt(plainTextBytes, initialVectorBytes);
|
||||
assertEquals('Encrypted bytes should match cipher text.',
|
||||
goog.crypt.byteArrayToHex(cipherTextBytes),
|
||||
goog.crypt.byteArrayToHex(encryptedBytes));
|
||||
|
||||
var decryptedBytes = cbc.decrypt(cipherTextBytes, initialVectorBytes);
|
||||
assertEquals('Decrypted bytes should match plain text.',
|
||||
goog.crypt.byteArrayToHex(plainTextBytes),
|
||||
goog.crypt.byteArrayToHex(decryptedBytes));
|
||||
}
|
||||
|
||||
function testAesCbcCipherAlgorithm() {
|
||||
// Test values from http://www.ietf.org/rfc/rfc3602.txt
|
||||
|
||||
// Case #1
|
||||
runCbcAesTest(
|
||||
goog.crypt.hexToByteArray('06a9214036b8a15b512e03d534120006'),
|
||||
goog.crypt.hexToByteArray('3dafba429d9eb430b422da802c9fac41'),
|
||||
stringToBytes('Single block msg'),
|
||||
goog.crypt.hexToByteArray('e353779c1079aeb82708942dbe77181a'));
|
||||
|
||||
// Case #2
|
||||
runCbcAesTest(
|
||||
goog.crypt.hexToByteArray('c286696d887c9aa0611bbb3e2025a45a'),
|
||||
goog.crypt.hexToByteArray('562e17996d093d28ddb3ba695a2e6f58'),
|
||||
goog.crypt.hexToByteArray(
|
||||
'000102030405060708090a0b0c0d0e0f' +
|
||||
'101112131415161718191a1b1c1d1e1f'),
|
||||
goog.crypt.hexToByteArray(
|
||||
'd296cd94c2cccf8a3a863028b5e1dc0a' +
|
||||
'7586602d253cfff91b8266bea6d61ab1'));
|
||||
|
||||
// Case #3
|
||||
runCbcAesTest(
|
||||
goog.crypt.hexToByteArray('6c3ea0477630ce21a2ce334aa746c2cd'),
|
||||
goog.crypt.hexToByteArray('c782dc4c098c66cbd9cd27d825682c81'),
|
||||
stringToBytes('This is a 48-byte message (exactly 3 AES blocks)'),
|
||||
goog.crypt.hexToByteArray(
|
||||
'd0a02b3836451753d493665d33f0e886' +
|
||||
'2dea54cdb293abc7506939276772f8d5' +
|
||||
'021c19216bad525c8579695d83ba2684'));
|
||||
|
||||
// Case #4
|
||||
runCbcAesTest(
|
||||
goog.crypt.hexToByteArray('56e47a38c5598974bc46903dba290349'),
|
||||
goog.crypt.hexToByteArray('8ce82eefbea0da3c44699ed7db51b7d9'),
|
||||
goog.crypt.hexToByteArray(
|
||||
'a0a1a2a3a4a5a6a7a8a9aaabacadaeaf' +
|
||||
'b0b1b2b3b4b5b6b7b8b9babbbcbdbebf' +
|
||||
'c0c1c2c3c4c5c6c7c8c9cacbcccdcecf' +
|
||||
'd0d1d2d3d4d5d6d7d8d9dadbdcdddedf'),
|
||||
goog.crypt.hexToByteArray(
|
||||
'c30e32ffedc0774e6aff6af0869f71aa' +
|
||||
'0f3af07a9a31a9c684db207eb0ef8e4e' +
|
||||
'35907aa632c3ffdf868bb7b29d3d46ad' +
|
||||
'83ce9f9a102ee99d49a53e87f4c3da55'));
|
||||
}
|
||||
@@ -0,0 +1,173 @@
|
||||
// Copyright 2008 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 Namespace with crypto related helper functions.
|
||||
*/
|
||||
|
||||
goog.provide('goog.crypt');
|
||||
|
||||
goog.require('goog.array');
|
||||
goog.require('goog.asserts');
|
||||
|
||||
|
||||
/**
|
||||
* Turns a string into an array of bytes; a "byte" being a JS number in the
|
||||
* range 0-255.
|
||||
* @param {string} str String value to arrify.
|
||||
* @return {!Array<number>} Array of numbers corresponding to the
|
||||
* UCS character codes of each character in str.
|
||||
*/
|
||||
goog.crypt.stringToByteArray = function(str) {
|
||||
var output = [], p = 0;
|
||||
for (var i = 0; i < str.length; i++) {
|
||||
var c = str.charCodeAt(i);
|
||||
while (c > 0xff) {
|
||||
output[p++] = c & 0xff;
|
||||
c >>= 8;
|
||||
}
|
||||
output[p++] = c;
|
||||
}
|
||||
return output;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Turns an array of numbers into the string given by the concatenation of the
|
||||
* characters to which the numbers correspond.
|
||||
* @param {Array<number>} bytes Array of numbers representing characters.
|
||||
* @return {string} Stringification of the array.
|
||||
*/
|
||||
goog.crypt.byteArrayToString = function(bytes) {
|
||||
var CHUNK_SIZE = 8192;
|
||||
|
||||
// Special-case the simple case for speed's sake.
|
||||
if (bytes.length < CHUNK_SIZE) {
|
||||
return String.fromCharCode.apply(null, bytes);
|
||||
}
|
||||
|
||||
// The remaining logic splits conversion by chunks since
|
||||
// Function#apply() has a maximum parameter count.
|
||||
// See discussion: http://goo.gl/LrWmZ9
|
||||
|
||||
var str = '';
|
||||
for (var i = 0; i < bytes.length; i += CHUNK_SIZE) {
|
||||
var chunk = goog.array.slice(bytes, i, i + CHUNK_SIZE);
|
||||
str += String.fromCharCode.apply(null, chunk);
|
||||
}
|
||||
return str;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Turns an array of numbers into the hex string given by the concatenation of
|
||||
* the hex values to which the numbers correspond.
|
||||
* @param {Uint8Array|Array<number>} array Array of numbers representing
|
||||
* characters.
|
||||
* @return {string} Hex string.
|
||||
*/
|
||||
goog.crypt.byteArrayToHex = function(array) {
|
||||
return goog.array.map(array, function(numByte) {
|
||||
var hexByte = numByte.toString(16);
|
||||
return hexByte.length > 1 ? hexByte : '0' + hexByte;
|
||||
}).join('');
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Converts a hex string into an integer array.
|
||||
* @param {string} hexString Hex string of 16-bit integers (two characters
|
||||
* per integer).
|
||||
* @return {!Array<number>} Array of {0,255} integers for the given string.
|
||||
*/
|
||||
goog.crypt.hexToByteArray = function(hexString) {
|
||||
goog.asserts.assert(hexString.length % 2 == 0,
|
||||
'Key string length must be multiple of 2');
|
||||
var arr = [];
|
||||
for (var i = 0; i < hexString.length; i += 2) {
|
||||
arr.push(parseInt(hexString.substring(i, i + 2), 16));
|
||||
}
|
||||
return arr;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Converts a JS string to a UTF-8 "byte" array.
|
||||
* @param {string} str 16-bit unicode string.
|
||||
* @return {!Array<number>} UTF-8 byte array.
|
||||
*/
|
||||
goog.crypt.stringToUtf8ByteArray = function(str) {
|
||||
// TODO(user): Use native implementations if/when available
|
||||
str = str.replace(/\r\n/g, '\n');
|
||||
var out = [], p = 0;
|
||||
for (var i = 0; i < str.length; i++) {
|
||||
var c = str.charCodeAt(i);
|
||||
if (c < 128) {
|
||||
out[p++] = c;
|
||||
} else if (c < 2048) {
|
||||
out[p++] = (c >> 6) | 192;
|
||||
out[p++] = (c & 63) | 128;
|
||||
} else {
|
||||
out[p++] = (c >> 12) | 224;
|
||||
out[p++] = ((c >> 6) & 63) | 128;
|
||||
out[p++] = (c & 63) | 128;
|
||||
}
|
||||
}
|
||||
return out;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Converts a UTF-8 byte array to JavaScript's 16-bit Unicode.
|
||||
* @param {Uint8Array|Array<number>} bytes UTF-8 byte array.
|
||||
* @return {string} 16-bit Unicode string.
|
||||
*/
|
||||
goog.crypt.utf8ByteArrayToString = function(bytes) {
|
||||
// TODO(user): Use native implementations if/when available
|
||||
var out = [], pos = 0, c = 0;
|
||||
while (pos < bytes.length) {
|
||||
var c1 = bytes[pos++];
|
||||
if (c1 < 128) {
|
||||
out[c++] = String.fromCharCode(c1);
|
||||
} else if (c1 > 191 && c1 < 224) {
|
||||
var c2 = bytes[pos++];
|
||||
out[c++] = String.fromCharCode((c1 & 31) << 6 | c2 & 63);
|
||||
} else {
|
||||
var c2 = bytes[pos++];
|
||||
var c3 = bytes[pos++];
|
||||
out[c++] = String.fromCharCode(
|
||||
(c1 & 15) << 12 | (c2 & 63) << 6 | c3 & 63);
|
||||
}
|
||||
}
|
||||
return out.join('');
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* XOR two byte arrays.
|
||||
* @param {!ArrayBufferView|!Array<number>} bytes1 Byte array 1.
|
||||
* @param {!ArrayBufferView|!Array<number>} bytes2 Byte array 2.
|
||||
* @return {!Array<number>} Resulting XOR of the two byte arrays.
|
||||
*/
|
||||
goog.crypt.xorByteArray = function(bytes1, bytes2) {
|
||||
goog.asserts.assert(
|
||||
bytes1.length == bytes2.length,
|
||||
'XOR array lengths must match');
|
||||
|
||||
var result = [];
|
||||
for (var i = 0; i < bytes1.length; i++) {
|
||||
result.push(bytes1[i] ^ bytes2[i]);
|
||||
}
|
||||
return result;
|
||||
};
|
||||
@@ -0,0 +1,85 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<!--
|
||||
Copyright 2009 The Closure Library Authors. All Rights Reserved.
|
||||
|
||||
Use of this source code is governed by the Apache License, Version 2.0.
|
||||
See the COPYING file for details.
|
||||
-->
|
||||
<!--
|
||||
-->
|
||||
<head>
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||
<title>Closure Performance Tests - UTF8 encoding and decoding</title>
|
||||
<link rel="stylesheet" type="text/css"
|
||||
href="../testing/performancetable.css"/>
|
||||
<script src="../base.js"></script>
|
||||
<script>
|
||||
goog.require('goog.crypt');
|
||||
goog.require('goog.string');
|
||||
goog.require('goog.testing.PerformanceTable');
|
||||
goog.require('goog.testing.jsunit');
|
||||
</script>
|
||||
</head>
|
||||
<body>
|
||||
<h1>Closure Performance Tests - UTF8 encoding and decoding</h1>
|
||||
<p>
|
||||
<strong>User-agent:</strong>
|
||||
<script>document.write(navigator.userAgent);</script>
|
||||
</p>
|
||||
<div id="perfTable"></div>
|
||||
<hr>
|
||||
|
||||
<script>
|
||||
var table = new goog.testing.PerformanceTable(
|
||||
goog.dom.getElement('perfTable'));
|
||||
|
||||
var STRING_LENGTH = 100000;
|
||||
|
||||
function testDecodeAscii() {
|
||||
var arr = [];
|
||||
for (var i = 0; i < STRING_LENGTH; i++) {
|
||||
arr.push(120);
|
||||
}
|
||||
table.run(goog.partial(goog.crypt.utf8ByteArrayToString, arr),
|
||||
'Decode UTF8 byte array with ASCII characters (1 byte / character)');
|
||||
}
|
||||
|
||||
function testDecodeLatin() {
|
||||
var arr = [];
|
||||
for (var i = 0; i < STRING_LENGTH; i++) {
|
||||
arr.push(195, 182);
|
||||
}
|
||||
table.run(goog.partial(goog.crypt.utf8ByteArrayToString, arr),
|
||||
'Decode UTF8 byte array with Latin characters (2 bytes / character)');
|
||||
}
|
||||
|
||||
function testDecodeLeftArrow() {
|
||||
var arr = [];
|
||||
for (var i = 0; i < STRING_LENGTH; i++) {
|
||||
arr.push(226, 134, 144);
|
||||
}
|
||||
table.run(goog.partial(goog.crypt.utf8ByteArrayToString, arr),
|
||||
'Decode UTF8 byte array with left arrows (3 bytes / character)');
|
||||
}
|
||||
|
||||
function testEncodeAscii() {
|
||||
var str = goog.string.repeat('x', STRING_LENGTH);
|
||||
table.run(goog.partial(goog.crypt.stringToUtf8ByteArray, str),
|
||||
'Encode ASCII string (1 byte / character)');
|
||||
}
|
||||
|
||||
function testEncodeLatin() {
|
||||
var str = goog.string.repeat('\u00F6', STRING_LENGTH);
|
||||
table.run(goog.partial(goog.crypt.stringToUtf8ByteArray, str),
|
||||
'Encode Latin string (2 bytes / character)');
|
||||
}
|
||||
|
||||
function testEncodeLeftArrow() {
|
||||
var str = goog.string.repeat('\u2190', STRING_LENGTH);
|
||||
table.run(goog.partial(goog.crypt.stringToUtf8ByteArray, str),
|
||||
'Encode left arrows (3 bytes / character)');
|
||||
}
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,22 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<!--
|
||||
Copyright 2008 The Closure Library Authors. All Rights Reserved.
|
||||
|
||||
Use of this source code is governed by the Apache License, Version 2.0.
|
||||
See the COPYING file for details.
|
||||
-->
|
||||
<head>
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
|
||||
<title>
|
||||
Closure Unit Tests - goog.crypt
|
||||
</title>
|
||||
<script src="../base.js">
|
||||
</script>
|
||||
<script>
|
||||
goog.require('goog.cryptTest');
|
||||
</script>
|
||||
</head>
|
||||
<body>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,169 @@
|
||||
// Copyright 2008 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.
|
||||
|
||||
goog.provide('goog.cryptTest');
|
||||
goog.setTestOnly('goog.cryptTest');
|
||||
|
||||
goog.require('goog.crypt');
|
||||
goog.require('goog.string');
|
||||
goog.require('goog.testing.jsunit');
|
||||
|
||||
var UTF8_RANGES_BYTE_ARRAY = [
|
||||
0x00,
|
||||
0x7F,
|
||||
0xC2, 0x80,
|
||||
0xDF, 0xBF,
|
||||
0xE0, 0xA0, 0x80,
|
||||
0xEF, 0xBF, 0xBF];
|
||||
|
||||
var UTF8_RANGES_STRING = '\u0000\u007F\u0080\u07FF\u0800\uFFFF';
|
||||
|
||||
function testStringToUtf8ByteArray() {
|
||||
// Known encodings taken from Java's String.getBytes("UTF8")
|
||||
|
||||
assertArrayEquals('ASCII',
|
||||
[72, 101, 108, 108, 111, 44, 32, 119, 111, 114, 108, 100],
|
||||
goog.crypt.stringToUtf8ByteArray('Hello, world'));
|
||||
|
||||
assertArrayEquals('Latin',
|
||||
[83, 99, 104, 195, 182, 110],
|
||||
goog.crypt.stringToUtf8ByteArray('Sch\u00f6n'));
|
||||
|
||||
assertArrayEquals('limits of the first 3 UTF-8 character ranges',
|
||||
UTF8_RANGES_BYTE_ARRAY,
|
||||
goog.crypt.stringToUtf8ByteArray(UTF8_RANGES_STRING));
|
||||
}
|
||||
|
||||
function testUtf8ByteArrayToString() {
|
||||
// Known encodings taken from Java's String.getBytes("UTF8")
|
||||
|
||||
assertEquals('ASCII', 'Hello, world', goog.crypt.utf8ByteArrayToString(
|
||||
[72, 101, 108, 108, 111, 44, 32, 119, 111, 114, 108, 100]));
|
||||
|
||||
assertEquals('Latin', 'Sch\u00f6n', goog.crypt.utf8ByteArrayToString(
|
||||
[83, 99, 104, 195, 182, 110]));
|
||||
|
||||
assertEquals('limits of the first 3 UTF-8 character ranges',
|
||||
UTF8_RANGES_STRING,
|
||||
goog.crypt.utf8ByteArrayToString(UTF8_RANGES_BYTE_ARRAY));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Same as testUtf8ByteArrayToString but with Uint8Array instead of
|
||||
* Array<number>.
|
||||
*/
|
||||
function testUint8ArrayToString() {
|
||||
if (!goog.global.Uint8Array) {
|
||||
// Uint8Array not supported.
|
||||
return;
|
||||
}
|
||||
|
||||
var arr = new Uint8Array(
|
||||
[72, 101, 108, 108, 111, 44, 32, 119, 111, 114, 108, 100]);
|
||||
assertEquals('ASCII', 'Hello, world', goog.crypt.utf8ByteArrayToString(arr));
|
||||
|
||||
arr = new Uint8Array([83, 99, 104, 195, 182, 110]);
|
||||
assertEquals('Latin', 'Sch\u00f6n', goog.crypt.utf8ByteArrayToString(arr));
|
||||
|
||||
arr = new Uint8Array(UTF8_RANGES_BYTE_ARRAY);
|
||||
assertEquals('limits of the first 3 UTF-8 character ranges',
|
||||
UTF8_RANGES_STRING,
|
||||
goog.crypt.utf8ByteArrayToString(arr));
|
||||
}
|
||||
|
||||
function testByteArrayToString() {
|
||||
assertEquals('', goog.crypt.byteArrayToString([]));
|
||||
assertEquals('abc', goog.crypt.byteArrayToString([97, 98, 99]));
|
||||
}
|
||||
|
||||
function testHexToByteArray() {
|
||||
assertElementsEquals(
|
||||
[202, 254, 222, 173],
|
||||
// Java magic number
|
||||
goog.crypt.hexToByteArray('cafedead'));
|
||||
|
||||
assertElementsEquals(
|
||||
[222, 173, 190, 239],
|
||||
// IBM magic number
|
||||
goog.crypt.hexToByteArray('DEADBEEF'));
|
||||
}
|
||||
|
||||
function testByteArrayToHex() {
|
||||
assertEquals(
|
||||
// Java magic number
|
||||
'cafedead',
|
||||
goog.crypt.byteArrayToHex([202, 254, 222, 173]));
|
||||
|
||||
assertEquals(
|
||||
// IBM magic number
|
||||
'deadbeef',
|
||||
goog.crypt.byteArrayToHex([222, 173, 190, 239]));
|
||||
}
|
||||
|
||||
|
||||
/** Same as testByteArrayToHex but with Uint8Array instead of Array<number>. */
|
||||
function testUint8ArrayToHex() {
|
||||
if (!goog.isDef(goog.global.Uint8Array)) {
|
||||
// Uint8Array not supported.
|
||||
return;
|
||||
}
|
||||
|
||||
assertEquals(
|
||||
// Java magic number
|
||||
'cafedead',
|
||||
goog.crypt.byteArrayToHex(new Uint8Array([202, 254, 222, 173])));
|
||||
|
||||
assertEquals(
|
||||
// IBM magic number
|
||||
'deadbeef',
|
||||
goog.crypt.byteArrayToHex(new Uint8Array([222, 173, 190, 239])));
|
||||
}
|
||||
|
||||
function testXorByteArray() {
|
||||
assertElementsEquals(
|
||||
[20, 83, 96, 66],
|
||||
goog.crypt.xorByteArray([202, 254, 222, 173], [222, 173, 190, 239]));
|
||||
}
|
||||
|
||||
|
||||
/** Same as testXorByteArray but with Uint8Array instead of Array<number>. */
|
||||
function testXorUint8Array() {
|
||||
if (!goog.isDef(goog.global.Uint8Array)) {
|
||||
// Uint8Array not supported.
|
||||
return;
|
||||
}
|
||||
|
||||
assertElementsEquals(
|
||||
[20, 83, 96, 66],
|
||||
goog.crypt.xorByteArray(
|
||||
new Uint8Array([202, 254, 222, 173]),
|
||||
new Uint8Array([222, 173, 190, 239])));
|
||||
}
|
||||
|
||||
|
||||
// Tests a one-megabyte byte array conversion to string.
|
||||
// This would break on many JS implementations unless byteArrayToString
|
||||
// split the input up.
|
||||
// See discussion and bug report: http://goo.gl/LrWmZ9
|
||||
function testByteArrayToStringCallStack() {
|
||||
// One megabyte is 2 to the 20th.
|
||||
var count = Math.pow(2, 20);
|
||||
var bytes = [];
|
||||
for (var i = 0; i < count; i++) {
|
||||
bytes.push('A'.charCodeAt(0));
|
||||
}
|
||||
var str = goog.crypt.byteArrayToString(bytes);
|
||||
assertEquals(goog.string.repeat('A', count), str);
|
||||
}
|
||||
@@ -0,0 +1,69 @@
|
||||
// Copyright 2011 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 Abstract cryptographic hash interface.
|
||||
*
|
||||
* See goog.crypt.Sha1 and goog.crypt.Md5 for sample implementations.
|
||||
*
|
||||
*/
|
||||
|
||||
goog.provide('goog.crypt.Hash');
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Create a cryptographic hash instance.
|
||||
*
|
||||
* @constructor
|
||||
* @struct
|
||||
*/
|
||||
goog.crypt.Hash = function() {
|
||||
/**
|
||||
* The block size for the hasher.
|
||||
* @type {number}
|
||||
*/
|
||||
this.blockSize = -1;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Resets the internal accumulator.
|
||||
*/
|
||||
goog.crypt.Hash.prototype.reset = goog.abstractMethod;
|
||||
|
||||
|
||||
/**
|
||||
* Adds a byte array (array with values in [0-255] range) or a string (might
|
||||
* only contain 8-bit, i.e., Latin1 characters) to the internal accumulator.
|
||||
*
|
||||
* Many hash functions operate on blocks of data and implement optimizations
|
||||
* when a full chunk of data is readily available. Hence it is often preferable
|
||||
* to provide large chunks of data (a kilobyte or more) than to repeatedly
|
||||
* call the update method with few tens of bytes. If this is not possible, or
|
||||
* not feasible, it might be good to provide data in multiplies of hash block
|
||||
* size (often 64 bytes). Please see the implementation and performance tests
|
||||
* of your favourite hash.
|
||||
*
|
||||
* @param {Array<number>|Uint8Array|string} bytes Data used for the update.
|
||||
* @param {number=} opt_length Number of bytes to use.
|
||||
*/
|
||||
goog.crypt.Hash.prototype.update = goog.abstractMethod;
|
||||
|
||||
|
||||
/**
|
||||
* @return {!Array<number>} The finalized hash computed
|
||||
* from the internal accumulator.
|
||||
*/
|
||||
goog.crypt.Hash.prototype.digest = goog.abstractMethod;
|
||||
@@ -0,0 +1,184 @@
|
||||
// Copyright 2008 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 32-bit hashing functions.
|
||||
*
|
||||
* This is a direct port from the Google Java Hash class
|
||||
*
|
||||
*/
|
||||
|
||||
goog.provide('goog.crypt.hash32');
|
||||
|
||||
goog.require('goog.crypt');
|
||||
|
||||
|
||||
/**
|
||||
* Default seed used during hashing, digits of pie.
|
||||
* See SEED32 in http://go/base.hash.java
|
||||
* @type {number}
|
||||
*/
|
||||
goog.crypt.hash32.SEED32 = 314159265;
|
||||
|
||||
|
||||
/**
|
||||
* Arbitrary constant used during hashing.
|
||||
* See CONSTANT32 in http://go/base.hash.java
|
||||
* @type {number}
|
||||
*/
|
||||
goog.crypt.hash32.CONSTANT32 = -1640531527;
|
||||
|
||||
|
||||
/**
|
||||
* Hashes a string to a 32-bit value.
|
||||
* @param {string} str String to hash.
|
||||
* @return {number} 32-bit hash.
|
||||
*/
|
||||
goog.crypt.hash32.encodeString = function(str) {
|
||||
return goog.crypt.hash32.encodeByteArray(goog.crypt.stringToByteArray(str));
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Hashes a string to a 32-bit value, converting the string to UTF-8 before
|
||||
* doing the encoding.
|
||||
* @param {string} str String to hash.
|
||||
* @return {number} 32-bit hash.
|
||||
*/
|
||||
goog.crypt.hash32.encodeStringUtf8 = function(str) {
|
||||
return goog.crypt.hash32.encodeByteArray(
|
||||
goog.crypt.stringToUtf8ByteArray(str));
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Hashes an integer to a 32-bit value.
|
||||
* @param {number} value Number to hash.
|
||||
* @return {number} 32-bit hash.
|
||||
*/
|
||||
goog.crypt.hash32.encodeInteger = function(value) {
|
||||
// TODO(user): Does this make sense in JavaScript with doubles? Should we
|
||||
// force the value to be in the correct range?
|
||||
return goog.crypt.hash32.mix32_({
|
||||
a: value,
|
||||
b: goog.crypt.hash32.CONSTANT32,
|
||||
c: goog.crypt.hash32.SEED32
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Hashes a "byte" array to a 32-bit value using the supplied seed.
|
||||
* @param {Array<number>} bytes Array of bytes.
|
||||
* @param {number=} opt_offset The starting position to use for hash
|
||||
* computation.
|
||||
* @param {number=} opt_length Number of bytes that are used for hashing.
|
||||
* @param {number=} opt_seed The seed.
|
||||
* @return {number} 32-bit hash.
|
||||
*/
|
||||
goog.crypt.hash32.encodeByteArray = function(
|
||||
bytes, opt_offset, opt_length, opt_seed) {
|
||||
var offset = opt_offset || 0;
|
||||
var length = opt_length || bytes.length;
|
||||
var seed = opt_seed || goog.crypt.hash32.SEED32;
|
||||
|
||||
var mix = {
|
||||
a: goog.crypt.hash32.CONSTANT32,
|
||||
b: goog.crypt.hash32.CONSTANT32,
|
||||
c: seed
|
||||
};
|
||||
|
||||
var keylen;
|
||||
for (keylen = length; keylen >= 12; keylen -= 12, offset += 12) {
|
||||
mix.a += goog.crypt.hash32.wordAt_(bytes, offset);
|
||||
mix.b += goog.crypt.hash32.wordAt_(bytes, offset + 4);
|
||||
mix.c += goog.crypt.hash32.wordAt_(bytes, offset + 8);
|
||||
goog.crypt.hash32.mix32_(mix);
|
||||
}
|
||||
// Hash any remaining bytes
|
||||
mix.c += length;
|
||||
switch (keylen) { // deal with rest. Some cases fall through
|
||||
case 11: mix.c += (bytes[offset + 10]) << 24;
|
||||
case 10: mix.c += (bytes[offset + 9] & 0xff) << 16;
|
||||
case 9 : mix.c += (bytes[offset + 8] & 0xff) << 8;
|
||||
// the first byte of c is reserved for the length
|
||||
case 8 :
|
||||
mix.b += goog.crypt.hash32.wordAt_(bytes, offset + 4);
|
||||
mix.a += goog.crypt.hash32.wordAt_(bytes, offset);
|
||||
break;
|
||||
case 7 : mix.b += (bytes[offset + 6] & 0xff) << 16;
|
||||
case 6 : mix.b += (bytes[offset + 5] & 0xff) << 8;
|
||||
case 5 : mix.b += (bytes[offset + 4] & 0xff);
|
||||
case 4 :
|
||||
mix.a += goog.crypt.hash32.wordAt_(bytes, offset);
|
||||
break;
|
||||
case 3 : mix.a += (bytes[offset + 2] & 0xff) << 16;
|
||||
case 2 : mix.a += (bytes[offset + 1] & 0xff) << 8;
|
||||
case 1 : mix.a += (bytes[offset + 0] & 0xff);
|
||||
// case 0 : nothing left to add
|
||||
}
|
||||
return goog.crypt.hash32.mix32_(mix);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Performs an inplace mix of an object with the integer properties (a, b, c)
|
||||
* and returns the final value of c.
|
||||
* @param {Object} mix Object with properties, a, b, and c.
|
||||
* @return {number} The end c-value for the mixing.
|
||||
* @private
|
||||
*/
|
||||
goog.crypt.hash32.mix32_ = function(mix) {
|
||||
var a = mix.a, b = mix.b, c = mix.c;
|
||||
a -= b; a -= c; a ^= c >>> 13;
|
||||
b -= c; b -= a; b ^= a << 8;
|
||||
c -= a; c -= b; c ^= b >>> 13;
|
||||
a -= b; a -= c; a ^= c >>> 12;
|
||||
b -= c; b -= a; b ^= a << 16;
|
||||
c -= a; c -= b; c ^= b >>> 5;
|
||||
a -= b; a -= c; a ^= c >>> 3;
|
||||
b -= c; b -= a; b ^= a << 10;
|
||||
c -= a; c -= b; c ^= b >>> 15;
|
||||
mix.a = a; mix.b = b; mix.c = c;
|
||||
return c;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Returns the word at a given offset. Treating an array of bytes a word at a
|
||||
* time is far more efficient than byte-by-byte.
|
||||
* @param {Array<number>} bytes Array of bytes.
|
||||
* @param {number} offset Offset in the byte array.
|
||||
* @return {number} Integer value for the word.
|
||||
* @private
|
||||
*/
|
||||
goog.crypt.hash32.wordAt_ = function(bytes, offset) {
|
||||
var a = goog.crypt.hash32.toSigned_(bytes[offset + 0]);
|
||||
var b = goog.crypt.hash32.toSigned_(bytes[offset + 1]);
|
||||
var c = goog.crypt.hash32.toSigned_(bytes[offset + 2]);
|
||||
var d = goog.crypt.hash32.toSigned_(bytes[offset + 3]);
|
||||
return a + (b << 8) + (c << 16) + (d << 24);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Converts an unsigned "byte" to signed, that is, convert a value in the range
|
||||
* (0, 2^8-1) to (-2^7, 2^7-1) in order to be compatible with Java's byte type.
|
||||
* @param {number} n Unsigned "byte" value.
|
||||
* @return {number} Signed "byte" value.
|
||||
* @private
|
||||
*/
|
||||
goog.crypt.hash32.toSigned_ = function(n) {
|
||||
return n > 127 ? n - 256 : n;
|
||||
};
|
||||
@@ -0,0 +1,22 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<!--
|
||||
Copyright 2008 The Closure Library Authors. All Rights Reserved.
|
||||
|
||||
Use of this source code is governed by the Apache License, Version 2.0.
|
||||
See the COPYING file for details.
|
||||
-->
|
||||
<head>
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
|
||||
<title>
|
||||
Closure Unit Tests - goog.crypt.hash32
|
||||
</title>
|
||||
<script src="../base.js">
|
||||
</script>
|
||||
<script>
|
||||
goog.require('goog.crypt.hash32Test');
|
||||
</script>
|
||||
</head>
|
||||
<body>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,284 @@
|
||||
// Copyright 2008 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.
|
||||
|
||||
goog.provide('goog.crypt.hash32Test');
|
||||
goog.setTestOnly('goog.crypt.hash32Test');
|
||||
|
||||
goog.require('goog.crypt.hash32');
|
||||
goog.require('goog.testing.TestCase');
|
||||
goog.require('goog.testing.jsunit');
|
||||
|
||||
// NOTE: This test uses a custom test case, see end of script block
|
||||
|
||||
// Test data based on known input/output pairs generated using
|
||||
// http://go/hash.java
|
||||
|
||||
function testEncodeInteger() {
|
||||
assertEquals(898813988, goog.crypt.hash32.encodeInteger(305419896));
|
||||
}
|
||||
|
||||
function testEncodeByteArray() {
|
||||
assertEquals(-1497024495,
|
||||
goog.crypt.hash32.encodeByteArray([10, 20, 30, 40]));
|
||||
assertEquals(-961586214,
|
||||
goog.crypt.hash32.encodeByteArray([3, 1, 4, 1, 5, 9]));
|
||||
assertEquals(-1482202299,
|
||||
goog.crypt.hash32.encodeByteArray([127, 0, 0, 0, 123, 45]));
|
||||
assertEquals(170907881,
|
||||
goog.crypt.hash32.encodeByteArray([9, 1, 1]));
|
||||
}
|
||||
|
||||
function testKnownByteArrays() {
|
||||
for (var i = 0; i < byteArrays.length; i++) {
|
||||
assertEquals(byteArrays[i],
|
||||
goog.crypt.hash32.encodeByteArray(createByteArray(i)));
|
||||
}
|
||||
}
|
||||
|
||||
function testEncodeString() {
|
||||
assertEquals(-937588052, goog.crypt.hash32.encodeString('Hello, world'));
|
||||
assertEquals(62382810, goog.crypt.hash32.encodeString('Sch\xF6n'));
|
||||
}
|
||||
|
||||
function testEncodeStringUtf8() {
|
||||
assertEquals(-937588052,
|
||||
goog.crypt.hash32.encodeStringUtf8('Hello, world'));
|
||||
assertEquals(-833263351, goog.crypt.hash32.encodeStringUtf8('Sch\xF6n'));
|
||||
|
||||
assertEquals(-1771620293, goog.crypt.hash32.encodeStringUtf8(
|
||||
'\u043A\u0440'));
|
||||
}
|
||||
|
||||
function testEncodeString_ascii() {
|
||||
assertEquals('For ascii characters UTF8 should be the same',
|
||||
goog.crypt.hash32.encodeStringUtf8('abc123'),
|
||||
goog.crypt.hash32.encodeString('abc123'));
|
||||
|
||||
assertEquals('For ascii characters UTF8 should be the same',
|
||||
goog.crypt.hash32.encodeStringUtf8('The,quick.brown-fox'),
|
||||
goog.crypt.hash32.encodeString('The,quick.brown-fox'));
|
||||
|
||||
assertNotEquals('For non-ascii characters UTF-8 encoding is different',
|
||||
goog.crypt.hash32.encodeStringUtf8('Sch\xF6n'),
|
||||
goog.crypt.hash32.encodeString('Sch\xF6n'));
|
||||
}
|
||||
|
||||
function testEncodeString_poe() {
|
||||
var poe = "Once upon a midnight dreary, while I pondered weak and weary," +
|
||||
"Over many a quaint and curious volume of forgotten lore," +
|
||||
"While I nodded, nearly napping, suddenly there came a tapping," +
|
||||
"As of some one gently rapping, rapping at my chamber door." +
|
||||
"`'Tis some visitor,' I muttered, `tapping at my chamber door -" +
|
||||
"Only this, and nothing more.'" +
|
||||
"Ah, distinctly I remember it was in the bleak December," +
|
||||
"And each separate dying ember wrought its ghost upon the floor." +
|
||||
"Eagerly I wished the morrow; - vainly I had sought to borrow" +
|
||||
"From my books surcease of sorrow - sorrow for the lost Lenore -" +
|
||||
"For the rare and radiant maiden whom the angels named Lenore -" +
|
||||
"Nameless here for evermore." +
|
||||
"And the silken sad uncertain rustling of each purple curtain" +
|
||||
"Thrilled me - filled me with fantastic terrors never felt before;" +
|
||||
"So that now, to still the beating of my heart, I stood repeating" +
|
||||
"`'Tis some visitor entreating entrance at my chamber door -" +
|
||||
"Some late visitor entreating entrance at my chamber door; -" +
|
||||
"This it is, and nothing more,'" +
|
||||
"Presently my soul grew stronger; hesitating then no longer," +
|
||||
"`Sir,' said I, `or Madam, truly your forgiveness I implore;" +
|
||||
"But the fact is I was napping, and so gently you came rapping," +
|
||||
"And so faintly you came tapping, tapping at my chamber door," +
|
||||
"That I scarce was sure I heard you' - here I opened wide the door; -" +
|
||||
"Darkness there, and nothing more." +
|
||||
"Deep into that darkness peering, long I stood there wondering, " +
|
||||
"fearing," +
|
||||
"Doubting, dreaming dreams no mortal ever dared to dream before" +
|
||||
"But the silence was unbroken, and the darkness gave no token," +
|
||||
"And the only word there spoken was the whispered word, `Lenore!'" +
|
||||
"This I whispered, and an echo murmured back the word, `Lenore!'" +
|
||||
"Merely this and nothing more." +
|
||||
"Back into the chamber turning, all my soul within me burning," +
|
||||
"Soon again I heard a tapping somewhat louder than before." +
|
||||
"`Surely,\' said I, `surely that is something at my window lattice;" +
|
||||
"Let me see then, what thereat is, and this mystery explore -" +
|
||||
"Let my heart be still a moment and this mystery explore; -" +
|
||||
"'Tis the wind and nothing more!'";
|
||||
|
||||
assertEquals(147608747, goog.crypt.hash32.encodeString(poe));
|
||||
assertEquals(147608747, goog.crypt.hash32.encodeStringUtf8(poe));
|
||||
}
|
||||
|
||||
function testBenchmarking() {
|
||||
if (!testCase) return;
|
||||
// Not a real test, just outputs some timing
|
||||
function makeString(n) {
|
||||
var str = [];
|
||||
for (var i = 0; i < n; i++) {
|
||||
str.push(String.fromCharCode(Math.round(Math.random() * 500)));
|
||||
}
|
||||
return str.join('');
|
||||
}
|
||||
for (var i = 0; i < 50000; i += 10000) {
|
||||
var str = makeString(i);
|
||||
var start = goog.now();
|
||||
var hash = goog.crypt.hash32.encodeString(str);
|
||||
var diff = goog.now() - start;
|
||||
testCase.saveMessage(
|
||||
'testBenchmarking : hashing ' + i + ' chars in ' + diff + 'ms');
|
||||
}
|
||||
}
|
||||
|
||||
function createByteArray(n) {
|
||||
var arr = [];
|
||||
for (var i = 0; i < n; i++) {
|
||||
arr.push(i);
|
||||
}
|
||||
return arr;
|
||||
}
|
||||
|
||||
var byteArrays = {
|
||||
0: 1539411136,
|
||||
1: 1773524747,
|
||||
2: -254958930,
|
||||
3: 1532114172,
|
||||
4: 1923165449,
|
||||
5: 1611874589,
|
||||
6: 1502126780,
|
||||
7: -751745251,
|
||||
8: -292491321,
|
||||
9: 1106193218,
|
||||
10: -722791438,
|
||||
11: -2130666060,
|
||||
12: -259304553,
|
||||
13: 871461192,
|
||||
14: 865773084,
|
||||
15: 1615738330,
|
||||
16: -1836636447,
|
||||
17: -485722519,
|
||||
18: -120832227,
|
||||
19: 1954449704,
|
||||
20: 491312921,
|
||||
21: -1955462668,
|
||||
22: 168565425,
|
||||
23: -105893922,
|
||||
24: 620486614,
|
||||
25: -1789602428,
|
||||
26: 1765793554,
|
||||
27: 1723370948,
|
||||
28: -1275405721,
|
||||
29: 140421019,
|
||||
30: -1438726307,
|
||||
31: 538438903,
|
||||
32: -729123980,
|
||||
33: 1213490939,
|
||||
34: -1814248478,
|
||||
35: 1943703398,
|
||||
36: 1603073219,
|
||||
37: -2139639543,
|
||||
38: -694153941,
|
||||
39: 137511516,
|
||||
40: -249943726,
|
||||
41: -1166126060,
|
||||
42: 53464833,
|
||||
43: -915350862,
|
||||
44: 1306585409,
|
||||
45: 1064798289,
|
||||
46: 335555913,
|
||||
47: 224485496,
|
||||
48: 275599760,
|
||||
49: 409559869,
|
||||
50: 673770580,
|
||||
51: -2113819879,
|
||||
52: -791338727,
|
||||
53: -1716479479,
|
||||
54: 1795018816,
|
||||
55: 2020139343,
|
||||
56: -1652827750,
|
||||
57: -1509632558,
|
||||
58: 751641995,
|
||||
59: -217881377,
|
||||
60: -476546900,
|
||||
61: -1893349644,
|
||||
62: -729290332,
|
||||
63: 1359899321,
|
||||
64: 1811814306,
|
||||
65: 2100363086,
|
||||
66: -794920327,
|
||||
67: -1667555017,
|
||||
68: -549980099,
|
||||
69: -21170740,
|
||||
70: -1324143722,
|
||||
71: 1406730195,
|
||||
72: 2111381574,
|
||||
73: -1667480052,
|
||||
74: 1071811178,
|
||||
75: -1080194099,
|
||||
76: -181186882,
|
||||
77: 268677507,
|
||||
78: -546766334,
|
||||
79: 555953522,
|
||||
80: -981311675,
|
||||
81: 1988867392,
|
||||
82: 773172547,
|
||||
83: 1160806722,
|
||||
84: -1455460187,
|
||||
85: 83493600,
|
||||
86: 155365142,
|
||||
87: 1714618071,
|
||||
88: 1487712615,
|
||||
89: -810670278,
|
||||
90: 2031655097,
|
||||
91: 1286349470,
|
||||
92: -1873594211,
|
||||
93: 1875867480,
|
||||
94: -1096259787,
|
||||
95: -1054968610,
|
||||
96: -1723043458,
|
||||
97: 1278708307,
|
||||
98: -601104085,
|
||||
99: 1497928579,
|
||||
100: 1329732615,
|
||||
101: -1281696190,
|
||||
102: 1471511953,
|
||||
103: -62666299,
|
||||
104: 807569747,
|
||||
105: -1927974759,
|
||||
106: 1462243717,
|
||||
107: -862975602,
|
||||
108: 824369927,
|
||||
109: -1448816781,
|
||||
110: 1434162022,
|
||||
111: -881501413,
|
||||
112: -1554381107,
|
||||
113: -1730883204,
|
||||
114: 431236217,
|
||||
115: 1877278608,
|
||||
116: -673864625,
|
||||
117: 143000665,
|
||||
118: -596902829,
|
||||
119: 1038860559,
|
||||
120: 805884326,
|
||||
121: -1536181710,
|
||||
122: -1357373256,
|
||||
123: 1405134250,
|
||||
124: -860816481,
|
||||
125: 1393578269,
|
||||
126: -810682545,
|
||||
127: -635515639
|
||||
};
|
||||
|
||||
var testCase;
|
||||
if (G_testRunner) {
|
||||
testCase = new goog.testing.TestCase(document.title);
|
||||
testCase.autoDiscoverTests();
|
||||
G_testRunner.initialize(testCase);
|
||||
}
|
||||
@@ -0,0 +1,244 @@
|
||||
// Copyright 2011 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 Unit tests for the abstract cryptographic hash interface.
|
||||
*
|
||||
*/
|
||||
|
||||
goog.provide('goog.crypt.hashTester');
|
||||
|
||||
goog.require('goog.array');
|
||||
goog.require('goog.crypt');
|
||||
goog.require('goog.dom');
|
||||
goog.require('goog.testing.PerformanceTable');
|
||||
goog.require('goog.testing.PseudoRandom');
|
||||
goog.require('goog.testing.asserts');
|
||||
goog.setTestOnly('hashTester');
|
||||
|
||||
|
||||
/**
|
||||
* Runs basic tests.
|
||||
*
|
||||
* @param {!goog.crypt.Hash} hash A hash instance.
|
||||
*/
|
||||
goog.crypt.hashTester.runBasicTests = function(hash) {
|
||||
// Compute first hash.
|
||||
hash.update([97, 158]);
|
||||
var golden1 = hash.digest();
|
||||
|
||||
// Compute second hash.
|
||||
hash.reset();
|
||||
hash.update('aB');
|
||||
var golden2 = hash.digest();
|
||||
assertTrue('Two different inputs resulted in a hash collision',
|
||||
!!goog.testing.asserts.findDifferences(golden1, golden2));
|
||||
|
||||
// Empty hash.
|
||||
hash.reset();
|
||||
var empty = hash.digest();
|
||||
assertTrue('Empty hash collided with a non-trivial one',
|
||||
!!goog.testing.asserts.findDifferences(golden1, empty) &&
|
||||
!!goog.testing.asserts.findDifferences(golden2, empty));
|
||||
|
||||
// Zero-length array update.
|
||||
hash.reset();
|
||||
hash.update([]);
|
||||
assertArrayEquals('Updating with an empty array did not give an empty hash',
|
||||
empty, hash.digest());
|
||||
|
||||
// Zero-length string update.
|
||||
hash.reset();
|
||||
hash.update('');
|
||||
assertArrayEquals('Updating with an empty string did not give an empty hash',
|
||||
empty, hash.digest());
|
||||
|
||||
// Recompute the first hash.
|
||||
hash.reset();
|
||||
hash.update([97, 158]);
|
||||
assertArrayEquals('The reset did not produce the initial state',
|
||||
golden1, hash.digest());
|
||||
|
||||
// Check for a trivial collision.
|
||||
hash.reset();
|
||||
hash.update([158, 97]);
|
||||
assertTrue('Swapping bytes resulted in a hash collision',
|
||||
!!goog.testing.asserts.findDifferences(golden1, hash.digest()));
|
||||
|
||||
// Compare array and string input.
|
||||
hash.reset();
|
||||
hash.update([97, 66]);
|
||||
assertArrayEquals('String and array inputs should give the same result',
|
||||
golden2, hash.digest());
|
||||
|
||||
// Compute in parts.
|
||||
hash.reset();
|
||||
hash.update('a');
|
||||
hash.update([158]);
|
||||
assertArrayEquals('Partial updates resulted in a different hash',
|
||||
golden1, hash.digest());
|
||||
|
||||
// Test update with specified length.
|
||||
hash.reset();
|
||||
hash.update('aB', 0);
|
||||
hash.update([97, 158, 32], 2);
|
||||
assertArrayEquals('Updating with an explicit buffer length did not work',
|
||||
golden1, hash.digest());
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Runs block tests.
|
||||
*
|
||||
* @param {!goog.crypt.Hash} hash A hash instance.
|
||||
* @param {number} blockBytes Size of the hash block.
|
||||
*/
|
||||
goog.crypt.hashTester.runBlockTests = function(hash, blockBytes) {
|
||||
// Compute a message which is 1 byte shorter than hash block size.
|
||||
var chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
|
||||
var message = '';
|
||||
for (var i = 0; i < blockBytes - 1; i++) {
|
||||
message += chars.charAt(i % chars.length);
|
||||
}
|
||||
|
||||
// Compute golden hash for 1 block + 2 bytes.
|
||||
hash.update(message + '123');
|
||||
var golden1 = hash.digest();
|
||||
|
||||
// Compute golden hash for 2 blocks + 1 byte.
|
||||
hash.reset();
|
||||
hash.update(message + message + '123');
|
||||
var golden2 = hash.digest();
|
||||
|
||||
// Almost fill a block, then overflow.
|
||||
hash.reset();
|
||||
hash.update(message);
|
||||
hash.update('123');
|
||||
assertArrayEquals(golden1, hash.digest());
|
||||
|
||||
// Fill a block.
|
||||
hash.reset();
|
||||
hash.update(message + '1');
|
||||
hash.update('23');
|
||||
assertArrayEquals(golden1, hash.digest());
|
||||
|
||||
// Overflow a block.
|
||||
hash.reset();
|
||||
hash.update(message + '12');
|
||||
hash.update('3');
|
||||
assertArrayEquals(golden1, hash.digest());
|
||||
|
||||
// Test single overflow with an array.
|
||||
hash.reset();
|
||||
hash.update(goog.crypt.stringToByteArray(message + '123'));
|
||||
assertArrayEquals(golden1, hash.digest());
|
||||
|
||||
// Almost fill a block, then overflow this and the next block.
|
||||
hash.reset();
|
||||
hash.update(message);
|
||||
hash.update(message + '123');
|
||||
assertArrayEquals(golden2, hash.digest());
|
||||
|
||||
// Fill two blocks.
|
||||
hash.reset();
|
||||
hash.update(message + message + '12');
|
||||
hash.update('3');
|
||||
assertArrayEquals(golden2, hash.digest());
|
||||
|
||||
// Test double overflow with an array.
|
||||
hash.reset();
|
||||
hash.update(goog.crypt.stringToByteArray(message));
|
||||
hash.update(goog.crypt.stringToByteArray(message + '123'));
|
||||
assertArrayEquals(golden2, hash.digest());
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Runs performance tests.
|
||||
*
|
||||
* @param {function():!goog.crypt.Hash} hashFactory A hash factory.
|
||||
* @param {string} hashName Name of the hashing function.
|
||||
*/
|
||||
goog.crypt.hashTester.runPerfTests = function(hashFactory, hashName) {
|
||||
var body = goog.dom.getDocument().body;
|
||||
var perfTable = goog.dom.createElement('div');
|
||||
goog.dom.appendChild(body, perfTable);
|
||||
|
||||
var table = new goog.testing.PerformanceTable(perfTable);
|
||||
|
||||
function runPerfTest(byteLength, updateCount) {
|
||||
var label = (hashName + ': ' + updateCount + ' update(s) of ' + byteLength +
|
||||
' bytes');
|
||||
|
||||
function run(data, dataType) {
|
||||
table.run(function() {
|
||||
var hash = hashFactory();
|
||||
for (var i = 0; i < updateCount; i++) {
|
||||
hash.update(data, byteLength);
|
||||
}
|
||||
var digest = hash.digest();
|
||||
}, label + ' (' + dataType + ')');
|
||||
}
|
||||
|
||||
var byteArray = goog.crypt.hashTester.createRandomByteArray_(byteLength);
|
||||
var byteString = goog.crypt.hashTester.createByteString_(byteArray);
|
||||
|
||||
run(byteArray, 'byte array');
|
||||
run(byteString, 'byte string');
|
||||
}
|
||||
|
||||
var MESSAGE_LENGTH_LONG = 10000000; // 10 Mbytes
|
||||
var MESSAGE_LENGTH_SHORT = 10; // 10 bytes
|
||||
var MESSAGE_COUNT_SHORT = MESSAGE_LENGTH_LONG / MESSAGE_LENGTH_SHORT;
|
||||
|
||||
runPerfTest(MESSAGE_LENGTH_LONG, 1);
|
||||
runPerfTest(MESSAGE_LENGTH_SHORT, MESSAGE_COUNT_SHORT);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Creates and returns a random byte array.
|
||||
*
|
||||
* @param {number} length Length of the byte array.
|
||||
* @return {!Array<number>} An array of bytes.
|
||||
* @private
|
||||
*/
|
||||
goog.crypt.hashTester.createRandomByteArray_ = function(length) {
|
||||
var random = new goog.testing.PseudoRandom(0);
|
||||
var bytes = [];
|
||||
|
||||
for (var i = 0; i < length; ++i) {
|
||||
// Generates an integer from 0 to 255.
|
||||
var b = Math.floor(random.random() * 0x100);
|
||||
bytes.push(b);
|
||||
}
|
||||
|
||||
return bytes;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Creates a string from an array of bytes.
|
||||
*
|
||||
* @param {!Array<number>} bytes An array of bytes.
|
||||
* @return {string} The string encoded by the bytes.
|
||||
* @private
|
||||
*/
|
||||
goog.crypt.hashTester.createByteString_ = function(bytes) {
|
||||
var str = '';
|
||||
goog.array.forEach(bytes, function(b) {
|
||||
str += String.fromCharCode(b);
|
||||
});
|
||||
return str;
|
||||
};
|
||||
@@ -0,0 +1,160 @@
|
||||
// Copyright 2011 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 HMAC in JavaScript.
|
||||
*
|
||||
* Usage:
|
||||
* var hmac = new goog.crypt.Hmac(new goog.crypt.sha1(), key, 64);
|
||||
* var digest = hmac.getHmac(bytes);
|
||||
*
|
||||
* @author benyu@google.com (Jige Yu) - port to closure
|
||||
*/
|
||||
|
||||
|
||||
goog.provide('goog.crypt.Hmac');
|
||||
|
||||
goog.require('goog.crypt.Hash');
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @constructor
|
||||
* @param {!goog.crypt.Hash} hasher An object to serve as a hash function.
|
||||
* @param {Array<number>} key The secret key to use to calculate the hmac.
|
||||
* Should be an array of not more than {@code blockSize} integers in
|
||||
{0, 255}.
|
||||
* @param {number=} opt_blockSize Optional. The block size {@code hasher} uses.
|
||||
* If not specified, uses the block size from the hasher, or 16 if it is
|
||||
* not specified.
|
||||
* @extends {goog.crypt.Hash}
|
||||
* @final
|
||||
* @struct
|
||||
*/
|
||||
goog.crypt.Hmac = function(hasher, key, opt_blockSize) {
|
||||
goog.crypt.Hmac.base(this, 'constructor');
|
||||
|
||||
/**
|
||||
* The underlying hasher to calculate hash.
|
||||
*
|
||||
* @type {!goog.crypt.Hash}
|
||||
* @private
|
||||
*/
|
||||
this.hasher_ = hasher;
|
||||
|
||||
this.blockSize = opt_blockSize || hasher.blockSize || 16;
|
||||
|
||||
/**
|
||||
* The outer padding array of hmac
|
||||
*
|
||||
* @type {!Array<number>}
|
||||
* @private
|
||||
*/
|
||||
this.keyO_ = new Array(this.blockSize);
|
||||
|
||||
/**
|
||||
* The inner padding array of hmac
|
||||
*
|
||||
* @type {!Array<number>}
|
||||
* @private
|
||||
*/
|
||||
this.keyI_ = new Array(this.blockSize);
|
||||
|
||||
this.initialize_(key);
|
||||
};
|
||||
goog.inherits(goog.crypt.Hmac, goog.crypt.Hash);
|
||||
|
||||
|
||||
/**
|
||||
* Outer padding byte of HMAC algorith, per http://en.wikipedia.org/wiki/HMAC
|
||||
*
|
||||
* @type {number}
|
||||
* @private
|
||||
*/
|
||||
goog.crypt.Hmac.OPAD_ = 0x5c;
|
||||
|
||||
|
||||
/**
|
||||
* Inner padding byte of HMAC algorith, per http://en.wikipedia.org/wiki/HMAC
|
||||
*
|
||||
* @type {number}
|
||||
* @private
|
||||
*/
|
||||
goog.crypt.Hmac.IPAD_ = 0x36;
|
||||
|
||||
|
||||
/**
|
||||
* Initializes Hmac by precalculating the inner and outer paddings.
|
||||
*
|
||||
* @param {Array<number>} key The secret key to use to calculate the hmac.
|
||||
* Should be an array of not more than {@code blockSize} integers in
|
||||
{0, 255}.
|
||||
* @private
|
||||
*/
|
||||
goog.crypt.Hmac.prototype.initialize_ = function(key) {
|
||||
if (key.length > this.blockSize) {
|
||||
this.hasher_.update(key);
|
||||
key = this.hasher_.digest();
|
||||
this.hasher_.reset();
|
||||
}
|
||||
// Precalculate padded and xor'd keys.
|
||||
var keyByte;
|
||||
for (var i = 0; i < this.blockSize; i++) {
|
||||
if (i < key.length) {
|
||||
keyByte = key[i];
|
||||
} else {
|
||||
keyByte = 0;
|
||||
}
|
||||
this.keyO_[i] = keyByte ^ goog.crypt.Hmac.OPAD_;
|
||||
this.keyI_[i] = keyByte ^ goog.crypt.Hmac.IPAD_;
|
||||
}
|
||||
// Be ready for an immediate update.
|
||||
this.hasher_.update(this.keyI_);
|
||||
};
|
||||
|
||||
|
||||
/** @override */
|
||||
goog.crypt.Hmac.prototype.reset = function() {
|
||||
this.hasher_.reset();
|
||||
this.hasher_.update(this.keyI_);
|
||||
};
|
||||
|
||||
|
||||
/** @override */
|
||||
goog.crypt.Hmac.prototype.update = function(bytes, opt_length) {
|
||||
this.hasher_.update(bytes, opt_length);
|
||||
};
|
||||
|
||||
|
||||
/** @override */
|
||||
goog.crypt.Hmac.prototype.digest = function() {
|
||||
var temp = this.hasher_.digest();
|
||||
this.hasher_.reset();
|
||||
this.hasher_.update(this.keyO_);
|
||||
this.hasher_.update(temp);
|
||||
return this.hasher_.digest();
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Calculates an HMAC for a given message.
|
||||
*
|
||||
* @param {Array<number>|Uint8Array|string} message Data to Hmac.
|
||||
* @return {!Array<number>} the digest of the given message.
|
||||
*/
|
||||
goog.crypt.Hmac.prototype.getHmac = function(message) {
|
||||
this.reset();
|
||||
this.update(message);
|
||||
return this.digest();
|
||||
};
|
||||
@@ -0,0 +1,22 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<!--
|
||||
Copyright 2011 The Closure Library Authors. All Rights Reserved.
|
||||
|
||||
Use of this source code is governed by the Apache License, Version 2.0.
|
||||
See the COPYING file for details.
|
||||
-->
|
||||
<head>
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
|
||||
<title>
|
||||
Closure Unit Tests - goog.crypt.sha1
|
||||
</title>
|
||||
<script src="../base.js">
|
||||
</script>
|
||||
<script>
|
||||
goog.require('goog.crypt.HmacTest');
|
||||
</script>
|
||||
</head>
|
||||
<body>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,142 @@
|
||||
// Copyright 2011 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.
|
||||
|
||||
goog.provide('goog.crypt.HmacTest');
|
||||
goog.setTestOnly('goog.crypt.HmacTest');
|
||||
|
||||
goog.require('goog.crypt.Hmac');
|
||||
goog.require('goog.crypt.Sha1');
|
||||
goog.require('goog.crypt.hashTester');
|
||||
goog.require('goog.testing.jsunit');
|
||||
|
||||
function stringToBytes(s) {
|
||||
var bytes = new Array(s.length);
|
||||
|
||||
for (var i = 0; i < s.length; ++i) {
|
||||
bytes[i] = s.charCodeAt(i) & 255;
|
||||
}
|
||||
return bytes;
|
||||
}
|
||||
|
||||
function hexToBytes(str) {
|
||||
var arr = [];
|
||||
|
||||
for (var i = 0; i < str.length; i += 2) {
|
||||
arr.push(parseInt(str.substring(i, i + 2), 16));
|
||||
}
|
||||
|
||||
return arr;
|
||||
}
|
||||
|
||||
function bytesToHex(b) {
|
||||
var hexchars = '0123456789abcdef';
|
||||
var hexrep = new Array(b.length * 2);
|
||||
|
||||
for (var i = 0; i < b.length; ++i) {
|
||||
hexrep[i * 2] = hexchars.charAt((b[i] >> 4) & 15);
|
||||
hexrep[i * 2 + 1] = hexchars.charAt(b[i] & 15);
|
||||
}
|
||||
return hexrep.join('');
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* helper to get an hmac of the given message with the given key.
|
||||
*/
|
||||
function getHmac(key, message, opt_blockSize) {
|
||||
var hasher = new goog.crypt.Sha1();
|
||||
var hmacer = new goog.crypt.Hmac(hasher, key, opt_blockSize);
|
||||
return bytesToHex(hmacer.getHmac(message));
|
||||
}
|
||||
|
||||
function testBasicOperations() {
|
||||
var hmac = new goog.crypt.Hmac(new goog.crypt.Sha1(), 'key', 64);
|
||||
goog.crypt.hashTester.runBasicTests(hmac);
|
||||
}
|
||||
|
||||
function testBasicOperationsWithNoBlockSize() {
|
||||
var hmac = new goog.crypt.Hmac(new goog.crypt.Sha1(), 'key');
|
||||
goog.crypt.hashTester.runBasicTests(hmac);
|
||||
}
|
||||
|
||||
function testHmac() {
|
||||
// HMAC test vectors from:
|
||||
// http://tools.ietf.org/html/2202
|
||||
|
||||
assertEquals('test 1 failed',
|
||||
'b617318655057264e28bc0b6fb378c8ef146be00',
|
||||
getHmac(hexToBytes('0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b'),
|
||||
stringToBytes('Hi There')));
|
||||
|
||||
assertEquals('test 2 failed',
|
||||
'effcdf6ae5eb2fa2d27416d5f184df9c259a7c79',
|
||||
getHmac(stringToBytes('Jefe'),
|
||||
stringToBytes('what do ya want for nothing?')));
|
||||
|
||||
assertEquals('test 3 failed',
|
||||
'125d7342b9ac11cd91a39af48aa17b4f63f175d3',
|
||||
getHmac(hexToBytes('aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa'),
|
||||
hexToBytes('dddddddddddddddddddddddddddddddddddddddd' +
|
||||
'dddddddddddddddddddddddddddddddddddddddd' +
|
||||
'dddddddddddddddddddd')));
|
||||
|
||||
assertEquals('test 4 failed',
|
||||
'4c9007f4026250c6bc8414f9bf50c86c2d7235da',
|
||||
getHmac(hexToBytes('0102030405060708090a0b0c0d0e0f10111213141516171819'),
|
||||
hexToBytes('cdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcd' +
|
||||
'cdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcd' +
|
||||
'cdcdcdcdcdcdcdcdcdcd')));
|
||||
|
||||
assertEquals('test 5 failed',
|
||||
'4c1a03424b55e07fe7f27be1d58bb9324a9a5a04',
|
||||
getHmac(hexToBytes('0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c'),
|
||||
stringToBytes('Test With Truncation')));
|
||||
|
||||
assertEquals('test 6 failed',
|
||||
'aa4ae5e15272d00e95705637ce8a3b55ed402112',
|
||||
getHmac(hexToBytes('aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa' +
|
||||
'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa' +
|
||||
'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa' +
|
||||
'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa'),
|
||||
stringToBytes(
|
||||
'Test Using Larger Than Block-Size Key - Hash Key First')));
|
||||
|
||||
assertEquals('test 7 failed',
|
||||
'b617318655057264e28bc0b6fb378c8ef146be00',
|
||||
getHmac(hexToBytes('0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b'),
|
||||
stringToBytes('Hi There'), 64));
|
||||
|
||||
assertEquals('test 8 failed',
|
||||
'941f806707826395dc510add6a45ce9933db976e',
|
||||
getHmac(hexToBytes('0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b'),
|
||||
stringToBytes('Hi There'), 32));
|
||||
}
|
||||
|
||||
|
||||
/** Regression test for Bug 12863104 */
|
||||
function testUpdateWithLongKey() {
|
||||
// Calling update() then digest() should give the same result as just
|
||||
// calling getHmac()
|
||||
var key = hexToBytes('aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa' +
|
||||
'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa' +
|
||||
'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa' +
|
||||
'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa');
|
||||
var message = 'Secret Message';
|
||||
var hmac = new goog.crypt.Hmac(new goog.crypt.Sha1(), key);
|
||||
hmac.update(message);
|
||||
var result1 = bytesToHex(hmac.digest());
|
||||
hmac.reset();
|
||||
var result2 = bytesToHex(hmac.getHmac(message));
|
||||
assertEquals('Results must be the same', result1, result2);
|
||||
}
|
||||
@@ -0,0 +1,435 @@
|
||||
// Copyright 2011 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 MD5 cryptographic hash.
|
||||
* Implementation of http://tools.ietf.org/html/rfc1321 with common
|
||||
* optimizations and tweaks (see http://en.wikipedia.org/wiki/MD5).
|
||||
*
|
||||
* Usage:
|
||||
* var md5 = new goog.crypt.Md5();
|
||||
* md5.update(bytes);
|
||||
* var hash = md5.digest();
|
||||
*
|
||||
* Performance:
|
||||
* Chrome 23 ~680 Mbit/s
|
||||
* Chrome 13 (in a VM) ~250 Mbit/s
|
||||
* Firefox 6.0 (in a VM) ~100 Mbit/s
|
||||
* IE9 (in a VM) ~27 Mbit/s
|
||||
* Firefox 3.6 ~15 Mbit/s
|
||||
* IE8 (in a VM) ~13 Mbit/s
|
||||
*
|
||||
*/
|
||||
|
||||
goog.provide('goog.crypt.Md5');
|
||||
|
||||
goog.require('goog.crypt.Hash');
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* MD5 cryptographic hash constructor.
|
||||
* @constructor
|
||||
* @extends {goog.crypt.Hash}
|
||||
* @final
|
||||
* @struct
|
||||
*/
|
||||
goog.crypt.Md5 = function() {
|
||||
goog.crypt.Md5.base(this, 'constructor');
|
||||
|
||||
this.blockSize = 512 / 8;
|
||||
|
||||
/**
|
||||
* Holds the current values of accumulated A-D variables (MD buffer).
|
||||
* @type {!Array<number>}
|
||||
* @private
|
||||
*/
|
||||
this.chain_ = new Array(4);
|
||||
|
||||
/**
|
||||
* A buffer holding the data until the whole block can be processed.
|
||||
* @type {!Array<number>}
|
||||
* @private
|
||||
*/
|
||||
this.block_ = new Array(this.blockSize);
|
||||
|
||||
/**
|
||||
* The length of yet-unprocessed data as collected in the block.
|
||||
* @type {number}
|
||||
* @private
|
||||
*/
|
||||
this.blockLength_ = 0;
|
||||
|
||||
/**
|
||||
* The total length of the message so far.
|
||||
* @type {number}
|
||||
* @private
|
||||
*/
|
||||
this.totalLength_ = 0;
|
||||
|
||||
this.reset();
|
||||
};
|
||||
goog.inherits(goog.crypt.Md5, goog.crypt.Hash);
|
||||
|
||||
|
||||
/**
|
||||
* Integer rotation constants used by the abbreviated implementation.
|
||||
* They are hardcoded in the unrolled implementation, so it is left
|
||||
* here commented out.
|
||||
* @type {Array<number>}
|
||||
* @private
|
||||
*
|
||||
goog.crypt.Md5.S_ = [
|
||||
7, 12, 17, 22, 7, 12, 17, 22, 7, 12, 17, 22, 7, 12, 17, 22,
|
||||
5, 9, 14, 20, 5, 9, 14, 20, 5, 9, 14, 20, 5, 9, 14, 20,
|
||||
4, 11, 16, 23, 4, 11, 16, 23, 4, 11, 16, 23, 4, 11, 16, 23,
|
||||
6, 10, 15, 21, 6, 10, 15, 21, 6, 10, 15, 21, 6, 10, 15, 21
|
||||
];
|
||||
*/
|
||||
|
||||
/**
|
||||
* Sine function constants used by the abbreviated implementation.
|
||||
* They are hardcoded in the unrolled implementation, so it is left
|
||||
* here commented out.
|
||||
* @type {Array<number>}
|
||||
* @private
|
||||
*
|
||||
goog.crypt.Md5.T_ = [
|
||||
0xd76aa478, 0xe8c7b756, 0x242070db, 0xc1bdceee,
|
||||
0xf57c0faf, 0x4787c62a, 0xa8304613, 0xfd469501,
|
||||
0x698098d8, 0x8b44f7af, 0xffff5bb1, 0x895cd7be,
|
||||
0x6b901122, 0xfd987193, 0xa679438e, 0x49b40821,
|
||||
0xf61e2562, 0xc040b340, 0x265e5a51, 0xe9b6c7aa,
|
||||
0xd62f105d, 0x02441453, 0xd8a1e681, 0xe7d3fbc8,
|
||||
0x21e1cde6, 0xc33707d6, 0xf4d50d87, 0x455a14ed,
|
||||
0xa9e3e905, 0xfcefa3f8, 0x676f02d9, 0x8d2a4c8a,
|
||||
0xfffa3942, 0x8771f681, 0x6d9d6122, 0xfde5380c,
|
||||
0xa4beea44, 0x4bdecfa9, 0xf6bb4b60, 0xbebfbc70,
|
||||
0x289b7ec6, 0xeaa127fa, 0xd4ef3085, 0x04881d05,
|
||||
0xd9d4d039, 0xe6db99e5, 0x1fa27cf8, 0xc4ac5665,
|
||||
0xf4292244, 0x432aff97, 0xab9423a7, 0xfc93a039,
|
||||
0x655b59c3, 0x8f0ccc92, 0xffeff47d, 0x85845dd1,
|
||||
0x6fa87e4f, 0xfe2ce6e0, 0xa3014314, 0x4e0811a1,
|
||||
0xf7537e82, 0xbd3af235, 0x2ad7d2bb, 0xeb86d391
|
||||
];
|
||||
*/
|
||||
|
||||
|
||||
/** @override */
|
||||
goog.crypt.Md5.prototype.reset = function() {
|
||||
this.chain_[0] = 0x67452301;
|
||||
this.chain_[1] = 0xefcdab89;
|
||||
this.chain_[2] = 0x98badcfe;
|
||||
this.chain_[3] = 0x10325476;
|
||||
|
||||
this.blockLength_ = 0;
|
||||
this.totalLength_ = 0;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Internal compress helper function. It takes a block of data (64 bytes)
|
||||
* and updates the accumulator.
|
||||
* @param {Array<number>|Uint8Array|string} buf The block to compress.
|
||||
* @param {number=} opt_offset Offset of the block in the buffer.
|
||||
* @private
|
||||
*/
|
||||
goog.crypt.Md5.prototype.compress_ = function(buf, opt_offset) {
|
||||
if (!opt_offset) {
|
||||
opt_offset = 0;
|
||||
}
|
||||
|
||||
// We allocate the array every time, but it's cheap in practice.
|
||||
var X = new Array(16);
|
||||
|
||||
// Get 16 little endian words. It is not worth unrolling this for Chrome 11.
|
||||
if (goog.isString(buf)) {
|
||||
for (var i = 0; i < 16; ++i) {
|
||||
X[i] = (buf.charCodeAt(opt_offset++)) |
|
||||
(buf.charCodeAt(opt_offset++) << 8) |
|
||||
(buf.charCodeAt(opt_offset++) << 16) |
|
||||
(buf.charCodeAt(opt_offset++) << 24);
|
||||
}
|
||||
} else {
|
||||
for (var i = 0; i < 16; ++i) {
|
||||
X[i] = (buf[opt_offset++]) |
|
||||
(buf[opt_offset++] << 8) |
|
||||
(buf[opt_offset++] << 16) |
|
||||
(buf[opt_offset++] << 24);
|
||||
}
|
||||
}
|
||||
|
||||
var A = this.chain_[0];
|
||||
var B = this.chain_[1];
|
||||
var C = this.chain_[2];
|
||||
var D = this.chain_[3];
|
||||
var sum = 0;
|
||||
|
||||
/*
|
||||
* This is an abbreviated implementation, it is left here commented out for
|
||||
* reference purposes. See below for an unrolled version in use.
|
||||
*
|
||||
var f, n, tmp;
|
||||
for (var i = 0; i < 64; ++i) {
|
||||
|
||||
if (i < 16) {
|
||||
f = (D ^ (B & (C ^ D)));
|
||||
n = i;
|
||||
} else if (i < 32) {
|
||||
f = (C ^ (D & (B ^ C)));
|
||||
n = (5 * i + 1) % 16;
|
||||
} else if (i < 48) {
|
||||
f = (B ^ C ^ D);
|
||||
n = (3 * i + 5) % 16;
|
||||
} else {
|
||||
f = (C ^ (B | (~D)));
|
||||
n = (7 * i) % 16;
|
||||
}
|
||||
|
||||
tmp = D;
|
||||
D = C;
|
||||
C = B;
|
||||
sum = (A + f + goog.crypt.Md5.T_[i] + X[n]) & 0xffffffff;
|
||||
B += ((sum << goog.crypt.Md5.S_[i]) & 0xffffffff) |
|
||||
(sum >>> (32 - goog.crypt.Md5.S_[i]));
|
||||
A = tmp;
|
||||
}
|
||||
*/
|
||||
|
||||
/*
|
||||
* This is an unrolled MD5 implementation, which gives ~30% speedup compared
|
||||
* to the abbreviated implementation above, as measured on Chrome 11. It is
|
||||
* important to keep 32-bit croppings to minimum and inline the integer
|
||||
* rotation.
|
||||
*/
|
||||
sum = (A + (D ^ (B & (C ^ D))) + X[0] + 0xd76aa478) & 0xffffffff;
|
||||
A = B + (((sum << 7) & 0xffffffff) | (sum >>> 25));
|
||||
sum = (D + (C ^ (A & (B ^ C))) + X[1] + 0xe8c7b756) & 0xffffffff;
|
||||
D = A + (((sum << 12) & 0xffffffff) | (sum >>> 20));
|
||||
sum = (C + (B ^ (D & (A ^ B))) + X[2] + 0x242070db) & 0xffffffff;
|
||||
C = D + (((sum << 17) & 0xffffffff) | (sum >>> 15));
|
||||
sum = (B + (A ^ (C & (D ^ A))) + X[3] + 0xc1bdceee) & 0xffffffff;
|
||||
B = C + (((sum << 22) & 0xffffffff) | (sum >>> 10));
|
||||
sum = (A + (D ^ (B & (C ^ D))) + X[4] + 0xf57c0faf) & 0xffffffff;
|
||||
A = B + (((sum << 7) & 0xffffffff) | (sum >>> 25));
|
||||
sum = (D + (C ^ (A & (B ^ C))) + X[5] + 0x4787c62a) & 0xffffffff;
|
||||
D = A + (((sum << 12) & 0xffffffff) | (sum >>> 20));
|
||||
sum = (C + (B ^ (D & (A ^ B))) + X[6] + 0xa8304613) & 0xffffffff;
|
||||
C = D + (((sum << 17) & 0xffffffff) | (sum >>> 15));
|
||||
sum = (B + (A ^ (C & (D ^ A))) + X[7] + 0xfd469501) & 0xffffffff;
|
||||
B = C + (((sum << 22) & 0xffffffff) | (sum >>> 10));
|
||||
sum = (A + (D ^ (B & (C ^ D))) + X[8] + 0x698098d8) & 0xffffffff;
|
||||
A = B + (((sum << 7) & 0xffffffff) | (sum >>> 25));
|
||||
sum = (D + (C ^ (A & (B ^ C))) + X[9] + 0x8b44f7af) & 0xffffffff;
|
||||
D = A + (((sum << 12) & 0xffffffff) | (sum >>> 20));
|
||||
sum = (C + (B ^ (D & (A ^ B))) + X[10] + 0xffff5bb1) & 0xffffffff;
|
||||
C = D + (((sum << 17) & 0xffffffff) | (sum >>> 15));
|
||||
sum = (B + (A ^ (C & (D ^ A))) + X[11] + 0x895cd7be) & 0xffffffff;
|
||||
B = C + (((sum << 22) & 0xffffffff) | (sum >>> 10));
|
||||
sum = (A + (D ^ (B & (C ^ D))) + X[12] + 0x6b901122) & 0xffffffff;
|
||||
A = B + (((sum << 7) & 0xffffffff) | (sum >>> 25));
|
||||
sum = (D + (C ^ (A & (B ^ C))) + X[13] + 0xfd987193) & 0xffffffff;
|
||||
D = A + (((sum << 12) & 0xffffffff) | (sum >>> 20));
|
||||
sum = (C + (B ^ (D & (A ^ B))) + X[14] + 0xa679438e) & 0xffffffff;
|
||||
C = D + (((sum << 17) & 0xffffffff) | (sum >>> 15));
|
||||
sum = (B + (A ^ (C & (D ^ A))) + X[15] + 0x49b40821) & 0xffffffff;
|
||||
B = C + (((sum << 22) & 0xffffffff) | (sum >>> 10));
|
||||
sum = (A + (C ^ (D & (B ^ C))) + X[1] + 0xf61e2562) & 0xffffffff;
|
||||
A = B + (((sum << 5) & 0xffffffff) | (sum >>> 27));
|
||||
sum = (D + (B ^ (C & (A ^ B))) + X[6] + 0xc040b340) & 0xffffffff;
|
||||
D = A + (((sum << 9) & 0xffffffff) | (sum >>> 23));
|
||||
sum = (C + (A ^ (B & (D ^ A))) + X[11] + 0x265e5a51) & 0xffffffff;
|
||||
C = D + (((sum << 14) & 0xffffffff) | (sum >>> 18));
|
||||
sum = (B + (D ^ (A & (C ^ D))) + X[0] + 0xe9b6c7aa) & 0xffffffff;
|
||||
B = C + (((sum << 20) & 0xffffffff) | (sum >>> 12));
|
||||
sum = (A + (C ^ (D & (B ^ C))) + X[5] + 0xd62f105d) & 0xffffffff;
|
||||
A = B + (((sum << 5) & 0xffffffff) | (sum >>> 27));
|
||||
sum = (D + (B ^ (C & (A ^ B))) + X[10] + 0x02441453) & 0xffffffff;
|
||||
D = A + (((sum << 9) & 0xffffffff) | (sum >>> 23));
|
||||
sum = (C + (A ^ (B & (D ^ A))) + X[15] + 0xd8a1e681) & 0xffffffff;
|
||||
C = D + (((sum << 14) & 0xffffffff) | (sum >>> 18));
|
||||
sum = (B + (D ^ (A & (C ^ D))) + X[4] + 0xe7d3fbc8) & 0xffffffff;
|
||||
B = C + (((sum << 20) & 0xffffffff) | (sum >>> 12));
|
||||
sum = (A + (C ^ (D & (B ^ C))) + X[9] + 0x21e1cde6) & 0xffffffff;
|
||||
A = B + (((sum << 5) & 0xffffffff) | (sum >>> 27));
|
||||
sum = (D + (B ^ (C & (A ^ B))) + X[14] + 0xc33707d6) & 0xffffffff;
|
||||
D = A + (((sum << 9) & 0xffffffff) | (sum >>> 23));
|
||||
sum = (C + (A ^ (B & (D ^ A))) + X[3] + 0xf4d50d87) & 0xffffffff;
|
||||
C = D + (((sum << 14) & 0xffffffff) | (sum >>> 18));
|
||||
sum = (B + (D ^ (A & (C ^ D))) + X[8] + 0x455a14ed) & 0xffffffff;
|
||||
B = C + (((sum << 20) & 0xffffffff) | (sum >>> 12));
|
||||
sum = (A + (C ^ (D & (B ^ C))) + X[13] + 0xa9e3e905) & 0xffffffff;
|
||||
A = B + (((sum << 5) & 0xffffffff) | (sum >>> 27));
|
||||
sum = (D + (B ^ (C & (A ^ B))) + X[2] + 0xfcefa3f8) & 0xffffffff;
|
||||
D = A + (((sum << 9) & 0xffffffff) | (sum >>> 23));
|
||||
sum = (C + (A ^ (B & (D ^ A))) + X[7] + 0x676f02d9) & 0xffffffff;
|
||||
C = D + (((sum << 14) & 0xffffffff) | (sum >>> 18));
|
||||
sum = (B + (D ^ (A & (C ^ D))) + X[12] + 0x8d2a4c8a) & 0xffffffff;
|
||||
B = C + (((sum << 20) & 0xffffffff) | (sum >>> 12));
|
||||
sum = (A + (B ^ C ^ D) + X[5] + 0xfffa3942) & 0xffffffff;
|
||||
A = B + (((sum << 4) & 0xffffffff) | (sum >>> 28));
|
||||
sum = (D + (A ^ B ^ C) + X[8] + 0x8771f681) & 0xffffffff;
|
||||
D = A + (((sum << 11) & 0xffffffff) | (sum >>> 21));
|
||||
sum = (C + (D ^ A ^ B) + X[11] + 0x6d9d6122) & 0xffffffff;
|
||||
C = D + (((sum << 16) & 0xffffffff) | (sum >>> 16));
|
||||
sum = (B + (C ^ D ^ A) + X[14] + 0xfde5380c) & 0xffffffff;
|
||||
B = C + (((sum << 23) & 0xffffffff) | (sum >>> 9));
|
||||
sum = (A + (B ^ C ^ D) + X[1] + 0xa4beea44) & 0xffffffff;
|
||||
A = B + (((sum << 4) & 0xffffffff) | (sum >>> 28));
|
||||
sum = (D + (A ^ B ^ C) + X[4] + 0x4bdecfa9) & 0xffffffff;
|
||||
D = A + (((sum << 11) & 0xffffffff) | (sum >>> 21));
|
||||
sum = (C + (D ^ A ^ B) + X[7] + 0xf6bb4b60) & 0xffffffff;
|
||||
C = D + (((sum << 16) & 0xffffffff) | (sum >>> 16));
|
||||
sum = (B + (C ^ D ^ A) + X[10] + 0xbebfbc70) & 0xffffffff;
|
||||
B = C + (((sum << 23) & 0xffffffff) | (sum >>> 9));
|
||||
sum = (A + (B ^ C ^ D) + X[13] + 0x289b7ec6) & 0xffffffff;
|
||||
A = B + (((sum << 4) & 0xffffffff) | (sum >>> 28));
|
||||
sum = (D + (A ^ B ^ C) + X[0] + 0xeaa127fa) & 0xffffffff;
|
||||
D = A + (((sum << 11) & 0xffffffff) | (sum >>> 21));
|
||||
sum = (C + (D ^ A ^ B) + X[3] + 0xd4ef3085) & 0xffffffff;
|
||||
C = D + (((sum << 16) & 0xffffffff) | (sum >>> 16));
|
||||
sum = (B + (C ^ D ^ A) + X[6] + 0x04881d05) & 0xffffffff;
|
||||
B = C + (((sum << 23) & 0xffffffff) | (sum >>> 9));
|
||||
sum = (A + (B ^ C ^ D) + X[9] + 0xd9d4d039) & 0xffffffff;
|
||||
A = B + (((sum << 4) & 0xffffffff) | (sum >>> 28));
|
||||
sum = (D + (A ^ B ^ C) + X[12] + 0xe6db99e5) & 0xffffffff;
|
||||
D = A + (((sum << 11) & 0xffffffff) | (sum >>> 21));
|
||||
sum = (C + (D ^ A ^ B) + X[15] + 0x1fa27cf8) & 0xffffffff;
|
||||
C = D + (((sum << 16) & 0xffffffff) | (sum >>> 16));
|
||||
sum = (B + (C ^ D ^ A) + X[2] + 0xc4ac5665) & 0xffffffff;
|
||||
B = C + (((sum << 23) & 0xffffffff) | (sum >>> 9));
|
||||
sum = (A + (C ^ (B | (~D))) + X[0] + 0xf4292244) & 0xffffffff;
|
||||
A = B + (((sum << 6) & 0xffffffff) | (sum >>> 26));
|
||||
sum = (D + (B ^ (A | (~C))) + X[7] + 0x432aff97) & 0xffffffff;
|
||||
D = A + (((sum << 10) & 0xffffffff) | (sum >>> 22));
|
||||
sum = (C + (A ^ (D | (~B))) + X[14] + 0xab9423a7) & 0xffffffff;
|
||||
C = D + (((sum << 15) & 0xffffffff) | (sum >>> 17));
|
||||
sum = (B + (D ^ (C | (~A))) + X[5] + 0xfc93a039) & 0xffffffff;
|
||||
B = C + (((sum << 21) & 0xffffffff) | (sum >>> 11));
|
||||
sum = (A + (C ^ (B | (~D))) + X[12] + 0x655b59c3) & 0xffffffff;
|
||||
A = B + (((sum << 6) & 0xffffffff) | (sum >>> 26));
|
||||
sum = (D + (B ^ (A | (~C))) + X[3] + 0x8f0ccc92) & 0xffffffff;
|
||||
D = A + (((sum << 10) & 0xffffffff) | (sum >>> 22));
|
||||
sum = (C + (A ^ (D | (~B))) + X[10] + 0xffeff47d) & 0xffffffff;
|
||||
C = D + (((sum << 15) & 0xffffffff) | (sum >>> 17));
|
||||
sum = (B + (D ^ (C | (~A))) + X[1] + 0x85845dd1) & 0xffffffff;
|
||||
B = C + (((sum << 21) & 0xffffffff) | (sum >>> 11));
|
||||
sum = (A + (C ^ (B | (~D))) + X[8] + 0x6fa87e4f) & 0xffffffff;
|
||||
A = B + (((sum << 6) & 0xffffffff) | (sum >>> 26));
|
||||
sum = (D + (B ^ (A | (~C))) + X[15] + 0xfe2ce6e0) & 0xffffffff;
|
||||
D = A + (((sum << 10) & 0xffffffff) | (sum >>> 22));
|
||||
sum = (C + (A ^ (D | (~B))) + X[6] + 0xa3014314) & 0xffffffff;
|
||||
C = D + (((sum << 15) & 0xffffffff) | (sum >>> 17));
|
||||
sum = (B + (D ^ (C | (~A))) + X[13] + 0x4e0811a1) & 0xffffffff;
|
||||
B = C + (((sum << 21) & 0xffffffff) | (sum >>> 11));
|
||||
sum = (A + (C ^ (B | (~D))) + X[4] + 0xf7537e82) & 0xffffffff;
|
||||
A = B + (((sum << 6) & 0xffffffff) | (sum >>> 26));
|
||||
sum = (D + (B ^ (A | (~C))) + X[11] + 0xbd3af235) & 0xffffffff;
|
||||
D = A + (((sum << 10) & 0xffffffff) | (sum >>> 22));
|
||||
sum = (C + (A ^ (D | (~B))) + X[2] + 0x2ad7d2bb) & 0xffffffff;
|
||||
C = D + (((sum << 15) & 0xffffffff) | (sum >>> 17));
|
||||
sum = (B + (D ^ (C | (~A))) + X[9] + 0xeb86d391) & 0xffffffff;
|
||||
B = C + (((sum << 21) & 0xffffffff) | (sum >>> 11));
|
||||
|
||||
this.chain_[0] = (this.chain_[0] + A) & 0xffffffff;
|
||||
this.chain_[1] = (this.chain_[1] + B) & 0xffffffff;
|
||||
this.chain_[2] = (this.chain_[2] + C) & 0xffffffff;
|
||||
this.chain_[3] = (this.chain_[3] + D) & 0xffffffff;
|
||||
};
|
||||
|
||||
|
||||
/** @override */
|
||||
goog.crypt.Md5.prototype.update = function(bytes, opt_length) {
|
||||
if (!goog.isDef(opt_length)) {
|
||||
opt_length = bytes.length;
|
||||
}
|
||||
var lengthMinusBlock = opt_length - this.blockSize;
|
||||
|
||||
// Copy some object properties to local variables in order to save on access
|
||||
// time from inside the loop (~10% speedup was observed on Chrome 11).
|
||||
var block = this.block_;
|
||||
var blockLength = this.blockLength_;
|
||||
var i = 0;
|
||||
|
||||
// The outer while loop should execute at most twice.
|
||||
while (i < opt_length) {
|
||||
// When we have no data in the block to top up, we can directly process the
|
||||
// input buffer (assuming it contains sufficient data). This gives ~30%
|
||||
// speedup on Chrome 14 and ~70% speedup on Firefox 6.0, but requires that
|
||||
// the data is provided in large chunks (or in multiples of 64 bytes).
|
||||
if (blockLength == 0) {
|
||||
while (i <= lengthMinusBlock) {
|
||||
this.compress_(bytes, i);
|
||||
i += this.blockSize;
|
||||
}
|
||||
}
|
||||
|
||||
if (goog.isString(bytes)) {
|
||||
while (i < opt_length) {
|
||||
block[blockLength++] = bytes.charCodeAt(i++);
|
||||
if (blockLength == this.blockSize) {
|
||||
this.compress_(block);
|
||||
blockLength = 0;
|
||||
// Jump to the outer loop so we use the full-block optimization.
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
while (i < opt_length) {
|
||||
block[blockLength++] = bytes[i++];
|
||||
if (blockLength == this.blockSize) {
|
||||
this.compress_(block);
|
||||
blockLength = 0;
|
||||
// Jump to the outer loop so we use the full-block optimization.
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
this.blockLength_ = blockLength;
|
||||
this.totalLength_ += opt_length;
|
||||
};
|
||||
|
||||
|
||||
/** @override */
|
||||
goog.crypt.Md5.prototype.digest = function() {
|
||||
// This must accommodate at least 1 padding byte (0x80), 8 bytes of
|
||||
// total bitlength, and must end at a 64-byte boundary.
|
||||
var pad = new Array((this.blockLength_ < 56 ?
|
||||
this.blockSize :
|
||||
this.blockSize * 2) - this.blockLength_);
|
||||
|
||||
// Add padding: 0x80 0x00*
|
||||
pad[0] = 0x80;
|
||||
for (var i = 1; i < pad.length - 8; ++i) {
|
||||
pad[i] = 0;
|
||||
}
|
||||
// Add the total number of bits, little endian 64-bit integer.
|
||||
var totalBits = this.totalLength_ * 8;
|
||||
for (var i = pad.length - 8; i < pad.length; ++i) {
|
||||
pad[i] = totalBits & 0xff;
|
||||
totalBits /= 0x100; // Don't use bit-shifting here!
|
||||
}
|
||||
this.update(pad);
|
||||
|
||||
var digest = new Array(16);
|
||||
var n = 0;
|
||||
for (var i = 0; i < 4; ++i) {
|
||||
for (var j = 0; j < 32; j += 8) {
|
||||
digest[n++] = (this.chain_[i] >>> j) & 0xff;
|
||||
}
|
||||
}
|
||||
return digest;
|
||||
};
|
||||
@@ -0,0 +1,39 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<!--
|
||||
Copyright 2011 The Closure Library Authors. All Rights Reserved.
|
||||
|
||||
Use of this source code is governed by the Apache License, Version 2.0.
|
||||
See the COPYING file for details.
|
||||
|
||||
-->
|
||||
<head>
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||
<title>Closure Performance Tests - goog.crypt.Md5</title>
|
||||
<link rel="stylesheet" type="text/css" href="../testing/performancetable.css"/>
|
||||
<script src="../base.js"></script>
|
||||
<script>
|
||||
goog.require('goog.crypt.Md5');
|
||||
goog.require('goog.crypt.hashTester')
|
||||
goog.require('goog.testing.PerformanceTable');
|
||||
goog.require('goog.testing.PseudoRandom');
|
||||
goog.require('goog.testing.jsunit');
|
||||
</script>
|
||||
</head>
|
||||
<body>
|
||||
<h1>Closure Performance Tests - goog.crypt.Md5</h1>
|
||||
<p>
|
||||
<strong>User-agent:</strong>
|
||||
<script>document.write(navigator.userAgent);</script>
|
||||
</p>
|
||||
<script>
|
||||
|
||||
function testHashing() {
|
||||
goog.crypt.hashTester.runPerfTests(function() {
|
||||
return new goog.crypt.Md5();
|
||||
}, 'MD5');
|
||||
}
|
||||
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,23 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<!--
|
||||
Copyright 2011 The Closure Library Authors. All Rights Reserved.
|
||||
|
||||
Use of this source code is governed by the Apache License, Version 2.0.
|
||||
See the COPYING file for details.
|
||||
|
||||
-->
|
||||
<head>
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
|
||||
<title>
|
||||
Closure Unit Tests - goog.crypt.Md5
|
||||
</title>
|
||||
<script src="../base.js">
|
||||
</script>
|
||||
<script>
|
||||
goog.require('goog.crypt.Md5Test');
|
||||
</script>
|
||||
</head>
|
||||
<body>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,147 @@
|
||||
// Copyright 2011 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.
|
||||
|
||||
goog.provide('goog.crypt.Md5Test');
|
||||
goog.setTestOnly('goog.crypt.Md5Test');
|
||||
|
||||
goog.require('goog.crypt');
|
||||
goog.require('goog.crypt.Md5');
|
||||
goog.require('goog.crypt.hashTester');
|
||||
goog.require('goog.testing.jsunit');
|
||||
|
||||
var sixty = '123456789012345678901234567890123456789012345678901234567890';
|
||||
|
||||
function testBasicOperations() {
|
||||
var md5 = new goog.crypt.Md5();
|
||||
goog.crypt.hashTester.runBasicTests(md5);
|
||||
}
|
||||
|
||||
function testBlockOperations() {
|
||||
var md5 = new goog.crypt.Md5();
|
||||
goog.crypt.hashTester.runBlockTests(md5, 64);
|
||||
}
|
||||
|
||||
function testHashing() {
|
||||
// Empty stream.
|
||||
var md5 = new goog.crypt.Md5();
|
||||
assertEquals('d41d8cd98f00b204e9800998ecf8427e',
|
||||
goog.crypt.byteArrayToHex(md5.digest()));
|
||||
|
||||
// Simple stream.
|
||||
md5.reset();
|
||||
md5.update([97]);
|
||||
assertEquals('0cc175b9c0f1b6a831c399e269772661',
|
||||
goog.crypt.byteArrayToHex(md5.digest()));
|
||||
|
||||
// Simple stream with two updates.
|
||||
md5.reset();
|
||||
md5.update([97]);
|
||||
md5.update('bc');
|
||||
assertEquals('900150983cd24fb0d6963f7d28e17f72',
|
||||
goog.crypt.byteArrayToHex(md5.digest()));
|
||||
|
||||
// RFC 1321 standard test.
|
||||
md5.reset();
|
||||
md5.update('abcdefghijklmnopqrstuvwxyz');
|
||||
assertEquals('c3fcd3d76192e4007dfb496cca67e13b',
|
||||
goog.crypt.byteArrayToHex(md5.digest()));
|
||||
|
||||
// RFC 1321 standard test with two updates.
|
||||
md5.reset();
|
||||
md5.update('message ');
|
||||
md5.update('digest');
|
||||
assertEquals('f96b697d7cb7938d525a2f31aaf161d0',
|
||||
goog.crypt.byteArrayToHex(md5.digest()));
|
||||
|
||||
// RFC 1321 standard test with three updates.
|
||||
md5.reset();
|
||||
md5.update('ABCDEFGHIJKLMNOPQRSTUVWXYZ');
|
||||
md5.update('abcdefghijklmnopqrstuvwxyz');
|
||||
md5.update('0123456789');
|
||||
assertEquals('d174ab98d277d9f5a5611c2c9f419d9f',
|
||||
goog.crypt.byteArrayToHex(md5.digest()));
|
||||
}
|
||||
|
||||
function testPadding() {
|
||||
// Message + padding fits in two 64-byte blocks.
|
||||
var md5 = new goog.crypt.Md5();
|
||||
md5.update(sixty);
|
||||
md5.update(sixty.substr(0, 59));
|
||||
assertEquals('6261005311809757906e04c0d670492d',
|
||||
goog.crypt.byteArrayToHex(md5.digest()));
|
||||
|
||||
// Message + padding does not fit in two 64-byte blocks.
|
||||
md5.reset();
|
||||
md5.update(sixty);
|
||||
md5.update(sixty);
|
||||
assertEquals('1d453b96d48d5e0cec4a20a71fecaa81',
|
||||
goog.crypt.byteArrayToHex(md5.digest()));
|
||||
}
|
||||
|
||||
function testTwoAccumulators() {
|
||||
// Two accumulators in parallel.
|
||||
var md5_A = new goog.crypt.Md5();
|
||||
var md5_B = new goog.crypt.Md5();
|
||||
md5_A.update(sixty);
|
||||
md5_B.update(sixty);
|
||||
md5_A.update(sixty + '1');
|
||||
md5_B.update(sixty + '2');
|
||||
assertEquals('0801d688cc107d4789ec8b9a4519f01f',
|
||||
goog.crypt.byteArrayToHex(md5_A.digest()));
|
||||
assertEquals('6e1a35ffc185d1e684d6ed281c0d4bd2',
|
||||
goog.crypt.byteArrayToHex(md5_B.digest()));
|
||||
}
|
||||
|
||||
function testCollision() {
|
||||
// Check a known collision.
|
||||
var A = [0xd1, 0x31, 0xdd, 0x02, 0xc5, 0xe6, 0xee, 0xc4,
|
||||
0x69, 0x3d, 0x9a, 0x06, 0x98, 0xaf, 0xf9, 0x5c,
|
||||
0x2f, 0xca, 0xb5, 0x87, 0x12, 0x46, 0x7e, 0xab,
|
||||
0x40, 0x04, 0x58, 0x3e, 0xb8, 0xfb, 0x7f, 0x89,
|
||||
0x55, 0xad, 0x34, 0x06, 0x09, 0xf4, 0xb3, 0x02,
|
||||
0x83, 0xe4, 0x88, 0x83, 0x25, 0x71, 0x41, 0x5a,
|
||||
0x08, 0x51, 0x25, 0xe8, 0xf7, 0xcd, 0xc9, 0x9f,
|
||||
0xd9, 0x1d, 0xbd, 0xf2, 0x80, 0x37, 0x3c, 0x5b,
|
||||
0xd8, 0x82, 0x3e, 0x31, 0x56, 0x34, 0x8f, 0x5b,
|
||||
0xae, 0x6d, 0xac, 0xd4, 0x36, 0xc9, 0x19, 0xc6,
|
||||
0xdd, 0x53, 0xe2, 0xb4, 0x87, 0xda, 0x03, 0xfd,
|
||||
0x02, 0x39, 0x63, 0x06, 0xd2, 0x48, 0xcd, 0xa0,
|
||||
0xe9, 0x9f, 0x33, 0x42, 0x0f, 0x57, 0x7e, 0xe8,
|
||||
0xce, 0x54, 0xb6, 0x70, 0x80, 0xa8, 0x0d, 0x1e,
|
||||
0xc6, 0x98, 0x21, 0xbc, 0xb6, 0xa8, 0x83, 0x93,
|
||||
0x96, 0xf9, 0x65, 0x2b, 0x6f, 0xf7, 0x2a, 0x70];
|
||||
var B = [0xd1, 0x31, 0xdd, 0x02, 0xc5, 0xe6, 0xee, 0xc4,
|
||||
0x69, 0x3d, 0x9a, 0x06, 0x98, 0xaf, 0xf9, 0x5c,
|
||||
0x2f, 0xca, 0xb5, 0x07, 0x12, 0x46, 0x7e, 0xab,
|
||||
0x40, 0x04, 0x58, 0x3e, 0xb8, 0xfb, 0x7f, 0x89,
|
||||
0x55, 0xad, 0x34, 0x06, 0x09, 0xf4, 0xb3, 0x02,
|
||||
0x83, 0xe4, 0x88, 0x83, 0x25, 0xf1, 0x41, 0x5a,
|
||||
0x08, 0x51, 0x25, 0xe8, 0xf7, 0xcd, 0xc9, 0x9f,
|
||||
0xd9, 0x1d, 0xbd, 0x72, 0x80, 0x37, 0x3c, 0x5b,
|
||||
0xd8, 0x82, 0x3e, 0x31, 0x56, 0x34, 0x8f, 0x5b,
|
||||
0xae, 0x6d, 0xac, 0xd4, 0x36, 0xc9, 0x19, 0xc6,
|
||||
0xdd, 0x53, 0xe2, 0x34, 0x87, 0xda, 0x03, 0xfd,
|
||||
0x02, 0x39, 0x63, 0x06, 0xd2, 0x48, 0xcd, 0xa0,
|
||||
0xe9, 0x9f, 0x33, 0x42, 0x0f, 0x57, 0x7e, 0xe8,
|
||||
0xce, 0x54, 0xb6, 0x70, 0x80, 0x28, 0x0d, 0x1e,
|
||||
0xc6, 0x98, 0x21, 0xbc, 0xb6, 0xa8, 0x83, 0x93,
|
||||
0x96, 0xf9, 0x65, 0xab, 0x6f, 0xf7, 0x2a, 0x70];
|
||||
var digest = '79054025255fb1a26e4bc422aef54eb4';
|
||||
var md5_A = new goog.crypt.Md5();
|
||||
var md5_B = new goog.crypt.Md5();
|
||||
md5_A.update(A);
|
||||
md5_B.update(B);
|
||||
assertEquals(digest, goog.crypt.byteArrayToHex(md5_A.digest()));
|
||||
assertEquals(digest, goog.crypt.byteArrayToHex(md5_B.digest()));
|
||||
}
|
||||
@@ -0,0 +1,128 @@
|
||||
// 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;
|
||||
};
|
||||
@@ -0,0 +1,25 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<!--
|
||||
Copyright 2012 The Closure Library Authors. All Rights Reserved.
|
||||
|
||||
Use of this source code is governed by the Apache License, Version 2.0.
|
||||
See the COPYING file for details.
|
||||
-->
|
||||
<!--
|
||||
Unit test for goog.crypt.pbkdf2
|
||||
-->
|
||||
<head>
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
|
||||
<title>
|
||||
Closure Unit Tests - goog.crypt.pbkdf2
|
||||
</title>
|
||||
<script src="../base.js">
|
||||
</script>
|
||||
<script>
|
||||
goog.require('goog.crypt.pbkdf2Test');
|
||||
</script>
|
||||
</head>
|
||||
<body>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,61 @@
|
||||
// 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.
|
||||
|
||||
goog.provide('goog.crypt.pbkdf2Test');
|
||||
goog.setTestOnly('goog.crypt.pbkdf2Test');
|
||||
|
||||
goog.require('goog.crypt');
|
||||
goog.require('goog.crypt.pbkdf2');
|
||||
goog.require('goog.testing.jsunit');
|
||||
goog.require('goog.userAgent');
|
||||
|
||||
function testPBKDF2() {
|
||||
// PBKDF2 test vectors from:
|
||||
// http://tools.ietf.org/html/rfc6070
|
||||
|
||||
if (goog.userAgent.IE && goog.userAgent.isVersionOrHigher('7')) {
|
||||
return;
|
||||
}
|
||||
|
||||
var testPassword = goog.crypt.stringToByteArray('password');
|
||||
var testSalt = goog.crypt.stringToByteArray('salt');
|
||||
|
||||
assertElementsEquals(
|
||||
goog.crypt.hexToByteArray('0c60c80f961f0e71f3a9b524af6012062fe037a6'),
|
||||
goog.crypt.pbkdf2.deriveKeySha1(testPassword, testSalt, 1, 160));
|
||||
|
||||
assertElementsEquals(
|
||||
goog.crypt.hexToByteArray('ea6c014dc72d6f8ccd1ed92ace1d41f0d8de8957'),
|
||||
goog.crypt.pbkdf2.deriveKeySha1(testPassword, testSalt, 2, 160));
|
||||
|
||||
assertElementsEquals(
|
||||
goog.crypt.hexToByteArray('4b007901b765489abead49d926f721d065a429c1'),
|
||||
goog.crypt.pbkdf2.deriveKeySha1(testPassword, testSalt, 4096, 160));
|
||||
|
||||
testPassword = goog.crypt.stringToByteArray('passwordPASSWORDpassword');
|
||||
testSalt =
|
||||
goog.crypt.stringToByteArray('saltSALTsaltSALTsaltSALTsaltSALTsalt');
|
||||
|
||||
assertElementsEquals(
|
||||
goog.crypt.hexToByteArray(
|
||||
'3d2eec4fe41c849b80c8d83662c0e44a8b291a964cf2f07038'),
|
||||
goog.crypt.pbkdf2.deriveKeySha1(testPassword, testSalt, 4096, 200));
|
||||
|
||||
testPassword = goog.crypt.stringToByteArray('pass\0word');
|
||||
testSalt = goog.crypt.stringToByteArray('sa\0lt');
|
||||
|
||||
assertElementsEquals(
|
||||
goog.crypt.hexToByteArray('56fa6aa75548099dcc37d7f03425e0c3'),
|
||||
goog.crypt.pbkdf2.deriveKeySha1(testPassword, testSalt, 4096, 128));
|
||||
}
|
||||
@@ -0,0 +1,311 @@
|
||||
// Copyright 2005 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 SHA-1 cryptographic hash.
|
||||
* Variable names follow the notation in FIPS PUB 180-3:
|
||||
* http://csrc.nist.gov/publications/fips/fips180-3/fips180-3_final.pdf.
|
||||
*
|
||||
* Usage:
|
||||
* var sha1 = new goog.crypt.sha1();
|
||||
* sha1.update(bytes);
|
||||
* var hash = sha1.digest();
|
||||
*
|
||||
* Performance:
|
||||
* Chrome 23: ~400 Mbit/s
|
||||
* Firefox 16: ~250 Mbit/s
|
||||
*
|
||||
* Note: The idiom expr|0 is used to provide a type-hint to the VM, in order
|
||||
* to avoid unnecessary uint32-double-uint32 roundtripping.
|
||||
*/
|
||||
|
||||
goog.provide('goog.crypt.Sha1');
|
||||
|
||||
goog.require('goog.crypt.Hash');
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* SHA-1 cryptographic hash constructor.
|
||||
*
|
||||
* The properties declared here are discussed in the above algorithm document.
|
||||
* @constructor
|
||||
* @extends {goog.crypt.Hash}
|
||||
* @final
|
||||
* @struct
|
||||
*/
|
||||
goog.crypt.Sha1 = function() {
|
||||
goog.crypt.Sha1.base(this, 'constructor');
|
||||
|
||||
this.blockSize = 512 / 8;
|
||||
|
||||
/**
|
||||
* Holds the previous values of accumulated variables a-e in the compress_
|
||||
* function.
|
||||
* @type {!Array<number>}
|
||||
* @private
|
||||
*/
|
||||
this.chain_ = [];
|
||||
|
||||
/**
|
||||
* A buffer holding the partially computed hash result.
|
||||
* @type {!Array<number>}
|
||||
* @private
|
||||
*/
|
||||
this.buf_ = [];
|
||||
|
||||
/**
|
||||
* An array of 80 bytes, each a part of the message to be hashed. Referred to
|
||||
* as the message schedule in the docs.
|
||||
* @type {!Array<number>}
|
||||
* @private
|
||||
*/
|
||||
this.W_ = [];
|
||||
|
||||
/**
|
||||
* Contains data needed to pad messages less than 64 bytes.
|
||||
* @type {!Array<number>}
|
||||
* @private
|
||||
*/
|
||||
this.pad_ = [];
|
||||
|
||||
this.pad_[0] = 128;
|
||||
for (var i = 1; i < this.blockSize; ++i) {
|
||||
this.pad_[i] = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @private {number}
|
||||
*/
|
||||
this.inbuf_ = 0;
|
||||
|
||||
/**
|
||||
* @private {number}
|
||||
*/
|
||||
this.total_ = 0;
|
||||
|
||||
this.reset();
|
||||
};
|
||||
goog.inherits(goog.crypt.Sha1, goog.crypt.Hash);
|
||||
|
||||
|
||||
/** @override */
|
||||
goog.crypt.Sha1.prototype.reset = function() {
|
||||
this.chain_[0] = 0x67452301;
|
||||
this.chain_[1] = 0xefcdab89;
|
||||
this.chain_[2] = 0x98badcfe;
|
||||
this.chain_[3] = 0x10325476;
|
||||
this.chain_[4] = 0xc3d2e1f0;
|
||||
|
||||
this.inbuf_ = 0;
|
||||
this.total_ = 0;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Internal compress helper function.
|
||||
* @param {!Array<number>|!Uint8Array|string} buf Block to compress.
|
||||
* @param {number=} opt_offset Offset of the block in the buffer.
|
||||
* @private
|
||||
*/
|
||||
goog.crypt.Sha1.prototype.compress_ = function(buf, opt_offset) {
|
||||
if (!opt_offset) {
|
||||
opt_offset = 0;
|
||||
}
|
||||
|
||||
var W = this.W_;
|
||||
var i;
|
||||
|
||||
// get 16 big endian words
|
||||
if (goog.isString(buf)) {
|
||||
for (i = 0; i < 16; i++) {
|
||||
// TODO(user): [bug 8140122] Recent versions of Safari for Mac OS and iOS
|
||||
// have a bug that turns the post-increment ++ operator into pre-increment
|
||||
// during JIT compilation. We have code that depends heavily on SHA-1 for
|
||||
// correctness and which is affected by this bug, so I've removed all uses
|
||||
// of post-increment ++ in which the result value is used. We can revert
|
||||
// this change once the Safari bug
|
||||
// (https://bugs.webkit.org/show_bug.cgi?id=109036) has been fixed and
|
||||
// most clients have been updated.
|
||||
W[i] = (((buf.charCodeAt(opt_offset) << 24) |
|
||||
(buf.charCodeAt(opt_offset + 1) << 16) |
|
||||
(buf.charCodeAt(opt_offset + 2) << 8) |
|
||||
(buf.charCodeAt(opt_offset + 3))) & 0xffffffff) | 0;
|
||||
opt_offset += 4;
|
||||
}
|
||||
} else {
|
||||
for (i = 0; i < 16; i++) {
|
||||
W[i] = (((buf[opt_offset] << 24) |
|
||||
(buf[opt_offset + 1] << 16) |
|
||||
(buf[opt_offset + 2] << 8) |
|
||||
(buf[opt_offset + 3])) & 0xffffffff) | 0;
|
||||
opt_offset += 4;
|
||||
}
|
||||
}
|
||||
|
||||
var a = this.chain_[0];
|
||||
var b = this.chain_[1];
|
||||
var c = this.chain_[2];
|
||||
var d = this.chain_[3];
|
||||
var e = this.chain_[4];
|
||||
var f, k, t;
|
||||
|
||||
// Steps 0-16.
|
||||
for (i = 0; i < 16; i++) {
|
||||
f = d ^ (b & (c ^ d));
|
||||
k = 0x5a827999;
|
||||
|
||||
t = ((((a << 5) | (a >>> 27)) + f + e + k + W[i]) & 0xffffffff) | 0;
|
||||
e = d;
|
||||
d = c;
|
||||
c = (((b << 30) | (b >>> 2)) & 0xffffffff) | 0;
|
||||
b = a;
|
||||
a = t;
|
||||
}
|
||||
// Steps 16-80. W is formally described as an 80-word array, and usually
|
||||
// computed that way. However, only 16 elements are needed for any iteration
|
||||
// so we compute W on the fly and keep only the last 16 values. This improves
|
||||
// performance by about 10% on Chrome 35.
|
||||
for (i = 16; i < 80; i++) {
|
||||
t = W[(i - 3) & 15] ^ W[(i - 8) & 15] ^ W[(i - 14) & 15] ^ W[i & 15];
|
||||
W[i & 15] = (((t << 1) | (t >>> 31)) & 0xfffffff) | 0;
|
||||
if (i < 40) {
|
||||
if (i < 20) {
|
||||
f = d ^ (b & (c ^ d));
|
||||
k = 0x5a827999;
|
||||
} else {
|
||||
f = b ^ c ^ d;
|
||||
k = 0x6ed9eba1;
|
||||
}
|
||||
} else {
|
||||
if (i < 60) {
|
||||
f = (b & c) | (d & (b | c));
|
||||
k = 0x8f1bbcdc;
|
||||
} else {
|
||||
f = b ^ c ^ d;
|
||||
k = 0xca62c1d6;
|
||||
}
|
||||
}
|
||||
|
||||
t = ((((a << 5) | (a >>> 27)) + f + e + k + W[i & 15]) & 0xffffffff) | 0;
|
||||
e = d;
|
||||
d = c;
|
||||
c = (((b << 30) | (b >>> 2)) & 0xffffffff) | 0;
|
||||
b = a;
|
||||
a = t;
|
||||
}
|
||||
|
||||
this.chain_[0] = ((this.chain_[0] + a) & 0xfffffff) | 0;
|
||||
this.chain_[1] = ((this.chain_[1] + b) & 0xfffffff) | 0;
|
||||
this.chain_[2] = ((this.chain_[2] + c) & 0xfffffff) | 0;
|
||||
this.chain_[3] = ((this.chain_[3] + d) & 0xfffffff) | 0;
|
||||
this.chain_[4] = ((this.chain_[4] + e) & 0xfffffff) | 0;
|
||||
};
|
||||
|
||||
|
||||
/** @override */
|
||||
goog.crypt.Sha1.prototype.update = function(bytes, opt_length) {
|
||||
// TODO(johnlenz): tighten the function signature and remove this check
|
||||
if (bytes === null) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!goog.isDef(opt_length)) {
|
||||
opt_length = bytes.length;
|
||||
}
|
||||
opt_length = (bytes.length < opt_length) ? bytes.length : opt_length;
|
||||
|
||||
var lengthMinusBlock = opt_length - this.blockSize;
|
||||
var n = 0;
|
||||
// Using local instead of member variables gives ~5% speedup on Firefox 16.
|
||||
var buf = this.buf_;
|
||||
var inbuf = this.inbuf_;
|
||||
|
||||
// The outer while loop should execute at most twice.
|
||||
while (n < opt_length) {
|
||||
// When we have no data in the block to top up, we can directly process the
|
||||
// input buffer (assuming it contains sufficient data). This gives ~25%
|
||||
// speedup on Chrome 23 and ~15% speedup on Firefox 16, but requires that
|
||||
// the data is provided in large chunks (or in multiples of 64 bytes).
|
||||
if (inbuf === 0) {
|
||||
while (n <= lengthMinusBlock) {
|
||||
this.compress_(bytes, n);
|
||||
n += this.blockSize;
|
||||
}
|
||||
}
|
||||
|
||||
if (goog.isString(bytes)) {
|
||||
while (n < opt_length) {
|
||||
buf[inbuf] = bytes.charCodeAt(n);
|
||||
++inbuf;
|
||||
++n;
|
||||
if (inbuf == this.blockSize) {
|
||||
this.compress_(buf);
|
||||
inbuf = 0;
|
||||
// Jump to the outer loop so we use the full-block optimization.
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
while (n < opt_length) {
|
||||
buf[inbuf] = bytes[n];
|
||||
++inbuf;
|
||||
++n;
|
||||
if (inbuf == this.blockSize) {
|
||||
this.compress_(buf);
|
||||
inbuf = 0;
|
||||
// Jump to the outer loop so we use the full-block optimization.
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
this.inbuf_ = inbuf;
|
||||
this.total_ += opt_length;
|
||||
};
|
||||
|
||||
|
||||
/** @override */
|
||||
goog.crypt.Sha1.prototype.digest = function() {
|
||||
var digest = [];
|
||||
var totalBits = this.total_ * 8;
|
||||
|
||||
var i;
|
||||
|
||||
// Add pad 0x80 0x00*.
|
||||
if (this.inbuf_ < 56) {
|
||||
this.update(this.pad_, 56 - this.inbuf_);
|
||||
} else {
|
||||
this.update(this.pad_, this.blockSize - (this.inbuf_ - 56));
|
||||
}
|
||||
|
||||
// Add # bits.
|
||||
for (i = this.blockSize - 1; i >= 56; i--) {
|
||||
this.buf_[i] = totalBits & 255;
|
||||
totalBits /= 256; // Don't use bit-shifting here!
|
||||
}
|
||||
|
||||
this.compress_(this.buf_);
|
||||
|
||||
var n = 0;
|
||||
for (i = 0; i < 5; i++) {
|
||||
for (var j = 24; j >= 0; j -= 8) {
|
||||
digest[n] = (this.chain_[i] >> j) & 255;
|
||||
++n;
|
||||
}
|
||||
}
|
||||
|
||||
return digest;
|
||||
};
|
||||
@@ -0,0 +1,22 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<!--
|
||||
Copyright 2010 The Closure Library Authors. All Rights Reserved.
|
||||
|
||||
Use of this source code is governed by the Apache License, Version 2.0.
|
||||
See the COPYING file for details.
|
||||
-->
|
||||
<head>
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
|
||||
<title>
|
||||
Closure Unit Tests - goog.crypt.shaX Monte Carlo KATs
|
||||
</title>
|
||||
<script src="../base.js">
|
||||
</script>
|
||||
<script>
|
||||
goog.require('goog.crypt.ShaMcTest');
|
||||
</script>
|
||||
</head>
|
||||
<body>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,130 @@
|
||||
/* Warning: These tests take about 8 minutes to run. */
|
||||
|
||||
goog.provide('goog.crypt.ShaMcTest');
|
||||
goog.setTestOnly('goog.crypt.ShaMcTest');
|
||||
|
||||
goog.require('goog.crypt');
|
||||
goog.require('goog.crypt.Sha1');
|
||||
goog.require('goog.crypt.Sha224');
|
||||
goog.require('goog.crypt.Sha256');
|
||||
goog.require('goog.crypt.Sha384');
|
||||
goog.require('goog.crypt.Sha512');
|
||||
|
||||
goog.require('goog.testing.jsunit');
|
||||
goog.require('goog.userAgent');
|
||||
|
||||
function testSha1() {
|
||||
var sha = new goog.crypt.Sha1();
|
||||
var initial_state = 'Sha1';
|
||||
var count = 1638;
|
||||
var state = goog.crypt.stringToByteArray(initial_state);
|
||||
var digest;
|
||||
for (var i = 0; i < count; i++) {
|
||||
sha.reset();
|
||||
sha.update(state);
|
||||
digest = sha.digest();
|
||||
state = goog.array.concat(digest, state);
|
||||
}
|
||||
assertEquals(32764, state.length);
|
||||
assertEquals('9da05831d6441141b62545eb4bf3bcc92b8c8276',
|
||||
goog.crypt.byteArrayToHex(digest));
|
||||
sha.reset();
|
||||
for (var i = 0; i < (32764 + 10); i++) {
|
||||
sha.update(state, i);
|
||||
}
|
||||
assertEquals('70a4f1a7b523d9989a1cfd0f512a906abbfefe5f',
|
||||
goog.crypt.byteArrayToHex(sha.digest()));
|
||||
}
|
||||
|
||||
function testSha224() {
|
||||
var sha = new goog.crypt.Sha224();
|
||||
var initial_state = 'Sha224';
|
||||
var count = 1170;
|
||||
var state = goog.crypt.stringToByteArray(initial_state);
|
||||
var digest;
|
||||
for (var i = 0; i < count; i++) {
|
||||
sha.reset();
|
||||
sha.update(state);
|
||||
digest = sha.digest();
|
||||
state = goog.array.concat(digest, state);
|
||||
}
|
||||
assertEquals(32766, state.length);
|
||||
assertEquals('c7636f5369a057fde53f3a70cb2880795a35af53db38ed8a04cbcbfe',
|
||||
goog.crypt.byteArrayToHex(digest));
|
||||
sha.reset();
|
||||
for (var i = 0; i < (32766 + 10); i++) {
|
||||
sha.update(state, i);
|
||||
}
|
||||
assertEquals('69f7e71bbf9a7bd15832fa77e09cbe458dcea284ddb00a69eb3ed78a',
|
||||
goog.crypt.byteArrayToHex(sha.digest()));
|
||||
}
|
||||
|
||||
function testSha256() {
|
||||
var sha = new goog.crypt.Sha256();
|
||||
var initial_state = 'Sha256';
|
||||
var count = 1024;
|
||||
var state = goog.crypt.stringToByteArray(initial_state);
|
||||
var digest;
|
||||
for (var i = 0; i < count; i++) {
|
||||
sha.reset();
|
||||
sha.update(state);
|
||||
digest = sha.digest();
|
||||
state = goog.array.concat(digest, state);
|
||||
}
|
||||
assertEquals(32774, state.length);
|
||||
assertEquals('bdc98db7476b58c33161211099b02c27da6bed3959a8b1d4e600f4d628ba0200',
|
||||
goog.crypt.byteArrayToHex(digest));
|
||||
sha.reset();
|
||||
for (var i = 0; i < (32774 + 10); i++) {
|
||||
sha.update(state, i);
|
||||
}
|
||||
assertEquals('26cc26f6429ce20c1b537d67cc288231a18de2a258d8bf529751439cd7c71d37',
|
||||
goog.crypt.byteArrayToHex(sha.digest()));
|
||||
}
|
||||
|
||||
function testSha384() {
|
||||
var sha = new goog.crypt.Sha384();
|
||||
var initial_state = 'Sha384';
|
||||
var count = 682;
|
||||
var state = goog.crypt.stringToByteArray(initial_state);
|
||||
var digest;
|
||||
for (var i = 0; i < count; i++) {
|
||||
sha.reset();
|
||||
sha.update(state);
|
||||
digest = sha.digest();
|
||||
state = goog.array.concat(digest, state);
|
||||
}
|
||||
assertEquals(32742, state.length);
|
||||
assertEquals('1e7017a365fd31f6c439efb3eabef783a1e09ebcbb357bc4c9aac5fa9d731a167ee8105cd1c76159a1c27c56c5d1bc8c',
|
||||
goog.crypt.byteArrayToHex(digest));
|
||||
sha.reset();
|
||||
for (var i = 0; i < (32742 + 10); i++) {
|
||||
sha.update(state, i);
|
||||
}
|
||||
assertEquals('0cd4695e15f9089e767b2866e1728588d5cece4ad13e4943aa5bd5f9debbe133e2fac302851a2e90e13c318ace25fbb8',
|
||||
goog.crypt.byteArrayToHex(sha.digest()));
|
||||
}
|
||||
|
||||
function testSha512() {
|
||||
var sha = new goog.crypt.Sha512();
|
||||
var initial_state = 'Sha512';
|
||||
var count = 512;
|
||||
var state = goog.crypt.stringToByteArray(initial_state);
|
||||
var digest;
|
||||
for (var i = 0; i < count; i++) {
|
||||
sha.reset();
|
||||
sha.update(state);
|
||||
digest = sha.digest();
|
||||
state = goog.array.concat(digest, state);
|
||||
}
|
||||
assertEquals(32774, state.length);
|
||||
assertEquals('5c9c25961a9171e2a79b9be65e05ce238752e7bfbaf3696c6ed63b8ee2735315d2cb58bf70a5f08dd70ecab029bd0725dcdd84dacd063ea9148cb3e5d7fa948a',
|
||||
goog.crypt.byteArrayToHex(digest));
|
||||
sha.reset();
|
||||
for (var i = 0; i < (32774 + 10); i++) {
|
||||
sha.update(state, i);
|
||||
}
|
||||
assertEquals('10a310e050cf9b2e9d4fc3c0a8f8e183c158ff28c23a42fd5b7777f449cfbe92655eee2bb42fb47c6900e001153b74a5db777b9b2d1543dc30fe98face94f106',
|
||||
goog.crypt.byteArrayToHex(sha.digest()));
|
||||
}
|
||||
|
||||
@@ -0,0 +1,40 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<!--
|
||||
Copyright 2011 The Closure Library Authors. All Rights Reserved.
|
||||
|
||||
Use of this source code is governed by the Apache License, Version 2.0.
|
||||
See the COPYING file for details.
|
||||
|
||||
-->
|
||||
<head>
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||
<title>Closure Performance Tests - goog.crypt.Sha1</title>
|
||||
<link rel="stylesheet" type="text/css" href="../testing/performancetable.css"/>
|
||||
<script src="../base.js"></script>
|
||||
<script>
|
||||
goog.require('goog.crypt.Sha1');
|
||||
goog.require('goog.crypt.hashTester');
|
||||
goog.require('goog.testing.PerformanceTable');
|
||||
goog.require('goog.testing.PseudoRandom');
|
||||
goog.require('goog.testing.jsunit');
|
||||
</script>
|
||||
</head>
|
||||
<body>
|
||||
<h1>Closure Performance Tests - goog.crypt.Sha1</h1>
|
||||
<p>
|
||||
<strong>User-agent:</strong>
|
||||
<script>document.write(navigator.userAgent);</script>
|
||||
</p>
|
||||
|
||||
<script>
|
||||
|
||||
function testHashing() {
|
||||
goog.crypt.hashTester.runPerfTests(function() {
|
||||
return new goog.crypt.Sha1();
|
||||
}, 'SHA1');
|
||||
}
|
||||
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,22 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<!--
|
||||
Copyright 2010 The Closure Library Authors. All Rights Reserved.
|
||||
|
||||
Use of this source code is governed by the Apache License, Version 2.0.
|
||||
See the COPYING file for details.
|
||||
-->
|
||||
<head>
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
|
||||
<title>
|
||||
Closure Unit Tests - goog.crypt.sha1
|
||||
</title>
|
||||
<script src="../base.js">
|
||||
</script>
|
||||
<script>
|
||||
goog.require('goog.crypt.Sha1Test');
|
||||
</script>
|
||||
</head>
|
||||
<body>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,118 @@
|
||||
// Copyright 2010 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.
|
||||
|
||||
goog.provide('goog.crypt.Sha1Test');
|
||||
goog.setTestOnly('goog.crypt.Sha1Test');
|
||||
|
||||
goog.require('goog.crypt');
|
||||
goog.require('goog.crypt.Sha1');
|
||||
goog.require('goog.crypt.hashTester');
|
||||
goog.require('goog.testing.jsunit');
|
||||
goog.require('goog.userAgent');
|
||||
|
||||
function testBasicOperations() {
|
||||
var sha1 = new goog.crypt.Sha1();
|
||||
goog.crypt.hashTester.runBasicTests(sha1);
|
||||
}
|
||||
|
||||
function testBlockOperations() {
|
||||
var sha1 = new goog.crypt.Sha1();
|
||||
goog.crypt.hashTester.runBlockTests(sha1, 64);
|
||||
}
|
||||
|
||||
function testHashing() {
|
||||
// Test vectors from:
|
||||
// csrc.nist.gov/publications/fips/fips180-2/fips180-2withchangenotice.pdf
|
||||
|
||||
// Empty stream.
|
||||
var sha1 = new goog.crypt.Sha1();
|
||||
assertEquals('da39a3ee5e6b4b0d3255bfef95601890afd80709',
|
||||
goog.crypt.byteArrayToHex(sha1.digest()));
|
||||
|
||||
// Test one-block message.
|
||||
sha1.reset();
|
||||
sha1.update([0x61, 0x62, 0x63]);
|
||||
assertEquals('a9993e364706816aba3e25717850c26c9cd0d89d',
|
||||
goog.crypt.byteArrayToHex(sha1.digest()));
|
||||
|
||||
// Test multi-block message.
|
||||
sha1.reset();
|
||||
sha1.update('abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq');
|
||||
assertEquals('84983e441c3bd26ebaae4aa1f95129e5e54670f1',
|
||||
goog.crypt.byteArrayToHex(sha1.digest()));
|
||||
|
||||
// The following test might cause timeouts on IE7.
|
||||
if (!goog.userAgent.IE || goog.userAgent.isVersionOrHigher('8')) {
|
||||
// Test long message.
|
||||
var thousandAs = [];
|
||||
for (var i = 0; i < 1000; ++i) {
|
||||
thousandAs[i] = 0x61;
|
||||
}
|
||||
sha1.reset();
|
||||
for (var i = 0; i < 1000; ++i) {
|
||||
sha1.update(thousandAs);
|
||||
}
|
||||
assertEquals('34aa973cd4c4daa4f61eeb2bdbad27316534016f',
|
||||
goog.crypt.byteArrayToHex(sha1.digest()));
|
||||
}
|
||||
|
||||
// Test standard message.
|
||||
sha1.reset();
|
||||
sha1.update('The quick brown fox jumps over the lazy dog');
|
||||
assertEquals('2fd4e1c67a2d28fced849ee1bb76e7391b93eb12',
|
||||
goog.crypt.byteArrayToHex(sha1.digest()));
|
||||
|
||||
sha1.reset();
|
||||
sha1.update(goog.string.repeat('a', 1024));
|
||||
assertEquals('8eca554631df9ead14510e1a70ae48c70f9b9384',
|
||||
goog.crypt.byteArrayToHex(sha1.digest()));
|
||||
|
||||
}
|
||||
|
||||
function testLength() {
|
||||
var sha = new goog.crypt.Sha1();
|
||||
|
||||
// Test that truncating a message works.
|
||||
sha.reset();
|
||||
sha.update('abc');
|
||||
assertEquals('a9993e364706816aba3e25717850c26c9cd0d89d',
|
||||
goog.crypt.byteArrayToHex(sha.digest()));
|
||||
sha.reset();
|
||||
sha.update('abcde', 3);
|
||||
assertEquals('a9993e364706816aba3e25717850c26c9cd0d89d',
|
||||
goog.crypt.byteArrayToHex(sha.digest()));
|
||||
|
||||
// Test that lengths work correctly.
|
||||
var message = goog.crypt.hexToByteArray(
|
||||
'd9b28b643d16efc8a17a532c05deb79069421bf4cda67f58310ae3bc956e4720' +
|
||||
'f9d2ab845d360fe8c19a734c25fed7b089623b14edc69f78512a03dcb58e6740');
|
||||
|
||||
// Lengths from 0 to 64.
|
||||
sha.reset();
|
||||
for (var i = 0; i < 64; i++) {
|
||||
sha.update(message, i);
|
||||
}
|
||||
assertElementsEquals(goog.crypt.hexToByteArray(
|
||||
'04df2fcf7b12b7735e0a3d05d9723702aa70de30'),
|
||||
sha.digest());
|
||||
|
||||
// Lengths from 0 to 71 to include message overrun cases.
|
||||
sha.reset();
|
||||
for (var i = 0; i < 71; i++) {
|
||||
sha.update(message, i);
|
||||
}
|
||||
assertElementsEquals(goog.crypt.hexToByteArray(
|
||||
'f62df7546b7f70351a5c25bfd9e77ba90ca697f4'),
|
||||
sha.digest());
|
||||
}
|
||||
@@ -0,0 +1,515 @@
|
||||
// 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 Base class for SHA-2 cryptographic hash.
|
||||
*
|
||||
* Variable names follow the notation in FIPS PUB 180-3:
|
||||
* http://csrc.nist.gov/publications/fips/fips180-3/fips180-3_final.pdf.
|
||||
*
|
||||
* Some code similar to SHA1 are borrowed from sha1.js written by mschilder@.
|
||||
*
|
||||
*/
|
||||
|
||||
goog.provide('goog.crypt.Sha2');
|
||||
|
||||
goog.require('goog.array');
|
||||
goog.require('goog.asserts');
|
||||
goog.require('goog.crypt.Hash');
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* SHA-2 cryptographic hash constructor.
|
||||
* This constructor should not be used directly to create the object. Rather,
|
||||
* one should use the constructor of the sub-classes.
|
||||
* @param {number} numHashBlocks The size of output in 16-byte blocks.
|
||||
* @param {!Array<number>} initHashBlocks The hash-specific initialization
|
||||
* @constructor
|
||||
* @extends {goog.crypt.Hash}
|
||||
* @struct
|
||||
*/
|
||||
goog.crypt.Sha2 = function(numHashBlocks, initHashBlocks) {
|
||||
goog.crypt.Sha2.base(this, 'constructor');
|
||||
|
||||
this.blockSize = goog.crypt.Sha2.BLOCKSIZE_;
|
||||
|
||||
/**
|
||||
* A chunk holding the currently processed message bytes. Once the chunk has
|
||||
* 64 bytes, we feed it into computeChunk_ function and reset this.chunk_.
|
||||
* @private {!Array<number>|!Uint8Array}
|
||||
*/
|
||||
this.chunk_ = goog.global['Uint8Array'] ?
|
||||
new Uint8Array(this.blockSize) : new Array(this.blockSize);
|
||||
|
||||
/**
|
||||
* Current number of bytes in this.chunk_.
|
||||
* @private {number}
|
||||
*/
|
||||
this.inChunk_ = 0;
|
||||
|
||||
/**
|
||||
* Total number of bytes in currently processed message.
|
||||
* @private {number}
|
||||
*/
|
||||
this.total_ = 0;
|
||||
|
||||
|
||||
/**
|
||||
* Holds the previous values of accumulated hash a-h in the computeChunk_
|
||||
* function.
|
||||
* @private {!Array<number>|!Int32Array}
|
||||
*/
|
||||
this.hash_ = [];
|
||||
|
||||
/**
|
||||
* The number of output hash blocks (each block is 4 bytes long).
|
||||
* @private {number}
|
||||
*/
|
||||
this.numHashBlocks_ = numHashBlocks;
|
||||
|
||||
/**
|
||||
* @private {!Array<number>} initHashBlocks
|
||||
*/
|
||||
this.initHashBlocks_ = initHashBlocks;
|
||||
|
||||
/**
|
||||
* Temporary array used in chunk computation. Allocate here as a
|
||||
* member rather than as a local within computeChunk_() as a
|
||||
* performance optimization to reduce the number of allocations and
|
||||
* reduce garbage collection.
|
||||
* @private {!Int32Array|!Array<number>}
|
||||
*/
|
||||
this.w_ = goog.global['Int32Array'] ? new Int32Array(64) : new Array(64);
|
||||
|
||||
if (!goog.isDef(goog.crypt.Sha2.Kx_)) {
|
||||
// This is the first time this constructor has been called.
|
||||
if (goog.global['Int32Array']) {
|
||||
// Typed arrays exist
|
||||
goog.crypt.Sha2.Kx_ = new Int32Array(goog.crypt.Sha2.K_);
|
||||
} else {
|
||||
// Typed arrays do not exist
|
||||
goog.crypt.Sha2.Kx_ = goog.crypt.Sha2.K_;
|
||||
}
|
||||
}
|
||||
|
||||
this.reset();
|
||||
};
|
||||
goog.inherits(goog.crypt.Sha2, goog.crypt.Hash);
|
||||
|
||||
|
||||
/**
|
||||
* The block size
|
||||
* @private {number}
|
||||
*/
|
||||
goog.crypt.Sha2.BLOCKSIZE_ = 512 / 8;
|
||||
|
||||
|
||||
/**
|
||||
* Contains data needed to pad messages less than BLOCK_SIZE_ bytes.
|
||||
* @private {!Array<number>}
|
||||
*/
|
||||
goog.crypt.Sha2.PADDING_ = goog.array.concat(128,
|
||||
goog.array.repeat(0, goog.crypt.Sha2.BLOCKSIZE_ - 1));
|
||||
|
||||
|
||||
/** @override */
|
||||
goog.crypt.Sha2.prototype.reset = function() {
|
||||
this.inChunk_ = 0;
|
||||
this.total_ = 0;
|
||||
this.hash_ = goog.global['Int32Array'] ?
|
||||
new Int32Array(this.initHashBlocks_) :
|
||||
goog.array.clone(this.initHashBlocks_);
|
||||
};
|
||||
|
||||
|
||||
/** Helper function to precompute a message schedule.
|
||||
*
|
||||
* TODO(dlg): This is essentially static...
|
||||
*
|
||||
* @param {!Array|Uint8Array|string} buf Data used for the update.
|
||||
* @param {number=} opt_offset Optional offset into the data.
|
||||
*
|
||||
* @return {!Array|Int32Array} w A 64-element array of uint32s, representing the
|
||||
* prescheduled message, with round constants already added.
|
||||
*/
|
||||
goog.crypt.Sha2.prototype.preschedule = function(buf, opt_offset) {
|
||||
if (!opt_offset) {
|
||||
opt_offset = 0;
|
||||
}
|
||||
|
||||
// Divide the chunk into 16 32-bit-words.
|
||||
var w = goog.global['Int32Array'] ? new Int32Array(64) : new Array(64);
|
||||
var i;
|
||||
// get 16 big endian words
|
||||
if (goog.isString(buf)) {
|
||||
for (i = 0; i < 16; i++) {
|
||||
w[i] = (((buf.charCodeAt(opt_offset) << 24) |
|
||||
(buf.charCodeAt(opt_offset + 1) << 16) |
|
||||
(buf.charCodeAt(opt_offset + 2) << 8) |
|
||||
(buf.charCodeAt(opt_offset + 3))) & 0xffffffff) | 0;
|
||||
opt_offset += 4;
|
||||
}
|
||||
} else {
|
||||
for (i = 0; i < 16; i++) {
|
||||
w[i] = (((buf[opt_offset] << 24) |
|
||||
(buf[opt_offset + 1] << 16) |
|
||||
(buf[opt_offset + 2] << 8) |
|
||||
(buf[opt_offset + 3])) & 0xffffffff) | 0;
|
||||
opt_offset += 4;
|
||||
}
|
||||
}
|
||||
for (i = 16; i < 64; i++) {
|
||||
var w_15 = w[i - 15] | 0;
|
||||
var s0 = ((((w_15 >>> 7) | (w_15 << 25)) ^
|
||||
((w_15 >>> 18) | (w_15 << 14)) ^
|
||||
(w_15 >>> 3)) & 0xffffffff) | 0;
|
||||
var w_2 = w[i - 2] | 0;
|
||||
var s1 = ((((w_2 >>> 17) | (w_2 << 15)) ^
|
||||
((w_2 >>> 19) | (w_2 << 13)) ^
|
||||
(w_2 >>> 10)) & 0xffffffff) | 0;
|
||||
|
||||
// As a performance optimization, construct the sum a pair at a time
|
||||
// with casting to integer (bitwise OR) to eliminate unnecessary
|
||||
// double<->integer conversions.
|
||||
var partialSum1 = (((w[i - 16] | 0) + s0) & 0xffffffff) | 0;
|
||||
var partialSum2 = (((w[i - 7] | 0) + s1) & 0xffffffff) | 0;
|
||||
w[i] = (partialSum1 + partialSum2) | 0;
|
||||
}
|
||||
for (i = 0; i < 64; i++) {
|
||||
w[i] = (w[i] + (goog.crypt.Sha2.Kx_[i] | 0) | 0);
|
||||
}
|
||||
return w;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Update this goog.crypt.Sha2 instance's chaining value using a precomputed
|
||||
* schedule. Increment the total digested bytes by 64.
|
||||
*
|
||||
* @param {Array.<Uint32Array[80]>} precomputed_schedule An SHA2-32b schedule
|
||||
* precomputed by goog.crypt.Sha2.preschedule.
|
||||
*/
|
||||
goog.crypt.Sha2.prototype.scheduledUpdate = function(precomputed_schedule) {
|
||||
var w = precomputed_schedule;
|
||||
|
||||
var a = this.hash_[0] | 0;
|
||||
var b = this.hash_[1] | 0;
|
||||
var c = this.hash_[2] | 0;
|
||||
var d = this.hash_[3] | 0;
|
||||
var e = this.hash_[4] | 0;
|
||||
var f = this.hash_[5] | 0;
|
||||
var g = this.hash_[6] | 0;
|
||||
var h = this.hash_[7] | 0;
|
||||
for (var i = 0; i < 64; i++) {
|
||||
var S0 = ((a >>> 2) | (a << 30)) ^
|
||||
((a >>> 13) | (a << 19)) ^
|
||||
((a >>> 22) | (a << 10));
|
||||
var maj = ((a & b) ^ (a & c) ^ (b & c));
|
||||
var t2 = (S0 + maj) | 0;
|
||||
var S1 = ((e >>> 6) | (e << 26)) ^
|
||||
((e >>> 11) | (e << 21)) ^
|
||||
((e >>> 25) | (e << 7));
|
||||
var ch = ((e & f) ^ ((~ e) & g));
|
||||
|
||||
var partialSum1 = (h + S1) | 0;
|
||||
var partialSum3 = (ch + (w[i] | 0)) | 0;
|
||||
var t1 = (partialSum1 + partialSum3) | 0;
|
||||
|
||||
h = g;
|
||||
g = f;
|
||||
f = e;
|
||||
e = (d + t1) | 0;
|
||||
d = c;
|
||||
c = b;
|
||||
b = a;
|
||||
a = (t1 + t2) | 0;
|
||||
}
|
||||
this.total_ += this.blockSize;
|
||||
|
||||
this.hash_[0] = (this.hash_[0] + a) | 0;
|
||||
this.hash_[1] = (this.hash_[1] + b) | 0;
|
||||
this.hash_[2] = (this.hash_[2] + c) | 0;
|
||||
this.hash_[3] = (this.hash_[3] + d) | 0;
|
||||
this.hash_[4] = (this.hash_[4] + e) | 0;
|
||||
this.hash_[5] = (this.hash_[5] + f) | 0;
|
||||
this.hash_[6] = (this.hash_[6] + g) | 0;
|
||||
this.hash_[7] = (this.hash_[7] + h) | 0;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Helper function to compute the hashes for a given 512-bit message chunk.
|
||||
* @param {!Array|Uint8Array|string} buf Data used for the update.
|
||||
* @param {number=} opt_offset Optional offset into the data.
|
||||
*
|
||||
* @private
|
||||
*/
|
||||
goog.crypt.Sha2.prototype.computeChunk_ = function(buf, opt_offset) {
|
||||
// Performance notes:
|
||||
// - Sum numbers pairwise and cast to integer using | after to avoid
|
||||
// unnecessary double<->integer conversions.
|
||||
// - The message schedule is updated "in-place" to reduce the amount
|
||||
// of garbage that has to be collected.
|
||||
|
||||
if (!opt_offset) {
|
||||
opt_offset = 0;
|
||||
}
|
||||
|
||||
// The message schedule.
|
||||
var w = this.w_;
|
||||
var i;
|
||||
// Divide the chunk into 16 32-bit-words.
|
||||
if (goog.isString(buf)) {
|
||||
for (i = 0; i < 16; i++) {
|
||||
// TODO(user): [bug 8140122] Recent versions of Safari for Mac OS and iOS
|
||||
// have a bug that turns the post-increment ++ operator into pre-increment
|
||||
// during JIT compilation.
|
||||
// TODO(someone): Bug resolved 2013-02-27 at:
|
||||
// https://bugs.webkit.org/show_bug.cgi?id=109036,
|
||||
// https://bugs.webkit.org/show_bug.cgi?id=110991
|
||||
// (Is this still needed? If there's no significant performance advantage,
|
||||
// current code is clearer.)
|
||||
w[i] = (buf.charCodeAt(opt_offset) << 24) |
|
||||
(buf.charCodeAt(opt_offset + 1) << 16) |
|
||||
(buf.charCodeAt(opt_offset + 2) << 8) |
|
||||
(buf.charCodeAt(opt_offset + 3));
|
||||
opt_offset += 4;
|
||||
}
|
||||
} else {
|
||||
for (i = 0; i < 16; i++) {
|
||||
w[i] = (buf[opt_offset] << 24) |
|
||||
(buf[opt_offset + 1] << 16) |
|
||||
(buf[opt_offset + 2] << 8) |
|
||||
(buf[opt_offset + 3]);
|
||||
opt_offset += 4;
|
||||
}
|
||||
}
|
||||
|
||||
var a = this.hash_[0] | 0;
|
||||
var b = this.hash_[1] | 0;
|
||||
var c = this.hash_[2] | 0;
|
||||
var d = this.hash_[3] | 0;
|
||||
var e = this.hash_[4] | 0;
|
||||
var f = this.hash_[5] | 0;
|
||||
var g = this.hash_[6] | 0;
|
||||
var h = this.hash_[7] | 0;
|
||||
// Do steps 0-16.
|
||||
for (i = 0; i < 16; i++) {
|
||||
var S0 = ((a >>> 2) | (a << 30)) ^
|
||||
((a >>> 13) | (a << 19)) ^
|
||||
((a >>> 22) | (a << 10));
|
||||
var maj = ((a & b) ^ (a & c) ^ (b & c));
|
||||
var t2 = (S0 + maj) | 0;
|
||||
var S1 = ((e >>> 6) | (e << 26)) ^
|
||||
((e >>> 11) | (e << 21)) ^
|
||||
((e >>> 25) | (e << 7));
|
||||
var ch = ((e & f) ^ ((~ e) & g));
|
||||
|
||||
var partialSum1 = (h + S1) | 0;
|
||||
var partialSum2 = (ch + (goog.crypt.Sha2.Kx_[i] | 0)) | 0;
|
||||
var partialSum3 = (partialSum2 + (w[i] | 0)) | 0;
|
||||
var t1 = (partialSum1 + partialSum3) | 0;
|
||||
|
||||
h = g;
|
||||
g = f;
|
||||
f = e;
|
||||
e = (d + t1) | 0;
|
||||
d = c;
|
||||
c = b;
|
||||
b = a;
|
||||
a = (t1 + t2) | 0;
|
||||
}
|
||||
|
||||
// Do steps 16-64.
|
||||
for (i = 16; i < 64; i++) {
|
||||
var w_15 = w[(i - 15) & 15] | 0;
|
||||
var s0 = ((w_15 >>> 7) | (w_15 << 25)) ^
|
||||
((w_15 >>> 18) | (w_15 << 14)) ^
|
||||
(w_15 >>> 3);
|
||||
var w_2 = w[(i - 2) & 15] | 0;
|
||||
var s1 = ((w_2 >>> 17) | (w_2 << 15)) ^
|
||||
((w_2 >>> 19) | (w_2 << 13)) ^
|
||||
(w_2 >>> 10);
|
||||
|
||||
var partialSum1 = ((w[(i - 16) & 15] | 0) + s0) | 0;
|
||||
var partialSum2 = ((w[(i - 7) & 15] | 0) + s1) | 0;
|
||||
w[i & 15] = (partialSum1 + partialSum2) | 0;
|
||||
|
||||
var S0 = ((a >>> 2) | (a << 30)) ^
|
||||
((a >>> 13) | (a << 19)) ^
|
||||
((a >>> 22) | (a << 10));
|
||||
var maj = ((a & b) ^ (a & c) ^ (b & c));
|
||||
var t2 = (S0 + maj) | 0;
|
||||
var S1 = ((e >>> 6) | (e << 26)) ^
|
||||
((e >>> 11) | (e << 21)) ^
|
||||
((e >>> 25) | (e << 7));
|
||||
var ch = ((e & f) ^ ((~ e) & g));
|
||||
|
||||
var partialSum1 = (h + S1) | 0;
|
||||
var partialSum2 = (ch + (goog.crypt.Sha2.Kx_[i] | 0)) | 0;
|
||||
var partialSum3 = (partialSum2 + (w[i & 15] | 0)) | 0;
|
||||
var t1 = (partialSum1 + partialSum3) | 0;
|
||||
|
||||
h = g;
|
||||
g = f;
|
||||
f = e;
|
||||
e = (d + t1) | 0;
|
||||
d = c;
|
||||
c = b;
|
||||
b = a;
|
||||
a = (t1 + t2) | 0;
|
||||
}
|
||||
|
||||
this.hash_[0] = (this.hash_[0] + a) | 0;
|
||||
this.hash_[1] = (this.hash_[1] + b) | 0;
|
||||
this.hash_[2] = (this.hash_[2] + c) | 0;
|
||||
this.hash_[3] = (this.hash_[3] + d) | 0;
|
||||
this.hash_[4] = (this.hash_[4] + e) | 0;
|
||||
this.hash_[5] = (this.hash_[5] + f) | 0;
|
||||
this.hash_[6] = (this.hash_[6] + g) | 0;
|
||||
this.hash_[7] = (this.hash_[7] + h) | 0;
|
||||
};
|
||||
|
||||
|
||||
/** @override */
|
||||
goog.crypt.Sha2.prototype.update = function(bytes, opt_length) {
|
||||
if (!goog.isDef(opt_length)) {
|
||||
opt_length = bytes.length;
|
||||
}
|
||||
opt_length = (bytes.length < opt_length) ? bytes.length : opt_length;
|
||||
// Process the message from left to right up to |opt_length| bytes.
|
||||
// When we get a 512-bit chunk, compute the hash of it and reset
|
||||
// this.chunk_. If the message isn't a multiple of 64 bytes (512 bits)
|
||||
// we store the partial chunk in this.chunk_, and the index of the end
|
||||
// of the partial chunk into this.inChunk_.
|
||||
var n = 0;
|
||||
var inbuf = this.inChunk_;
|
||||
var buf = this.chunk_;
|
||||
var lengthMinusBlock = opt_length - this.blockSize;
|
||||
// The outer while loop should execute at most twice.
|
||||
while (n < opt_length) {
|
||||
// When we have no data in the block to top up, we can directly process the
|
||||
// input buffer (assuming it contains sufficient data). This gives ~25%
|
||||
// speedup on Chrome 23 and ~15% speedup on Firefox 16, but requires that
|
||||
// the data is provided in large chunks (or in multiples of 64 bytes).
|
||||
if (inbuf == 0) {
|
||||
while (n <= lengthMinusBlock) {
|
||||
this.computeChunk_(bytes, n);
|
||||
n += this.blockSize;
|
||||
}
|
||||
}
|
||||
|
||||
if (goog.isString(bytes)) {
|
||||
while (n < opt_length) {
|
||||
buf[inbuf] = bytes.charCodeAt(n);
|
||||
++inbuf;
|
||||
++n;
|
||||
if (inbuf == this.blockSize) {
|
||||
this.computeChunk_(buf);
|
||||
inbuf = 0;
|
||||
// Jump to the outer loop so we use the full-block optimization.
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
while (n < opt_length) {
|
||||
buf[inbuf] = bytes[n];
|
||||
++inbuf;
|
||||
++n;
|
||||
if (inbuf == this.blockSize) {
|
||||
this.computeChunk_(buf);
|
||||
inbuf = 0;
|
||||
// Jump to the outer loop so we use the full-block optimization.
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Save the current position in this.chunk_ to support partial updates.
|
||||
this.inChunk_ = inbuf;
|
||||
|
||||
// Update the total message bytes processed.
|
||||
this.total_ += opt_length;
|
||||
};
|
||||
|
||||
|
||||
/** @override */
|
||||
goog.crypt.Sha2.prototype.digest = function() {
|
||||
var digest = [];
|
||||
var totalBits = this.total_ * 8;
|
||||
|
||||
// Append pad 0x80 0x00*.
|
||||
if (this.inChunk_ < 56) {
|
||||
this.update(goog.crypt.Sha2.PADDING_, 56 - this.inChunk_);
|
||||
} else {
|
||||
this.update(goog.crypt.Sha2.PADDING_,
|
||||
this.blockSize - (this.inChunk_ - 56));
|
||||
}
|
||||
|
||||
// Append number of bits as a big-endian 64-bit uint.
|
||||
for (var i = 63; i >= 56; i--) {
|
||||
this.chunk_[i] = totalBits & 255;
|
||||
totalBits /= 256; // Don't use bit-shifting here!
|
||||
}
|
||||
this.computeChunk_(this.chunk_);
|
||||
|
||||
// Finally, output the result's digest.
|
||||
var n = 0;
|
||||
for (var i = 0; i < this.numHashBlocks_; i++) {
|
||||
for (var j = 24; j >= 0; j -= 8) {
|
||||
digest[n++] = ((this.hash_[i] >> j) & 255);
|
||||
}
|
||||
}
|
||||
return digest;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Constants used in SHA-2.
|
||||
* @const
|
||||
* @private {!Array<number>}
|
||||
*/
|
||||
goog.crypt.Sha2.K_ = [
|
||||
0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5,
|
||||
0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5,
|
||||
0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3,
|
||||
0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174,
|
||||
0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc,
|
||||
0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da,
|
||||
0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7,
|
||||
0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967,
|
||||
0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13,
|
||||
0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85,
|
||||
0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3,
|
||||
0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070,
|
||||
0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5,
|
||||
0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3,
|
||||
0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208,
|
||||
0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2
|
||||
];
|
||||
|
||||
|
||||
/**
|
||||
* Sha2.K as an Int32Array if this JS supports typed arrays; otherwise,
|
||||
* the same array as Sha2.K.
|
||||
*
|
||||
* The compiler cannot remove an Int32Array, even if it is not needed
|
||||
* (There are certain cases where creating an Int32Array is not
|
||||
* side-effect free). Instead, the first time we construct a Sha2
|
||||
* instance, we convert or assign Sha2.K as appropriate.
|
||||
* @private {undefined|!Array<number>|!Int32Array}
|
||||
*/
|
||||
goog.crypt.Sha2.Kx_;
|
||||
@@ -0,0 +1,50 @@
|
||||
// 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 SHA-224 cryptographic hash.
|
||||
*
|
||||
* Usage:
|
||||
* var sha224 = new goog.crypt.Sha224();
|
||||
* sha224.update(bytes);
|
||||
* var hash = sha224.digest();
|
||||
*
|
||||
*/
|
||||
|
||||
goog.provide('goog.crypt.Sha224');
|
||||
|
||||
goog.require('goog.crypt.Sha2');
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* SHA-224 cryptographic hash constructor.
|
||||
*
|
||||
* @constructor
|
||||
* @extends {goog.crypt.Sha2}
|
||||
* @final
|
||||
* @struct
|
||||
*/
|
||||
goog.crypt.Sha224 = function() {
|
||||
goog.crypt.Sha224.base(this, 'constructor',
|
||||
7, goog.crypt.Sha224.INIT_HASH_BLOCK_);
|
||||
};
|
||||
goog.inherits(goog.crypt.Sha224, goog.crypt.Sha2);
|
||||
|
||||
|
||||
/** @private {!Array<number>} */
|
||||
goog.crypt.Sha224.INIT_HASH_BLOCK_ = [
|
||||
0xc1059ed8, 0x367cd507, 0x3070dd17, 0xf70e5939,
|
||||
0xffc00b31, 0x68581511, 0x64f98fa7, 0xbefa4fa4];
|
||||
|
||||
@@ -0,0 +1,40 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<!--
|
||||
Copyright 2012 The Closure Library Authors. All Rights Reserved.
|
||||
|
||||
Use of this source code is governed by the Apache License, Version 2.0.
|
||||
See the COPYING file for details.
|
||||
|
||||
-->
|
||||
<head>
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||
<title>Closure Performance Tests - goog.crypt.Sha224</title>
|
||||
<link rel="stylesheet" type="text/css" href="../testing/performancetable.css"/>
|
||||
<script src="../base.js"></script>
|
||||
<script>
|
||||
goog.require('goog.crypt.Sha224');
|
||||
goog.require('goog.crypt.hashTester');
|
||||
goog.require('goog.testing.PerformanceTable');
|
||||
goog.require('goog.testing.PseudoRandom');
|
||||
goog.require('goog.testing.jsunit');
|
||||
</script>
|
||||
</head>
|
||||
<body>
|
||||
<h1>Closure Performance Tests - goog.crypt.Sha224</h1>
|
||||
<p>
|
||||
<strong>User-agent:</strong>
|
||||
<script>document.write(navigator.userAgent);</script>
|
||||
</p>
|
||||
|
||||
<script>
|
||||
|
||||
function testHashing() {
|
||||
goog.crypt.hashTester.runPerfTests(function() {
|
||||
return new goog.crypt.Sha224();
|
||||
}, 'SHA224');
|
||||
}
|
||||
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,22 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<!--
|
||||
Copyright 2012 The Closure Library Authors. All Rights Reserved.
|
||||
|
||||
Use of this source code is governed by the Apache License, Version 2.0.
|
||||
See the COPYING file for details.
|
||||
-->
|
||||
<head>
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
|
||||
<title>
|
||||
Closure Unit Tests - goog.crypt.sha224
|
||||
</title>
|
||||
<script src="../base.js">
|
||||
</script>
|
||||
<script>
|
||||
goog.require('goog.crypt.Sha224Test');
|
||||
</script>
|
||||
</head>
|
||||
<body>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,75 @@
|
||||
// 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.
|
||||
|
||||
goog.provide('goog.crypt.Sha224Test');
|
||||
goog.setTestOnly('goog.crypt.Sha224Test');
|
||||
|
||||
goog.require('goog.crypt');
|
||||
goog.require('goog.crypt.Sha224');
|
||||
goog.require('goog.crypt.hashTester');
|
||||
goog.require('goog.testing.jsunit');
|
||||
|
||||
function testBasicOperations() {
|
||||
var sha224 = new goog.crypt.Sha224();
|
||||
goog.crypt.hashTester.runBasicTests(sha224);
|
||||
}
|
||||
|
||||
function testHashing() {
|
||||
// Some test vectors from:
|
||||
// csrc.nist.gov/publications/fips/fips180-2/fips180-2withchangenotice.pdf
|
||||
|
||||
var sha224 = new goog.crypt.Sha224();
|
||||
|
||||
// NIST one block test vector.
|
||||
sha224.update(goog.crypt.stringToByteArray('abc'));
|
||||
assertEquals(
|
||||
'23097d223405d8228642a477bda255b32aadbce4bda0b3f7e36c9da7',
|
||||
goog.crypt.byteArrayToHex(sha224.digest()));
|
||||
|
||||
// NIST multi-block test vector.
|
||||
sha224.reset();
|
||||
sha224.update(
|
||||
goog.crypt.stringToByteArray(
|
||||
'abcdbcdecdefdefgefghfghighij' +
|
||||
'hijkijkljklmklmnlmnomnopnopq'));
|
||||
assertEquals(
|
||||
'75388b16512776cc5dba5da1fd890150b0c6455cb4f58b1952522525',
|
||||
goog.crypt.byteArrayToHex(sha224.digest()));
|
||||
|
||||
// Message larger than one block (but less than two).
|
||||
sha224.reset();
|
||||
var biggerThanOneBlock = 'abcdbcdecdefdefgefghfghighij' +
|
||||
'hijkijkljklmklmnlmnomnopnopq' +
|
||||
'asdfljhr78yasdfljh45opa78sdf' +
|
||||
'120839414104897aavnasdfafasd';
|
||||
assertTrue(biggerThanOneBlock.length > goog.crypt.Sha2.BLOCKSIZE_ &&
|
||||
biggerThanOneBlock.length < 2 * goog.crypt.Sha2.BLOCKSIZE_);
|
||||
sha224.update(goog.crypt.stringToByteArray(biggerThanOneBlock));
|
||||
assertEquals(
|
||||
'27c9b678012becd6891bac653f355b2d26f63132e840644d565f5dac',
|
||||
goog.crypt.byteArrayToHex(sha224.digest()));
|
||||
|
||||
// Message larger than two blocks.
|
||||
sha224.reset();
|
||||
var biggerThanTwoBlocks = 'abcdbcdecdefdefgefghfghighij' +
|
||||
'hijkijkljklmklmnlmnomnopnopq' +
|
||||
'asdfljhr78yasdfljh45opa78sdf' +
|
||||
'120839414104897aavnasdfafasd' +
|
||||
'laasdouvhalacbnalalseryalcla';
|
||||
assertTrue(biggerThanTwoBlocks.length > 2 * goog.crypt.Sha2.BLOCKSIZE_);
|
||||
sha224.update(goog.crypt.stringToByteArray(biggerThanTwoBlocks));
|
||||
assertEquals(
|
||||
'1c2c1455cc984eef6f25ec9d79b1c661b3794887c3d0b24111ed9803',
|
||||
goog.crypt.byteArrayToHex(sha224.digest()));
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
// 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 SHA-256 cryptographic hash.
|
||||
*
|
||||
* Usage:
|
||||
* var sha256 = new goog.crypt.Sha256();
|
||||
* sha256.update(bytes);
|
||||
* var hash = sha256.digest();
|
||||
*
|
||||
*/
|
||||
|
||||
goog.provide('goog.crypt.Sha256');
|
||||
|
||||
goog.require('goog.crypt.Sha2');
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* SHA-256 cryptographic hash constructor.
|
||||
*
|
||||
* @constructor
|
||||
* @extends {goog.crypt.Sha2}
|
||||
* @final
|
||||
* @struct
|
||||
*/
|
||||
goog.crypt.Sha256 = function() {
|
||||
goog.crypt.Sha256.base(this, 'constructor',
|
||||
8, goog.crypt.Sha256.INIT_HASH_BLOCK_);
|
||||
};
|
||||
goog.inherits(goog.crypt.Sha256, goog.crypt.Sha2);
|
||||
|
||||
|
||||
/** @private {!Array<number>} */
|
||||
goog.crypt.Sha256.INIT_HASH_BLOCK_ = [
|
||||
0x6a09e667, 0xbb67ae85, 0x3c6ef372, 0xa54ff53a,
|
||||
0x510e527f, 0x9b05688c, 0x1f83d9ab, 0x5be0cd19];
|
||||
@@ -0,0 +1,40 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<!--
|
||||
Copyright 2012 The Closure Library Authors. All Rights Reserved.
|
||||
|
||||
Use of this source code is governed by the Apache License, Version 2.0.
|
||||
See the COPYING file for details.
|
||||
|
||||
-->
|
||||
<head>
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||
<title>Closure Performance Tests - goog.crypt.Sha256</title>
|
||||
<link rel="stylesheet" type="text/css" href="../testing/performancetable.css"/>
|
||||
<script src="../base.js"></script>
|
||||
<script>
|
||||
goog.require('goog.crypt.Sha256');
|
||||
goog.require('goog.crypt.hashTester');
|
||||
goog.require('goog.testing.PerformanceTable');
|
||||
goog.require('goog.testing.PseudoRandom');
|
||||
goog.require('goog.testing.jsunit');
|
||||
</script>
|
||||
</head>
|
||||
<body>
|
||||
<h1>Closure Performance Tests - goog.crypt.Sha256</h1>
|
||||
<p>
|
||||
<strong>User-agent:</strong>
|
||||
<script>document.write(navigator.userAgent);</script>
|
||||
</p>
|
||||
|
||||
<script>
|
||||
|
||||
function testHashing() {
|
||||
goog.crypt.hashTester.runPerfTests(function() {
|
||||
return new goog.crypt.Sha256();
|
||||
}, 'SHA256');
|
||||
}
|
||||
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,22 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<!--
|
||||
Copyright 2012 The Closure Library Authors. All Rights Reserved.
|
||||
|
||||
Use of this source code is governed by the Apache License, Version 2.0.
|
||||
See the COPYING file for details.
|
||||
-->
|
||||
<head>
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
|
||||
<title>
|
||||
Closure Unit Tests - goog.crypt.sha256
|
||||
</title>
|
||||
<script src="../base.js">
|
||||
</script>
|
||||
<script>
|
||||
goog.require('goog.crypt.Sha256Test');
|
||||
</script>
|
||||
</head>
|
||||
<body>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,102 @@
|
||||
// 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.
|
||||
|
||||
goog.provide('goog.crypt.Sha256Test');
|
||||
goog.setTestOnly('goog.crypt.Sha256Test');
|
||||
|
||||
goog.require('goog.array');
|
||||
goog.require('goog.crypt');
|
||||
goog.require('goog.crypt.Sha256');
|
||||
goog.require('goog.crypt.hashTester');
|
||||
goog.require('goog.testing.jsunit');
|
||||
|
||||
function testBasicOperations() {
|
||||
var sha256 = new goog.crypt.Sha256();
|
||||
goog.crypt.hashTester.runBasicTests(sha256);
|
||||
}
|
||||
|
||||
function testHashing() {
|
||||
// Some test vectors from:
|
||||
// csrc.nist.gov/publications/fips/fips180-2/fips180-2withchangenotice.pdf
|
||||
|
||||
var sha256 = new goog.crypt.Sha256();
|
||||
|
||||
// Empty message.
|
||||
sha256.update([]);
|
||||
assertEquals(
|
||||
'e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855',
|
||||
goog.crypt.byteArrayToHex(sha256.digest()));
|
||||
|
||||
// NIST one block test vector.
|
||||
sha256.reset();
|
||||
sha256.update(goog.crypt.stringToByteArray('abc'));
|
||||
assertEquals(
|
||||
'ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad',
|
||||
goog.crypt.byteArrayToHex(sha256.digest()));
|
||||
|
||||
// NIST multi-block test vector.
|
||||
sha256.reset();
|
||||
sha256.update(
|
||||
goog.crypt.stringToByteArray(
|
||||
'abcdbcdecdefdefgefghfghighij' +
|
||||
'hijkijkljklmklmnlmnomnopnopq'));
|
||||
assertEquals(
|
||||
'248d6a61d20638b8e5c026930c3e6039a33ce45964ff2167f6ecedd419db06c1',
|
||||
goog.crypt.byteArrayToHex(sha256.digest()));
|
||||
|
||||
// Message larger than one block (but less than two).
|
||||
sha256.reset();
|
||||
var biggerThanOneBlock = 'abcdbcdecdefdefgefghfghighij' +
|
||||
'hijkijkljklmklmnlmnomnopnopq' +
|
||||
'asdfljhr78yasdfljh45opa78sdf' +
|
||||
'120839414104897aavnasdfafasd';
|
||||
assertTrue(biggerThanOneBlock.length > goog.crypt.Sha2.BLOCKSIZE_ &&
|
||||
biggerThanOneBlock.length < 2 * goog.crypt.Sha2.BLOCKSIZE_);
|
||||
sha256.update(goog.crypt.stringToByteArray(biggerThanOneBlock));
|
||||
assertEquals(
|
||||
'390a5035433e46b740600f3117d11ece3c64706dc889106666ac04fe4f458abc',
|
||||
goog.crypt.byteArrayToHex(sha256.digest()));
|
||||
|
||||
// Message larger than two blocks.
|
||||
sha256.reset();
|
||||
var biggerThanTwoBlocks = 'abcdbcdecdefdefgefghfghighij' +
|
||||
'hijkijkljklmklmnlmnomnopnopq' +
|
||||
'asdfljhr78yasdfljh45opa78sdf' +
|
||||
'120839414104897aavnasdfafasd' +
|
||||
'laasdouvhalacbnalalseryalcla';
|
||||
assertTrue(biggerThanTwoBlocks.length > 2 * goog.crypt.Sha2.BLOCKSIZE_);
|
||||
sha256.update(goog.crypt.stringToByteArray(biggerThanTwoBlocks));
|
||||
assertEquals(
|
||||
'd655c513fd347e9be372d891f8bb42895ca310fabf6ead6681ebc66a04e84db5',
|
||||
goog.crypt.byteArrayToHex(sha256.digest()));
|
||||
}
|
||||
|
||||
function testPreschedule() {
|
||||
// Test using prescheduled messages.
|
||||
var sha = new goog.crypt.Sha256();
|
||||
var message = goog.crypt.hexToByteArray(
|
||||
'd9b28b643d16efc8a17a532c05deb79069421bf4cda67f58310ae3bc956e4720' +
|
||||
'f9d2ab845d360fe8c19a734c25fed7b089623b14edc69f78512a03dcb58e6740');
|
||||
|
||||
var scheduled = sha.preschedule(message);
|
||||
sha.scheduledUpdate(scheduled);
|
||||
var w_scheduled = goog.array.toArray(sha.hash_);
|
||||
var digest_scheduled = sha.digest();
|
||||
|
||||
sha.reset();
|
||||
sha.update(message);
|
||||
var w_afterupdate = goog.array.toArray(sha.hash_);
|
||||
assertElementsEquals(w_scheduled, w_afterupdate);
|
||||
assertElementsEquals(sha.digest(), digest_scheduled);
|
||||
}
|
||||
@@ -0,0 +1,550 @@
|
||||
// Copyright 2014 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 Base class for the 64-bit SHA-2 cryptographic hashes.
|
||||
*
|
||||
* Variable names follow the notation in FIPS PUB 180-3:
|
||||
* http://csrc.nist.gov/publications/fips/fips180-3/fips180-3_final.pdf.
|
||||
*
|
||||
* This code borrows heavily from the 32-bit SHA2 implementation written by
|
||||
* Yue Zhang (zysxqn@).
|
||||
*
|
||||
* @author fy@google.com (Frank Yellin)
|
||||
*/
|
||||
|
||||
goog.provide('goog.crypt.Sha2_64bit');
|
||||
|
||||
goog.require('goog.array');
|
||||
goog.require('goog.asserts');
|
||||
goog.require('goog.crypt.Hash');
|
||||
goog.require('goog.math.Long');
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Constructs a SHA-2 64-bit cryptographic hash.
|
||||
* This class should not be used. Rather, one should use one of its
|
||||
* subclasses.
|
||||
* @constructor
|
||||
* @param {number} numHashBlocks The size of the output in 16-byte blocks
|
||||
* @param {!Array<number>} initHashBlocks The hash-specific initialization
|
||||
* vector, as a sequence of sixteen 32-bit numbers.
|
||||
* @extends {goog.crypt.Hash}
|
||||
* @struct
|
||||
*/
|
||||
goog.crypt.Sha2_64bit = function(numHashBlocks, initHashBlocks) {
|
||||
goog.crypt.Sha2_64bit.base(this, 'constructor');
|
||||
|
||||
/**
|
||||
* The number of bytes that are digested in each pass of this hasher.
|
||||
* @const {number}
|
||||
*/
|
||||
this.blockSize = goog.crypt.Sha2_64bit.BLOCK_SIZE_;
|
||||
|
||||
/**
|
||||
* A chunk holding the currently processed message bytes. Once the chunk has
|
||||
* {@code this.blocksize} bytes, we feed it into [@code computeChunk_}.
|
||||
* @private {!Uint8Array|!Array<number>}
|
||||
*/
|
||||
this.chunk_ = goog.isDef(goog.global.Uint8Array) ?
|
||||
new Uint8Array(goog.crypt.Sha2_64bit.BLOCK_SIZE_) :
|
||||
new Array(goog.crypt.Sha2_64bit.BLOCK_SIZE_);
|
||||
|
||||
/**
|
||||
* Current number of bytes in {@code this.chunk_}.
|
||||
* @private {number}
|
||||
*/
|
||||
this.chunkBytes_ = 0;
|
||||
|
||||
/**
|
||||
* Total number of bytes in currently processed message.
|
||||
* @private {number}
|
||||
*/
|
||||
this.total_ = 0;
|
||||
|
||||
/**
|
||||
* Holds the previous values of accumulated hash a-h in the
|
||||
* {@code computeChunk_} function.
|
||||
* @private {!Array<!goog.math.Long>}
|
||||
*/
|
||||
this.hash_ = [];
|
||||
|
||||
/**
|
||||
* The number of blocks of output produced by this hash function, where each
|
||||
* block is eight bytes long.
|
||||
* @private {number}
|
||||
*/
|
||||
this.numHashBlocks_ = numHashBlocks;
|
||||
|
||||
/**
|
||||
* Temporary array used in chunk computation. Allocate here as a
|
||||
* member rather than as a local within computeChunk_() as a
|
||||
* performance optimization to reduce the number of allocations and
|
||||
* reduce garbage collection.
|
||||
* @type {!Array<!goog.math.Long>}
|
||||
* @private
|
||||
*/
|
||||
this.w_ = [];
|
||||
|
||||
/**
|
||||
* The value to which {@code this.hash_} should be reset when this
|
||||
* Hasher is reset.
|
||||
* @private @const {!Array<!goog.math.Long>}
|
||||
*/
|
||||
this.initHashBlocks_ = goog.crypt.Sha2_64bit.toLongArray_(initHashBlocks);
|
||||
|
||||
/**
|
||||
* If true, we have taken the digest from this hasher, but we have not
|
||||
* yet reset it.
|
||||
*
|
||||
* @private {boolean}
|
||||
*/
|
||||
this.needsReset_ = false;
|
||||
|
||||
this.reset();
|
||||
};
|
||||
goog.inherits(goog.crypt.Sha2_64bit, goog.crypt.Hash);
|
||||
|
||||
|
||||
/**
|
||||
* The number of bytes that are digested in each pass of this hasher.
|
||||
* @private @const {number}
|
||||
*/
|
||||
goog.crypt.Sha2_64bit.BLOCK_SIZE_ = 1024 / 8;
|
||||
|
||||
|
||||
/**
|
||||
* Contains data needed to pad messages less than {@code blocksize} bytes.
|
||||
* @private {!Array<number>}
|
||||
*/
|
||||
goog.crypt.Sha2_64bit.PADDING_ = goog.array.concat(
|
||||
[0x80], goog.array.repeat(0, goog.crypt.Sha2_64bit.BLOCK_SIZE_ - 1));
|
||||
|
||||
|
||||
/**
|
||||
* Resets this hash function.
|
||||
* @override
|
||||
*/
|
||||
goog.crypt.Sha2_64bit.prototype.reset = function() {
|
||||
this.chunkBytes_ = 0;
|
||||
this.total_ = 0;
|
||||
this.hash_ = goog.array.clone(this.initHashBlocks_);
|
||||
this.needsReset_ = false;
|
||||
};
|
||||
|
||||
|
||||
/** @override */
|
||||
goog.crypt.Sha2_64bit.prototype.update = function(message, opt_length) {
|
||||
var length = goog.isDef(opt_length) ? opt_length : message.length;
|
||||
|
||||
// Make sure this hasher is usable.
|
||||
if (this.needsReset_) {
|
||||
throw Error('this hasher needs to be reset');
|
||||
}
|
||||
// Process the message from left to right up to |length| bytes.
|
||||
// When we get a 512-bit chunk, compute the hash of it and reset
|
||||
// this.chunk_. The message might not be multiple of 512 bits so we
|
||||
// might end up with a chunk that is less than 512 bits. We store
|
||||
// such partial chunk in chunk_ and it will be filled up later
|
||||
// in digest().
|
||||
var chunkBytes = this.chunkBytes_;
|
||||
|
||||
// The input message could be either byte array or string.
|
||||
if (goog.isString(message)) {
|
||||
for (var i = 0; i < length; i++) {
|
||||
var b = message.charCodeAt(i);
|
||||
if (b > 255) {
|
||||
throw Error('Characters must be in range [0,255]');
|
||||
}
|
||||
this.chunk_[chunkBytes++] = b;
|
||||
if (chunkBytes == this.blockSize) {
|
||||
this.computeChunk_();
|
||||
chunkBytes = 0;
|
||||
}
|
||||
}
|
||||
} else if (goog.isArray(message)) {
|
||||
for (var i = 0; i < length; i++) {
|
||||
var b = message[i];
|
||||
// Hack: b|0 coerces b to an integer, so the last part confirms that
|
||||
// b has no fractional part.
|
||||
if (!goog.isNumber(b) || b < 0 || b > 255 || b != (b | 0)) {
|
||||
throw Error('message must be a byte array');
|
||||
}
|
||||
this.chunk_[chunkBytes++] = b;
|
||||
if (chunkBytes == this.blockSize) {
|
||||
this.computeChunk_();
|
||||
chunkBytes = 0;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
throw Error('message must be string or array');
|
||||
}
|
||||
|
||||
// Record the current bytes in chunk to support partial update.
|
||||
this.chunkBytes_ = chunkBytes;
|
||||
|
||||
// Record total message bytes we have processed so far.
|
||||
this.total_ += length;
|
||||
};
|
||||
|
||||
|
||||
/** @override */
|
||||
goog.crypt.Sha2_64bit.prototype.digest = function() {
|
||||
if (this.needsReset_) {
|
||||
throw Error('this hasher needs to be reset');
|
||||
}
|
||||
var totalBits = this.total_ * 8;
|
||||
|
||||
// Append pad 0x80 0x00* until this.chunkBytes_ == 112
|
||||
if (this.chunkBytes_ < 112) {
|
||||
this.update(goog.crypt.Sha2_64bit.PADDING_, 112 - this.chunkBytes_);
|
||||
} else {
|
||||
// the rest of this block, plus 112 bytes of next block
|
||||
this.update(goog.crypt.Sha2_64bit.PADDING_,
|
||||
this.blockSize - this.chunkBytes_ + 112);
|
||||
}
|
||||
|
||||
// Append # bits in the 64-bit big-endian format.
|
||||
for (var i = 127; i >= 112; i--) {
|
||||
this.chunk_[i] = totalBits & 255;
|
||||
totalBits /= 256; // Don't use bit-shifting here!
|
||||
}
|
||||
this.computeChunk_();
|
||||
|
||||
// Finally, output the result digest.
|
||||
var n = 0;
|
||||
var digest = new Array(8 * this.numHashBlocks_);
|
||||
for (var i = 0; i < this.numHashBlocks_; i++) {
|
||||
var block = this.hash_[i];
|
||||
var high = block.getHighBits();
|
||||
var low = block.getLowBits();
|
||||
for (var j = 24; j >= 0; j -= 8) {
|
||||
digest[n++] = ((high >> j) & 255);
|
||||
}
|
||||
for (var j = 24; j >= 0; j -= 8) {
|
||||
digest[n++] = ((low >> j) & 255);
|
||||
}
|
||||
}
|
||||
|
||||
// The next call to this hasher must be a reset
|
||||
this.needsReset_ = true;
|
||||
return digest;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Updates this hash by processing the 1024-bit message chunk in this.chunk_.
|
||||
* @private
|
||||
*/
|
||||
goog.crypt.Sha2_64bit.prototype.computeChunk_ = function() {
|
||||
var chunk = this.chunk_;
|
||||
var K_ = goog.crypt.Sha2_64bit.K_;
|
||||
|
||||
// Divide the chunk into 16 64-bit-words.
|
||||
var w = this.w_;
|
||||
for (var i = 0; i < 16; i++) {
|
||||
var offset = i * 8;
|
||||
w[i] = new goog.math.Long(
|
||||
(chunk[offset + 4] << 24) | (chunk[offset + 5] << 16) |
|
||||
(chunk[offset + 6] << 8) | (chunk[offset + 7]),
|
||||
(chunk[offset] << 24) | (chunk[offset + 1] << 16) |
|
||||
(chunk[offset + 2] << 8) | (chunk[offset + 3]));
|
||||
|
||||
}
|
||||
|
||||
// Extend the w[] array to be the number of rounds.
|
||||
for (var i = 16; i < 80; i++) {
|
||||
var s0 = this.sigma0_(w[i - 15]);
|
||||
var s1 = this.sigma1_(w[i - 2]);
|
||||
w[i] = this.sum_(w[i - 16], w[i - 7], s0, s1);
|
||||
}
|
||||
|
||||
var a = this.hash_[0];
|
||||
var b = this.hash_[1];
|
||||
var c = this.hash_[2];
|
||||
var d = this.hash_[3];
|
||||
var e = this.hash_[4];
|
||||
var f = this.hash_[5];
|
||||
var g = this.hash_[6];
|
||||
var h = this.hash_[7];
|
||||
for (var i = 0; i < 80; i++) {
|
||||
var S0 = this.Sigma0_(a);
|
||||
var maj = this.majority_(a, b, c);
|
||||
var t2 = S0.add(maj);
|
||||
var S1 = this.Sigma1_(e);
|
||||
var ch = this.choose_(e, f, g);
|
||||
var t1 = this.sum_(h, S1, ch, K_[i], w[i]);
|
||||
h = g;
|
||||
g = f;
|
||||
f = e;
|
||||
e = d.add(t1);
|
||||
d = c;
|
||||
c = b;
|
||||
b = a;
|
||||
a = t1.add(t2);
|
||||
}
|
||||
|
||||
this.hash_[0] = this.hash_[0].add(a);
|
||||
this.hash_[1] = this.hash_[1].add(b);
|
||||
this.hash_[2] = this.hash_[2].add(c);
|
||||
this.hash_[3] = this.hash_[3].add(d);
|
||||
this.hash_[4] = this.hash_[4].add(e);
|
||||
this.hash_[5] = this.hash_[5].add(f);
|
||||
this.hash_[6] = this.hash_[6].add(g);
|
||||
this.hash_[7] = this.hash_[7].add(h);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Calculates the SHA2 64-bit sigma0 function.
|
||||
* rotateRight(value, 1) ^ rotateRight(value, 8) ^ (value >>> 7)
|
||||
*
|
||||
* @private
|
||||
* @param {!goog.math.Long} value
|
||||
* @return {!goog.math.Long}
|
||||
*/
|
||||
goog.crypt.Sha2_64bit.prototype.sigma0_ = function(value) {
|
||||
var valueLow = value.getLowBits();
|
||||
var valueHigh = value.getHighBits();
|
||||
// Implementation note: We purposely do not use the shift operations defined
|
||||
// in goog.math.Long. Inlining the code for specific values of shifting and
|
||||
// not generating the intermediate results doubles the speed of this code.
|
||||
var low = (valueLow >>> 1) ^ (valueHigh << 31) ^
|
||||
(valueLow >>> 8) ^ (valueHigh << 24) ^
|
||||
(valueLow >>> 7) ^ (valueHigh << 25);
|
||||
var high = (valueHigh >>> 1) ^ (valueLow << 31) ^
|
||||
(valueHigh >>> 8) ^ (valueLow << 24) ^
|
||||
(valueHigh >>> 7);
|
||||
return new goog.math.Long(low, high);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Calculates the SHA2 64-bit sigma1 function.
|
||||
* rotateRight(value, 19) ^ rotateRight(value, 61) ^ (value >>> 6)
|
||||
*
|
||||
* @private
|
||||
* @param {!goog.math.Long} value
|
||||
* @return {!goog.math.Long}
|
||||
*/
|
||||
goog.crypt.Sha2_64bit.prototype.sigma1_ = function(value) {
|
||||
var valueLow = value.getLowBits();
|
||||
var valueHigh = value.getHighBits();
|
||||
// Implementation note: See _sigma0() above
|
||||
var low = (valueLow >>> 19) ^ (valueHigh << 13) ^
|
||||
(valueHigh >>> 29) ^ (valueLow << 3) ^
|
||||
(valueLow >>> 6) ^ (valueHigh << 26);
|
||||
var high = (valueHigh >>> 19) ^ (valueLow << 13) ^
|
||||
(valueLow >>> 29) ^ (valueHigh << 3) ^
|
||||
(valueHigh >>> 6);
|
||||
return new goog.math.Long(low, high);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Calculates the SHA2 64-bit Sigma0 function.
|
||||
* rotateRight(value, 28) ^ rotateRight(value, 34) ^ rotateRight(value, 39)
|
||||
*
|
||||
* @private
|
||||
* @param {!goog.math.Long} value
|
||||
* @return {!goog.math.Long}
|
||||
*/
|
||||
goog.crypt.Sha2_64bit.prototype.Sigma0_ = function(value) {
|
||||
var valueLow = value.getLowBits();
|
||||
var valueHigh = value.getHighBits();
|
||||
// Implementation note: See _sigma0() above
|
||||
var low = (valueLow >>> 28) ^ (valueHigh << 4) ^
|
||||
(valueHigh >>> 2) ^ (valueLow << 30) ^
|
||||
(valueHigh >>> 7) ^ (valueLow << 25);
|
||||
var high = (valueHigh >>> 28) ^ (valueLow << 4) ^
|
||||
(valueLow >>> 2) ^ (valueHigh << 30) ^
|
||||
(valueLow >>> 7) ^ (valueHigh << 25);
|
||||
return new goog.math.Long(low, high);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Calculates the SHA2 64-bit Sigma1 function.
|
||||
* rotateRight(value, 14) ^ rotateRight(value, 18) ^ rotateRight(value, 41)
|
||||
*
|
||||
* @private
|
||||
* @param {!goog.math.Long} value
|
||||
* @return {!goog.math.Long}
|
||||
*/
|
||||
goog.crypt.Sha2_64bit.prototype.Sigma1_ = function(value) {
|
||||
var valueLow = value.getLowBits();
|
||||
var valueHigh = value.getHighBits();
|
||||
// Implementation note: See _sigma0() above
|
||||
var low = (valueLow >>> 14) ^ (valueHigh << 18) ^
|
||||
(valueLow >>> 18) ^ (valueHigh << 14) ^
|
||||
(valueHigh >>> 9) ^ (valueLow << 23);
|
||||
var high = (valueHigh >>> 14) ^ (valueLow << 18) ^
|
||||
(valueHigh >>> 18) ^ (valueLow << 14) ^
|
||||
(valueLow >>> 9) ^ (valueHigh << 23);
|
||||
return new goog.math.Long(low, high);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Calculates the SHA-2 64-bit choose function.
|
||||
*
|
||||
* This function uses {@code value} as a mask to choose bits from either
|
||||
* {@code one} if the bit is set or {@code two} if the bit is not set.
|
||||
*
|
||||
* @private
|
||||
* @param {!goog.math.Long} value
|
||||
* @param {!goog.math.Long} one
|
||||
* @param {!goog.math.Long} two
|
||||
* @return {!goog.math.Long}
|
||||
*/
|
||||
goog.crypt.Sha2_64bit.prototype.choose_ = function(value, one, two) {
|
||||
var valueLow = value.getLowBits();
|
||||
var valueHigh = value.getHighBits();
|
||||
return new goog.math.Long(
|
||||
(valueLow & one.getLowBits()) | (~valueLow & two.getLowBits()),
|
||||
(valueHigh & one.getHighBits()) | (~valueHigh & two.getHighBits()));
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Calculates the SHA-2 64-bit majority function.
|
||||
* This function returns, for each bit position, the bit held by the majority
|
||||
* of its three arguments.
|
||||
*
|
||||
* @private
|
||||
* @param {!goog.math.Long} one
|
||||
* @param {!goog.math.Long} two
|
||||
* @param {!goog.math.Long} three
|
||||
* @return {!goog.math.Long}
|
||||
*/
|
||||
goog.crypt.Sha2_64bit.prototype.majority_ = function(one, two, three) {
|
||||
return new goog.math.Long(
|
||||
(one.getLowBits() & two.getLowBits()) |
|
||||
(two.getLowBits() & three.getLowBits()) |
|
||||
(one.getLowBits() & three.getLowBits()),
|
||||
(one.getHighBits() & two.getHighBits()) |
|
||||
(two.getHighBits() & three.getHighBits()) |
|
||||
(one.getHighBits() & three.getHighBits()));
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Adds two or more goog.math.Long values.
|
||||
*
|
||||
* @private
|
||||
* @param {!goog.math.Long} one first summand
|
||||
* @param {!goog.math.Long} two second summand
|
||||
* @param {...goog.math.Long} var_args more arguments to sum
|
||||
* @return {!goog.math.Long} The resulting sum.
|
||||
*/
|
||||
goog.crypt.Sha2_64bit.prototype.sum_ = function(one, two, var_args) {
|
||||
// The low bits may be signed, but they represent a 32-bit unsigned quantity.
|
||||
// We must be careful to normalize them.
|
||||
// This doesn't matter for the high bits.
|
||||
// Implementation note: Performance testing shows that this method runs
|
||||
// fastest when the first two arguments are pulled out of the loop.
|
||||
var low = (one.getLowBits() ^ 0x80000000) + (two.getLowBits() ^ 0x80000000);
|
||||
var high = one.getHighBits() + two.getHighBits();
|
||||
for (var i = arguments.length - 1; i >= 2; --i) {
|
||||
low += arguments[i].getLowBits() ^ 0x80000000;
|
||||
high += arguments[i].getHighBits();
|
||||
}
|
||||
// Because of the ^0x80000000, each value we added is 0x80000000 too small.
|
||||
// Add arguments.length * 0x80000000 to the current sum. We can do this
|
||||
// quickly by adding 0x80000000 to low when the number of arguments is
|
||||
// odd, and adding (number of arguments) >> 1 to high.
|
||||
if (arguments.length & 1) {
|
||||
low += 0x80000000;
|
||||
}
|
||||
high += arguments.length >> 1;
|
||||
|
||||
// If low is outside the range [0, 0xFFFFFFFF], its overflow or underflow
|
||||
// should be added to high. We don't actually need to modify low or
|
||||
// normalize high because the goog.math.Long constructor already does that.
|
||||
high += Math.floor(low / 0x100000000);
|
||||
return new goog.math.Long(low, high);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Converts an array of 32-bit integers into an array of goog.math.Long
|
||||
* elements.
|
||||
*
|
||||
* @private
|
||||
* @param {!Array<number>} values An array of 32-bit numbers. Its length
|
||||
* must be even. Each pair of numbers represents a 64-bit integer
|
||||
* in big-endian order
|
||||
* @return {!Array<!goog.math.Long>}
|
||||
*/
|
||||
goog.crypt.Sha2_64bit.toLongArray_ = function(values) {
|
||||
goog.asserts.assert(values.length % 2 == 0);
|
||||
var result = [];
|
||||
for (var i = 0; i < values.length; i += 2) {
|
||||
result.push(new goog.math.Long(values[i + 1], values[i]));
|
||||
}
|
||||
return result;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Fixed constants used in SHA-512 variants.
|
||||
*
|
||||
* These values are from Section 4.2.3 of
|
||||
* http://csrc.nist.gov/publications/fips/fips180-4/fips-180-4.pdf
|
||||
* @const
|
||||
* @private {!Array<!goog.math.Long>}
|
||||
*/
|
||||
goog.crypt.Sha2_64bit.K_ = goog.crypt.Sha2_64bit.toLongArray_([
|
||||
0x428a2f98, 0xd728ae22, 0x71374491, 0x23ef65cd,
|
||||
0xb5c0fbcf, 0xec4d3b2f, 0xe9b5dba5, 0x8189dbbc,
|
||||
0x3956c25b, 0xf348b538, 0x59f111f1, 0xb605d019,
|
||||
0x923f82a4, 0xaf194f9b, 0xab1c5ed5, 0xda6d8118,
|
||||
0xd807aa98, 0xa3030242, 0x12835b01, 0x45706fbe,
|
||||
0x243185be, 0x4ee4b28c, 0x550c7dc3, 0xd5ffb4e2,
|
||||
0x72be5d74, 0xf27b896f, 0x80deb1fe, 0x3b1696b1,
|
||||
0x9bdc06a7, 0x25c71235, 0xc19bf174, 0xcf692694,
|
||||
0xe49b69c1, 0x9ef14ad2, 0xefbe4786, 0x384f25e3,
|
||||
0x0fc19dc6, 0x8b8cd5b5, 0x240ca1cc, 0x77ac9c65,
|
||||
0x2de92c6f, 0x592b0275, 0x4a7484aa, 0x6ea6e483,
|
||||
0x5cb0a9dc, 0xbd41fbd4, 0x76f988da, 0x831153b5,
|
||||
0x983e5152, 0xee66dfab, 0xa831c66d, 0x2db43210,
|
||||
0xb00327c8, 0x98fb213f, 0xbf597fc7, 0xbeef0ee4,
|
||||
0xc6e00bf3, 0x3da88fc2, 0xd5a79147, 0x930aa725,
|
||||
0x06ca6351, 0xe003826f, 0x14292967, 0x0a0e6e70,
|
||||
0x27b70a85, 0x46d22ffc, 0x2e1b2138, 0x5c26c926,
|
||||
0x4d2c6dfc, 0x5ac42aed, 0x53380d13, 0x9d95b3df,
|
||||
0x650a7354, 0x8baf63de, 0x766a0abb, 0x3c77b2a8,
|
||||
0x81c2c92e, 0x47edaee6, 0x92722c85, 0x1482353b,
|
||||
0xa2bfe8a1, 0x4cf10364, 0xa81a664b, 0xbc423001,
|
||||
0xc24b8b70, 0xd0f89791, 0xc76c51a3, 0x0654be30,
|
||||
0xd192e819, 0xd6ef5218, 0xd6990624, 0x5565a910,
|
||||
0xf40e3585, 0x5771202a, 0x106aa070, 0x32bbd1b8,
|
||||
0x19a4c116, 0xb8d2d0c8, 0x1e376c08, 0x5141ab53,
|
||||
0x2748774c, 0xdf8eeb99, 0x34b0bcb5, 0xe19b48a8,
|
||||
0x391c0cb3, 0xc5c95a63, 0x4ed8aa4a, 0xe3418acb,
|
||||
0x5b9cca4f, 0x7763e373, 0x682e6ff3, 0xd6b2b8a3,
|
||||
0x748f82ee, 0x5defb2fc, 0x78a5636f, 0x43172f60,
|
||||
0x84c87814, 0xa1f0ab72, 0x8cc70208, 0x1a6439ec,
|
||||
0x90befffa, 0x23631e28, 0xa4506ceb, 0xde82bde9,
|
||||
0xbef9a3f7, 0xb2c67915, 0xc67178f2, 0xe372532b,
|
||||
0xca273ece, 0xea26619c, 0xd186b8c7, 0x21c0c207,
|
||||
0xeada7dd6, 0xcde0eb1e, 0xf57d4f7f, 0xee6ed178,
|
||||
0x06f067aa, 0x72176fba, 0x0a637dc5, 0xa2c898a6,
|
||||
0x113f9804, 0xbef90dae, 0x1b710b35, 0x131c471b,
|
||||
0x28db77f5, 0x23047d84, 0x32caab7b, 0x40c72493,
|
||||
0x3c9ebe0a, 0x15c9bebc, 0x431d67c4, 0x9c100d4c,
|
||||
0x4cc5d4be, 0xcb3e42b6, 0x597f299c, 0xfc657e2a,
|
||||
0x5fcb6fab, 0x3ad6faec, 0x6c44198c, 0x4a475817
|
||||
]);
|
||||
@@ -0,0 +1,22 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<!--
|
||||
Copyright 2012 The Closure Library Authors. All Rights Reserved.
|
||||
|
||||
Use of this source code is governed by the Apache License, Version 2.0.
|
||||
See the COPYING file for details.
|
||||
-->
|
||||
<head>
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
|
||||
<title>
|
||||
Closure Unit Tests - goog.crypt.sha2 64-bit hashes
|
||||
</title>
|
||||
<script src="../base.js">
|
||||
</script>
|
||||
<script>
|
||||
goog.require('goog.crypt.Sha2_64bit_test');
|
||||
</script>
|
||||
</head>
|
||||
<body>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,278 @@
|
||||
// Copyright 2014 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.
|
||||
|
||||
goog.provide('goog.crypt.Sha2_64bit_test');
|
||||
goog.setTestOnly('goog.crypt.Sha2_64bit_test');
|
||||
|
||||
goog.require('goog.array');
|
||||
goog.require('goog.crypt');
|
||||
goog.require('goog.crypt.Sha384');
|
||||
goog.require('goog.crypt.Sha512');
|
||||
goog.require('goog.crypt.Sha512_256');
|
||||
goog.require('goog.crypt.hashTester');
|
||||
goog.require('goog.testing.jsunit');
|
||||
goog.require('goog.userAgent');
|
||||
|
||||
|
||||
/**
|
||||
* Each object in the test vector array is a source text and one or more
|
||||
* hashes of that source text. The source text is either a string or a
|
||||
* byte array.
|
||||
* <p>
|
||||
* All hash values, except for the empty string, are from public sources:
|
||||
* csrc.nist.gov/publications/fips/fips180-2/fips180-2withchangenotice.pdf
|
||||
* csrc.nist.gov/groups/ST/toolkit/documents/Examples/SHA384.pdf
|
||||
* csrc.nist.gov/groups/ST/toolkit/documents/Examples/SHA512_256.pdf
|
||||
* csrc.nist.gov/groups/ST/toolkit/documents/Examples/SHA2_Additional.pdf
|
||||
* en.wikipedia.org/wiki/SHA-2#Examples_of_SHA-2_variants
|
||||
*/
|
||||
var TEST_VECTOR = [
|
||||
{
|
||||
// Make sure the algorithm correctly handles the empty string
|
||||
source:
|
||||
'',
|
||||
512:
|
||||
'cf83e1357eefb8bdf1542850d66d8007d620e4050b5715dc83f4a921d36ce9ce' +
|
||||
'47d0d13c5d85f2b0ff8318d2877eec2f63b931bd47417a81a538327af927da3e'
|
||||
},
|
||||
{
|
||||
source:
|
||||
'abc',
|
||||
512:
|
||||
'ddaf35a193617abacc417349ae20413112e6fa4e89a97ea20a9eeee64b55d39a' +
|
||||
'2192992a274fc1a836ba3c23a3feebbd454d4423643ce80e2a9ac94fa54ca49f',
|
||||
384:
|
||||
'cb00753f45a35e8bb5a03d699ac65007272c32ab0eded163' +
|
||||
'1a8b605a43ff5bed8086072ba1e7cc2358baeca134c825a7',
|
||||
256:
|
||||
'53048e2681941ef99b2e29b76b4c7dabe4c2d0c634fc6d46e0e2f13107e7af23'
|
||||
},
|
||||
{
|
||||
source:
|
||||
'abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmn' +
|
||||
'hijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu',
|
||||
512:
|
||||
'8e959b75dae313da8cf4f72814fc143f8f7779c6eb9f7fa17299aeadb6889018' +
|
||||
'501d289e4900f7e4331b99dec4b5433ac7d329eeb6dd26545e96e55b874be909',
|
||||
384:
|
||||
'09330c33f71147e83d192fc782cd1b4753111b173b3b05d2' +
|
||||
'2fa08086e3b0f712fcc7c71a557e2db966c3e9fa91746039',
|
||||
256:
|
||||
'3928e184fb8690f840da3988121d31be65cb9d3ef83ee6146feac861e19b563a'
|
||||
},
|
||||
{
|
||||
source:
|
||||
'The quick brown fox jumps over the lazy dog',
|
||||
512:
|
||||
'07e547d9586f6a73f73fbac0435ed76951218fb7d0c8d788a309d785436bbb64' +
|
||||
'2e93a252a954f23912547d1e8a3b5ed6e1bfd7097821233fa0538f3db854fee6',
|
||||
384:
|
||||
'ca737f1014a48f4c0b6dd43cb177b0afd9e5169367544c49' +
|
||||
'4011e3317dbf9a509cb1e5dc1e85a941bbee3d7f2afbc9b1',
|
||||
256:
|
||||
'dd9d67b371519c339ed8dbd25af90e976a1eeefd4ad3d889005e532fc5bef04d'
|
||||
}
|
||||
];
|
||||
|
||||
|
||||
/**
|
||||
* For each integer key N, the value is the SHA-512 value of a string
|
||||
* consisting of N repetitions of the character 'a'.
|
||||
*/
|
||||
var TEST_FENCEPOST_VECTOR = {
|
||||
110:
|
||||
'c825949632e509824543f7eaf159fb6041722fce3c1cdcbb613b3d37ff107c51' +
|
||||
'9417baac32f8e74fe29d7f4823bf6886956603dca5354a6ed6e4a542e06b7d28',
|
||||
111:
|
||||
'fa9121c7b32b9e01733d034cfc78cbf67f926c7ed83e82200ef8681819692176' +
|
||||
'0b4beff48404df811b953828274461673c68d04e297b0eb7b2b4d60fc6b566a2',
|
||||
112:
|
||||
'c01d080efd492776a1c43bd23dd99d0a2e626d481e16782e75d54c2503b5dc32' +
|
||||
'bd05f0f1ba33e568b88fd2d970929b719ecbb152f58f130a407c8830604b70ca',
|
||||
113:
|
||||
'55ddd8ac210a6e18ba1ee055af84c966e0dbff091c43580ae1be703bdb85da31' +
|
||||
'acf6948cf5bd90c55a20e5450f22fb89bd8d0085e39f85a86cc46abbca75e24d'
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Simple sanity tests for hash functions.
|
||||
*/
|
||||
function testBasicOperations() {
|
||||
var sha512 = new goog.crypt.Sha512();
|
||||
goog.crypt.hashTester.runBasicTests(sha512);
|
||||
|
||||
var sha384 = new goog.crypt.Sha384();
|
||||
goog.crypt.hashTester.runBasicTests(sha384);
|
||||
|
||||
var sha256 = new goog.crypt.Sha512_256();
|
||||
goog.crypt.hashTester.runBasicTests(sha256);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Function called by the actual testers to ensure that specific strings
|
||||
* hash to specific published values.
|
||||
*
|
||||
* Each item in the vector has a "source" and one or more additional keys.
|
||||
* If the item has a key matching the key argument passed to this
|
||||
* function, it is the expected value of the hash function.
|
||||
*
|
||||
* @param {!goog.crypt.Sha2_64bit} hasher The hasher to test
|
||||
* @param {number} length The length of the resulting hash, in bits.
|
||||
* Also the key to use in TEST_VECTOR for the expected hash value
|
||||
*/
|
||||
function hashGoldenTester(hasher, length) {
|
||||
goog.array.forEach(TEST_VECTOR, function(data) {
|
||||
hasher.update(data.source);
|
||||
var digest = hasher.digest();
|
||||
assertEquals('Hash digest has the wrong length', length, digest.length * 8);
|
||||
if (data[length]) {
|
||||
// We're given an expected value
|
||||
var expected = goog.crypt.hexToByteArray(data[length]);
|
||||
assertElementsEquals(
|
||||
'Wrong result for hash' + length + '(\'' + data.source + '\')',
|
||||
expected, digest);
|
||||
}
|
||||
hasher.reset();
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
/** Test that Sha512() returns the published values */
|
||||
function testHashing512() {
|
||||
hashGoldenTester(new goog.crypt.Sha512(), 512);
|
||||
}
|
||||
|
||||
|
||||
/** Test that Sha384 returns the published values */
|
||||
function testHashing384() {
|
||||
hashGoldenTester(new goog.crypt.Sha384(), 384);
|
||||
}
|
||||
|
||||
|
||||
/** Test that Sha512_256 returns the published values */
|
||||
function testHashing256() {
|
||||
hashGoldenTester(new goog.crypt.Sha512_256(), 256);
|
||||
}
|
||||
|
||||
|
||||
/** Test that the opt_length works */
|
||||
function testHashing_optLength() {
|
||||
var hasher = new goog.crypt.Sha512();
|
||||
hasher.update('1234567890');
|
||||
var digest1 = hasher.digest();
|
||||
hasher.reset();
|
||||
hasher.update('12345678901234567890', 10);
|
||||
var digest2 = hasher.digest();
|
||||
assertElementsEquals(digest1, digest2);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Make sure that we correctly handle strings whose length is 110-113.
|
||||
* This is the area where we are likely to hit fencepost errors in the padding
|
||||
* code.
|
||||
*/
|
||||
function testFencepostErrors() {
|
||||
var hasher = new goog.crypt.Sha512();
|
||||
A64 = 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa';
|
||||
A128 = A64 + A64;
|
||||
for (var i = 110; i <= 113; i++) {
|
||||
hasher.update(A128, i);
|
||||
var digest = hasher.digest();
|
||||
var expected = goog.crypt.hexToByteArray(TEST_FENCEPOST_VECTOR[i]);
|
||||
assertElementsEquals('Fencepost ' + i, expected, digest);
|
||||
hasher.reset();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/** Test one really large string using SHA512 */
|
||||
function testHashing512Large() {
|
||||
// This test tends to time out on IE7.
|
||||
if (!goog.userAgent.IE || goog.userAgent.isVersionOrHigher('8')) {
|
||||
var hasher = new goog.crypt.Sha512();
|
||||
hasher.update(goog.array.repeat(0, 1000000));
|
||||
var digest = hasher.digest();
|
||||
var expected = goog.crypt.hexToByteArray(
|
||||
'ce044bc9fd43269d5bbc946cbebc3bb711341115cc4abdf2edbc3ff2c57ad4b1' +
|
||||
'5deb699bda257fea5aef9c6e55fcf4cf9dc25a8c3ce25f2efe90908379bff7ed');
|
||||
assertElementsEquals(expected, digest);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/** Check that the code throws an error for bad input */
|
||||
function testBadInput_nullNotAllowed() {
|
||||
var hasher = new goog.crypt.Sha512();
|
||||
assertThrows('Null input not allowed', function() {
|
||||
hasher.update({});
|
||||
});
|
||||
}
|
||||
|
||||
function testBadInput_noFloatingPoint() {
|
||||
var hasher = new goog.crypt.Sha512();
|
||||
assertThrows('Floating point not allows', function() {
|
||||
hasher.update([1, 2, 3, 4, 4.5]);
|
||||
});
|
||||
}
|
||||
|
||||
function testBadInput_negativeNotAllowed() {
|
||||
var hasher = new goog.crypt.Sha512();
|
||||
assertThrows('Negative not allowed', function() {
|
||||
hasher.update([1, 2, 3, 4, -10]);
|
||||
});
|
||||
}
|
||||
|
||||
function testBadInput_mustBeByteArray() {
|
||||
var hasher = new goog.crypt.Sha512();
|
||||
assertThrows('Must be byte array', function() {
|
||||
hasher.update([1, 2, 3, 4, {}]);
|
||||
});
|
||||
}
|
||||
|
||||
function testBadInput_byteTooLarge() {
|
||||
var hasher = new goog.crypt.Sha512();
|
||||
assertThrows('>255 not allowed', function() {
|
||||
hasher.update([1, 2, 3, 4, 256]);
|
||||
});
|
||||
}
|
||||
|
||||
function testBadInput_characterTooLarge() {
|
||||
var hasher = new goog.crypt.Sha512();
|
||||
assertThrows('>255 not allowed', function() {
|
||||
hasher.update('abc' + String.fromCharCode(256));
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
function testHasherNeedsReset_beforeDigest() {
|
||||
var hasher = new goog.crypt.Sha512();
|
||||
hasher.update('abc');
|
||||
hasher.digest();
|
||||
assertThrows('Need reset after digest', function() {
|
||||
hasher.digest();
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
function testHasherNeedsReset_beforeUpdate() {
|
||||
var hasher = new goog.crypt.Sha512();
|
||||
hasher.update('abc');
|
||||
hasher.digest();
|
||||
assertThrows('Need reset after digest', function() {
|
||||
hasher.update('abc');
|
||||
});
|
||||
}
|
||||
@@ -0,0 +1,59 @@
|
||||
// Copyright 2014 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 SHA-384 cryptographic hash.
|
||||
*
|
||||
* Usage:
|
||||
* var sha384 = new goog.crypt.Sha384();
|
||||
* sha384.update(bytes);
|
||||
* var hash = sha384.digest();
|
||||
*
|
||||
* @author fy@google.com (Frank Yellin)
|
||||
*/
|
||||
|
||||
goog.provide('goog.crypt.Sha384');
|
||||
|
||||
goog.require('goog.crypt.Sha2_64bit');
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Constructs a SHA-384 cryptographic hash.
|
||||
*
|
||||
* @constructor
|
||||
* @extends {goog.crypt.Sha2_64bit}
|
||||
* @final
|
||||
* @struct
|
||||
*/
|
||||
goog.crypt.Sha384 = function() {
|
||||
goog.crypt.Sha384.base(this, 'constructor', 6 /* numHashBlocks */,
|
||||
goog.crypt.Sha384.INIT_HASH_BLOCK_);
|
||||
};
|
||||
goog.inherits(goog.crypt.Sha384, goog.crypt.Sha2_64bit);
|
||||
|
||||
|
||||
/** @private {!Array<number>} */
|
||||
goog.crypt.Sha384.INIT_HASH_BLOCK_ = [
|
||||
// Section 5.3.4 of
|
||||
// csrc.nist.gov/publications/fips/fips180-4/fips-180-4.pdf
|
||||
0xcbbb9d5d, 0xc1059ed8, // H0
|
||||
0x629a292a, 0x367cd507, // H1
|
||||
0x9159015a, 0x3070dd17, // H2
|
||||
0x152fecd8, 0xf70e5939, // H3
|
||||
0x67332667, 0xffc00b31, // H4
|
||||
0x8eb44a87, 0x68581511, // H5
|
||||
0xdb0c2e0d, 0x64f98fa7, // H6
|
||||
0x47b5481d, 0xbefa4fa4 // H7
|
||||
];
|
||||
@@ -0,0 +1,59 @@
|
||||
// Copyright 2014 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 SHA-512 cryptographic hash.
|
||||
*
|
||||
* Usage:
|
||||
* var sha512 = new goog.crypt.Sha512();
|
||||
* sha512.update(bytes);
|
||||
* var hash = sha512.digest();
|
||||
*
|
||||
* @author fy@google.com (Frank Yellin)
|
||||
*/
|
||||
|
||||
goog.provide('goog.crypt.Sha512');
|
||||
|
||||
goog.require('goog.crypt.Sha2_64bit');
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Constructs a SHA-512 cryptographic hash.
|
||||
*
|
||||
* @constructor
|
||||
* @extends {goog.crypt.Sha2_64bit}
|
||||
* @final
|
||||
* @struct
|
||||
*/
|
||||
goog.crypt.Sha512 = function() {
|
||||
goog.crypt.Sha512.base(this, 'constructor', 8 /* numHashBlocks */,
|
||||
goog.crypt.Sha512.INIT_HASH_BLOCK_);
|
||||
};
|
||||
goog.inherits(goog.crypt.Sha512, goog.crypt.Sha2_64bit);
|
||||
|
||||
|
||||
/** @private {!Array<number>} */
|
||||
goog.crypt.Sha512.INIT_HASH_BLOCK_ = [
|
||||
// Section 5.3.5 of
|
||||
// csrc.nist.gov/publications/fips/fips180-4/fips-180-4.pdf
|
||||
0x6a09e667, 0xf3bcc908, // H0
|
||||
0xbb67ae85, 0x84caa73b, // H1
|
||||
0x3c6ef372, 0xfe94f82b, // H2
|
||||
0xa54ff53a, 0x5f1d36f1, // H3
|
||||
0x510e527f, 0xade682d1, // H4
|
||||
0x9b05688c, 0x2b3e6c1f, // H5
|
||||
0x1f83d9ab, 0xfb41bd6b, // H6
|
||||
0x5be0cd19, 0x137e2179 // H7
|
||||
];
|
||||
@@ -0,0 +1,65 @@
|
||||
// Copyright 2014 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 SHA-512/256 cryptographic hash.
|
||||
*
|
||||
* WARNING: SHA-256 and SHA-512/256 are different members of the SHA-2
|
||||
* family of hashes. Although both give 32-byte results, the two results
|
||||
* should bear no relationship to each other.
|
||||
*
|
||||
* Please be careful before using this hash function.
|
||||
* <p>
|
||||
* Usage:
|
||||
* var sha512_256 = new goog.crypt.Sha512_256();
|
||||
* sha512_256.update(bytes);
|
||||
* var hash = sha512_256.digest();
|
||||
*
|
||||
* @author fy@google.com (Frank Yellin)
|
||||
*/
|
||||
|
||||
goog.provide('goog.crypt.Sha512_256');
|
||||
|
||||
goog.require('goog.crypt.Sha2_64bit');
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Constructs a SHA-512/256 cryptographic hash.
|
||||
*
|
||||
* @constructor
|
||||
* @extends {goog.crypt.Sha2_64bit}
|
||||
* @final
|
||||
* @struct
|
||||
*/
|
||||
goog.crypt.Sha512_256 = function() {
|
||||
goog.crypt.Sha512_256.base(this, 'constructor', 4 /* numHashBlocks */,
|
||||
goog.crypt.Sha512_256.INIT_HASH_BLOCK_);
|
||||
};
|
||||
goog.inherits(goog.crypt.Sha512_256, goog.crypt.Sha2_64bit);
|
||||
|
||||
|
||||
/** @private {!Array<number>} */
|
||||
goog.crypt.Sha512_256.INIT_HASH_BLOCK_ = [
|
||||
// Section 5.3.6.2 of
|
||||
// csrc.nist.gov/publications/fips/fips180-4/fips-180-4.pdf
|
||||
0x22312194, 0xFC2BF72C, // H0
|
||||
0x9F555FA3, 0xC84C64C2, // H1
|
||||
0x2393B86B, 0x6F53B151, // H2
|
||||
0x96387719, 0x5940EABD, // H3
|
||||
0x96283EE2, 0xA88EFFE3, // H4
|
||||
0xBE5E1E25, 0x53863992, // H5
|
||||
0x2B0199FC, 0x2C85B8AA, // H6
|
||||
0x0EB72DDC, 0x81C52CA2 // H7
|
||||
];
|
||||
@@ -0,0 +1,41 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<!--
|
||||
Copyright 2014 The Closure Library Authors. All Rights Reserved.
|
||||
|
||||
Use of this source code is governed by the Apache License, Version 2.0.
|
||||
See the COPYING file for details.
|
||||
|
||||
Author: fy@google.com (Frank Yellin)
|
||||
-->
|
||||
<head>
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||
<title>Closure Performance Tests - goog.crypt.Sha512</title>
|
||||
<link rel="stylesheet" type="text/css" href="../testing/performancetable.css"/>
|
||||
<script src="../base.js"></script>
|
||||
<script>
|
||||
goog.require('goog.crypt.Sha512');
|
||||
goog.require('goog.crypt.hashTester');
|
||||
goog.require('goog.testing.jsunit');
|
||||
</script>
|
||||
</head>
|
||||
<body>
|
||||
<h1>Closure Performance Tests - goog.crypt.Sha512</h1>
|
||||
<p>
|
||||
<strong>User-agent:</strong>
|
||||
<script>document.write(navigator.userAgent);</script>
|
||||
</p>
|
||||
|
||||
<script>
|
||||
|
||||
function testHashing() {
|
||||
goog.crypt.hashTester.runPerfTests(
|
||||
function() {
|
||||
return new goog.crypt.Sha512();
|
||||
} /* hashFactory */,
|
||||
'SHA512' /* hashName */);
|
||||
}
|
||||
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
Reference in New Issue
Block a user