《对基于HTTP协议的密码传输安全的一些思考》相关js代码
首先是 RSA 加密代码:
function Random() {
return Math.round(Math.random() * 254) + 1;
}
function ToBase32(value) {
var base32 = 'abcdefghijklmnopqrstuvwxyz456789';
var length = parseInt(((value.length << 4) + 4) / 5);
var result = '';
var cur_i = 0;
var cur_u = 0;
var index;
var k;
for (var i = 0; i < length; i++) {
index = 0;
for (var j = 0; j < 5; j++) {
k = i * 5 + j;
if (k == value.length << 4)
break;
if ((k & 0xf) == 0)
cur_u = value[cur_i++];
index <<= 1;
index |= (cur_u & 0x8000) == 0 ? 0 : 1;
cur_u <<= 1;
}
result += base32.charAt(index);
}
return result;
}
function FromBase32(value) {
var base32 = 'abcdefghijklmnopqrstuvwxyz456789';
var bl = value.length * 5 >>> 3;
var result = new Array(bl + 1 >>> 1);
var cur_i = 0;
var cur_v = 0;
var index = (bl & 1) << 3;
var k = 0;
while (k < value.length * 5 && (index >>> 4) < result.length) {
if (k % 5 == 0)
{
cur_v = base32.indexOf(value.charAt(cur_i++));
if (cur_i == value.length && (value.length & 7) != 0)
cur_v <<= value.length * 5 & 7;
}
result[index >>> 4] <<= 1;
result[index >>> 4] |= (cur_v & 0x10) == 0 ? 0 : 1;
cur_v <<= 1;
index++;
k++;
}
return result;
}
function Multiply(value1, value2) {
var result = new Array(value1.length + value2.length);
for (var i = 0; i < value1.length + value2.length; i++)
result[i] = 0;
for (var i = value1.length - 1; i >= 0; i--)
{
var inc = 0;
for (var j = value2.length - 1; j >= 0; j--)
{
var tmp = value1[i] * value2[j] + result[i + j + 1] + inc;
result[i + j + 1] = tmp & 0xffff;
inc = tmp >>> 0x10;
}
result[i] = inc;
}
return result;
}
function Modulus(value, modulus) {
if (value.length < modulus.length)
return value;
var h = 0;
var result = new Array(modulus.length);
var cur = result.length;
for (var i = 0; i < result.length; i++)
result[i] = value[i];
do
{
var div = parseInt((((h << 0x10) | result[0]) >>> 0) / modulus[0]);
if (div > 0)
{
var sub = 0;
for (var i = result.length - 1; i >= 0; i--)
{
var tmp = div * modulus[i] + sub;
sub = tmp >>> 0x10;
tmp &= 0xffff;
if (result[i] >= tmp)
result[i] -= tmp;
else
{
result[i] += 0x10000 - tmp;
sub++;
}
}
while (h < sub)
{
var add = 0;
for (var i = result.length - 1; i >= 0; i--)
{
var tmp = result[i] + modulus[i] + add;
add = tmp >>> 0x10;
result[i] = tmp & 0xffff;
}
h += add;
}
}
if (cur >= value.length)
break;
h = result[0];
for (var i = 0; i < result.length - 1; i++)
result[i] = result[i + 1];
result[result.length - 1] = value[cur++];
}
while (true);
return result;
}
function Encrypt(str, keySize, exponent, modulus) {
var data = new Array(keySize >>> 4);
data[0] = 2;
var index = 2;
for (var i = 2; i < keySize / 8 - str.length - 1; i++) {
data[index >>> 1] <<= 8;
data[index >>> 1] |= Random() & 0xff;
index++;
}
data[index >>> 1] <<= 8;
index++;
for(var i = 0; i < str.length; i++) {
data[index >>> 1] <<= 8;
data[index >>> 1] |= str.charCodeAt(i) & 0xff;
index++;
}
var result = new Array(1);
result[0] = 1;
for (var i = exponent.length - 1; i >= 0; i--)
for (var j = 0; j < 0x10; j++)
{
if (i == 0 && (exponent[i] >>> j) == 0)
break;
if (((exponent[i] >>> j) & 1) != 0)
result = Modulus(Multiply(result, data), modulus);
data = Modulus(Multiply(data, data), modulus);
}
return ToBase32(result);
}
function RSA(str, keySize, exponent, modulus) {
if (typeof(str) != 'string')
return '';
var max = keySize / 8 - 11;
var length = str.length;
var index = 0;
var result = '';
var e = FromBase32(exponent);
var m = FromBase32(modulus);
while (length > max) {
result += Encrypt(str.substr(index, max), keySize, e, m);
length -= max;
index += max;
}
result += Encrypt(str.substr(index, length), keySize, e, m);
return result;
}
return Math.round(Math.random() * 254) + 1;
}
function ToBase32(value) {
var base32 = 'abcdefghijklmnopqrstuvwxyz456789';
var length = parseInt(((value.length << 4) + 4) / 5);
var result = '';
var cur_i = 0;
var cur_u = 0;
var index;
var k;
for (var i = 0; i < length; i++) {
index = 0;
for (var j = 0; j < 5; j++) {
k = i * 5 + j;
if (k == value.length << 4)
break;
if ((k & 0xf) == 0)
cur_u = value[cur_i++];
index <<= 1;
index |= (cur_u & 0x8000) == 0 ? 0 : 1;
cur_u <<= 1;
}
result += base32.charAt(index);
}
return result;
}
function FromBase32(value) {
var base32 = 'abcdefghijklmnopqrstuvwxyz456789';
var bl = value.length * 5 >>> 3;
var result = new Array(bl + 1 >>> 1);
var cur_i = 0;
var cur_v = 0;
var index = (bl & 1) << 3;
var k = 0;
while (k < value.length * 5 && (index >>> 4) < result.length) {
if (k % 5 == 0)
{
cur_v = base32.indexOf(value.charAt(cur_i++));
if (cur_i == value.length && (value.length & 7) != 0)
cur_v <<= value.length * 5 & 7;
}
result[index >>> 4] <<= 1;
result[index >>> 4] |= (cur_v & 0x10) == 0 ? 0 : 1;
cur_v <<= 1;
index++;
k++;
}
return result;
}
function Multiply(value1, value2) {
var result = new Array(value1.length + value2.length);
for (var i = 0; i < value1.length + value2.length; i++)
result[i] = 0;
for (var i = value1.length - 1; i >= 0; i--)
{
var inc = 0;
for (var j = value2.length - 1; j >= 0; j--)
{
var tmp = value1[i] * value2[j] + result[i + j + 1] + inc;
result[i + j + 1] = tmp & 0xffff;
inc = tmp >>> 0x10;
}
result[i] = inc;
}
return result;
}
function Modulus(value, modulus) {
if (value.length < modulus.length)
return value;
var h = 0;
var result = new Array(modulus.length);
var cur = result.length;
for (var i = 0; i < result.length; i++)
result[i] = value[i];
do
{
var div = parseInt((((h << 0x10) | result[0]) >>> 0) / modulus[0]);
if (div > 0)
{
var sub = 0;
for (var i = result.length - 1; i >= 0; i--)
{
var tmp = div * modulus[i] + sub;
sub = tmp >>> 0x10;
tmp &= 0xffff;
if (result[i] >= tmp)
result[i] -= tmp;
else
{
result[i] += 0x10000 - tmp;
sub++;
}
}
while (h < sub)
{
var add = 0;
for (var i = result.length - 1; i >= 0; i--)
{
var tmp = result[i] + modulus[i] + add;
add = tmp >>> 0x10;
result[i] = tmp & 0xffff;
}
h += add;
}
}
if (cur >= value.length)
break;
h = result[0];
for (var i = 0; i < result.length - 1; i++)
result[i] = result[i + 1];
result[result.length - 1] = value[cur++];
}
while (true);
return result;
}
function Encrypt(str, keySize, exponent, modulus) {
var data = new Array(keySize >>> 4);
data[0] = 2;
var index = 2;
for (var i = 2; i < keySize / 8 - str.length - 1; i++) {
data[index >>> 1] <<= 8;
data[index >>> 1] |= Random() & 0xff;
index++;
}
data[index >>> 1] <<= 8;
index++;
for(var i = 0; i < str.length; i++) {
data[index >>> 1] <<= 8;
data[index >>> 1] |= str.charCodeAt(i) & 0xff;
index++;
}
var result = new Array(1);
result[0] = 1;
for (var i = exponent.length - 1; i >= 0; i--)
for (var j = 0; j < 0x10; j++)
{
if (i == 0 && (exponent[i] >>> j) == 0)
break;
if (((exponent[i] >>> j) & 1) != 0)
result = Modulus(Multiply(result, data), modulus);
data = Modulus(Multiply(data, data), modulus);
}
return ToBase32(result);
}
function RSA(str, keySize, exponent, modulus) {
if (typeof(str) != 'string')
return '';
var max = keySize / 8 - 11;
var length = str.length;
var index = 0;
var result = '';
var e = FromBase32(exponent);
var m = FromBase32(modulus);
while (length > max) {
result += Encrypt(str.substr(index, max), keySize, e, m);
length -= max;
index += max;
}
result += Encrypt(str.substr(index, length), keySize, e, m);
return result;
}
其中:str 为待加密字符串,在这里仅支持 ASCII 字符;keySize 为密钥位数,一般在 .NET 中为 1024 位;exponent 和 modulus 为 RSA 加密密钥。一般使用时可以从服务器获取 keySize, exponent 和 modulus。
然后是 SHA1 哈希代码:
function HashTransform(h, buffer) {
var A = h[0], B = h[1], C = h[2], D = h[3], E = h[4];
var expand = new Array();
expand.length = 80;
for (var i = 0; i < 0x10; i++)
expand[i] = (buffer[i * 4] << 24) | (buffer[i * 4 + 1] << 16) | (buffer[i * 4 + 2] << 8) | buffer[i * 4 + 3];
for (var i = 16; i < 80; i++)
{
expand[i] = expand[i - 3] ^ expand[i - 8] ^ expand[i - 14] ^ expand[i - 16];
expand[i] = (expand[i] << 1) | (expand[i] >>> 31);
}
var index = 0;
while (index < 20)
{
E += ((((A << 5) | (A >>> 0x1b)) + (D ^ (B & (C ^ D)))) + expand[index]) + 0x5a827999;
B = (B << 30) | (B >>> 2);
D += ((((E << 5) | (E >>> 0x1b)) + (C ^ (A & (B ^ C)))) + expand[index + 1]) + 0x5a827999;
A = (A << 30) | (A >>> 2);
C += ((((D << 5) | (D >>> 0x1b)) + (B ^ (E & (A ^ B)))) + expand[index + 2]) + 0x5a827999;
E = (E << 30) | (E >>> 2);
B += ((((C << 5) | (C >>> 0x1b)) + (A ^ (D & (E ^ A)))) + expand[index + 3]) + 0x5a827999;
D = (D << 30) | (D >>> 2);
A += ((((B << 5) | (B >>> 0x1b)) + (E ^ (C & (D ^ E)))) + expand[index + 4]) + 0x5a827999;
C = (C << 30) | (C >>> 2);
index += 5;
}
while (index < 40)
{
E += ((((A << 5) | (A >>> 0x1b)) + ((B ^ C) ^ D)) + expand[index]) + 0x6ed9eba1;
B = (B << 30) | (B >>> 2);
D += ((((E << 5) | (E >>> 0x1b)) + ((A ^ B) ^ C)) + expand[index + 1]) + 0x6ed9eba1;
A = (A << 30) | (A >>> 2);
C += ((((D << 5) | (D >>> 0x1b)) + ((E ^ A) ^ B)) + expand[index + 2]) + 0x6ed9eba1;
E = (E << 30) | (E >>> 2);
B += ((((C << 5) | (C >>> 0x1b)) + ((D ^ E) ^ A)) + expand[index + 3]) + 0x6ed9eba1;
D = (D << 30) | (D >>> 2);
A += ((((B << 5) | (B >>> 0x1b)) + ((C ^ D) ^ E)) + expand[index + 4]) + 0x6ed9eba1;
C = (C << 30) | (C >>> 2);
index += 5;
}
while (index < 60)
{
E += ((((A << 5) | (A >>> 0x1b)) + ((B & C) | (D & (B | C)))) + expand[index]) + 0x8f1bbcdc;
B = (B << 30) | (B >>> 2);
D += ((((E << 5) | (E >>> 0x1b)) + ((A & B) | (C & (A | B)))) + expand[index + 1]) + 0x8f1bbcdc;
A = (A << 30) | (A >>> 2);
C += ((((D << 5) | (D >>> 0x1b)) + ((E & A) | (B & (E | A)))) + expand[index + 2]) + 0x8f1bbcdc;
E = (E << 30) | (E >>> 2);
B += ((((C << 5) | (C >>> 0x1b)) + ((D & E) | (A & (D | E)))) + expand[index + 3]) + 0x8f1bbcdc;
D = (D << 30) | (D >>> 2);
A += ((((B << 5) | (B >>> 0x1b)) + ((C & D) | (E & (C | D)))) + expand[index + 4]) + 0x8f1bbcdc;
C = (C << 30) | (C >>> 2);
index += 5;
}
while (index < 80)
{
E += ((((A << 5) | (A >>> 0x1b)) + ((B ^ C) ^ D)) + expand[index]) + 0xca62c1d6;
B = (B << 30) | (B >>> 2);
D += ((((E << 5) | (E >>> 0x1b)) + ((A ^ B) ^ C)) + expand[index + 1]) + 0xca62c1d6;
A = (A << 30) | (A >>> 2);
C += ((((D << 5) | (D >>> 0x1b)) + ((E ^ A) ^ B)) + expand[index + 2]) + 0xca62c1d6;
E = (E << 30) | (E >>> 2);
B += ((((C << 5) | (C >>> 0x1b)) + ((D ^ E) ^ A)) + expand[index + 3]) + 0xca62c1d6;
D = (D << 30) | (D >>> 2);
A += ((((B << 5) | (B >>> 0x1b)) + ((C ^ D) ^ E)) + expand[index + 4]) + 0xca62c1d6;
C = (C << 30) | (C >>> 2);
index += 5;
}
h[0] += A;
h[1] += B;
h[2] += C;
h[3] += D;
h[4] += E;
}
function HashData(h, value, buffer, offset) {
var length = value.length;
var srcOffset = 0;
var dstOffset = offset & 0x3f;
var count = offset + length;
if (dstOffset > 0 && (dstOffset + length) >= 0x40) {
var x = srcOffset, y = dstOffset;
for (var i = 0; i < 0x40 - dstOffset; i++)
buffer[y++] = value[x++] & 0xff;
srcOffset += 0x40 - dstOffset;
length -= 0x40 - dstOffset;
HashTransform(h, buffer);
dstOffset = 0;
}
while (length >= 0x40)
{
var x = srcOffset, y = 0;
for (var i = 0; i < 0x40; i++)
buffer[y++] = value[x++] & 0xff;
srcOffset += 0x40;
length -= 0x40;
HashTransform(h, buffer);
}
if (length > 0) {
var x = srcOffset, y = dstOffset;
for (var i = 0; i < length; i++)
buffer[y++] = value[x++] & 0xff;
}
return count;
}
function SHA1(str) {
if (typeof(str) != 'string')
return '';
var value = new Array();
value.length = str.length;
for (var i = 0; i < value.length; i++)
value[i] = str.charCodeAt(i) & 0xff;
var h = new Array(0x67452301, 0xefcdab89, 0x98badcfe, 0x10325476, 0xc3d2e1f0);
var buffer = new Array();
buffer.length = 0x40;
var count = HashData(h, value, buffer, 0);
var length = 0x40 - (count & 0x3f);
if (length <= 8)
length += 0x40;
var block = new Array()
block.length = length;
block[0] = 0x80;
for (var i = 1; i < length - 8; i++)
block[i] = 0;
var bit = count << 3;
for (var i = 1; i <= 8; i++) {
block[length - i] = bit & 0xff;
bit >>>= 8;
}
HashData(h, block, buffer, count);
var base32 = 'abcdefghijklmnopqrstuvwxyz456789';
var result = '';
var cur_i = 0;
var cur_u = 0;
var index;
var k;
for (var i = 0; i < 32; i++) {
index = 0;
for (var j = 0; j < 5; j++) {
k = i * 5 + j;
if (k == 160)
break;
if (k % 32 == 0)
cur_u = h[cur_i++];
index <<= 1;
index |= (cur_u & 0x80000000) == 0 ? 0 : 1;
cur_u <<= 1;
}
result += base32.charAt(index);
}
return result;
}
var A = h[0], B = h[1], C = h[2], D = h[3], E = h[4];
var expand = new Array();
expand.length = 80;
for (var i = 0; i < 0x10; i++)
expand[i] = (buffer[i * 4] << 24) | (buffer[i * 4 + 1] << 16) | (buffer[i * 4 + 2] << 8) | buffer[i * 4 + 3];
for (var i = 16; i < 80; i++)
{
expand[i] = expand[i - 3] ^ expand[i - 8] ^ expand[i - 14] ^ expand[i - 16];
expand[i] = (expand[i] << 1) | (expand[i] >>> 31);
}
var index = 0;
while (index < 20)
{
E += ((((A << 5) | (A >>> 0x1b)) + (D ^ (B & (C ^ D)))) + expand[index]) + 0x5a827999;
B = (B << 30) | (B >>> 2);
D += ((((E << 5) | (E >>> 0x1b)) + (C ^ (A & (B ^ C)))) + expand[index + 1]) + 0x5a827999;
A = (A << 30) | (A >>> 2);
C += ((((D << 5) | (D >>> 0x1b)) + (B ^ (E & (A ^ B)))) + expand[index + 2]) + 0x5a827999;
E = (E << 30) | (E >>> 2);
B += ((((C << 5) | (C >>> 0x1b)) + (A ^ (D & (E ^ A)))) + expand[index + 3]) + 0x5a827999;
D = (D << 30) | (D >>> 2);
A += ((((B << 5) | (B >>> 0x1b)) + (E ^ (C & (D ^ E)))) + expand[index + 4]) + 0x5a827999;
C = (C << 30) | (C >>> 2);
index += 5;
}
while (index < 40)
{
E += ((((A << 5) | (A >>> 0x1b)) + ((B ^ C) ^ D)) + expand[index]) + 0x6ed9eba1;
B = (B << 30) | (B >>> 2);
D += ((((E << 5) | (E >>> 0x1b)) + ((A ^ B) ^ C)) + expand[index + 1]) + 0x6ed9eba1;
A = (A << 30) | (A >>> 2);
C += ((((D << 5) | (D >>> 0x1b)) + ((E ^ A) ^ B)) + expand[index + 2]) + 0x6ed9eba1;
E = (E << 30) | (E >>> 2);
B += ((((C << 5) | (C >>> 0x1b)) + ((D ^ E) ^ A)) + expand[index + 3]) + 0x6ed9eba1;
D = (D << 30) | (D >>> 2);
A += ((((B << 5) | (B >>> 0x1b)) + ((C ^ D) ^ E)) + expand[index + 4]) + 0x6ed9eba1;
C = (C << 30) | (C >>> 2);
index += 5;
}
while (index < 60)
{
E += ((((A << 5) | (A >>> 0x1b)) + ((B & C) | (D & (B | C)))) + expand[index]) + 0x8f1bbcdc;
B = (B << 30) | (B >>> 2);
D += ((((E << 5) | (E >>> 0x1b)) + ((A & B) | (C & (A | B)))) + expand[index + 1]) + 0x8f1bbcdc;
A = (A << 30) | (A >>> 2);
C += ((((D << 5) | (D >>> 0x1b)) + ((E & A) | (B & (E | A)))) + expand[index + 2]) + 0x8f1bbcdc;
E = (E << 30) | (E >>> 2);
B += ((((C << 5) | (C >>> 0x1b)) + ((D & E) | (A & (D | E)))) + expand[index + 3]) + 0x8f1bbcdc;
D = (D << 30) | (D >>> 2);
A += ((((B << 5) | (B >>> 0x1b)) + ((C & D) | (E & (C | D)))) + expand[index + 4]) + 0x8f1bbcdc;
C = (C << 30) | (C >>> 2);
index += 5;
}
while (index < 80)
{
E += ((((A << 5) | (A >>> 0x1b)) + ((B ^ C) ^ D)) + expand[index]) + 0xca62c1d6;
B = (B << 30) | (B >>> 2);
D += ((((E << 5) | (E >>> 0x1b)) + ((A ^ B) ^ C)) + expand[index + 1]) + 0xca62c1d6;
A = (A << 30) | (A >>> 2);
C += ((((D << 5) | (D >>> 0x1b)) + ((E ^ A) ^ B)) + expand[index + 2]) + 0xca62c1d6;
E = (E << 30) | (E >>> 2);
B += ((((C << 5) | (C >>> 0x1b)) + ((D ^ E) ^ A)) + expand[index + 3]) + 0xca62c1d6;
D = (D << 30) | (D >>> 2);
A += ((((B << 5) | (B >>> 0x1b)) + ((C ^ D) ^ E)) + expand[index + 4]) + 0xca62c1d6;
C = (C << 30) | (C >>> 2);
index += 5;
}
h[0] += A;
h[1] += B;
h[2] += C;
h[3] += D;
h[4] += E;
}
function HashData(h, value, buffer, offset) {
var length = value.length;
var srcOffset = 0;
var dstOffset = offset & 0x3f;
var count = offset + length;
if (dstOffset > 0 && (dstOffset + length) >= 0x40) {
var x = srcOffset, y = dstOffset;
for (var i = 0; i < 0x40 - dstOffset; i++)
buffer[y++] = value[x++] & 0xff;
srcOffset += 0x40 - dstOffset;
length -= 0x40 - dstOffset;
HashTransform(h, buffer);
dstOffset = 0;
}
while (length >= 0x40)
{
var x = srcOffset, y = 0;
for (var i = 0; i < 0x40; i++)
buffer[y++] = value[x++] & 0xff;
srcOffset += 0x40;
length -= 0x40;
HashTransform(h, buffer);
}
if (length > 0) {
var x = srcOffset, y = dstOffset;
for (var i = 0; i < length; i++)
buffer[y++] = value[x++] & 0xff;
}
return count;
}
function SHA1(str) {
if (typeof(str) != 'string')
return '';
var value = new Array();
value.length = str.length;
for (var i = 0; i < value.length; i++)
value[i] = str.charCodeAt(i) & 0xff;
var h = new Array(0x67452301, 0xefcdab89, 0x98badcfe, 0x10325476, 0xc3d2e1f0);
var buffer = new Array();
buffer.length = 0x40;
var count = HashData(h, value, buffer, 0);
var length = 0x40 - (count & 0x3f);
if (length <= 8)
length += 0x40;
var block = new Array()
block.length = length;
block[0] = 0x80;
for (var i = 1; i < length - 8; i++)
block[i] = 0;
var bit = count << 3;
for (var i = 1; i <= 8; i++) {
block[length - i] = bit & 0xff;
bit >>>= 8;
}
HashData(h, block, buffer, count);
var base32 = 'abcdefghijklmnopqrstuvwxyz456789';
var result = '';
var cur_i = 0;
var cur_u = 0;
var index;
var k;
for (var i = 0; i < 32; i++) {
index = 0;
for (var j = 0; j < 5; j++) {
k = i * 5 + j;
if (k == 160)
break;
if (k % 32 == 0)
cur_u = h[cur_i++];
index <<= 1;
index |= (cur_u & 0x80000000) == 0 ? 0 : 1;
cur_u <<= 1;
}
result += base32.charAt(index);
}
return result;
}
其中:str 为待加密字符串,在这里仅支持 ASCII 字符。
另外,RSA 中的 exponent 和 modulus 以及 RSA 和 SHA1 的返回值均使用伪 Base32 编码,.NET 可参考 http://www.cnblogs.com/hust21941/archive/2008/08/13/base32.html ,其他语言可以自行修改。