两人一组结对编程:html
参考http://www.cnblogs.com/rocedu/p/6766748.html#SECDSAjava
结对实现中缀表达式转后缀表达式的功能 MyBC.javanode
结对实现从上面功能中获取的表达式中实现后缀表达式求值的功能,调用MyDC.javagit
上传测试代码运行结果截图和码云连接算法
栈的一个应用是用来对四则运算表达式进行求值。express
表达式Exp = S1 + OP + S2(S1 ,S2是两个操做数,OP为运算符)有三种标识方法:编程
OP + S1 + S2 为前缀表示法数组
S1 + OP + S2 为中缀表示法安全
S1 + S2 + OP 为后缀表示法服务器
例如:Exp = a * b + (c - d / e) * f
前缀式: + * a b * - c / d e f
中缀式: a * b + c - d / e * f
后缀式: a b * c d e / - f * +
咱们能够看出:
1.操做数之间的相对次序不变;
2.运算符的相对次序不一样;
3.中缀式丢失了括弧信息,导致运算次序不肯定;
4.前缀式的运算规则为:连续出现的两个操做数和在它们以前且紧靠它们的运算符构成一个最小表达式;
5.后缀式的运算规则为:运算符在式中出现的顺序恰为表达式的运算顺序;每一个运算符和在它以前出现且紧靠它的两个操做数构成一个最小表达式。
项目编译和运行
MyDC.java
/** * @Author 16487 */ import java.util.StringTokenizer; import java.util.Stack; public class MyDC { /** constant for addition symbol */ private final char ADD = '+'; /** constant for subtraction symbol */ private final char SUBTRACT = '-'; /** constant for multiplication symbol */ private final char MULTIPLY = '*'; /** constant for division symbol */ private final char DIVIDE = '/'; /** the stack */ private Stack<Integer> stack; // MyDC my= new MyDC(); public MyDC() { stack = new Stack<Integer>(); } public int evaluate (String expr) { int op1, op2, result = 0; String token; StringTokenizer tokenizer = new StringTokenizer (expr); while (tokenizer.hasMoreTokens()) { token = tokenizer.nextToken(); //System.out.println(token); //若是是运算符,调用isOperator if (isOperator(token)) { char []c=token.toCharArray(); op1=stack.pop(); //从栈中弹出操做数2 op2=stack.pop(); //从栈中弹出操做数1 result=evalSingleOp(c[0],op1,op2); //根据运算符和两个操做数调用evalSingleOp计算result; stack.push(result); //计算result入栈; } else{ //若是是操做数 if(token.matches("[0-9]+")) { int number=Integer.parseInt(token); stack.push(number); } } } return result; } private boolean isOperator (String token) { return ( token.equals("+") || token.equals("-") || token.equals("*") || token.equals("/") ); } private int evalSingleOp (char operation, int op1, int op2) { int result = 0; switch (operation) { case ADD: result = op1 + op2; break; case SUBTRACT: result = op1 - op2; break; case MULTIPLY: result = op1 * op2; break; case DIVIDE: result = op1 / op2; } return result; } }
MyDCTester.java
/** * @Author 16487 */ import java.util.Scanner; public class MyDCTester { public static void main (String[] args) { String expression, again; int result; try { Scanner in = new Scanner(System.in); do { MyDC evaluator = new MyDC(); System.out.println ("Enter a valid postfix expression: "); expression = in.nextLine(); result = evaluator.evaluate (expression); System.out.println ("That expression equals " + result); System.out.print ("Evaluate another expression [Y/N]? "); again = in.nextLine(); System.out.println(); } while (again.equalsIgnoreCase("Y")); } catch (Exception IOException) { System.out.println("Input exception reported"); } } }
Caculate.java
/** * @Author 16487 */ import java.util.Scanner; public class Caculate { public static void main(String[] args) { MyDC a = new MyDC(); MyBC b = new MyBC(); String str; int result; System.out.println("输入算式:"); Scanner reader = new Scanner(System.in); str = reader.nextLine(); str = b.result(str); result = a.evaluate(str); System.out.println("答案为:"+result); } }
MyBC.java
/** * @Author 16487 */ import java.util.*; public class MyBC { public String result(String s) { Stack<String> sta = new Stack<String>(); //新建栈 String str = ""; StringTokenizer t=new StringTokenizer(s); while (t.hasMoreTokens()){ //依次遍历元素,转为后缀表达式 String temp; String c; c=t.nextToken(); if (c.equals("+") || c.equals("-")) { //遇到优先级最低的“+”、“-”,弹出“(”以前的全部元素 while (sta.size() != 0) { temp = sta.pop(); if (temp.equals("(")) { sta.push("("); break; } str = str + temp + " "; } sta.push(c); } else if (c.equals("*")|| c.equals("÷")) { //遇到优先级高的“*”、“/”,弹出“(”以前的“*”、“/” while (sta.size() != 0) { temp = sta.pop(); if (temp.equals("(") || temp.equals("+") || temp.equals("-")) { sta.push(temp); break; } else { str = str + temp + " "; } } sta.push(c); } else if (c.equals("(")) { //遇到“(”直接入栈 sta.push(c); } else if (c.equals(")")) { //遇到“)”,弹出“(”以前的全部元素 while (sta.size() != 0) { temp = sta.pop(); if (temp.equals("(")) { break; } else { str = str + temp + " "; } } } else //遇到数字,直接存入数组 { str = str + c + " "; } } while (sta.size()!=0){ //弹出栈中剩余的元素 str=str+sta.pop()+" "; } return str; } }
结对编程:1人负责客户端,一人负责服务器
注意责任归宿,要会经过测试证实本身没有问题
基于Java Socket实现客户端/服务器功能,传输方式用TCP
客户端让用户输入中缀表达式,而后把中缀表达式调用MyBC.java的功能转化为后缀表达式,把后缀表达式经过网络发送给服务器
服务器接收到后缀表达式,调用MyDC.java的功能计算后缀表达式的值,把结果发送给客户端
客户端显示服务器发送过来的结果
上传测试结果截图和码云连接
Java为TCP协议提供了两个类,分别在客户端编程和服务器端编程中使用它们。在应用程序开始通讯以前,须要先建立一个链接,由客户端程序发起;而服务器端的程序须要一直监听着主机的特定端口号,等待客户端的链接。在客户端中咱们只须要使用Socket实例,而服务端要同时处理ServerSocket实例和Socket实例;两者而且都使用OutputStream和InpuStream来发送和接收数据。
项目编译和运行
Client.java
/** * @Author 16487 */ import java.io.*; import java.net.*; import java.lang.*; import java.util.Scanner; public class Client { public static void main(String args[]) { Socket mysocket; DataInputStream in=null; DataOutputStream out=null; try{ mysocket=new Socket("127.1.0.0",2010); in=new DataInputStream(mysocket.getInputStream()); out=new DataOutputStream(mysocket.getOutputStream()); System.out.println("请输入算式:"); Scanner scanner=new Scanner(System.in); String str=scanner.nextLine(); MyBC b=new MyBC(); str=b.result(str); out.writeUTF(str); String s=in.readUTF(); //in读取信息,堵塞状态 System.out.println("客户收到服务器的回答:"+s); Thread.sleep(500); } catch(Exception e) { System.out.println("服务器已断开"+e); } } }
Server.java
/** * @Author 16487 */ import java.io.*; import java.net.*; public class Server { public static void main(String args[]) { int answer; ServerSocket serverForClient=null; Socket socketOnServer=null; DataOutputStream out=null; DataInputStream in=null; try { serverForClient = new ServerSocket(2010); } catch(IOException e1) { System.out.println(e1); } try{ System.out.println("等待客户呼叫"); socketOnServer = serverForClient.accept(); //堵塞状态,除非有客户呼叫 out=new DataOutputStream(socketOnServer.getOutputStream()); in=new DataInputStream(socketOnServer.getInputStream()); String s=in.readUTF(); // in读取信息,堵塞状态 System.out.println("服务器收到客户的提问:"+s); MyDC d=new MyDC(); answer=d.evaluate(s); out.writeUTF(answer+""); Thread.sleep(500); } catch(Exception e) { System.out.println("客户已断开"+e); } } }
加密结对编程:1人负责客户端,一人负责服务器
注意责任归宿,要会经过测试证实本身没有问题
基于Java Socket实现客户端/服务器功能,传输方式用TCP
客户端让用户输入中缀表达式,而后把中缀表达式调用MyBC.java的功能转化为后缀表达式,把后缀表达式用3DES或AES算法加密后经过网络把密文发送给服务器
服务器接收到后缀表达式表达式后,进行解密(和客户端协商密钥,能够用数组保存),而后调用MyDC.java的功能计算后缀表达式的值,把结果发送给客户端
客户端显示服务器发送过来的结果
上传测试结果截图和码云连接
项目编译和运行
Client1.java
/** * @Author 16487 */ import java.io.*; import java.net.*; import java.lang.*; import java.util.Scanner; public class Client1 { public static void main(String args[]) throws Exception { String key = ""; int n = -1; byte[] a = new byte[128]; try { File f = new File("key1.dat"); InputStream in = new FileInputStream(f); while ((n = in.read(a, 0, 100)) != -1) { key = key + new String(a, 0, n); } in.close(); } catch (IOException e) { System.out.println("File read Error" + e); } Socket mysocket; DataInputStream in = null; DataOutputStream out = null; System.out.println("请输入算式:"); Scanner scanner = new Scanner(System.in); String str = scanner.nextLine();//输入算式 MyBC b = new MyBC(); str = b.result(str); String secret= Encorder.AESEncode(key,str);//客户端进行加密 try { mysocket = new Socket("127.1.0.0", 2010); in = new DataInputStream(mysocket.getInputStream()); out = new DataOutputStream(mysocket.getOutputStream()); out.writeUTF(key); out.writeUTF(secret); String s = in.readUTF(); //in读取信息,堵塞状态 System.out.println("客户收到服务器的回答:" + s); Thread.sleep(500); } catch (Exception e) { System.out.println("服务器已断开" + e); } } }
Server1.java
/** * @Author 16487 */ import java.io.*; import java.net.*; public class Server1 { public static void main (String args[]) throws Exception { /*String key=""; int n=-1; byte [] a=new byte[128]; try{ File f=new File("key1.dat"); InputStream in = new FileInputStream(f); while((n=in.read(a,0,100))!=-1) { key=key+new String (a,0,n); } in.close(); } catch(IOException e) { System.out.println("File read Error"+e); }*/ ServerSocket serverForClient=null; Socket socketOnServer=null; DataOutputStream out=null; DataInputStream in=null; try { serverForClient = new ServerSocket(2010); } catch(IOException e1) { System.out.println(e1); } try{ System.out.println("等待客户呼叫"); socketOnServer = serverForClient.accept(); //堵塞状态,除非有客户呼叫 out=new DataOutputStream(socketOnServer.getOutputStream()); in=new DataInputStream(socketOnServer.getInputStream()); String key = in.readUTF(); String s=in.readUTF(); // in读取信息,堵塞状态 System.out.println("服务器收到的信息:"+s); String clear= Encorder.AESDncode(key,s); MyDC d=new MyDC(); System.out.println("服务器收到客户的提问:"+clear); int answer=d.evaluate(clear); out.writeUTF(answer+""); Thread.sleep(500); } catch(Exception e) { System.out.println("客户已断开"+e); } } }
Encorder.java
/** * @Author 16487 */ import java.io.IOException; import java.io.UnsupportedEncodingException; import java.security.InvalidKeyException; import java.security.NoSuchAlgorithmException; import java.security.SecureRandom; import java.util.Base64; import java.util.Scanner; import javax.crypto.BadPaddingException; import javax.crypto.Cipher; import javax.crypto.IllegalBlockSizeException; import javax.crypto.KeyGenerator; import javax.crypto.NoSuchPaddingException; import javax.crypto.SecretKey; import javax.crypto.spec.SecretKeySpec; import sun.misc.BASE64Decoder; import sun.misc.BASE64Encoder; /* * AES对称加密和解密 */ public class Encorder { /* * 加密 * 1.构造密钥生成器 * 2.根据ecnodeRules规则初始化密钥生成器 * 3.产生密钥 * 4.建立和初始化密码器 * 5.内容加密 * 6.返回字符串 */ public static String AESEncode(String encodeRules,String content){ try { //1.构造密钥生成器,指定为AES算法,不区分大小写 KeyGenerator keygen=KeyGenerator.getInstance("AES"); //2.根据ecnodeRules规则初始化密钥生成器 //生成一个128位的随机源,根据传入的字节数组 keygen.init(128, new SecureRandom(encodeRules.getBytes())); //3.产生原始对称密钥 SecretKey original_key=keygen.generateKey(); //4.得到原始对称密钥的字节数组 byte [] raw=original_key.getEncoded(); //5.根据字节数组生成AES密钥 SecretKey key=new SecretKeySpec(raw, "AES"); //6.根据指定算法AES自成密码器 Cipher cipher=Cipher.getInstance("AES"); //7.初始化密码器,第一个参数为加密(Encrypt_mode)或者解密解密(Decrypt_mode)操做,第二个参数为使用的KEY cipher.init(Cipher.ENCRYPT_MODE, key); //8.获取加密内容的字节数组(这里要设置为utf-8)否则内容中若是有中文和英文混合中文就会解密为乱码 byte [] byte_encode=content.getBytes("utf-8"); //9.根据密码器的初始化方式--加密:将数据加密 byte [] byte_AES=cipher.doFinal(byte_encode); //10.将加密后的数据转换为字符串 //这里用Base64Encoder中会找不到包 //解决办法: //在项目的Build path中先移除JRE System Library,再添加库JRE System Library,从新编译后就一切正常了。 String AES_encode=new String(new BASE64Encoder().encode(byte_AES)); //11.将字符串返回 return AES_encode; } catch (NoSuchAlgorithmException e) { e.printStackTrace(); } catch (NoSuchPaddingException e) { e.printStackTrace(); } catch (InvalidKeyException e) { e.printStackTrace(); } catch (IllegalBlockSizeException e) { e.printStackTrace(); } catch (BadPaddingException e) { e.printStackTrace(); } catch (UnsupportedEncodingException e) { e.printStackTrace(); } //若是有错就返加nulll return null; } /* * 解密 * 解密过程: * 1.同加密1-4步 * 2.将加密后的字符串反纺成byte[]数组 * 3.将加密内容解密 */ public static String AESDncode(String encodeRules,String content){ try { //1.构造密钥生成器,指定为AES算法,不区分大小写 KeyGenerator keygen=KeyGenerator.getInstance("AES"); //2.根据ecnodeRules规则初始化密钥生成器 //生成一个128位的随机源,根据传入的字节数组 keygen.init(128, new SecureRandom(encodeRules.getBytes())); //3.产生原始对称密钥 SecretKey original_key=keygen.generateKey(); //4.得到原始对称密钥的字节数组 byte [] raw=original_key.getEncoded(); //5.根据字节数组生成AES密钥 SecretKey key=new SecretKeySpec(raw, "AES"); //6.根据指定算法AES自成密码器 Cipher cipher=Cipher.getInstance("AES"); //7.初始化密码器,第一个参数为加密(Encrypt_mode)或者解密(Decrypt_mode)操做,第二个参数为使用的KEY cipher.init(Cipher.DECRYPT_MODE, key); //8.将加密并编码后的内容解码成字节数组 byte [] byte_content= new BASE64Decoder().decodeBuffer(content); /* * 解密 */ byte [] byte_decode=cipher.doFinal(byte_content); String AES_decode=new String(byte_decode,"utf-8"); return AES_decode; } catch (NoSuchAlgorithmException e) { e.printStackTrace(); } catch (NoSuchPaddingException e) { e.printStackTrace(); } catch (InvalidKeyException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } catch (IllegalBlockSizeException e) { e.printStackTrace(); } catch (BadPaddingException e) { e.printStackTrace(); } //若是有错就返加nulll return null; } }
Skey_AES.java
/** * @Author 16487 */ import java.io.*; import javax.crypto.*; public class Skey_AES{ public static void main(String args[]) throws Exception{ KeyGenerator kg=KeyGenerator.getInstance("AES"); kg.init(128); SecretKey k=kg.generateKey( ); FileOutputStream f=new FileOutputStream("key1.dat"); ObjectOutputStream b=new ObjectOutputStream(f); b.writeObject(k); } }
密钥分发结对编程:1人负责客户端,一人负责服务器
注意责任归宿,要会经过测试证实本身没有问题
基于Java Socket实现客户端/服务器功能,传输方式用TCP
客户端让用户输入中缀表达式,而后把中缀表达式调用MyBC.java的功能转化为后缀表达式,把后缀表达式用3DES或AES算法加密经过网络把密文发送给服务器
客户端和服务器用DH算法进行3DES或AES算法的密钥交换
服务器接收到后缀表达式表达式后,进行解密,而后调用MyDC.java的功能计算后缀表达式的值,把结果发送给客户端
客户端显示服务器发送过来的结果
上传测试结果截图和码云连接
以甲乙双方发送数据为模型进行分析
一、甲方(消息发送方,下同)构建密钥对(公钥+私钥),甲方公布公钥给乙方(消息接收方,下同)
二、乙方以甲方发送过来的公钥做为参数构造密钥对(公钥+私钥),将构造出来的公钥公布给甲方
三、甲方用“甲方的私钥+乙方的公钥”构造本地密钥
四、乙方用“乙方的私钥+甲方的公钥”构造本地的密钥
五、这个时候,甲乙两方本地新构造出来的密钥应该同样,甲乙双方能够经过本地密钥进行数据的加密和解密
六、而后就可使用AES这类对称加密算法进行数据的安全传送了。
项目编译和运行
Client2.java
/** * @Author 16487 */ import javax.crypto.spec.*; import javax.crypto.Cipher; import javax.crypto.KeyGenerator; import javax.crypto.SecretKey; import java.io.DataInputStream; import java.io.DataOutputStream; import java.net.Socket; import java.util.Scanner; public class Client2 { public static void main(String[] args) { Scanner inn = new Scanner(System.in); Socket mysocket; DataInputStream in = null; DataOutputStream out = null; try { mysocket = new Socket("127.1.0.0", 2010); in = new DataInputStream(mysocket.getInputStream()); out = new DataOutputStream(mysocket.getOutputStream()); KeyGenerator kg = KeyGenerator.getInstance("DESede"); kg.init(168); SecretKey k = kg.generateKey(); byte[] kb = k.getEncoded(); System.out.println("请输入中缀表达式:"); String infix = inn.nextLine(); MyBC1 myBC1 = new MyBC1(); String suffix = myBC1.infixToSuffix(infix); System.out.println(suffix); //中缀表达式加密 Cipher cp = Cipher.getInstance("DESede"); cp.init(Cipher.ENCRYPT_MODE, k); byte ptext[] = suffix.getBytes("UTF8"); byte ctext[] = cp.doFinal(ptext); out.writeUTF(ctext.length + ""); for (int i = 0; i < ctext.length; i++) { out.writeUTF(ctext[i] + ""); } //对密钥进行加密 KeyAgree keyAgree = new KeyAgree(); SecretKeySpec k1 = keyAgree.KeyAgree("Serverpub.dat","Clientpri.dat"); cp.init(Cipher.ENCRYPT_MODE, k1); byte ckey[] = cp.doFinal(kb); out.writeUTF(ckey.length + ""); for (int i = 0; i < ckey.length; i++) { out.writeUTF(ckey[i] + ""); } String result = in.readUTF(); System.out.println("收到客户回答" + result); Thread.sleep(500); } catch (Exception e) { System.out.println("服务器已断开" + e); } } }
Server2.java
/** * @Author 16487 */ import javax.crypto.Cipher; import javax.crypto.spec.SecretKeySpec; import java.io.*; import java.net.*; public class Server2 { public static void main(String[] args) { ServerSocket serverForClient = null; Socket socketOnServer = null; DataOutputStream out = null; DataInputStream in = null; MyDC myDC = new MyDC(); try{ serverForClient = new ServerSocket(2010); }catch (IOException e1){ System.out.println("等待客户呼叫"+e1); } try{ System.out.println("服务器收到的信息"); socketOnServer = serverForClient.accept(); out = new DataOutputStream(socketOnServer.getOutputStream()); in = new DataInputStream(socketOnServer.getInputStream()); //获取密文 String clength = in.readUTF(); byte []ctext = new byte[Integer.parseInt(clength)]; for(int i=0; i<Integer.parseInt(clength); i++){ String temp = in.readUTF(); ctext[i] = Byte.parseByte(temp); } //获取密钥 String keylength = in.readUTF(); byte []ckey = new byte[Integer.parseInt(keylength)]; for(int i=0; i<Integer.parseInt(keylength); i++){ String temp = in.readUTF(); ckey[i] = Byte.parseByte(temp); } //密钥解密 SecretKeySpec k1 = KeyAgree.KeyAgree("Clientpub.dat","Serverpri.dat"); Cipher cp=Cipher.getInstance("DESede"); cp.init(Cipher.DECRYPT_MODE, k1); byte []pkey=cp.doFinal(ckey); //密文解密 SecretKeySpec k=new SecretKeySpec(pkey,"DESede"); cp.init(Cipher.DECRYPT_MODE, k); byte []ptext=cp.doFinal(ctext); String suffix = new String(ptext,"UTF8"); System.out.println("服务器提供的解密"+suffix); out.writeUTF(myDC.evaluate(suffix)+""); Thread.sleep(500); }catch (Exception e){ System.out.println("客户已断开"); } } }
MyBC1.java
/** * @Author 16487 */ import java.util.Stack; public class MyBC1 { public MyBC1(){} public static String infixToSuffix(String exp){ Stack<String> s = new Stack<String>(); // 建立操做符堆栈 String suffix = ""; // 要输出的后缀表达式字符串 String suffix1 = ""; //上一次的后缀表达式 String suffix2 = ""; String str[] = exp.split(" "); int length = str.length; // 输入的中缀表达式的长度 String temp=""; for (int i = 0; i < length; i++) { // 对该中缀表达式的每个字符并进行判断 switch (str[i]) { case " ":break; // 忽略空格 case "(": s.push(str[i]); // 若是是左括号直接压入堆栈 break; case "+": case "-": if(s.size() != 0){ // 碰到'+' '-',将栈中的全部运算符所有弹出去,直至碰到左括号为止,输出到队列中去 temp = s.pop(); if (temp.equals("(")) { // 将左括号放回堆栈,终止循环 s.push(temp); s.push(str[i]); break; } else{ s.push(str[i]); suffix2 = suffix2 + temp + " "; break; } } else{ s.push(str[i]); // 说明是当前为第一次进入或者其余前面运算都有括号等状况致使栈已经为空,此时须要将符号进栈 break; } // 若是是乘号或者除号,则弹出全部序列,直到碰到加好、减号、左括号为止,最后将该操做符压入堆栈 case "*": case "÷": if(s.size()!=0){ temp = s.pop(); if(temp.equals("+")||temp.equals("-")||temp.equals("(")){ s.push(temp); s.push(str[i]); break; } else{ s.push(str[i]); suffix2 = suffix2+temp+" "; break; } } else { s.push(str[i]); //当前为第一次进入或者其余前面运算都有括号等状况致使栈已经为空,此时须要将符号进栈 break; } // 若是碰到的是右括号,则距离栈顶的第一个左括号上面的全部运算符弹出栈并抛弃左括号 case ")": while (!s.isEmpty()) { temp = s.pop(); if (temp.equals("(")) { break; } else { suffix2 = suffix2+temp+" "; } } break; // 默认状况,若是读取到的是数字,则直接送至输出序列 default: suffix2 = suffix2+str[i]+" "; break; } } // 若是堆栈不为空,则把剩余运算符一次弹出,送至输出序列 while (s.size() != 0) { suffix2 = suffix2+s.pop()+" "; } if(suffix1.equals("")){ //第一个题目 suffix1 = suffix2; suffix = suffix2; } else{ if(suffix2.equals(suffix1)) suffix = ""; else suffix = suffix2; } suffix1 = suffix2; return suffix; } }
KeyAgree.java
/** * @Author 16487 */ import java.io.*; import java.security.*; import javax.crypto.*; import javax.crypto.spec.*; public class KeyAgree{ public KeyAgree(){} public static SecretKeySpec KeyAgree(String a,String b) throws Exception{ // 读取对方的DH公钥 FileInputStream f1=new FileInputStream(a); ObjectInputStream b1=new ObjectInputStream(f1); PublicKey pbk=(PublicKey)b1.readObject( ); //读取本身的DH私钥 FileInputStream f2=new FileInputStream(b); ObjectInputStream b2=new ObjectInputStream(f2); PrivateKey prk=(PrivateKey)b2.readObject( ); // 执行密钥协定 KeyAgreement ka=KeyAgreement.getInstance("DH"); ka.init(prk); ka.doPhase(pbk,true); //生成共享信息 byte[ ] s=ka.generateSecret(); byte []sb = new byte[24]; System.arraycopy(s, 0, sb, 0, 24); System.out.println("共享秘钥:"); for(int i=0;i<sb.length;i++){ System.out.print(sb[i]+" "); } System.out.println(); SecretKeySpec k=new SecretKeySpec(sb,"DESede"); return k; } }
Key_DH.java
/** * @Author 16487 */ import java.io.*; import java.math.*; import java.security.*; import java.security.spec.*; import javax.crypto.*; import javax.crypto.spec.*; import javax.crypto.interfaces.*; public class Key_DH{ //三个静态变量的定义从 // C:\j2sdk-1_4_0-doc\docs\guide\security\jce\JCERefGuide.html // 拷贝而来 // The 1024 bit Diffie-Hellman modulus values used by SKIP private static final byte skip1024ModulusBytes[] = { (byte)0xF4, (byte)0x88, (byte)0xFD, (byte)0x58, (byte)0x4E, (byte)0x49, (byte)0xDB, (byte)0xCD, (byte)0x20, (byte)0xB4, (byte)0x9D, (byte)0xE4, (byte)0x91, (byte)0x07, (byte)0x36, (byte)0x6B, (byte)0x33, (byte)0x6C, (byte)0x38, (byte)0x0D, (byte)0x45, (byte)0x1D, (byte)0x0F, (byte)0x7C, (byte)0x88, (byte)0xB3, (byte)0x1C, (byte)0x7C, (byte)0x5B, (byte)0x2D, (byte)0x8E, (byte)0xF6, (byte)0xF3, (byte)0xC9, (byte)0x23, (byte)0xC0, (byte)0x43, (byte)0xF0, (byte)0xA5, (byte)0x5B, (byte)0x18, (byte)0x8D, (byte)0x8E, (byte)0xBB, (byte)0x55, (byte)0x8C, (byte)0xB8, (byte)0x5D, (byte)0x38, (byte)0xD3, (byte)0x34, (byte)0xFD, (byte)0x7C, (byte)0x17, (byte)0x57, (byte)0x43, (byte)0xA3, (byte)0x1D, (byte)0x18, (byte)0x6C, (byte)0xDE, (byte)0x33, (byte)0x21, (byte)0x2C, (byte)0xB5, (byte)0x2A, (byte)0xFF, (byte)0x3C, (byte)0xE1, (byte)0xB1, (byte)0x29, (byte)0x40, (byte)0x18, (byte)0x11, (byte)0x8D, (byte)0x7C, (byte)0x84, (byte)0xA7, (byte)0x0A, (byte)0x72, (byte)0xD6, (byte)0x86, (byte)0xC4, (byte)0x03, (byte)0x19, (byte)0xC8, (byte)0x07, (byte)0x29, (byte)0x7A, (byte)0xCA, (byte)0x95, (byte)0x0C, (byte)0xD9, (byte)0x96, (byte)0x9F, (byte)0xAB, (byte)0xD0, (byte)0x0A, (byte)0x50, (byte)0x9B, (byte)0x02, (byte)0x46, (byte)0xD3, (byte)0x08, (byte)0x3D, (byte)0x66, (byte)0xA4, (byte)0x5D, (byte)0x41, (byte)0x9F, (byte)0x9C, (byte)0x7C, (byte)0xBD, (byte)0x89, (byte)0x4B, (byte)0x22, (byte)0x19, (byte)0x26, (byte)0xBA, (byte)0xAB, (byte)0xA2, (byte)0x5E, (byte)0xC3, (byte)0x55, (byte)0xE9, (byte)0x2F, (byte)0x78, (byte)0xC7 }; // The SKIP 1024 bit modulus private static final BigInteger skip1024Modulus = new BigInteger(1, skip1024ModulusBytes); // The base used with the SKIP 1024 bit modulus private static final BigInteger skip1024Base = BigInteger.valueOf(2); public static void main(String args[ ]) throws Exception{ DHParameterSpec DHP= new DHParameterSpec(skip1024Modulus,skip1024Base); KeyPairGenerator kpg= KeyPairGenerator.getInstance("DH"); kpg.initialize(DHP); KeyPair kp=kpg.genKeyPair(); PublicKey pbk=kp.getPublic(); PrivateKey prk=kp.getPrivate(); // 保存公钥 FileOutputStream f1=new FileOutputStream("Serverpub.dat"); ObjectOutputStream b1=new ObjectOutputStream(f1); b1.writeObject(pbk); FileOutputStream f2=new FileOutputStream("Clientpub.dat"); ObjectOutputStream b2=new ObjectOutputStream(f2); b2.writeObject(pbk); // 保存私钥 FileOutputStream f3=new FileOutputStream("Clientpri.dat"); ObjectOutputStream b3=new ObjectOutputStream(f3); b3.writeObject(prk); FileOutputStream f4=new FileOutputStream("Serverpri.dat"); ObjectOutputStream b4=new ObjectOutputStream(f4); b4.writeObject(prk); } }
完整性校验结对编程:1人负责客户端,一人负责服务器
注意责任归宿,要会经过测试证实本身没有问题
基于Java Socket实现客户端/服务器功能,传输方式用TCP
客户端让用户输入中缀表达式,而后把中缀表达式调用MyBC.java的功能转化为后缀表达式,把后缀表达式用3DES或AES算法加密经过网络把密文和明文的MD5値发送给服务器
客户端和服务器用DH算法进行3DES或AES算法的密钥交换
服务器接收到后缀表达式表达式后,进行解密,解密后计算明文的MD5值,和客户端传来的MD5进行比较,一致则调用MyDC.java的功能计算后缀表达式的值,把结果发送给客户端
客户端显示服务器发送过来的结果
上传测试结果截图和码云连接
项目编译和运行
Client3.java
/** * @Author 16487 */ import javax.crypto.Cipher; import javax.crypto.KeyGenerator; import javax.crypto.SecretKey; import javax.crypto.spec.SecretKeySpec; import java.io.DataInputStream; import java.io.DataOutputStream; import java.net.Socket; import java.security.MessageDigest; import java.util.Scanner; public class Client3 { public static void main(String[] args) { Scanner inn = new Scanner(System.in); Socket mysocket; DataInputStream in = null; DataOutputStream out = null; try { mysocket = new Socket("127.1.0.0", 2010); in = new DataInputStream(mysocket.getInputStream()); out = new DataOutputStream(mysocket.getOutputStream()); KeyGenerator kg = KeyGenerator.getInstance("DESede"); kg.init(168); SecretKey k = kg.generateKey(); byte[] kb = k.getEncoded(); System.out.println("请输入中缀表达式:"); String infix = inn.nextLine(); MyBC1 myBC1 = new MyBC1(); String suffix = myBC1.infixToSuffix(infix); System.out.println(suffix); //计算明文的MD5值 MessageDigest m = MessageDigest.getInstance("MD5"); m.update(suffix.getBytes("UTF8")); byte s[] = m.digest(); String r=""; for (int i=0; i<s.length; i++){ r+=Integer.toHexString((0x000000ff & s[i]) | 0xffffff00).substring(6); } System.out.println("明文的MD5"); System.out.println(r); out.writeUTF(s.length+""); for(int i=0; i<s.length; i++){ out.writeUTF(s[i]+""); } //中缀表达式加密 Cipher cp = Cipher.getInstance("DESede"); cp.init(Cipher.ENCRYPT_MODE, k); byte ptext[] = suffix.getBytes("UTF8"); byte ctext[] = cp.doFinal(ptext); out.writeUTF(ctext.length + ""); for (int i = 0; i < ctext.length; i++) { out.writeUTF(ctext[i] + ""); } //对密钥进行加密 KeyAgree keyAgree = new KeyAgree(); SecretKeySpec k1 = keyAgree.KeyAgree("Serverpub.dat","Clientpri.dat"); cp.init(Cipher.ENCRYPT_MODE, k1); byte ckey[] = cp.doFinal(kb); out.writeUTF(ckey.length + ""); for (int i = 0; i < ckey.length; i++) { out.writeUTF(ckey[i] + ""); } String result = in.readUTF(); System.out.println("收到客户回答" + result); Thread.sleep(500); } catch (Exception e) { System.out.println("服务器已断开" + e); } } }
Server3.java
/** * @Author 16487 */ import javax.crypto.Cipher; import javax.crypto.spec.SecretKeySpec; import java.io.DataInputStream; import java.io.DataOutputStream; import java.io.IOException; import java.net.ServerSocket; import java.net.Socket; import java.security.MessageDigest; public class Server3 { public static void main(String[] args) { ServerSocket serverForClient = null; Socket socketOnServer = null; DataOutputStream out = null; DataInputStream in = null; MyDC myDC = new MyDC(); try{ serverForClient = new ServerSocket(2010); }catch (IOException e1){ System.out.println("客户有需求了"+e1); } try{ System.out.println("等待客户呼叫"); socketOnServer = serverForClient.accept(); out = new DataOutputStream(socketOnServer.getOutputStream()); in = new DataInputStream(socketOnServer.getInputStream()); //获取明文MD5 String MD5length = in.readUTF(); byte []MD5 = new byte[Integer.parseInt(MD5length)]; for(int i=0; i<Integer.parseInt(MD5length); i++){ String temp1 = in.readUTF(); MD5[i] = Byte.parseByte(temp1); } //获取密文 String clength = in.readUTF(); byte []ctext = new byte[Integer.parseInt(clength)]; for(int i=0; i<Integer.parseInt(clength); i++){ String temp = in.readUTF(); ctext[i] = Byte.parseByte(temp); } //获取密钥 String keylength = in.readUTF(); byte []ckey = new byte[Integer.parseInt(keylength)]; for(int i=0; i<Integer.parseInt(keylength); i++){ String temp = in.readUTF(); ckey[i] = Byte.parseByte(temp); } //密钥解密 SecretKeySpec k1 = KeyAgree.KeyAgree("Clientpub.dat","Serverpri.dat"); Cipher cp=Cipher.getInstance("DESede"); cp.init(Cipher.DECRYPT_MODE, k1); byte []pkey=cp.doFinal(ckey); //密文解密 SecretKeySpec k=new SecretKeySpec(pkey,"DESede"); cp.init(Cipher.DECRYPT_MODE, k); byte []ptext=cp.doFinal(ctext); String suffix = new String(ptext,"UTF8"); //解密后的MD5 MessageDigest m = MessageDigest.getInstance("MD5"); m.update(suffix.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); } System.out.println("解密后的MD5"); System.out.println(result); System.out.println("客服收到客户需求"+suffix); out.writeUTF(myDC.evaluate(suffix)+""); Thread.sleep(500); }catch (Exception e){ System.out.println("服务器断开链接"); } } }
步骤 | 耗时 | 百分比 |
---|---|---|
需求分析 | 100min | 24.4% |
设计 | 150min | 36.6% |
代码实现 | 100min | 24.4% |
测试 | 20min | 4.9% |
分析总结 | 40min | 9.7% |