基于JavaScript实现MD5散列函数辅助计算器
因为最近在学信息加密技术,搞清楚了加密原理,但又不想手动去计算,所以就用JavaScript写了一个网页版的MD5散列函数的辅助计算器,计算器的输入与输出都是16进制形式。
当然,因为我需要的是每一轮每一步的结果,所以计算器每一次运行只能计算一步。
首先,MD5的散列原理:
(1)填充消息:任意长度的消息首先需要进行填充处理,使得填充后的消息总长度与448模512同余。填充的方法是在消息后面添加一位1,后续都是0.
(2)添加原始消息长度:在填充后的消息后面再添加一个64位的二进制整数表示填充前原始消息的长度,第(1)步跟第(2)完成之后刚好消息的长度为512位。
(3)初始值(IV)的初始化MD5中有四个32位缓冲区,用A,B,C,D表示,用来存散列计算的中间结果和最终结果,缓冲区的值被称为链接变量。先将其分别初始化为:A=0x1234567、B=0x89abcdef、C=0xfedcba98、D=0x76543210,这些值以高端格式存储,即字节的最高有效位存于低地址字节位置。
(4)以512位的分组为单位,依据四个非线性函数对消息进行循环散列计算,四轮共64步计算。
非线性函数:FF(A,B,C,D,M,s,t) 表示 A = B+(A+(F(B,C,D)+M+T)<<<s)
F(X,Y,Z)=(X&Y)|((非B)&Z)
GG(A,B,C,D,M,s,t) 表示 A = B+(A+(G(B,C,D)+M+T)<<<s)
G(X,Y,Z)=(X&Z)|(Y&(非Z))
HH(A,B,C,D,M,s,t) 表示 A = B+(A+(H(B,C,D)+M+T)<<<s)
H(X,Y,Z)=(X^Y^Z)
II(A,B,C,D,M,s,t) 表示 A = B+(A+(I(B,C,D)+M+T)<<<s)
I(X,Y,Z)=Y^(X|(非Z)
(5)输出散列值。
写的这个计算器就是属于第(4)、第(5)部分。
计算器涉及到的内容有html网页、css样式表、JavaScript函数等基础操作。
主界面:七个输入数据的文本框框,一个结果文本框,四个计算按钮,一个显示公式的多行文本框
其中M[j]是填充后的消息分组;S是循环左移的位数;T[I]是常数,在下面。
主界面代码:利用了css盒子来进行布局;引用了一个外部样式表和三个外部js文件
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>MD5迭代计算</title>
<link rel="stylesheet" type="text/css" href="样式表.css">
<script type="text/javascript" src="zhuhanshu.js"></script>
<script type="text/javascript" src="进制转换.js"></script>
<script type="text/javascript" src="逻辑运算.js"></script>
</head>
<body>
<div><!---创建输入框 -->
<div id="box1">MD5散列函数辅助计算器(16进制)</div>
<div id="box2">**********每一次运行只计算一次**********</div>
<div id="box3">
<div id="box3_1">输入A:<input type="text" id="shu_1" onkeyup="UpperCase(this.id)"></div>
<div id="box3_2">输入B:<input type="text" id="shu_2" onkeyup="UpperCase(this.id)"></div>
</div>
<div id="box3">
<div id="box3_1">输入C:<input type="text" id="shu_3" onkeyup="UpperCase(this.id)"></div>
<div id="box3_2">输入D:<input type="text" id="shu_4" onkeyup="UpperCase(this.id)"></div>
</div>
<div id="box3">
<div id="box3_1">输入M[j]:<input type="text" id="shu_5" onkeyup="UpperCase(this.id)"></div>
<div id="box3_2">输入S:<input type="text" id="shu_6"></div>
</div>
<div id="box3">
<div id="box3_1">输入T[i]:<input type="text" id="shu_7" onkeyup="UpperCase(this.id)"></div>
<div id="box3_2">计算结果:<input type="text" id="shu_8"></div>
</div>
<div id="box4">
<!---创建事件按钮 -->
<div id="box4_1"><button onclick="FFjisuan()"><font size="6"> FF计算 </font></button></div>
<div id="box4_1"><button onclick="GGjisuan()"><font size="6"> GG计算 </font></button></div>
<div id="box4_1"><button onclick="HHjisuan()"><font size="6"> HH计算 </font></button></div>
<div id="box4_1"><button onclick="IIjisuan()"><font size="6"> II计算 </font></button></div>
</div>
<div id="textarea">
<textarea rows="12" cols="100">
公式:FF(A,B,C,D,M,s,t) 表示 A = B+(A+(F(B,C,D)+M+T)<<<s)
F(X,Y,Z)=(X&Y)|((非B)&Z)>
公式:FF(A,B,C,D,M,s,t) 表示 A = B+(A+(G(B,C,D)+M+T)<<<s)
G(X,Y,Z)=(X&Z)|(Y&(非Z))>
公式:FF(A,B,C,D,M,s,t) 表示 A = B+(A+(H(B,C,D)+M+T)<<<s)
H(X,Y,Z)=(X^Y^Z)>
公式:FF(A,B,C,D,M,s,t) 表示 A = B+(A+(I(B,C,D)+M+T)<<<s)
I(X,Y,Z)=Y^(X|(非Z)>
</textarea>
</div>
</div>
</body>
</html>
外部样式表代码:
input
{
width: 350px;
height: 30px;
font-size: 30PX;
}
#box1{
font-size: 50px;
font-weight: bold;
font-family: "隶书";
margin-left: 30%;
}
#box2{
font-size: 30px;
color: red;
font-weight: bold;
margin-left: 28%;
}
#box3{
font-size: 50px;
font-weight: bold;
width:100%;
height: 100px;
text-align: center;
}
#box3_1{
font-size: 30px;
font-weight: bold;
width:50%;
height: 100px;
float: left;
background-color: #00FFFF;
}
#box3_2{
font-size: 30px;
font-weight: bold;
width:50%;
height: 100px;
float: left;
background-color: #87CEFA;
}
#box4{
width:100%;
height: 50px;
text-align: center;
padding: 20px;
}
#box4_1{
width:10%;
height: 50px;
position: relative;
background: #009ACD;
border: 0;
color: #DDA07A;
padding: 20px 25px;
font-size: 20px;
box-shadow: -6px 6px 0 ;
float: left;
text-align: center;
margin-left: 7%;
}
#textarea
{
float: left;
width:100%;
height: 20%;
padding: 20px;
}
四个按钮点击事件代码:(依据四个非线性函数来写)
//主体函数
//
//第一轮计算函数
function FFjisuan()
{
/*公式:FF(A,B,C,D,M,s,t) 表示 A = B+(A+(F(B,C,D)+M+T)<<<s)
F(X,Y,Z)=(X&Y)|((非B)&Z)
*/
//判断文本框是否为空
var y = true;
y = kong();
if(y)
{
//获取输入框数据
var a = document.getElementById("shu_1").value;
var b = document.getElementById("shu_2").value;
var c = document.getElementById("shu_3").value;
var d = document.getElementById("shu_4").value;
var m = document.getElementById("shu_5").value;
var s = document.getElementById("shu_6").value;
var t = document.getElementById("shu_7").value;
//16进制转换为2进制
var A = tostring2(a);
var B = tostring2(b);
var C = tostring2(c);
var D = tostring2(d);
var M = tostring2(m);
var T = tostring2(t);
//对照公式逻辑运算
var e = luojiyu(B,C); //BC逻辑与运算
var m = luojifei(B); //B的非
var f = luojiyu(m,D); //B的非跟D逻辑与运算
var g = luojihuo(e,f); //逻辑或运算
var h = yihuo(g,A); //结果跟A异或运算
var i = yihuo(h,M); //结果跟M异或运算
var j = yihuo(i,T); //结果跟T异或运算
var k = shiftLeft(j,s); //循环左移
var l = yihuo(k,B); //结果跟B异或
var n = tostring16(l); //二进制转出为16进制
document.getElementById("shu_8").value = n; //输出结果
}
}
//第二轮计算函数
function GGjisuan()
{
/*公式:FF(A,B,C,D,M,s,t) 表示 A = B+(A+(G(B,C,D)+M+T)<<<s)
G(X,Y,Z)=(X&Z)|(Y&(非Z))
*/
//判断文本框是否为空
var y = true;
y = kong();
if(y)
{
//获取输入框数据
var a = document.getElementById("shu_1").value;
var b = document.getElementById("shu_2").value;
var c = document.getElementById("shu_3").value;
var d = document.getElementById("shu_4").value;
var m = document.getElementById("shu_5").value;
var s = document.getElementById("shu_6").value;
var t = document.getElementById("shu_7").value;
//16进制转换为2进制
var A = tostring2(a);
var B = tostring2(b);
var C = tostring2(c);
var D = tostring2(d);
var M = tostring2(m);
var T = tostring2(t);
//对照公式逻辑运算
var e = luojiyu(B,D); //BD逻辑与运算
var m = luojifei(D); //D的非
var f = luojiyu(m,C); //D的非跟C逻辑与运算
var g = luojihuo(e,f); //逻辑或运算
var h = yihuo(g,A); //结果跟A异或运算
var i = yihuo(h,M); //结果跟M异或运算
var j = yihuo(i,T); //结果跟T异或运算
var k = shiftLeft(j,s); //循环左移
var l = yihuo(k,B); //结果跟B异或
var n = tostring16(l); //二进制转出为16进制
document.getElementById("shu_8").value = n; //输出结果
}
}
//第三轮计算函数
function HHjisuan()
{
/*公式:FF(A,B,C,D,M,s,t) 表示 A = B+(A+(H(B,C,D)+M+T)<<<s)
H(X,Y,Z)=(X^Y^Z)
*/
//判断文本框是否为空
var y = true;
y = kong();
if(y)
{
//获取输入框数据
var a = document.getElementById("shu_1").value;
var b = document.getElementById("shu_2").value;
var c = document.getElementById("shu_3").value;
var d = document.getElementById("shu_4").value;
var m = document.getElementById("shu_5").value;
var s = document.getElementById("shu_6").value;
var t = document.getElementById("shu_7").value;
//16进制转换为2进制
var A = tostring2(a);
var B = tostring2(b);
var C = tostring2(c);
var D = tostring2(d);
var M = tostring2(m);
var T = tostring2(t);
//对照公式逻辑运算
var e = yihuo(B,C); //BC异或
var m = yihuo(e,D); //结果与D异或
var h = yihuo(m,A); //结果跟A异或运算
var i = yihuo(h,M); //结果跟M异或运算
var j = yihuo(i,T); //结果跟T异或运算
var k = shiftLeft(j,s); //循环左移
var l = yihuo(k,B); //结果跟B异或
var n = tostring16(l); //二进制转出为16进制
document.getElementById("shu_8").value = n; //输出结果
}
}
//第四轮计算函数
function IIjisuan()
{
/*公式:FF(A,B,C,D,M,s,t) 表示 A = B+(A+(I(B,C,D)+M+T)<<<s)
I(X,Y,Z)=Y^(X|(非Z)
*/
//判断文本框是否为空
var y = true;
y = kong();
if(y)
{
//获取输入框数据
var a = document.getElementById("shu_1").value;
var b = document.getElementById("shu_2").value;
var c = document.getElementById("shu_3").value;
var d = document.getElementById("shu_4").value;
var m = document.getElementById("shu_5").value;
var s = document.getElementById("shu_6").value;
var t = document.getElementById("shu_7").value;
//16进制转换为2进制
var A = tostring2(a);
var B = tostring2(b);
var C = tostring2(c);
var D = tostring2(d);
var M = tostring2(m);
var T = tostring2(t);
//对照公式逻辑运算
var m = luojifei(D); //D的非
var e = luojihuo(B,m); //B跟D的非逻辑或运算
var g = yihuo(e,C); //结果跟C异或运算
var h = yihuo(g,A); //结果跟A异或运算
var i = yihuo(h,M); //结果跟M异或运算
var j = yihuo(i,T); //结果跟T异或运算
var k = shiftLeft(j,s); //循环左移
var l = yihuo(k,B); //结果跟B异或
var n = tostring16(l); //二进制转出为16进制
document.getElementById("shu_8").value = n; //输出结果
}
}
进制转换代码(16进制转2进制 和 2进制转16进制)
//将文本框中的小写字母转换为大写
function UpperCase(x)
{
var a = document.getElementById(x).value;
document.getElementById(x).value = a.toUpperCase();
}
//16进制转换2进制
function tostring2(str){
var val = "";
var b =str.split('');
for(var i =0;i<b.length;i++)
{
switch(b[i]){
case "0": val += "0000";break;
case "1": val += "0001";break;
case "2": val += "0010";break;
case "3": val += "0011";break;
case "4": val += "0100";break;
case "5": val += "0101";break;
case "6": val += "0110";break;
case "7": val += "0111";break;
case "8": val += "1000";break;
case "9": val += "1001";break;
case "A": val += "1010";break;
case "B": val += "1011";break;
case "C": val += "1100";break;
case "D": val += "1101";break;
case "E": val += "1110";break;
case "F": val += "1111";break;
}
}
return val;
}
//2进制转16进制
function tostring16(str)
{
var a = Number.parseInt(str,2).toString(16);
return a.toUpperCase();
}
逻辑运算代码:(与、或、非、异或以及需要用到的循环左移和文本框判断函数)
//逻辑与运算 同1取1,其余取0
function luojiyu(str1,str2) //输入字符串
{
var a = str1.split(''); //将字符串str1转换为数组
var b = str2.split(''); //将字符串str2转换为数组
var str = [];
for(var i =0;i<a.length;i++)
{
if(a[i]=="1" && b[i]=="1")
{
str[i]="1";
}
else
{
str[i]="0";
}
}
return str.join(''); //输出二进制字符串
}
//逻辑或运算,同0取0,其余为1
function luojihuo(str1,str2)
{
var a = str1.split(''); //将字符串str1转换为数组
var b = str2.split(''); //将字符串str2转换为数组
var str = [];
for(var i =0;i<a.length;i++)
{
if(a[i]=="0" && b[i]=="0")
{
str[i]="0";
}
else
{
str[i]="1";
}
}
return str.join(''); //输出二进制字符串
}
//逻辑非
function luojifei(str1)
{
var a = str1.split(''); //将字符串str1转换为数组
var str = [];
for(var i=0;i<a.length;i++)
{
if(a[i]=="1")
{
str[i]="0";
}
else
{
str[i]="1";
}
}
return str.join(''); //输出二进制字符串
}
//异或运算
function yihuo(str1,str2)
{
var a = str1.split(''); //将字符串str1转换为数组
var b = str2.split(''); //将字符串str2转换为数组
var str = [];
for(var i =0;i<a.length;i++) //循环按位异或,相同为0,不同为1
{
if(a[i]=="1" && b[i]=="1")
{
str[i]="0";
}
else if(a[i]=="1" && b[i]=="0")
{
str[i]="1";
}
else if(a[i]=="0" && b[i]=="1")
{
str[i]="1";
}
else if(a[i]=="0" && b[i]=="0")
{
str[i]="0";
}
}
return str.join(''); //输出二进制字符串
}
//循环左移
function shiftLeft(str, n) {
var len = str.length;
// 因为是循环移动,所以需要处理移动位数大于字符串长度的情况
n = n % len;
return str.slice(n, len) + str.slice(0, n); //数组元素左移输出
}
//判断文本框是否为空
function kong(a)
{
var b = ["A","B","C","D","M","S","T"]; //建立文本框提示数组
for(var i=1; i<8; i++) //循环判断文本框是否为空
{
var a = document.getElementById("shu_"+[i]).value; //获取当前ID的文本框的数据
if(a =="") //判断内容是否为空,为空就返回false,并终止程序,不为空就返回true
{
alert("请输入数据" + b[i-1]);
return false;
}
}
return true;
}
第一次写这玩意儿,如果大家有什么好的改进建议,可以给我留言。