2018-2019-20175307 实验五《网络编程与安全》实验报告
第一个任务
这个任务是要将输入的中缀表达式转换为后缀表达式,并用老师已经写好的后缀表达式进行计算,所以任务的难点就在于如何将中缀表达式转化为后缀表达式。对于这个难点,娄老师要求写成MyBC.java来进行操作。
因为第一次遇见这样的问题,所以果断转向百度求助,不出所料,有两篇博客,一篇为,另一篇为。
讲到了中缀表达式转后缀表达式的规则:
首先将各种运算符(包括括号)的优先级排列如下(数字越大,优先级越高):
1:(
2:+ -
3:* /
4:)
对输入的中缀表达式从左到右遍历:
1)如果遇到数字,直接添加到后缀表达式末尾;
2)如果遇到运算符+、-、*、/:
先判断栈是否为空。若是,则直接将此运算符压入栈。若不是,则查看当前栈顶元素。若栈顶元素优先级大于或等于此操作符级别,则弹出栈顶元素,将栈顶元素添加到后缀表达式中,并继续进行上述判断。如果不满足上述判断或者栈为空,将这个运算符入栈。要注意的是,经过上述步骤,这个运算符最终一定会入栈。
3)如果遇到括号:
如果是左括号,直接入栈。如果是右括号,弹出栈中第一个左括号前所有的操作符,并将左括号弹出。(右括号别入栈)。
4)字符串遍历结束后,如果栈不为空,则弹出栈中所有元素,将它们添加到后缀表达式的末尾,直到栈为空。
所以我就按照c++代码,写出了java的MyBC
while(i<length){
if(ch[i]>='0'&&ch[i]<='9'){
st+=ch[i];
}
else if(ch[i]=='+'||ch[i]=='-'||ch[i]=='*'||ch[i]=='/'){
if(stack.empty()){
temp = String.valueOf(ch[i]);
stack.push(temp);
}
else{
while (!stack.empty()){
tem=stack.peek().charAt(0);
if(getPriority(tem)>=getPriority(ch[i])){
st+=tem;
stack.pop();
}
else{
break;
}
}
temp = String.valueOf(ch[i]);
stack.push(temp);
}
}
else{
if(ch[i]=='('){
temp = String.valueOf(ch[i]);
stack.push(temp);
}
else{
while(!stack.peek().equals(String.valueOf('('))){
tem = stack.peek().charAt(0);
st+=tem;
stack.pop();
}
stack.pop();
}
}
i++;
}
但是出现了一些问题,就是在用MyDC的输入格式和MyBC输出格式不一样的情况。
因为没有注意到MyDC的输入的字符串中每个有效字符是由一个空格作为间隔的,所以在MyBC将中缀表达式转为后缀表达式的时候,并没有做处理,所以会导致最终MyDC计算结果为0的情况。
处理方法是在给st输出字符串添加元素的时候,多添加一个空格。
st+=tem;
替换为
st=st+tem+" ";
st+=ch[i];
替换为
st=st+ch[i]+" ";
就可以正确计算了。
第二个任务是
结对编程:1人负责客户端,一人负责服务器
- 基于Java Socket实现客户端/服务器功能,传输方式用TCP
- 客户端让用户输入中缀表达式,然后把中缀表达式调用MyBC.java的功能转化为后缀表达式,把后缀表达式通过网络发送给服务器
- 服务器接收到后缀表达式,调用MyDC.java的功能计算后缀表达式的值,把结果发送给客户端
- 客户端显示服务器发送过来的结果
- 上传测试结果截图和码云链接
因为团队项目恰好也有关服务器和客户端,所以基于Java Socket实现客户端/服务器功能,传输方式用TCP对我来说,并不是很难。在这里我直接用的是java书上的最简单的例子。
然后在客户端增加输入功能,然后将输入的中缀表达式通过任务一的MyDC转换为MyBC,最终传输给服务器端,服务器端在接收到后缀表达式侯,进行MyBC的计算,最终得到答案。
但是还是出现了一个问题
java writeUtf出现了java.lang.NullPointerException
后来发现是忘记没有实例化~new DataOutputStream
增加
in = new DataInputStream(client.getInputStream());out = new DataOutputStream(client.getOutputStream());
之后就可以正常使用了。
第三个任务是
加密结对编程:1人负责客户端,一人负责服务器
- 基于Java Socket实现客户端/服务器功能,传输方式用TCP
2. 客户端让用户输入中缀表达式,然后把中缀表达式调用MyBC.java的功能转化为后缀表达式,把后缀表达式用3DES或AES算法加密后通过网络把密文发送给服务器 - 服务器接收到后缀表达式表达式后,进行解密(和客户端协商密钥,可以用数组保存),然后调用MyDC.java的功能计算后缀表达式的值,把结果发送给客户端
- 客户端显示服务器发送过来的结果
- 上传测试结果截图和码云链接
因为我之前已经写过DES的算法了,所以这次选的是AES算法挑战一下,但是出现了很多的问题。
javax.crypto.BadPaddingException: Given final block not properly padded
其中一个就是这个问题。
百度之后果然由大神已经解决了这个问题。
博客链接
和一篇文库
kgen.init(128, new SecureRandom(key.getBytes()));
替换为
kgen.init(128, random);
就可以了,具体问题不是很懂。
第四个任务是
密钥分发结对编程:1人负责客户端,一人负责服务器
-
基于Java Socket实现客户端/服务器功能,传输方式用TCP
-
客户端让用户输入中缀表达式,然后把中缀表达式调用MyBC.java的功能转化为后缀表达式,把后缀表达式用3DES或AES算法加密通过网络把密文发送给服务器
3. 客户端和服务器用DH算法进行3DES或AES算法的密钥交换 -
服务器接收到后缀表达式表达式后,进行解密,然后调用MyDC.java的功能计算后缀表达式的值,把结果发送给客户端
-
客户端显示服务器发送过来的结果
-
上传测试结果截图和码云链接
密钥交换算法——DH
简述
1976年,W.Diffie和M.Hellman在发表的论文中提出了公钥加密算法思想,但当时并没有给出具体的实施方案,原因在于没有找到单向函数(也就是消息摘要算法),但在该论文中给出了通信双方通过信息交换协商密钥的算法,即Diffie-Hellman密钥交换算法(简称为DH算法)。该算法的目的在于让消息的收发双方可以在安全的条件下交换密钥,以备后续加密/解密使用。因此,DH算法是第一个密钥协商算法,但仅能用于密钥分配,不能用于加密或者解密消息。
DH密钥交换算法的安全性基于有限域上的离散对数难题。基于这种安全性,通过DH算法进行密钥分配,使得消息的收发双方可以安全地交换一个密钥,再通过这个密钥对数据进行加密和解密处理。
其实该算法的原理和上一部分中简单乘法及其类似,只是获取da或者db不是简单的方程式了,而是涉及到对数运算。对数运算被认为是“难”的,这个难建立在目前为止没有找到一个快速计算对数的算法,数学上没有证明这个算法是否存在。
因为之前密码学数学基础可上讲过a^b mod n的快速算法,所以我就按照这个算法去计算。
public static int quick (int a,int b,int m){
int ans=a;
String bin = binaryToDecimal(b);
char[] chr = bin.toCharArray();
for(int i=1;i<bin.length();i++){
if(chr[i]==1){
ans = (ans*ans*a)%m;
}
else {
ans = (ans*ans)%m;
}
}
return ans;
}
返回值便是a^b mod n。
还是按照socket方法,将生成的密钥作为下一个阶段AES的密钥,就可以保证接下来过程的正确性了。
第五个任务是
完整性校验结对编程:1人负责客户端,一人负责服务器
0. 注意责任归宿,要会通过测试证明自己没有问题
- 基于Java Socket实现客户端/服务器功能,传输方式用TCP
2. 客户端让用户输入中缀表达式,然后把中缀表达式调用MyBC.java的功能转化为后缀表达式,把后缀表达式用3DES或AES算法加密通过网络把密文和明文的MD5値发送给服务器 - 客户端和服务器用DH算法进行3DES或AES算法的密钥交换
- 服务器接收到后缀表达式表达式后,进行解密,解密后计算明文的MD5值,和客户端传来的MD5进行比较,一致则调用MyDC.java的功能计算后缀表达式的值,把结果发送给客户端
- 客户端显示服务器发送过来的结果
- 上传测试结果截图和码云链接
具体来说文件的MD5值就像是这个文件的“数字指纹”。每个文件的MD5值是不同的,如果任何人对文件做了任何改动,其MD5值也就是对应的“数字指纹”就会发生变化。比如下载服务器针对一个文件预先提供一个MD5值,用户下载完该文件后,用我这个算法重新计算下载文件的MD5值,通过比较这两个值是否相同,就能判断下载的文件是否出错,或者说下载的文件是否被篡改了。MD5实际上一种有损压缩技术,压缩前文件一样MD5值一定一样,反之MD5值一样并不能保证压缩前的数据是一样的。在密码学上发生这样的概率是很小的,所以MD5在密码加密领域有一席之地。但是专业的黑客甚至普通黑客也可以利用MD5值实际是有损压缩技术这一原理,将MD5的逆运算的值作为一张表俗称彩虹表的散列表来破解密码。
虽然MD5更多的是用在文件的校对上,但是也可以用在我们这个后缀表达式的信息上。
我的理解就是应该先用DH算法进行密钥的交换,生成双方一致的密钥,依此作为AES加密和解密的密钥。
MD5计算的是后缀表达式的值,保证后缀表达式的消息完整性。
因为我记得娄老师之前写过一篇密码学的博客,所以直接用的娄老师的代码。
MessageDigest m=MessageDigest.getInstance("MD5");
m.update(x.getBytes("UTF8"));
byte s[ ]=m.digest( );
String result="";
for (int i=0; i<s.length; i++){
result+=Integer.toHexString((0x000000ff & s[i]) |
0xffffff00).substring(6);
}
![](https://img2018.cnblogs.com/blog/1613137/201905/1613137-20190531082507910-2019602431.png)
![](https://img2018.cnblogs.com/blog/1613137/201905/1613137-20190531082513816-964509183.png)
posted on 2019-05-31 08:24 20175307GSC 阅读(223) 评论(0) 编辑 收藏 举报