safe2link/asset/blowfish.js

929 lines
35 KiB
JavaScript
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/**
* @class Blowfish
* @description
* Шифратор/дешифратор. Алгоритм Blowfish
*
* в режиме ecb: исходная строка разбивается на 8-байтные блоки, каждый блок
* шифруется. Если размер блока менее 8 байт, то дополняем его до 8 байт нулями.
* в режиме cbc: первый блок открытого текста, из 8 байт, перед шифрованием побитово
* складывается по модулю 2 (операция XOR) с вектором инициализации;
* последующие блоки открытого текста побитового складываются (XOR) с предыдущим результатом
* шифрования после этого зашифровываются.
*
* Подробнее о режимах шифрования:
* http://ru.wikipedia.org/wiki/%D0%A0%D0%B5%D0%B6%D0%B8%D0%BC_%D1%88%D0%B8%D1%84%D1%80%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D1%8F
*
* @example
* // Пример 1: режим ECB, по умолчанию
* var bf = new Blowfish("secret key");
* var encrypted = bf.encrypt("конфиденциальное сообщение");
* var decrypted = bf.decrypt(encrypted);
*
* // Пример 2: режим CBC (лучше подходит для шифрования длинных сообщений, более 1kb):
* var bf = new Blowfish("key", "cbc");
* var encrypted = bf.encrypt("secret message", "cbcvecto");
* var decrypted = bf.decrypt(encrypted, "cbcvecto");
*
* //В режиме CBC вектор иницаилазиации iv это дополнительный пароль.
*
* // Пример 3:
* // После шифрования получается бинарная строка. Чтобы передать
* // зашифрованное сообщение в эл.письме нужно закодировать бинарную
* // строку в base64
* var bf = new Blowfish("key");
*
* // Для удобства включил, в этот класс методы base64Encode и base64Decode
*
* // Шифрование
* var encrypted = bf.base64Encode(bf.encrypt("secret message"));
*
* // Расшифрование
* var encrypted = bf.base64Decode(encrypted);
* var decrypted = bf.decrypt(encrypted);
*
* @param {string} key пароль (может быть длинной до 56 байт)
* @param {string} [mode] режим шифрования
* @author Alexandr Gorlov <a.gorlov@gmail.com>
*/
var Blowfish = function(key, mode) {
// инициализация пароля
this.key = key;
// инициализация режима шифрования
if (mode === "ecb" || mode === "cbc") {
this.mode = mode;
}
// инициализация массивов с кодами символов (правда ведь?)
this.sBox0 = Blowfish.sBox0.slice();
this.sBox1 = Blowfish.sBox1.slice();
this.sBox2 = Blowfish.sBox2.slice();
this.sBox3 = Blowfish.sBox3.slice();
this.pArray = Blowfish.pArray.slice();
// инициализация шифра
this.generateSubkeys(key);
};
Blowfish.prototype = {
/**
* @type {Array}
*/
sBox0: null,
/**
* @type {Array}
*/
sBox1: null,
/**
* @type {Array}
*/
sBox2: null,
/**
* @type {Array}
*/
sBox3: null,
/**
* @type {Array}
*/
pArray: null,
/**
* Пароль
* @type {string}
*/
key: null,
/**
* Режим шифрования: ecb|cbc; по умолчанию: ecb
* @type {string}
*/
mode: "ecb",
/**
* Вектор инициализации для режима cbc
* @type {string}
*/
iv: "abc12345",
/**
* Набор символов для base64
* @type {string}
*/
keyStr: "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=",
/**
* Шифрует строку
* @param {string} string шифруемая строка
* @param {string} iv произвольная 8байтная строка - вектор инициализации;
* используется только в режиме CBC
* @throws {Error} кидает исключение при неизвестном режиме шифрования
* @return {string} зашифрованная строка
*/
encrypt: function(string, iv) {
if (this.mode === "ecb") {
return this.encryptECB(string);
}
if (this.mode === "cbc") {
return this.encryptCBC(string, iv);
}
throw new Error("Неизвестный режим шифрования.");
},
/**
* Расшифровывает строку
* @param {string} string зашифрованная строка
* @param {string} iv произвольная 8байтная строка - вектор инициализации
* (должен быть тотже, что и при шифровании) используется
* только в режиме CBC
* @throws {Error} кидает исключение при неизвестном режиме шифрования
* @return {string} расшифрованная строка
*/
decrypt: function(string, iv) {
if (this.mode === "ecb") {
return this.decryptECB(string);
}
if (this.mode === "cbc") {
return this.decryptCBC(string, iv);
}
throw new Error("Неизвестный режим шифрования.");
},
/**
* Шифрует в режиме ECB
* (приватный метод)
* @param {string} string шифруемая строка
* @return {string} зашифрованная строка
*/
encryptECB: function(string) {
string = this.utf8Decode(string);
var blocks = Math.ceil(string.length/8);
//1. разбить строку на 8-байтные блок-и
//2. разбить 8байтные блоки на 32-битные пары xL, xR
//3. зашифровать все блоки
//4. преобразовать результат в строку
var encryptedString = "";
for (var i = 0; i < blocks; i++) {
var block = string.substr(i * 8, 8);
if (block.length < 8) {
var count = 8 - block.length;
while (0 < count--) {
block += "\0";
}
}
var xL, xR;
//[xL, xR] = this.split64by32(block); не работает в IE, Chrome
var xLxR = this.split64by32(block);
xL = xLxR[0];
xR = xLxR[1];
//[xL, xR] = this.encipher(xL, xR); не работает в IE, Chrome
xLxR = this.encipher(xL, xR);
xL = xLxR[0];
xR = xLxR[1];
encryptedString += this.num2block32(xL) + this.num2block32(xR);
}
return encryptedString;
},
/**
* Шифрует в режиме CBC
* (приватный метод)
* @param {string} string шифруемая строка
* @param {string} iv 8-байтная строка - вектор инициализации
* @return {string} зашифрованная строка
*/
encryptCBC: function(string, iv) {
string = this.utf8Decode(string);
var blocks = Math.ceil(string.length/8);
//1. разбить строку на 8-байтные блок-и
//2. разбить 8байтные блоки на 32-битные пары xL, xR
//3. зашифровать все блоки
//4. преобразовать результат в строку
var ivL, ivR, ivLivR;
//[ivL, ivR] = this.split64by32(iv);
ivLivR = this.split64by32(iv);
ivL = ivLivR[0];
ivR = ivLivR[1];
var encryptedString = "";
for (var i = 0; i < blocks; i++) {
var block = string.substr(i * 8, 8);
if (block.length < 8) {
var count = 8 - block.length;
while (0 < count--) {
block += "\0";
}
}
var xL, xR, xLxR;
xLxR = this.split64by32(block);
xL = xLxR[0];
xR = xLxR[1];
xL = this.xor(xL, ivL);
xR = this.xor(xR, ivR);
xLxR = this.encipher(xL, xR);
xL = xLxR[0];
xR = xLxR[1];
// ivL = xL; - не используется
// ivR = xR; - не используется
//[ivL, ivR] = [xL, xR];
encryptedString += this.num2block32(xL) + this.num2block32(xR);
}
return encryptedString;
},
/**
* Расшифровать в режиме ECB
* (приватный метод)
* @param {string} string шифруемая строка
* @throws {Error} кидает исключение если зашифрованная строка повреждена
* @return {string} зашифрованная строка
*/
decryptECB: function(string) {
var blocks = Math.ceil(string.length/8);
var decryptedString = "";
for (var i = 0; i < blocks; i++) {
var block = string.substr(i * 8, 8);
if (block.length < 8) {
throw new Error("Зашифрованная строка повреждена: длинна зашифрованной строки должна быть кратна 8 баыйтам.");
}
var xL, xR, xLxR;
xLxR = this.split64by32(block);
xL = xLxR[0];
xR = xLxR[1];
xLxR = this.decipher(xL, xR);
xL = xLxR[0];
xR = xLxR[1];
decryptedString += this.num2block32(xL) + this.num2block32(xR);
}
decryptedString = this.utf8Encode(decryptedString);
return decryptedString;
},
/**
* Шифрует в режиме CBC
* (приватный метод)
* @param {string} string зашифрованная строка
* @param {string} iv 8-байтная строка - вектор инициализации
* @throws {Error} кидает исключение если зашифрованная строка повреждена
* @return {string} расшифрованая строка
*/
decryptCBC: function(string, iv) {
var blocks = Math.ceil(string.length/8);
var ivL, ivR, ivLtmp, ivRtmp, ivLivR;
ivLivR = this.split64by32(iv);
ivL = ivLivR[0];
ivR = ivLivR[1];
var decryptedString = "";
for (var i = 0; i < blocks; i++) {
var block = string.substr(i * 8, 8);
if (block.length < 8) {
throw new Error("Зашифрованная строка повреждена: длинна зашифрованной строки должна быть кратна 8 байтам.");
}
var xL, xR, xLxR;
xLxR = this.split64by32(block);
xL = xLxR[0];
xR = xLxR[1];
ivLtmp = xL;
ivRtmp = xR;
xLxR = this.decipher(xL, xR);
xL = xLxR[0];
xR = xLxR[1];
xL = this.xor(xL, ivL);
xR = this.xor(xR, ivR);
ivL = ivLtmp;
ivR = ivRtmp;
decryptedString += this.num2block32(xL) + this.num2block32(xR);
}
decryptedString = this.utf8Encode(decryptedString);
return decryptedString;
},
/**
* Функция F
* Function F looks like this:
* Divide xL into four eight-bit quarters: a, b, c, and d.
* Then, F(xL) = ((S1,a + S2,b mod 232) XOR S3,c) + S4,d mod 232.
* F(0xFFFFFF)
* ((S1[255] + S2[255]) XOR S3[255]) + S4[255]
* ((0x6e85076a + 0xdb83adf7) ^ 0x406000e0) + 0x3ac372e6
* @param {int32} xL 32битное значение
*/
F: function(xL) {
var a = xL >>> 24;
var b = xL << 8 >>> 24;
var c = xL << 16 >>> 24;
var d = xL << 24 >>> 24;
var res = this.addMod32(this.sBox0[a], this.sBox1[b]);
res = this.xor(res, this.sBox2[c]);
res = this.addMod32(res, this.sBox3[d]);
return res;
},
/**
* Шифрует строку из 8 байт (один блок)
* Encryption and Decryption:
* Blowfish has 16 rounds. The input is a 64-bit data element, x.
* Divide x into two 32-bit halves: xL, xR. Then, for i = 1 to 16:
* xL = xL XOR Pi
* xR = F(xL) XOR xR
* Swap xL and xR
* After the sixteenth round, swap xL and xR again to undo the last swap.
* Then, xR = xR XOR P17 and xL = xL XOR P18. Finally, recombine xL and xR
* to get the ciphertext.
* Function F looks like this:
* Divide xL into four eight-bit quarters: a, b, c, and d.
* Then, F(xL) = ((S1,a + S2,b mod 232) XOR S3,c) + S4,d mod 232.
* Decryption is exactly the same as encryption, except that P1, P2,..., P18
* are used in the reverse order.
* @param {int32} xL первые 4 символа в виде числа 32битного беззнакового
* @param {int32} xR оставшиеся 4 символа в виде числа 32битного беззнакового
* @return {Array} зашифрованный 8-байтный блок в виде пары 32битных чисел [xL, xR]
*/
encipher: function(xL, xR) {
var tmp;
for (var i = 0; i < 16; i++) {
xL = this.xor(xL, this.pArray[i]);
xR = this.xor(this.F(xL), xR);
tmp = xL;
xL = xR;
xR = tmp;
}
tmp = xL;
xL = xR;
xR = tmp;
xR = this.xor(xR, this.pArray[16]);
xL = this.xor(xL, this.pArray[17]);
return [xL, xR];
},
/**
* ??
* @param {int32} xL
* @param {int32} xR
* @return {Array}
*/
decipher: function(xL, xR) {
var tmp;
xL = this.xor(xL, this.pArray[17]);
xR = this.xor(xR, this.pArray[16]);
tmp = xL;
xL = xR;
xR = tmp;
for (var i = 15; i >= 0; i--) {
tmp = xL;
xL = xR;
xR = tmp;
xR = this.xor(this.F(xL), xR);
xL = this.xor(xL, this.pArray[i]);
}
return [xL, xR];
},
/**
* Генерация ключей (subkeys)
* Generating the Subkeys:
* The subkeys are calculated using the Blowfish algorithm:
* 1. Initialize first the P-array and then the four S-boxes, in order,
* with a fixed string. This string consists of the hexadecimal digits
* of pi (less the initial 3): P1 = 0x243f6a88, P2 = 0x85a308d3,
* P3 = 0x13198a2e, P4 = 0x03707344, etc.
* 2. XOR P1 with the first 32 bits of the key, XOR P2 with the second 32-bits
* of the key, and so on for all bits of the key (possibly up to P14).
* Repeatedly cycle through the key bits until the entire P-array has
* been XORed with key bits. (For every short key, there is at least one
* equivalent longer key; for example, if A is a 64-bit key, then AA,
* AAA, etc., are equivalent keys.)
* 3. Encrypt the all-zero string with the Blowfish algorithm, using the
* subkeys described in steps (1) and (2).
* 4. Replace P1 and P2 with the output of step (3).
* 5. Encrypt the output of step (3) using the Blowfish algorithm with the
* modified subkeys.
* 6. Replace P3 and P4 with the output of step (5).
* 7. Continue the process, replacing all entries of the P array, and then all
* four S-boxes in order, with the output of the continuously changing
* Blowfish algorithm.
* In total, 521 iterations are required to generate all required subkeys.
* Applications can store the subkeys rather than execute this derivation
* process multiple times.
*
* Долго пытался понять правильную последовательность генерации ключей,
* в итоге посмотрел как сделано в PHP реализации Crypt_Blowfish (PEAR)
* и разобрался.
* @param {string} key ключ
*/
generateSubkeys: function(key) {
var data = 0;
var k = 0;
var i, j;
for (i = 0; i < 18; i++) {
for (j = 4; j > 0; j--) {
data = this.fixNegative(data << 8 | key.charCodeAt(k));
k = (k + 1) % key.length;
}
this.pArray[i] = this.xor(this.pArray[i], data);
data = 0;
}
//var block64 = num2block32(0) + num2block32(0);
var block64 = [0, 0];
for (i = 0; i < 18; i += 2) {
block64 = this.encipher(block64[0], block64[1]);
this.pArray[i] = block64[0];
this.pArray[i + 1] = block64[1];
}
for (i = 0; i < 256; i += 2) {
block64 = this.encipher(block64[0], block64[1]);
this.sBox0[i] = block64[0];
this.sBox0[i + 1] = block64[1];
}
for (i = 0; i < 256; i += 2) {
block64 = this.encipher(block64[0], block64[1]);
this.sBox1[i] = block64[0];
this.sBox1[i + 1] = block64[1];
}
for (i = 0; i < 256; i += 2) {
block64 = this.encipher(block64[0], block64[1]);
this.sBox2[i] = block64[0];
this.sBox2[i + 1] = block64[1];
}
for (i = 0; i < 256; i += 2) {
block64 = this.encipher(block64[0], block64[1]);
this.sBox3[i] = block64[0];
this.sBox3[i + 1] = block64[1];
}
},
/**
* Преобразует 4х байтную строку, в 32битное целое число
* @param {string} block32
* @return {int}
*/
block32toNum: function(block32) {
return this.fixNegative(
block32.charCodeAt(0) << 24 |
block32.charCodeAt(1) << 16 |
block32.charCodeAt(2) << 8 |
block32.charCodeAt(3)
);
},
/**
* Преобразует 32битное число в строку (4 байта)
* @param {int} num 32 битное число
* @return {string} 4х-байтная строка
*/
num2block32: function(num) {
return String.fromCharCode(num >>> 24) +
String.fromCharCode(num << 8 >>> 24) +
String.fromCharCode(num << 16 >>> 24) +
String.fromCharCode(num << 24 >>> 24);
},
/**
* Операция XOR
* @param {int} a
* @param {int} b
* @return {int}
*/
xor: function(a, b) {
return this.fixNegative(a ^ b);
},
/**
* Сложение по модулю 2^32
* Складываем 2 числа и отрбрасываем все разряды больше 32
* @param {int} a
* @param {int} b
* @return {int}
*/
addMod32: function(a, b) {
return this.fixNegative((a + b) | 0); // | 0 приводит к 32битному значению
},
/**
* Преобразование signed int в unsigned int
* после побитовых операций javascript возвращает знаковое число
* However, for octet-data processing (eg, network stream, etc), usually
* want the "unsigned int" representation. This can be accomplished by
* adding a ">>> 0" (zero-fill right-shift) operator which internally tells
* Javascript to treat this as unsigned.
* @param {int} number целое число со знаком
* @return {int} целое число без знака
*/
fixNegative: function(number) {
return number >>> 0;
},
/**
* Разделим 64 битный блок на два 32-битных
* @param {string} block64 блок, состоящий из 64 бит (8 байт)
* @return {Array} [xL, xR]
*/
split64by32: function (block64) {
var xL = block64.substring(0, 4);
var xR = block64.substring(4, 8);
return [this.block32toNum(xL) , this.block32toNum(xR)];
},
/**
* Преобразует строку в последовательность байтов utf8
* на один символ может приходится больше одного байта
* Взял этот метод из библиотеки base64:
* http://www.webtoolkit.info/javascript-base64.html
*/
utf8Decode: function(string) {
var utftext = "";
for (var n = 0; n < string.length; n++) {
var c = string.charCodeAt(n);
if (c < 128) {
utftext += String.fromCharCode(c);
} else if (c > 127 && c < 2048) {
utftext += String.fromCharCode(c >> 6 | 192);
utftext += String.fromCharCode(c & 63 | 128);
} else {
utftext += String.fromCharCode(c >> 12 | 224);
utftext += String.fromCharCode(c >> 6 & 63 | 128);
utftext += String.fromCharCode(c & 63 | 128);
}
}
return utftext;
},
/**
* Преобразует байтовую-строку utf8 в строку javascript
*/
utf8Encode: function (utftext) {
var string = "";
var i = 0;
var c = 0;
var c1 = 0;
var c2 = 0;
while ( i < utftext.length ) {
c = utftext.charCodeAt(i);
if (c < 128) {
string += String.fromCharCode(c);
i++;
} else if((c > 191) && (c < 224)) {
c1 = utftext.charCodeAt(i+1);
string += String.fromCharCode(((c & 31) << 6) | (c1 & 63));
i += 2;
} else {
c1 = utftext.charCodeAt(i+1);
c2 = utftext.charCodeAt(i+2);
string += String.fromCharCode(((c & 15) << 12) | ((c1 & 63) << 6) | (c2 & 63));
i += 3;
}
}
return string;
},
/**
* Кодирует строку в base64
* @param {string} input
* @return {string}
*/
base64Encode : function (input) {
var output = "";
var chr1, chr2, chr3, enc1, enc2, enc3, enc4;
var i = 0;
//input = this.utf8Encode(input);
while (i < input.length) {
chr1 = input.charCodeAt(i++);
chr2 = input.charCodeAt(i++);
chr3 = input.charCodeAt(i++);
enc1 = chr1 >> 2;
enc2 = ((chr1 & 3) << 4) | (chr2 >> 4);
enc3 = ((chr2 & 15) << 2) | (chr3 >> 6);
enc4 = chr3 & 63;
if (isNaN(chr2)) {
enc3 = enc4 = 64;
} else if (isNaN(chr3)) {
enc4 = 64;
}
output = output +
this.keyStr.charAt(enc1) + this.keyStr.charAt(enc2) +
this.keyStr.charAt(enc3) + this.keyStr.charAt(enc4);
}
return output;
},
/**
* Раскодирует строку из base64
* @param {string} input
* @return {string}
*/
base64Decode : function (input) {
var output = "";
var chr1, chr2, chr3;
var enc1, enc2, enc3, enc4;
var i = 0;
input = input.replace(/[^A-Za-z0-9\+\/\=]/g, "");
while (i < input.length) {
enc1 = this.keyStr.indexOf(input.charAt(i++));
enc2 = this.keyStr.indexOf(input.charAt(i++));
enc3 = this.keyStr.indexOf(input.charAt(i++));
enc4 = this.keyStr.indexOf(input.charAt(i++));
chr1 = (enc1 << 2) | (enc2 >> 4);
chr2 = ((enc2 & 15) << 4) | (enc3 >> 2);
chr3 = ((enc3 & 3) << 6) | enc4;
output = output + String.fromCharCode(chr1);
if (enc3 != 64) {
output = output + String.fromCharCode(chr2);
}
if (enc4 != 64) {
output = output + String.fromCharCode(chr3);
}
}
//output = this.utf8Decode(output);
return output;
},
/**
* Удаляет символы \0 в конце строки
* @param {string} input
* @return {string}
*/
trimZeros: function(input) {
return input.replace(/\0+$/g, "");
}
}
/**
* @static
* @type {Array}
*/
Blowfish.pArray = [
0x243f6a88, 0x85a308d3, 0x13198a2e, 0x03707344, 0xa4093822, 0x299f31d0,
0x082efa98, 0xec4e6c89, 0x452821e6, 0x38d01377, 0xbe5466cf, 0x34e90c6c,
0xc0ac29b7, 0xc97c50dd, 0x3f84d5b5, 0xb5470917, 0x9216d5d9, 0x8979fb1b
];
/**
* @static
* @type {Array}
*/
Blowfish.sBox0 = [
0xd1310ba6, 0x98dfb5ac, 0x2ffd72db, 0xd01adfb7, 0xb8e1afed, 0x6a267e96,
0xba7c9045, 0xf12c7f99, 0x24a19947, 0xb3916cf7, 0x0801f2e2, 0x858efc16,
0x636920d8, 0x71574e69, 0xa458fea3, 0xf4933d7e, 0x0d95748f, 0x728eb658,
0x718bcd58, 0x82154aee, 0x7b54a41d, 0xc25a59b5, 0x9c30d539, 0x2af26013,
0xc5d1b023, 0x286085f0, 0xca417918, 0xb8db38ef, 0x8e79dcb0, 0x603a180e,
0x6c9e0e8b, 0xb01e8a3e, 0xd71577c1, 0xbd314b27, 0x78af2fda, 0x55605c60,
0xe65525f3, 0xaa55ab94, 0x57489862, 0x63e81440, 0x55ca396a, 0x2aab10b6,
0xb4cc5c34, 0x1141e8ce, 0xa15486af, 0x7c72e993, 0xb3ee1411, 0x636fbc2a,
0x2ba9c55d, 0x741831f6, 0xce5c3e16, 0x9b87931e, 0xafd6ba33, 0x6c24cf5c,
0x7a325381, 0x28958677, 0x3b8f4898, 0x6b4bb9af, 0xc4bfe81b, 0x66282193,
0x61d809cc, 0xfb21a991, 0x487cac60, 0x5dec8032, 0xef845d5d, 0xe98575b1,
0xdc262302, 0xeb651b88, 0x23893e81, 0xd396acc5, 0x0f6d6ff3, 0x83f44239,
0x2e0b4482, 0xa4842004, 0x69c8f04a, 0x9e1f9b5e, 0x21c66842, 0xf6e96c9a,
0x670c9c61, 0xabd388f0, 0x6a51a0d2, 0xd8542f68, 0x960fa728, 0xab5133a3,
0x6eef0b6c, 0x137a3be4, 0xba3bf050, 0x7efb2a98, 0xa1f1651d, 0x39af0176,
0x66ca593e, 0x82430e88, 0x8cee8619, 0x456f9fb4, 0x7d84a5c3, 0x3b8b5ebe,
0xe06f75d8, 0x85c12073, 0x401a449f, 0x56c16aa6, 0x4ed3aa62, 0x363f7706,
0x1bfedf72, 0x429b023d, 0x37d0d724, 0xd00a1248, 0xdb0fead3, 0x49f1c09b,
0x075372c9, 0x80991b7b, 0x25d479d8, 0xf6e8def7, 0xe3fe501a, 0xb6794c3b,
0x976ce0bd, 0x04c006ba, 0xc1a94fb6, 0x409f60c4, 0x5e5c9ec2, 0x196a2463,
0x68fb6faf, 0x3e6c53b5, 0x1339b2eb, 0x3b52ec6f, 0x6dfc511f, 0x9b30952c,
0xcc814544, 0xaf5ebd09, 0xbee3d004, 0xde334afd, 0x660f2807, 0x192e4bb3,
0xc0cba857, 0x45c8740f, 0xd20b5f39, 0xb9d3fbdb, 0x5579c0bd, 0x1a60320a,
0xd6a100c6, 0x402c7279, 0x679f25fe, 0xfb1fa3cc, 0x8ea5e9f8, 0xdb3222f8,
0x3c7516df, 0xfd616b15, 0x2f501ec8, 0xad0552ab, 0x323db5fa, 0xfd238760,
0x53317b48, 0x3e00df82, 0x9e5c57bb, 0xca6f8ca0, 0x1a87562e, 0xdf1769db,
0xd542a8f6, 0x287effc3, 0xac6732c6, 0x8c4f5573, 0x695b27b0, 0xbbca58c8,
0xe1ffa35d, 0xb8f011a0, 0x10fa3d98, 0xfd2183b8, 0x4afcb56c, 0x2dd1d35b,
0x9a53e479, 0xb6f84565, 0xd28e49bc, 0x4bfb9790, 0xe1ddf2da, 0xa4cb7e33,
0x62fb1341, 0xcee4c6e8, 0xef20cada, 0x36774c01, 0xd07e9efe, 0x2bf11fb4,
0x95dbda4d, 0xae909198, 0xeaad8e71, 0x6b93d5a0, 0xd08ed1d0, 0xafc725e0,
0x8e3c5b2f, 0x8e7594b7, 0x8ff6e2fb, 0xf2122b64, 0x8888b812, 0x900df01c,
0x4fad5ea0, 0x688fc31c, 0xd1cff191, 0xb3a8c1ad, 0x2f2f2218, 0xbe0e1777,
0xea752dfe, 0x8b021fa1, 0xe5a0cc0f, 0xb56f74e8, 0x18acf3d6, 0xce89e299,
0xb4a84fe0, 0xfd13e0b7, 0x7cc43b81, 0xd2ada8d9, 0x165fa266, 0x80957705,
0x93cc7314, 0x211a1477, 0xe6ad2065, 0x77b5fa86, 0xc75442f5, 0xfb9d35cf,
0xebcdaf0c, 0x7b3e89a0, 0xd6411bd3, 0xae1e7e49, 0x00250e2d, 0x2071b35e,
0x226800bb, 0x57b8e0af, 0x2464369b, 0xf009b91e, 0x5563911d, 0x59dfa6aa,
0x78c14389, 0xd95a537f, 0x207d5ba2, 0x02e5b9c5, 0x83260376, 0x6295cfa9,
0x11c81968, 0x4e734a41, 0xb3472dca, 0x7b14a94a, 0x1b510052, 0x9a532915,
0xd60f573f, 0xbc9bc6e4, 0x2b60a476, 0x81e67400, 0x08ba6fb5, 0x571be91f,
0xf296ec6b, 0x2a0dd915, 0xb6636521, 0xe7b9f9b6, 0xff34052e, 0xc5855664,
0x53b02d5d, 0xa99f8fa1, 0x08ba4799, 0x6e85076a
];
/**
* @static
* @type {Array}
*/
Blowfish.sBox1 = [
0x4b7a70e9, 0xb5b32944, 0xdb75092e, 0xc4192623, 0xad6ea6b0, 0x49a7df7d,
0x9cee60b8, 0x8fedb266, 0xecaa8c71, 0x699a17ff, 0x5664526c, 0xc2b19ee1,
0x193602a5, 0x75094c29, 0xa0591340, 0xe4183a3e, 0x3f54989a, 0x5b429d65,
0x6b8fe4d6, 0x99f73fd6, 0xa1d29c07, 0xefe830f5, 0x4d2d38e6, 0xf0255dc1,
0x4cdd2086, 0x8470eb26, 0x6382e9c6, 0x021ecc5e, 0x09686b3f, 0x3ebaefc9,
0x3c971814, 0x6b6a70a1, 0x687f3584, 0x52a0e286, 0xb79c5305, 0xaa500737,
0x3e07841c, 0x7fdeae5c, 0x8e7d44ec, 0x5716f2b8, 0xb03ada37, 0xf0500c0d,
0xf01c1f04, 0x0200b3ff, 0xae0cf51a, 0x3cb574b2, 0x25837a58, 0xdc0921bd,
0xd19113f9, 0x7ca92ff6, 0x94324773, 0x22f54701, 0x3ae5e581, 0x37c2dadc,
0xc8b57634, 0x9af3dda7, 0xa9446146, 0x0fd0030e, 0xecc8c73e, 0xa4751e41,
0xe238cd99, 0x3bea0e2f, 0x3280bba1, 0x183eb331, 0x4e548b38, 0x4f6db908,
0x6f420d03, 0xf60a04bf, 0x2cb81290, 0x24977c79, 0x5679b072, 0xbcaf89af,
0xde9a771f, 0xd9930810, 0xb38bae12, 0xdccf3f2e, 0x5512721f, 0x2e6b7124,
0x501adde6, 0x9f84cd87, 0x7a584718, 0x7408da17, 0xbc9f9abc, 0xe94b7d8c,
0xec7aec3a, 0xdb851dfa, 0x63094366, 0xc464c3d2, 0xef1c1847, 0x3215d908,
0xdd433b37, 0x24c2ba16, 0x12a14d43, 0x2a65c451, 0x50940002, 0x133ae4dd,
0x71dff89e, 0x10314e55, 0x81ac77d6, 0x5f11199b, 0x043556f1, 0xd7a3c76b,
0x3c11183b, 0x5924a509, 0xf28fe6ed, 0x97f1fbfa, 0x9ebabf2c, 0x1e153c6e,
0x86e34570, 0xeae96fb1, 0x860e5e0a, 0x5a3e2ab3, 0x771fe71c, 0x4e3d06fa,
0x2965dcb9, 0x99e71d0f, 0x803e89d6, 0x5266c825, 0x2e4cc978, 0x9c10b36a,
0xc6150eba, 0x94e2ea78, 0xa5fc3c53, 0x1e0a2df4, 0xf2f74ea7, 0x361d2b3d,
0x1939260f, 0x19c27960, 0x5223a708, 0xf71312b6, 0xebadfe6e, 0xeac31f66,
0xe3bc4595, 0xa67bc883, 0xb17f37d1, 0x018cff28, 0xc332ddef, 0xbe6c5aa5,
0x65582185, 0x68ab9802, 0xeecea50f, 0xdb2f953b, 0x2aef7dad, 0x5b6e2f84,
0x1521b628, 0x29076170, 0xecdd4775, 0x619f1510, 0x13cca830, 0xeb61bd96,
0x0334fe1e, 0xaa0363cf, 0xb5735c90, 0x4c70a239, 0xd59e9e0b, 0xcbaade14,
0xeecc86bc, 0x60622ca7, 0x9cab5cab, 0xb2f3846e, 0x648b1eaf, 0x19bdf0ca,
0xa02369b9, 0x655abb50, 0x40685a32, 0x3c2ab4b3, 0x319ee9d5, 0xc021b8f7,
0x9b540b19, 0x875fa099, 0x95f7997e, 0x623d7da8, 0xf837889a, 0x97e32d77,
0x11ed935f, 0x16681281, 0x0e358829, 0xc7e61fd6, 0x96dedfa1, 0x7858ba99,
0x57f584a5, 0x1b227263, 0x9b83c3ff, 0x1ac24696, 0xcdb30aeb, 0x532e3054,
0x8fd948e4, 0x6dbc3128, 0x58ebf2ef, 0x34c6ffea, 0xfe28ed61, 0xee7c3c73,
0x5d4a14d9, 0xe864b7e3, 0x42105d14, 0x203e13e0, 0x45eee2b6, 0xa3aaabea,
0xdb6c4f15, 0xfacb4fd0, 0xc742f442, 0xef6abbb5, 0x654f3b1d, 0x41cd2105,
0xd81e799e, 0x86854dc7, 0xe44b476a, 0x3d816250, 0xcf62a1f2, 0x5b8d2646,
0xfc8883a0, 0xc1c7b6a3, 0x7f1524c3, 0x69cb7492, 0x47848a0b, 0x5692b285,
0x095bbf00, 0xad19489d, 0x1462b174, 0x23820e00, 0x58428d2a, 0x0c55f5ea,
0x1dadf43e, 0x233f7061, 0x3372f092, 0x8d937e41, 0xd65fecf1, 0x6c223bdb,
0x7cde3759, 0xcbee7460, 0x4085f2a7, 0xce77326e, 0xa6078084, 0x19f8509e,
0xe8efd855, 0x61d99735, 0xa969a7aa, 0xc50c06c2, 0x5a04abfc, 0x800bcadc,
0x9e447a2e, 0xc3453484, 0xfdd56705, 0x0e1e9ec9, 0xdb73dbd3, 0x105588cd,
0x675fda79, 0xe3674340, 0xc5c43465, 0x713e38d8, 0x3d28f89e, 0xf16dff20,
0x153e21e7, 0x8fb03d4a, 0xe6e39f2b, 0xdb83adf7
];
/**
* @static
* @type {Array}
*/
Blowfish.sBox2 = [
0xe93d5a68, 0x948140f7, 0xf64c261c, 0x94692934, 0x411520f7, 0x7602d4f7,
0xbcf46b2e, 0xd4a20068, 0xd4082471, 0x3320f46a, 0x43b7d4b7, 0x500061af,
0x1e39f62e, 0x97244546, 0x14214f74, 0xbf8b8840, 0x4d95fc1d, 0x96b591af,
0x70f4ddd3, 0x66a02f45, 0xbfbc09ec, 0x03bd9785, 0x7fac6dd0, 0x31cb8504,
0x96eb27b3, 0x55fd3941, 0xda2547e6, 0xabca0a9a, 0x28507825, 0x530429f4,
0x0a2c86da, 0xe9b66dfb, 0x68dc1462, 0xd7486900, 0x680ec0a4, 0x27a18dee,
0x4f3ffea2, 0xe887ad8c, 0xb58ce006, 0x7af4d6b6, 0xaace1e7c, 0xd3375fec,
0xce78a399, 0x406b2a42, 0x20fe9e35, 0xd9f385b9, 0xee39d7ab, 0x3b124e8b,
0x1dc9faf7, 0x4b6d1856, 0x26a36631, 0xeae397b2, 0x3a6efa74, 0xdd5b4332,
0x6841e7f7, 0xca7820fb, 0xfb0af54e, 0xd8feb397, 0x454056ac, 0xba489527,
0x55533a3a, 0x20838d87, 0xfe6ba9b7, 0xd096954b, 0x55a867bc, 0xa1159a58,
0xcca92963, 0x99e1db33, 0xa62a4a56, 0x3f3125f9, 0x5ef47e1c, 0x9029317c,
0xfdf8e802, 0x04272f70, 0x80bb155c, 0x05282ce3, 0x95c11548, 0xe4c66d22,
0x48c1133f, 0xc70f86dc, 0x07f9c9ee, 0x41041f0f, 0x404779a4, 0x5d886e17,
0x325f51eb, 0xd59bc0d1, 0xf2bcc18f, 0x41113564, 0x257b7834, 0x602a9c60,
0xdff8e8a3, 0x1f636c1b, 0x0e12b4c2, 0x02e1329e, 0xaf664fd1, 0xcad18115,
0x6b2395e0, 0x333e92e1, 0x3b240b62, 0xeebeb922, 0x85b2a20e, 0xe6ba0d99,
0xde720c8c, 0x2da2f728, 0xd0127845, 0x95b794fd, 0x647d0862, 0xe7ccf5f0,
0x5449a36f, 0x877d48fa, 0xc39dfd27, 0xf33e8d1e, 0x0a476341, 0x992eff74,
0x3a6f6eab, 0xf4f8fd37, 0xa812dc60, 0xa1ebddf8, 0x991be14c, 0xdb6e6b0d,
0xc67b5510, 0x6d672c37, 0x2765d43b, 0xdcd0e804, 0xf1290dc7, 0xcc00ffa3,
0xb5390f92, 0x690fed0b, 0x667b9ffb, 0xcedb7d9c, 0xa091cf0b, 0xd9155ea3,
0xbb132f88, 0x515bad24, 0x7b9479bf, 0x763bd6eb, 0x37392eb3, 0xcc115979,
0x8026e297, 0xf42e312d, 0x6842ada7, 0xc66a2b3b, 0x12754ccc, 0x782ef11c,
0x6a124237, 0xb79251e7, 0x06a1bbe6, 0x4bfb6350, 0x1a6b1018, 0x11caedfa,
0x3d25bdd8, 0xe2e1c3c9, 0x44421659, 0x0a121386, 0xd90cec6e, 0xd5abea2a,
0x64af674e, 0xda86a85f, 0xbebfe988, 0x64e4c3fe, 0x9dbc8057, 0xf0f7c086,
0x60787bf8, 0x6003604d, 0xd1fd8346, 0xf6381fb0, 0x7745ae04, 0xd736fccc,
0x83426b33, 0xf01eab71, 0xb0804187, 0x3c005e5f, 0x77a057be, 0xbde8ae24,
0x55464299, 0xbf582e61, 0x4e58f48f, 0xf2ddfda2, 0xf474ef38, 0x8789bdc2,
0x5366f9c3, 0xc8b38e74, 0xb475f255, 0x46fcd9b9, 0x7aeb2661, 0x8b1ddf84,
0x846a0e79, 0x915f95e2, 0x466e598e, 0x20b45770, 0x8cd55591, 0xc902de4c,
0xb90bace1, 0xbb8205d0, 0x11a86248, 0x7574a99e, 0xb77f19b6, 0xe0a9dc09,
0x662d09a1, 0xc4324633, 0xe85a1f02, 0x09f0be8c, 0x4a99a025, 0x1d6efe10,
0x1ab93d1d, 0x0ba5a4df, 0xa186f20f, 0x2868f169, 0xdcb7da83, 0x573906fe,
0xa1e2ce9b, 0x4fcd7f52, 0x50115e01, 0xa70683fa, 0xa002b5c4, 0x0de6d027,
0x9af88c27, 0x773f8641, 0xc3604c06, 0x61a806b5, 0xf0177a28, 0xc0f586e0,
0x006058aa, 0x30dc7d62, 0x11e69ed7, 0x2338ea63, 0x53c2dd94, 0xc2c21634,
0xbbcbee56, 0x90bcb6de, 0xebfc7da1, 0xce591d76, 0x6f05e409, 0x4b7c0188,
0x39720a3d, 0x7c927c24, 0x86e3725f, 0x724d9db9, 0x1ac15bb4, 0xd39eb8fc,
0xed545578, 0x08fca5b5, 0xd83d7cd3, 0x4dad0fc4, 0x1e50ef5e, 0xb161e6f8,
0xa28514d9, 0x6c51133c, 0x6fd5c7e7, 0x56e14ec4, 0x362abfce, 0xddc6c837,
0xd79a3234, 0x92638212, 0x670efa8e, 0x406000e0
];
/**
* @static
* @type {Array}
*/
Blowfish.sBox3 = [
0x3a39ce37, 0xd3faf5cf, 0xabc27737, 0x5ac52d1b, 0x5cb0679e, 0x4fa33742,
0xd3822740, 0x99bc9bbe, 0xd5118e9d, 0xbf0f7315, 0xd62d1c7e, 0xc700c47b,
0xb78c1b6b, 0x21a19045, 0xb26eb1be, 0x6a366eb4, 0x5748ab2f, 0xbc946e79,
0xc6a376d2, 0x6549c2c8, 0x530ff8ee, 0x468dde7d, 0xd5730a1d, 0x4cd04dc6,
0x2939bbdb, 0xa9ba4650, 0xac9526e8, 0xbe5ee304, 0xa1fad5f0, 0x6a2d519a,
0x63ef8ce2, 0x9a86ee22, 0xc089c2b8, 0x43242ef6, 0xa51e03aa, 0x9cf2d0a4,
0x83c061ba, 0x9be96a4d, 0x8fe51550, 0xba645bd6, 0x2826a2f9, 0xa73a3ae1,
0x4ba99586, 0xef5562e9, 0xc72fefd3, 0xf752f7da, 0x3f046f69, 0x77fa0a59,
0x80e4a915, 0x87b08601, 0x9b09e6ad, 0x3b3ee593, 0xe990fd5a, 0x9e34d797,
0x2cf0b7d9, 0x022b8b51, 0x96d5ac3a, 0x017da67d, 0xd1cf3ed6, 0x7c7d2d28,
0x1f9f25cf, 0xadf2b89b, 0x5ad6b472, 0x5a88f54c, 0xe029ac71, 0xe019a5e6,
0x47b0acfd, 0xed93fa9b, 0xe8d3c48d, 0x283b57cc, 0xf8d56629, 0x79132e28,
0x785f0191, 0xed756055, 0xf7960e44, 0xe3d35e8c, 0x15056dd4, 0x88f46dba,
0x03a16125, 0x0564f0bd, 0xc3eb9e15, 0x3c9057a2, 0x97271aec, 0xa93a072a,
0x1b3f6d9b, 0x1e6321f5, 0xf59c66fb, 0x26dcf319, 0x7533d928, 0xb155fdf5,
0x03563482, 0x8aba3cbb, 0x28517711, 0xc20ad9f8, 0xabcc5167, 0xccad925f,
0x4de81751, 0x3830dc8e, 0x379d5862, 0x9320f991, 0xea7a90c2, 0xfb3e7bce,
0x5121ce64, 0x774fbe32, 0xa8b6e37e, 0xc3293d46, 0x48de5369, 0x6413e680,
0xa2ae0810, 0xdd6db224, 0x69852dfd, 0x09072166, 0xb39a460a, 0x6445c0dd,
0x586cdecf, 0x1c20c8ae, 0x5bbef7dd, 0x1b588d40, 0xccd2017f, 0x6bb4e3bb,
0xdda26a7e, 0x3a59ff45, 0x3e350a44, 0xbcb4cdd5, 0x72eacea8, 0xfa6484bb,
0x8d6612ae, 0xbf3c6f47, 0xd29be463, 0x542f5d9e, 0xaec2771b, 0xf64e6370,
0x740e0d8d, 0xe75b1357, 0xf8721671, 0xaf537d5d, 0x4040cb08, 0x4eb4e2cc,
0x34d2466a, 0x0115af84, 0xe1b00428, 0x95983a1d, 0x06b89fb4, 0xce6ea048,
0x6f3f3b82, 0x3520ab82, 0x011a1d4b, 0x277227f8, 0x611560b1, 0xe7933fdc,
0xbb3a792b, 0x344525bd, 0xa08839e1, 0x51ce794b, 0x2f32c9b7, 0xa01fbac9,
0xe01cc87e, 0xbcc7d1f6, 0xcf0111c3, 0xa1e8aac7, 0x1a908749, 0xd44fbd9a,
0xd0dadecb, 0xd50ada38, 0x0339c32a, 0xc6913667, 0x8df9317c, 0xe0b12b4f,
0xf79e59b7, 0x43f5bb3a, 0xf2d519ff, 0x27d9459c, 0xbf97222c, 0x15e6fc2a,
0x0f91fc71, 0x9b941525, 0xfae59361, 0xceb69ceb, 0xc2a86459, 0x12baa8d1,
0xb6c1075e, 0xe3056a0c, 0x10d25065, 0xcb03a442, 0xe0ec6e0e, 0x1698db3b,
0x4c98a0be, 0x3278e964, 0x9f1f9532, 0xe0d392df, 0xd3a0342b, 0x8971f21e,
0x1b0a7441, 0x4ba3348c, 0xc5be7120, 0xc37632d8, 0xdf359f8d, 0x9b992f2e,
0xe60b6f47, 0x0fe3f11d, 0xe54cda54, 0x1edad891, 0xce6279cf, 0xcd3e7e6f,
0x1618b166, 0xfd2c1d05, 0x848fd2c5, 0xf6fb2299, 0xf523f357, 0xa6327623,
0x93a83531, 0x56cccd02, 0xacf08162, 0x5a75ebb5, 0x6e163697, 0x88d273cc,
0xde966292, 0x81b949d0, 0x4c50901b, 0x71c65614, 0xe6c6c7bd, 0x327a140a,
0x45e1d006, 0xc3f27b9a, 0xc9aa53fd, 0x62a80f00, 0xbb25bfe2, 0x35bdd2f6,
0x71126905, 0xb2040222, 0xb6cbcf7c, 0xcd769c2b, 0x53113ec0, 0x1640e3d3,
0x38abbd60, 0x2547adf0, 0xba38209c, 0xf746ce76, 0x77afa1c5, 0x20756060,
0x85cbfe4e, 0x8ae88dd8, 0x7aaaf9b0, 0x4cf9aa7e, 0x1948c25c, 0x02fb8a8c,
0x01c36ae4, 0xd6ebe1f9, 0x90d4f869, 0xa65cdea0, 0x3f09252d, 0xc208e69f,
0xb74e6132, 0xce77e25b, 0x578fdfe3, 0x3ac372e6
];