Base64--网络传输
自从引用以来,Base64编码的标准极普及为的迅速。不过,把文件作为附件通过网际邮件扩充协议(MIME)传送时,Base64是标准的编码标准。然而,几乎所有的电子邮件客户端都是用MIME发送文件(以附件形式)的,这就意味着大多数的电子邮件客户端使用Base64对文件编码后通过网络传输。格式如下:
Content-Transfer-Encoding:base64(Gb2312)
这种传输格式又被称为U-t-U(Unixto Unix)传输协议,能兼容大多数的硬件设备并基于其上进行无损字节传输。但是缺点在于是,使用此种格式会使文件的大小增加百分之四十左右。
除了作为MIME的默认编码标准,base64编码也广泛用于其他领域。一个常见的例子是用于网络服务器完成基于HTTP的基本认证。当服务器想限制访问某些文件时,通过使用基于HTTP的基本认证系统,便可以对这些文件进行密码保护。而基本认证使用Base64编码标准对用户名和密码进行编码。这样,黑客们使用TCP通过端口连接ESMTP服务器时,手动输入量就会大大增加。
尽管Base64编码受到广泛的支持和应用,但却是当今最弱的编码标准之一,通过以下步骤就可以轻易地进行逆向工程。不仅仅是算法上的容易逆向,因为在网络上Base64用纯文本形式发送密码,使得Base64加密文本很容易受到sniffer程序的嗅探。
编码程序如下:
-
将要加密的文本的每个字符转换成标准的ASCII十进制码。
-
通过任何一种方式(手算、机器算、对照表格)将这部分十进制编码转换成二进制(文章最后附有转换表)编码。每个十进制码都对应器等价的八位二进制数值。
-
将这部分二进制数连结到一起,产生一串二进制数。
-
将这一大片的二进制字符串分割成每6个字符为一部分的小块。
-
通过任何一种方式(手算、机器算、对照表格)将这部分6字符的小块分别转换成相应的等价十进制数。
-
通过Base64表转换成Base64编码。
Base64编码转换表如下:
-
十进制
编码
十进制
编码
十进制
编码
十进制
编码
0
A
16
Q
32
g
48
w
1
B
17
R
33
h
49
x
2
C
18
S
34
i
50
y
3
D
19
T
35
j
51
z
4
E
20
U
36
k
52
0
5
F
21
V
37
l
53
1
6
G
22
W
38
m
54
2
7
H
23
X
39
n
55
3
8
I
24
Y
40
o
56
4
9
J
25
Z
41
p
57
5
10
K
26
a
42
q
58
6
11
L
27
b
43
r
59
7
12
M
28
c
44
s
60
8
13
N
29
d
45
t
61
9
14
O
30
e
46
u
62
+
15
P
31
f
47
v
63
/
例如:mne,通过ASCII字符表转化为是进制值为:m、109,n,110,e、101.合起来就是:109110101.转化为二进制就是:01101101 0110 1110 0110 0101。将它们分成六个字为一段:011011010110 111001 100101。而他们对应的十进制字符分别是:2722 57 37。Base64等价值就是:27、b,22、w,57、5,37、1,也就是说mne的Base64编码是bw51。
需要注意的是:如果被加密的字符串每3个一组,还剩1或2个字符,使用特殊字符“=”补齐Base64成为4个字。
知道了加密方式,要逆向就很简单了。将对应的Base64值转换为十进制,再通过计算转换成二进制编码。将这一串码分为8位1组,得到十进制码,最后再等价到相应的ASCII编码即可。
附1:ASCII编码表(部分)
二进制 | 十进制 | 十六进制 | 缩写/字符 | 解释 |
00000000 | 0 | 00 | NUL(null) | 空字符 |
00000001 | 1 | 01 | SOH(start of handing) | 标题开始 |
00000010 | 2 | 02 | STX(start of text) | 正文开始 |
00000011 | 3 | 03 | ETX(end of text) | 正文结束 |
00000100 | 4 | 04 | EOT(end of transmission) | 传输结束 |
00000101 | 5 | 05 | ENQ(enquiry) | 请求 |
00000110 | 6 | 06 | ACK(acknowledge) | 收到通知 |
00000111 | 7 | 07 | BEL(bell) | 响铃 |
00001000 | 8 | 08 | BS(backspace) | 退格 |
00001001 | 9 | 09 | HT(horizontal tab) | 水平制表符 |
00001010 | 10 | 0A | LF(NL line feed, new line) | 换行键 |
00001011 | 11 | 0B | VT(vertical tab) | 垂直制表符 |
00001100 | 12 | 0C | FF(NP form feed, new page) | 换页键 |
00001101 | 13 | 0D | CR(carriage return) | 回车键 |
00001110 | 14 | 0E | SO(shift out) | 不用切换 |
00001111 | 15 | 0F | SI(shift in) | 启用切换 |
00010000 | 16 | 10 | DLE(data link escape) | 数据链路转义 |
00010001 | 17 | 11 | DC1(device control 1) | 设备控制1 |
00010010 | 18 | 12 | DC2(device control 2) | 设备控制2 |
00010011 | 19 | 13 | DC3(device control 3) | 设备控制3 |
00010100 | 20 | 14 | DC4(device control 4) | 设备控制4 |
00010101 | 21 | 15 | NAK(negative acknowledge) | 拒绝接收 |
00010110 | 22 | 16 | SYN(synchronous idle) | 同步空闲 |
00010111 | 23 | 17 | ETB(end of trans. block) | 传输块结束 |
00011000 | 24 | 18 | CAN(cancel) | 取消 |
00011001 | 25 | 19 | EM(end of medium) | 介质中断 |
00011010 | 26 | 1A | SUB(substitute) | 替补 |
00011011 | 27 | 1B | ESC(escape) | 溢出 |
00011100 | 28 | 1C | FS(file separator) | 文件分割符 |
00011101 | 29 | 1D | GS(group separator) | 分组符 |
00011110 | 30 | 1E | RS(record separator) | 记录分离符 |
00011111 | 31 | 1F | US(unit separator) | 单元分隔符 |
附2:下列Perl脚本将会自动帮你做解密:
UseMIME::Base64;
Printdecode_base64(“Insert Text here”);
附3:使用Java脚本实现解密(代码):
<scripttype="text/javascript">
varbase64EncodeChars ="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
varbase64DecodeChars = new Array(
-1,-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1,-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1,-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 62, -1, -1, -1, 63,
52,53, 54, 55, 56, 57, 58, 59, 60, 61, -1, -1, -1, -1, -1, -1,
-1,0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
15,16, 17, 18, 19, 20, 21, 22, 23, 24, 25, -1, -1, -1, -1, -1,
-1,26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40,
41,42, 43, 44, 45, 46, 47, 48, 49, 50, 51, -1, -1, -1, -1, -1);
functionbase64Encode(str) {
varout, i, len;
varc1, c2, c3;
len= str.length;
i= 0;
out= "";
while(i< len) {
c1= str.charCodeAt(i++) & 0xff;
if(i== len)
{
out+= base64EncodeChars.charAt(c1 >> 2);
out+= base64EncodeChars.charAt((c1 & 0x3) << 4);
out+= "==";
break;
}
c2= str.charCodeAt(i++);
if(i== len)
{
out+= base64EncodeChars.charAt(c1 >> 2);
out+= base64EncodeChars.charAt(((c1 & 0x3)<< 4) | ((c2 &0xF0) >> 4));
out+= base64EncodeChars.charAt((c2 & 0xF) << 2);
out+= "=";
break;
}
c3= str.charCodeAt(i++);
out+= base64EncodeChars.charAt(c1 >> 2);
out+= base64EncodeChars.charAt(((c1 & 0x3)<< 4) | ((c2 &0xF0) >> 4));
out+= base64EncodeChars.charAt(((c2 & 0xF) << 2) | ((c3 &0xC0) >>6));
out+= base64EncodeChars.charAt(c3 & 0x3F);
}
returnout;
}
functionbase64Decode(str) {
varc1, c2, c3, c4;
vari, len, out;
len= str.length;
i= 0;
out= "";
while(i< len) {
/*c1 */
do{
c1= base64DecodeChars[str.charCodeAt(i++) & 0xff];
}while(i < len && c1 == -1);
if(c1== -1)
break;
/*c2 */
do{
c2= base64DecodeChars[str.charCodeAt(i++) & 0xff];
}while(i < len && c2 == -1);
if(c2== -1)
break;
out+= String.fromCharCode((c1 << 2) | ((c2 & 0x30) >>4));
/*c3 */
do{
c3= str.charCodeAt(i++) & 0xff;
if(c3== 61)
returnout;
c3= base64DecodeChars[c3];
}while(i < len && c3 == -1);
if(c3== -1)
break;
out+= String.fromCharCode(((c2 & 0XF) << 4) | ((c3 & 0x3C)>> 2));
/*c4 */
do{
c4= str.charCodeAt(i++) & 0xff;
if(c4== 61)
returnout;
c4= base64DecodeChars[c4];
}while(i < len && c4 == -1);
if(c4== -1)
break;
out+= String.fromCharCode(((c3 & 0x03) << 6) | c4);
}
returnout;
}
alert("原文:"+sTemp+"\n加密:"+base64Encode(sTemp)+"\n解密:"+base64Decode(base64Encode(sTemp)));
alert("原文:"+sTemp+"\n加密:"+base64Encode(sTemp)+"\n解密:"+base64Decode(base64Encode(sTemp)));
</script>
MD5
1.简介
MD5的全称是Message-Digest Algorithm 5(信息-摘要算法),在90年代初由MIT的计算机科学实验室和RSA Data Security Inc发明,经MD2、MD3和MD4发展而来。 http://www.ietf.org/rfc/rfc1321.txt,是一份最权威的文档,由ronaldl. rivest在1992年8月向ieft提交。
Message-Digest泛指字节串(Message)的Hash变换,就是把一个任意长度的字节串变换成一定长的大整数。请注意我使用了“字节串”而不是“字符串”这个词,是因为这种变换只与字节的值有关,与字符集或编码方式无关。
MD5将任意长度的“字节串”变换成一个128bit的大整数,并且它是一个不可逆的字符串变换算法,换句话说就是,即使你看到源程序和算法描述,也无法 将一个MD5的值变换回原始的字符串,从数学原理上说,是因为原始的字符串有无穷多个,这有点象不存在反函数的数学函数。
MD5的典型应用是对一段Message(字节串)产生fingerprint(指纹),以防止被“篡改”。举个例子,你将一段话写在一个叫 readme.txt文件中,并对这个readme.txt产生一个MD5的值并记录在案,然后你可以传播这个文件给别人,别人如果修改了文件中的任何内 容,你对这个文件重新计算MD5时就会发现。如果再有一个第三方的认证机构,用MD5还可以防止文件作者的“抵赖”,这就是所谓的数字签名应用。
MD5还广泛用于加密和解密技术上,在很多操作系统中,用户的密码是以MD5值(或类似的其它算法)的方式保存的,用户Login的时候,系统是把用户输入的密码计算成MD5值,然后再去和系统中保存的MD5值进行比较,而系统并不“知道”用户的密码是什么。
一些黑客破获这种密码的方法是一种被称为“跑字典”的方法。有两种方法得到字典,一种是日常搜集的用做密码的字符串表,另一种是用排列组合方法生成的,先用MD5程序计算出这些字典项的MD5值,然后再用目标的MD5值在这个字典中检索。
即使假设密码的最大长度为8,同时密码只能是字母和数字,共26+26+10=62个字符,排列组合出的字典的项数则是 P(62,1)+P(62,2)….+P(62,8),那也已经是一个很天文的数字了,存储这个字典就需要TB级的磁盘组,而且这种方法还有一个前提,就 是能获得目标账户的密码MD5值的情况下才可以。
2.用途
MD5的作用是对一段信息(message)生成信息摘要(message-digest),该摘要对该信息具有唯一性,可以作为数字签名。用于验证文件的有效性(是否有丢失或损坏的数据),对用户密码的加密,在哈希函数中计算散列值。
MD5的典型应用
(1).密码加密
将用户设置的密码进行md5运算后存入数据库。当用户登录时,只需再求一次md5值,并与数据库中的值进行比对。判断密码是否正确就知道用户的合法性了。 因为md5不可逆,所以即使数据库被突破或下载,也不可能知道用户密码。而这样带来的问题就是用户也不能找回密码,而只能在达成一定的条件后让用户重置密码。这就是为什么现在越来越多的网站不能找回密码,而只能重置密码。因为多数使用了不可逆算法(此处不只md5,也包括其它不可逆算法的应用)。
对于有找回密码功能的系统,密码机制要更加注意,要么你存储的就是明文,要么密码加密的机制是可以反向破解的。
(2).文件校验
因为md5的重码率低到只存在理论可能,因此常被用来校验数据是否被篡改(或者检查文件是否下载正确)。我们常见的,一些下载网站会给出文件的md5值,以供用户在下载后校验(一般称为 "check sum" or md5sum) ,因为即使在下载过程中,只改动了一个字节,其md5值也会改变。
3.特点
MD5采用的是对输入的任意长度的消息进行运算,产生一个128位的消息摘要,并且它是一个不可逆的字符串变换算法,换句话说就是,即使你看到源程序和算法描述,也无法将一个MD5的值变换回原始的字符串。
4.说明
唯一性和不可逆性都不是绝对的,从理论上分析是一种多对一的关系,但两个不同的信息产生相同摘要的概率很小。不可逆是指从输出反推输入所需的运算量和计算时间太大,使用穷搜字典的方法又需要太多的存储空间。
5.算法描述
算法输入是一个字节串,每个字节是8个bit.
算法的执行分为以下几个步骤:
第一步,补位:
MD5算法先对输入的数据进行补位,使得数据的长度(以byte为单位)对64求余的结果是56。
即数据扩展至LEN=K*64+56个字节,K为整数。
补位方法:补一个1,然后补0至满足上述要求。相当于补一个0x80的字节,再补值
为0的字节。这一步里总共补充的字节数为0~63个。
第二步,附加数据长度:
用一个64位的整数表示数据的原始长度(以bit为单位),将这个数字的8个字节按低位的在前,
高位在后的顺序附加在补位后的数据后面。这时,数据被填补后的总长度为:
LEN= K*64+56+8=(K+1)*64 Bytes。
※注意那个64位整数是输入数据的原始长度而不是填充字节后的长度,我就在这里栽了跟头.
第三步,初始化MD5参数:
有四个32位整数变量(A,B,C,D)用来计算信息摘要,每一个变量被初始化成以下
以十六进制数表示的数值,低位的字节在前面。
wordA: 01 23 45 67
wordB: 89 ab cd ef
wordC: fe dc ba 98
wordD: 76 54 32 10
※注意低位的字节在前面指的是LittleEndian平台上内存中字节的排列方式,
而在程序中书写时,要写成:
A=0x67452301
B=0xefcdab89
C=0x98badcfe
D=0x10325476
第四步,定义四个MD5基本的按位操作函数:
X,Y,Z为32位整数。
F(X,Y,Z)= (X and Y) or (not(X) and Z)
G(X,Y,Z)= (X and Z) or (Y and not(Z))
H(X,Y,Z)= X xor Y xor Z
I(X,Y,Z)= Y xor (X or not(Z))
再定义四个分别用于四轮变换的函数。
设Mj表示消息的第j个子分组(从0到15),<<<s表示循环左移s位,则四种操作为:
FF(a,b,c,d,Mj,s,ti)表示a=b+((a+(F(b,c,d)+Mj+ti)<<<s)
GG(a,b,c,d,Mj,s,ti)表示a=b+((a+(G(b,c,d)+Mj+ti)<<<s)
HH(a,b,c,d,Mj,s,ti)表示a=b+((a+(H(b,c,d)+Mj+ti)<<<s)
II(a,b,c,d,Mj,s,ti)表示a=b+((a+(I(b,c,d)+Mj+ti)<<<s)
第五步,对输入数据作变换。
处理数据,N是总的字节数,以64个字节为一组,每组作一次循环,每次循环进行四轮操作。
要变换的64个字节用16个32位的整数数组M[0...15]表示。而数组T[1... 64]表示一组常数,
T[i]为4294967296*abs(sin(i))的32位整数部分,i的单位是弧度,i的取值从1到64。
具体过程如下:
/*设置主循环变量*/
Fori = 0 to N/16-1 do
/*每循环一次,把数据原文存放在16个元素的数组X中.*/
Forj = 0 to 15 do
SetX[j] to M[i*16+j].
end/结束对J的循环
/*Save A as AA, B as BB, C as CC, and D as DD.
*/
AA= A
BB= B
CC= C
DD= D
/*第1轮*/
/*以 [abcdk s i]表示如下操作
a= b + ((a + F(b,c,d) + X[k] + T[i]) <<< s). */
/*Do the following 16 operations. */
[ABCD 0 7 1] [DABC 1 12 2] [CDAB 2 17 3] [BCDA 3 22 4]
[ABCD 4 7 5] [DABC 5 12 6] [CDAB 6 17 7] [BCDA 7 22 8]
[ABCD 8 7 9] [DABC 9 12 10] [CDAB 10 17 11] [BCDA 11 22 12]
[ABCD12 7 13] [DABC 13 12 14] [CDAB 14 17 15] [BCDA 15 22 16]
/*第2轮**/
/*以 [abcdk s i]表示如下操作
a= b + ((a + G(b,c,d) + X[k] + T[i]) <<< s). */
/*Do the following 16 operations. */
[ABCD 1 5 17] [DABC 6 9 18] [CDAB 11 14 19] [BCDA 0 20 20]
[ABCD 5 5 21] [DABC 10 9 22] [CDAB 15 14 23] [BCDA 4 20 24]
[ABCD 9 5 25] [DABC 14 9 26] [CDAB 3 14 27] [BCDA 8 20 28]
[ABCD13 5 29] [DABC 2 9 30] [CDAB 7 14 31] [BCDA 12 20 32]
/*第3轮*/
/*以 [abcdk s i]表示如下操作
a= b + ((a + H(b,c,d) + X[k] + T[i]) <<< s). */
/*Do the following 16 operations. */
[ABCD 5 4 33] [DABC 8 11 34] [CDAB 11 16 35] [BCDA 14 23 36]
[ABCD 1 4 37] [DABC 4 11 38] [CDAB 7 16 39] [BCDA 10 23 40]
[ABCD13 4 41] [DABC 0 11 42] [CDAB 3 16 43] [BCDA 6 23 44]
[ABCD 9 4 45] [DABC 12 11 46] [CDAB 15 16 47] [BCDA 2 23 48]
/*第4轮*/
/*以 [abcdk s i]表示如下操作
a= b + ((a + I(b,c,d) + X[k] + T[i]) <<< s). */
/*Do the following 16 operations. */
[ABCD 0 6 49] [DABC 7 10 50] [CDAB 14 15 51] [BCDA 5 21 52]
[ABCD12 6 53] [DABC 3 10 54] [CDAB 10 15 55] [BCDA 1 21 56]
[ABCD 8 6 57] [DABC 15 10 58] [CDAB 6 15 59] [BCDA 13 21 60]
[ABCD 4 6 61] [DABC 11 10 62] [CDAB 2 15 63] [BCDA 9 21 64]
/*然后进行如下操作*/
A= A + AA
B= B + BB
C= C + CC
D= D + DD
Nexti /* 结束对I的循环*/
第六步,输出结果。
A,B,C,D连续存放,共16个字节,128位。按十六进制依次输出这个16个字节。
最后,用程序语言实现算法后,可以输入以下几个信息对程序作一个简单的测试,
看看程序有没有错误。
MD5("") = d41d8cd98f00b204e9800998ecf8427e
MD5("a") = 0cc175b9c0f1b6a831c399e269772661
MD5("abc") = 900150983cd24fb0d6963f7d28e17f72
MD5("message digest") = f96b697d7cb7938d525a2f31aaf161d0
MD5("abcdefghijklmnopqrstuvwxyz") =c3fcd3d76192e4007dfb496cca67e13b
MD5("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789")=
d174ab98d277d9f5a5611c2c9f419d9f
MD5("123456789012345678901234567890123456789012345678901234567890123456789
01234567890")= 57edf4a22be3c955ac49da2e2107b67a
MD5算法之C#程序
[code]
//源文件:md5.cs
//MD5 Alogrithm
//by rufi 2004.6.20 http://rufi.yculblog.com/
usingSystem;
usingSystem.Collections;
usingSystem.IO;
publicclass MD5 {
//staticstate variables
privatestatic UInt32 A;
privatestatic UInt32 B;
privatestatic UInt32 C;
privatestatic UInt32 D;
//numberof bits to rotate in tranforming
privateconst int S11 = 7;
privateconst int S12 = 12;
privateconst int S13 = 17;
privateconst int S14 = 22;
privateconst int S21 = 5;
privateconst int S22 = 9;
privateconst int S23 = 14;
privateconst int S24 = 20;
privateconst int S31 = 4;
privateconst int S32 = 11;
privateconst int S33 = 16;
privateconst int S34 = 23;
privateconst int S41 = 6;
privateconst int S42 = 10;
privateconst int S43 = 15;
privateconst int S44 = 21;
/*F, G, H and I are basic MD5 functions.
*四个非线性函数:
*
*F(X,Y,Z) =(X&Y)|((~X)&Z)
*G(X,Y,Z) =(X&Z)|(Y&(~Z))
*H(X,Y,Z) =X^Y^Z
*I(X,Y,Z)=Y^(X|(~Z))
*
*(&与,|或,~非,^异或)
*/
privatestatic UInt32 F(UInt32 x,UInt32 y,UInt32 z){
return(x&y)|((~x)&z);
}
privatestatic UInt32 G(UInt32 x,UInt32 y,UInt32 z){
return(x&z)|(y&(~z));
}
privatestatic UInt32 H(UInt32 x,UInt32 y,UInt32 z){
returnx^y^z;
}
privatestatic UInt32 I(UInt32 x,UInt32 y,UInt32 z){
returny^(x|(~z));
}
/*FF, GG, HH, and II transformations for rounds 1, 2, 3, and 4.
*Rotation is separate from addition to prevent recomputation.
*/
privatestatic void FF(ref UInt32 a,UInt32 b,UInt32 c,UInt32 d,UInt32 mj,ints,UInt32 ti){
a= a + F(b,c,d) + mj + ti;
a= a << s | a >> (32-s);
a+= b;
}
privatestatic void GG(ref UInt32 a,UInt32 b,UInt32 c,UInt32 d,UInt32 mj,ints,UInt32 ti){
a= a + G(b,c,d) + mj + ti;
a= a << s | a >> (32-s);
a+= b;
}
privatestatic void HH(ref UInt32 a,UInt32 b,UInt32 c,UInt32 d,UInt32 mj,ints,UInt32 ti){
a= a + H(b,c,d) + mj + ti;
a= a << s | a >> (32-s);
a+= b;
}
privatestatic void II(ref UInt32 a,UInt32 b,UInt32 c,UInt32 d,UInt32 mj,ints,UInt32 ti){
a= a + I(b,c,d) + mj + ti;
a= a << s | a >> (32-s);
a+= b;
}
privatestatic void MD5_Init(){
A=0x67452301; //in memory, this is 0x01234567
B=0xefcdab89; //in memory, this is 0x89abcdef
C=0x98badcfe; //in memory, this is 0xfedcba98
D=0x10325476; //in memory, this is 0x76543210
}
privatestatic UInt32[] MD5_Append(byte[] input){
intzeros=0;
intones =1;
intsize=0;
intn = input.Length;
intm = n%64;
if(m < 56 ){
zeros= 55-m;
size=n-m+64;
}
elseif (m==56){
zeros= 0;
ones= 0;
size=n+8;
}
else{
zeros= 63-m+56;
size=n+64-m+64;
}
ArrayListbs = new ArrayList(input);
if(ones==1){
bs.Add((byte)0x80 ); // 0x80 = $10000000
}
for(inti=0;i<zeros;i++){
bs.Add((byte)0 );
}
UInt64N = (UInt64) n * 8;
byteh1=(byte)(N&0xFF);
byteh2=(byte)((N>>8)&0xFF);
byteh3=(byte)((N>>16)&0xFF);
byteh4=(byte)((N>>24)&0xFF);
byteh5=(byte)((N>>32)&0xFF);
byteh6=(byte)((N>>40)&0xFF);
byteh7=(byte)((N>>48)&0xFF);
byteh8=(byte)(N>>56);
bs.Add(h1);
bs.Add(h2);
bs.Add(h3);
bs.Add(h4);
bs.Add(h5);
bs.Add(h6);
bs.Add(h7);
bs.Add(h8);
byte[]ts=(byte[])bs.ToArray(typeof(byte));
/*Decodes input (byte[]) into output (UInt32[]). Assumes len is
*a multiple of 4.
*/
UInt32[]output = new UInt32[size/4];
for(Int64i=0,j=0;i<size;j++,i+=4){
output[j]=(UInt32)(ts[i]| ts[i+1]<<8 | ts[i+2]<<16 | ts[i+3]<<24);
}
returnoutput;
}
privatestatic UInt32[] MD5_Trasform(UInt32[] x){
UInt32a,b,c,d;
for(intk=0;k<x.Length;k+=16){
a=A;
b=B;
c=C;
d=D;
/*Round 1 */
FF(ref a, b, c, d, x[k+ 0], S11, 0xd76aa478); /* 1 */
FF(ref d, a, b, c, x[k+ 1], S12, 0xe8c7b756); /* 2 */
FF(ref c, d, a, b, x[k+ 2], S13, 0x242070db); /* 3 */
FF(ref b, c, d, a, x[k+ 3], S14, 0xc1bdceee); /* 4 */
FF(ref a, b, c, d, x[k+ 4], S11, 0xf57c0faf); /* 5 */
FF(ref d, a, b, c, x[k+ 5], S12, 0x4787c62a); /* 6 */
FF(ref c, d, a, b, x[k+ 6], S13, 0xa8304613); /* 7 */
FF(ref b, c, d, a, x[k+ 7], S14, 0xfd469501); /* 8 */
FF(ref a, b, c, d, x[k+ 8], S11, 0x698098d8); /* 9 */
FF(ref d, a, b, c, x[k+ 9], S12, 0x8b44f7af); /* 10 */
FF(ref c, d, a, b, x[k+10], S13, 0xffff5bb1); /* 11 */
FF(ref b, c, d, a, x[k+11], S14, 0x895cd7be); /* 12 */
FF(ref a, b, c, d, x[k+12], S11, 0x6b901122); /* 13 */
FF(ref d, a, b, c, x[k+13], S12, 0xfd987193); /* 14 */
FF(ref c, d, a, b, x[k+14], S13, 0xa679438e); /* 15 */
FF(ref b, c, d, a, x[k+15], S14, 0x49b40821); /* 16 */
/*Round 2 */
GG(ref a, b, c, d, x[k+ 1], S21, 0xf61e2562); /* 17 */
GG(ref d, a, b, c, x[k+ 6], S22, 0xc040b340); /* 18 */
GG(ref c, d, a, b, x[k+11], S23, 0x265e5a51); /* 19 */
GG(ref b, c, d, a, x[k+ 0], S24, 0xe9b6c7aa); /* 20 */
GG(ref a, b, c, d, x[k+ 5], S21, 0xd62f105d); /* 21 */
GG(ref d, a, b, c, x[k+10], S22, 0x2441453); /* 22 */
GG(ref c, d, a, b, x[k+15], S23, 0xd8a1e681); /* 23 */
GG(ref b, c, d, a, x[k+ 4], S24, 0xe7d3fbc8); /* 24 */
GG(ref a, b, c, d, x[k+ 9], S21, 0x21e1cde6); /* 25 */
GG(ref d, a, b, c, x[k+14], S22, 0xc33707d6); /* 26 */
GG(ref c, d, a, b, x[k+ 3], S23, 0xf4d50d87); /* 27 */
GG(ref b, c, d, a, x[k+ 8], S24, 0x455a14ed); /* 28 */
GG(ref a, b, c, d, x[k+13], S21, 0xa9e3e905); /* 29 */
GG(ref d, a, b, c, x[k+ 2], S22, 0xfcefa3f8); /* 30 */
GG(ref c, d, a, b, x[k+ 7], S23, 0x676f02d9); /* 31 */
GG(ref b, c, d, a, x[k+12], S24, 0x8d2a4c8a); /* 32 */
/*Round 3 */
HH(ref a, b, c, d, x[k+ 5], S31, 0xfffa3942); /* 33 */
HH(ref d, a, b, c, x[k+ 8], S32, 0x8771f681); /* 34 */
HH(ref c, d, a, b, x[k+11], S33, 0x6d9d6122); /* 35 */
HH(ref b, c, d, a, x[k+14], S34, 0xfde5380c); /* 36 */
HH(ref a, b, c, d, x[k+ 1], S31, 0xa4beea44); /* 37 */
HH(ref d, a, b, c, x[k+ 4], S32, 0x4bdecfa9); /* 38 */
HH(ref c, d, a, b, x[k+ 7], S33, 0xf6bb4b60); /* 39 */
HH(ref b, c, d, a, x[k+10], S34, 0xbebfbc70); /* 40 */
HH(ref a, b, c, d, x[k+13], S31, 0x289b7ec6); /* 41 */
HH(ref d, a, b, c, x[k+ 0], S32, 0xeaa127fa); /* 42 */
HH(ref c, d, a, b, x[k+ 3], S33, 0xd4ef3085); /* 43 */
HH(ref b, c, d, a, x[k+ 6], S34, 0x4881d05); /* 44 */
HH(ref a, b, c, d, x[k+ 9], S31, 0xd9d4d039); /* 45 */
HH(ref d, a, b, c, x[k+12], S32, 0xe6db99e5); /* 46 */
HH(ref c, d, a, b, x[k+15], S33, 0x1fa27cf8); /* 47 */
HH(ref b, c, d, a, x[k+ 2], S34, 0xc4ac5665); /* 48 */
/*Round 4 */
II(ref a, b, c, d, x[k+ 0], S41, 0xf4292244); /* 49 */
II(ref d, a, b, c, x[k+ 7], S42, 0x432aff97); /* 50 */
II(ref c, d, a, b, x[k+14], S43, 0xab9423a7); /* 51 */
II(ref b, c, d, a, x[k+ 5], S44, 0xfc93a039); /* 52 */
II(ref a, b, c, d, x[k+12], S41, 0x655b59c3); /* 53 */
II(ref d, a, b, c, x[k+ 3], S42, 0x8f0ccc92); /* 54 */
II(ref c, d, a, b, x[k+10], S43, 0xffeff47d); /* 55 */
II(ref b, c, d, a, x[k+ 1], S44, 0x85845dd1); /* 56 */
II(ref a, b, c, d, x[k+ 8], S41, 0x6fa87e4f); /* 57 */
II(ref d, a, b, c, x[k+15], S42, 0xfe2ce6e0); /* 58 */
II(ref c, d, a, b, x[k+ 6], S43, 0xa3014314); /* 59 */
II(ref b, c, d, a, x[k+13], S44, 0x4e0811a1); /* 60 */
II(ref a, b, c, d, x[k+ 4], S41, 0xf7537e82); /* 61 */
II(ref d, a, b, c, x[k+11], S42, 0xbd3af235); /* 62 */
II(ref c, d, a, b, x[k+ 2], S43, 0x2ad7d2bb); /* 63 */
II(ref b, c, d, a, x[k+ 9], S44, 0xeb86d391); /* 64 */
A+=a;
B+=b;
C+=c;
D+=d;
}
returnnew UInt32[]{A,B,C,D};
}
publicstatic byte[] MD5Array(byte[] input){
MD5_Init();
UInt32[]block = MD5_Append(input);
UInt32[]bits = MD5_Trasform(block);
/*Encodes bits (UInt32[]) into output (byte[]). Assumes len is
*a multiple of 4.
*/
byte[]output=new byte[bits.Length*4];
for(inti=0,j=0;i<bits.Length;i++,j+=4){
output[j]= (byte)(bits[i] & 0xff);
output[j+1]= (byte)((bits[i] >> 8) & 0xff);
output[j+2]= (byte)((bits[i] >> 16) & 0xff);
output[j+3]= (byte)((bits[i] >> 24) & 0xff);
}
returnoutput;
}
publicstatic string ArrayToHexString(byte[] array,bool uppercase){
stringhexString="";
stringformat="x2";
if(uppercase){
format="X2";
}
foreach(byteb in array){
hexString+= b.ToString(format);
}
returnhexString;
}
publicstatic string MDString(string message){
char[]c = message.ToCharArray();
byte[]b = new byte[c.Length];
for(inti=0;i<c.Length;i++){
b[i]=(byte)c[i];
}
byte[]digest = MD5Array(b);
returnArrayToHexString(digest,false);
}
publicstatic string MDFile(string fileName){
FileStreamfs=File.Open(fileName,FileMode.Open,FileAccess.Read);
byte[]array=new byte[fs.Length];
fs.Read(array,0,(int)fs.Length);
byte[]digest = MD5Array(array);
fs.Close();
returnArrayToHexString(digest,false);
}
publicstatic string Test(string message){
return"rnMD5 (""+message+"") = " +MD5.MDString(message);
}
publicstatic string TestSuite(){
strings = "";
s+=Test("");
s+=Test("a");
s+=Test("abc");
s+=Test("messagedigest");
s+=Test("abcdefghijklmnopqrstuvwxyz");
s+=Test("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789");
s+=Test("12345678901234567890123456789012345678901234567890123456789012345678901234567890");
returns;
}
}