课程:Java2实用教程 | 班级:201752 | 姓名:姚明宇 | 学号:20175223 |
---|---|---|---|
成绩: | 指导教师:娄嘉鹏 | 实验日期:5月31日 | |
实验密级: | 预习程度: | 实验时间: | |
仪器组次: | 必修/选修:选修 | 实验序号: |
目录java
实验仪器:android
名称 | 型号 | 数量 |
---|---|---|
PC端 | 1 |
20175233严顺尧-负责客户端
20175223姚明宇-负责服务器git
两人一组结对编程:算法
(代码已折叠)
express
编程
import java.util.*;
import java.util.stream.Collectors;public class MyBC{
private static final Map<Character, Integer> basic = new HashMap<Character, Integer>();
static {
basic.put('-', 1);
basic.put('+', 1);
basic.put('*', 2);
basic.put('/', 2);
basic.put('(', 0);
}apache//中缀表达式 转 后缀表达式 public static String toSuffix(String infix){ List<String> queue = new ArrayList<String>(); List<Character> stack = new ArrayList<Character>(); char[] charArr = infix.trim().toCharArray(); String standard = "*/+-()"; char ch = '&'; int len = 0; for (int i = 0; i < charArr.length; i++) { ch = charArr[i]; if(Character.isDigit(ch)) { len++; }else if(Character.isLetter(ch)) { len++; }else if(ch == '.'){ len++; }else if(Character.isSpaceChar(ch)) { if(len > 0) { queue.add(String.valueOf(Arrays.copyOfRange(charArr, i - len, i))); len = 0; } continue; }else if(standard.indexOf(ch) != -1) { if(len > 0) { queue.add(String.valueOf(Arrays.copyOfRange(charArr, i - len, i))); len = 0; } if(ch == '(') { stack.add(ch); continue; } if (!stack.isEmpty()) { int size = stack.size() - 1; boolean flag = false; while (size >= 0 && ch == ')' && stack.get(size) != '(') { queue.add(String.valueOf(stack.remove(size))); size--; flag = true; } while (size >= 0 && !flag && basic.get(stack.get(size)) >= basic.get(ch)) { queue.add(String.valueOf(stack.remove(size))); size--; } } if(ch != ')') { stack.add(ch); } else { stack.remove(stack.size() - 1); } } if(i == charArr.length - 1) { if(len > 0) { queue.add(String.valueOf(Arrays.copyOfRange(charArr, i - len+1, i+1))); } int size = stack.size() - 1; while (size >= 0) { queue.add(String.valueOf(stack.remove(size))); size--; } } } return queue.stream().collect(Collectors.joining(" ")); }}//中缀表达式 转 后缀表达式 public static String toSuffix(String infix){ List<String> queue = new ArrayList<String>(); List<Character> stack = new ArrayList<Character>(); char[] charArr = infix.trim().toCharArray(); String standard = "*/+-()"; char ch = '&'; int len = 0; for (int i = 0; i < charArr.length; i++) { ch = charArr[i]; if(Character.isDigit(ch)) { len++; }else if(Character.isLetter(ch)) { len++; }else if(ch == '.'){ len++; }else if(Character.isSpaceChar(ch)) { if(len > 0) { queue.add(String.valueOf(Arrays.copyOfRange(charArr, i - len, i))); len = 0; } continue; }else if(standard.indexOf(ch) != -1) { if(len > 0) { queue.add(String.valueOf(Arrays.copyOfRange(charArr, i - len, i))); len = 0; } if(ch == '(') { stack.add(ch); continue; } if (!stack.isEmpty()) { int size = stack.size() - 1; boolean flag = false; while (size >= 0 && ch == ')' && stack.get(size) != '(') { queue.add(String.valueOf(stack.remove(size))); size--; flag = true; } while (size >= 0 && !flag && basic.get(stack.get(size)) >= basic.get(ch)) { queue.add(String.valueOf(stack.remove(size))); size--; } } if(ch != ')') { stack.add(ch); } else { stack.remove(stack.size() - 1); } } if(i == charArr.length - 1) { if(len > 0) { queue.add(String.valueOf(Arrays.copyOfRange(charArr, i - len+1, i+1))); } int size = stack.size() - 1; while (size >= 0) { queue.add(String.valueOf(stack.remove(size))); size--; } } } return queue.stream().collect(Collectors.joining(" ")); }
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 Stackstack; public MyDC() { stack = new Stack ( ); } public int evaluate(String expr) { int op1, op2, result = 0; String token; StringTokenizer tokenizer = new StringTokenizer (expr); while (tokenizer.hasMoreTokens ( )) { token = tokenizer.nextToken ( ); //若是是运算符,调用isOperator if (isOperator(token)==true) { op2=stack.pop(); op1=stack.pop(); //从栈中弹出操做数2 //从栈中弹出操做数1 result=evalSingleOp(token.charAt(0),op1,op2); //根据运算符和两个操做数调用evalSingleOp计算result; stack.push(result); //计算result入栈; } else//若是是操做数 { stack.push(Integer.parseInt(token)); } //操做数入栈; } 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; break; default:return 0; } return result; } }
import java.util.Scanner; public class MyBCTest { public static void main(String[] args) { MyBC mybc = new MyBC (); MyDC mydc = new MyDC (); String inExpression; String str; Scanner reader = new Scanner (System.in); System.out.println ("Enter a expression: "); inExpression = reader.nextLine (); str = mybc.toSuffix (inExpression); System.out.println ("Exchange the expression by MyBC: " +str); System.out.println ("The calculation result of MyDC: " +mydc.evaluate(str)); } }
实现后缀表达式求值的功能:数组
MyDC evaluator = new MyDC ( ); //用 Scanner 输入 evaluator 的内容 String result = evaluator.evaluate (expression); //输出 result
结对编程:1人负责客户端,一人负责服务器安全
(代码已折叠)
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.net.Socket;
import java.util.Scanner;public class Client {
public static void main(String args[]) {
Scanner reader = new Scanner (System.in);
System.out.println ("客户输入一个中缀表达式: ");
String str = reader.nextLine ();
Socket mysocket;
DataInputStream in = null;
DataOutputStream out = null;
try {
mysocket = new Socket ("127.0.0.1", 2010);
in = new DataInputStream (mysocket.getInputStream ( ));
out = new DataOutputStream (mysocket.getOutputStream ( ));
out.writeUTF (str);
//in读取信息,堵塞状态
String temp = in.readUTF ( );
System.out.println ("客户收到服务器的后缀表达式:\n" + temp);
String answer = in.readUTF ( );
System.out.println ("客户收到服务器的计算结果:\n" + answer);
Thread.sleep (500);
} catch (Exception e) {
System.out.println ("服务器已断开" + e);
}
}
}
import java.io.*; import java.net.*; public class Server { public static void main(String args[]) { String question, temp, answer; MyDC mydc = new MyDC (); 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 ( )); // in读取信息,堵塞状态 question = in.readUTF ( ); System.out.println ("服务器收到客户的中缀表达式:\n" + question); temp = MyBC.toSuffix (question); System.out.println ("服务器将中缀表达式变形为后缀表达式:\n" +temp); out.writeUTF (temp); answer = String.valueOf(mydc.evaluate(temp)); out.writeUTF (answer); Thread.sleep (500); } catch (Exception e) { System.out.println ("客户已断开" + e); } } }
1.服务器创建连接。
ServerSocket serverForClient = new ServerSocket (2010);; Socket socketOnServer = null; socketOnServer = serverForClient.accept ( );
客户端创建对应连接相连。
Socket mysocket = new Socket ("127.0.0.1", 2010);
再建立 in , out 对象,使用 in.readUTF(); out.writeUTF();
进行数据交换。
2.服务器实现把中缀表达式转化为后缀表达式的功能:
String temp = MyBC.toSuffix (question);
注:因为 MyBC 类中的 toSuffix()
方法为 public static
静态方法,能够直接经过类名调用。
3.服务器实现后缀表达式求值的功能:
MyDC str = new MyDC ( ); String result = str.evaluate (expression);
4.服务器经过 out.writeUTF(result);
输出 result;客户端经过 in.readUTF();
接受后,打印输出。
加密结对编程:1人负责客户端,一人负责服务器
(代码已折叠)
import javax.crypto.*;
import javax.crypto.spec.SecretKeySpec;
import java.io.UnsupportedEncodingException;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;public class AES {
public static String ecodes(String content, String key) {
if (content == null || content.length ( ) < 1) {
return null;
}
try {
KeyGenerator kgen = KeyGenerator.getInstance ("AES");
SecureRandom random = SecureRandom.getInstance ("SHA1PRNG");
random.setSeed (key.getBytes ( ));
kgen.init (128, random);
SecretKey secretKey = kgen.generateKey ( );
byte[] enCodeFormat = secretKey.getEncoded ( );
SecretKeySpec secretKeySpec = new SecretKeySpec (enCodeFormat, "AES");
Cipher cipher = Cipher.getInstance ("AES");
byte[] byteContent = content.getBytes ("utf-8");
cipher.init (Cipher.ENCRYPT_MODE, secretKeySpec);
byte[] byteRresult = cipher.doFinal (byteContent);
StringBuffer sb = new StringBuffer ( );
for (int i = 0; i < byteRresult.length; i++) {
String hex = Integer.toHexString (byteRresult[i] & 0xFF);
if (hex.length ( ) == 1) {
hex = '0' + hex;
}
sb.append (hex.toUpperCase ( ));
}
return sb.toString ( );
} catch (NoSuchAlgorithmException e) {
e.printStackTrace ( );
} catch (NoSuchPaddingException e) {
e.printStackTrace ( );
} catch (InvalidKeyException e) {
e.printStackTrace ( );
} catch (UnsupportedEncodingException e) {
e.printStackTrace ( );
} catch (IllegalBlockSizeException e) {
e.printStackTrace ( );
} catch (BadPaddingException e) {
e.printStackTrace ( );
}
return null;
}public static String dcodes(String content, String key) { if (content == null || content.length ( ) < 1) { return null; } if (content.trim ( ).length ( ) < 19) { return content; } byte[] byteRresult = new byte[content.length ( ) / 2]; for (int i = 0; i < content.length ( ) / 2; i++) { int high = Integer.parseInt (content.substring (i * 2, i * 2 + 1), 16); int low = Integer.parseInt (content.substring (i * 2 + 1, i * 2 + 2), 16); byteRresult[i] = (byte) (high * 16 + low); } try { KeyGenerator kgen = KeyGenerator.getInstance ("AES"); SecureRandom random = SecureRandom.getInstance ("SHA1PRNG"); random.setSeed (key.getBytes ( )); kgen.init (128, random); SecretKey secretKey = kgen.generateKey ( ); byte[] enCodeFormat = secretKey.getEncoded ( ); SecretKeySpec secretKeySpec = new SecretKeySpec (enCodeFormat, "AES"); Cipher cipher = Cipher.getInstance ("AES"); cipher.init (Cipher.DECRYPT_MODE, secretKeySpec); byte[] result = cipher.doFinal (byteRresult); return new String (result); } 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 ( ); } return null; }
}
public static String dcodes(String content, String key) { if (content == null || content.length ( ) < 1) { return null; } if (content.trim ( ).length ( ) < 19) { return content; } byte[] byteRresult = new byte[content.length ( ) / 2]; for (int i = 0; i < content.length ( ) / 2; i++) { int high = Integer.parseInt (content.substring (i * 2, i * 2 + 1), 16); int low = Integer.parseInt (content.substring (i * 2 + 1, i * 2 + 2), 16); byteRresult[i] = (byte) (high * 16 + low); } try { KeyGenerator kgen = KeyGenerator.getInstance ("AES"); SecureRandom random = SecureRandom.getInstance ("SHA1PRNG"); random.setSeed (key.getBytes ( )); kgen.init (128, random); SecretKey secretKey = kgen.generateKey ( ); byte[] enCodeFormat = secretKey.getEncoded ( ); SecretKeySpec secretKeySpec = new SecretKeySpec (enCodeFormat, "AES"); Cipher cipher = Cipher.getInstance ("AES"); cipher.init (Cipher.DECRYPT_MODE, secretKeySpec); byte[] result = cipher.doFinal (byteRresult); return new String (result); } 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 ( ); } return null; }
import java.io.*; import java.net.*; public class ServerAES { public static void main(String args[]) { String miwen, temp, answer; MyDC mydc = new MyDC ( ); 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 ( )); // in读取信息,堵塞状态 miwen = in.readUTF ( ); System.out.println ("服务器收到客户的密文:\n" + miwen); String key = "20175223yaomingyushidashuaibi111"; String mingwen = AES.dcodes (miwen, key); answer = String.valueOf (mydc.evaluate (mingwen)); out.writeUTF (answer); System.out.println ("\n**计算结果由客户端打印输出**"); Thread.sleep (500); } catch (Exception e) { System.out.println ("客户已断开" + e); } } }
import java.io.DataInputStream; import java.io.DataOutputStream; import java.net.Socket; import java.util.Scanner; public class ClientAES { public static void main(String args[]) { Scanner reader = new Scanner (System.in); System.out.println ("客户输入一个中缀表达式: "); String str = reader.nextLine ( ); Socket mysocket; DataInputStream in = null; DataOutputStream out = null; try { mysocket = new Socket ("127.0.0.1", 2010); in = new DataInputStream (mysocket.getInputStream ( )); out = new DataOutputStream (mysocket.getOutputStream ( )); String key = "20175223yaomingyushidashuaibi111"; //将中缀表达式变形为后缀表达式 String temp = MyBC.toSuffix (str); System.out.println ("服务器将中缀表达式变形为后缀表达式:\n" + temp); //输入密文,32字符密钥 String miwen = AES.ecodes (temp, key); System.out.println ("客户发往服务器的密文:\n" + miwen + "\n"); out.writeUTF (miwen); //in读取信息,堵塞状态 String answer = in.readUTF ( ); System.out.println ("客户收到服务器的计算结果:\n" + answer); Thread.sleep (500); } catch (Exception e) { System.out.println ("服务器已断开" + e); } } }
1.首先,服务器和客户端协商密钥为:String key = "20175223yaomingyushidashuaibi111";
,各自存在本地;
AES算法及其相关方法经过 AES.java 实现。
2.客户端实现把中缀表达式转化为后缀表达式的功能(同 网络编程与安全-2
),将后缀表达式明文加密:
String = MyBC.toSuffix (str); String miwen = AES.ecodes(mingwen,key);
再发往服务器。
3.服务器将接收到的密文用密钥解密,调用方法 mydc.evaluate()
计算后缀表达式:
String mingwen = AES.dcodes(miwen, key); String answer = String.valueOf(mydc.evaluate(mingwen));
4.服务器将答案发往客户端,由客户端打印输出。
密钥分发结对编程:1人负责客户端,一人负责服务器
(代码已折叠)
import javax.crypto.Cipher;
import javax.crypto.KeyAgreement;
import javax.crypto.SecretKey;
import javax.crypto.interfaces.DHPrivateKey;
import javax.crypto.interfaces.DHPublicKey;
import javax.crypto.spec.DHParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.security.*;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.util.HashMap;
import java.util.Map;
/**
*/
public class DH {
//非对称密钥算法
public static final String KEY_ALGORITHM="DH";
//本地密钥算法,即对称加密算法。可选des,aes,desede
public static final String SECRET_ALGORITHM="AES";
//私钥
private static final String PRIVATE_KEY="DHPrivateKey";
}
/**@throws Exception
*/
public static void main(String[] args) throws Exception {
//生成甲方的密钥对
Map<String,Object> keyMap1=DH.initKey();
//甲方的公钥
byte[] publicKey1=DH.getPublicKey(keyMap1);
//甲方的私钥
byte[] privateKey1=DH.getPrivateKey(keyMap1);
System.out.println("甲方公钥:/n"+Base64.encodeBase64String(publicKey1));
System.out.println("甲方私钥:/n"+Base64.encodeBase64String(privateKey1));
//由甲方的公钥产生的密钥对
Map<String,Object> keyMap2=DH.initKey(publicKey1);
byte[] publicKey2=DH.getPublicKey(keyMap2);
byte[] privateKey2=DH.getPrivateKey(keyMap2);
System.out.println("乙方公钥:/n"+Base64.encodeBase64String(publicKey2));
System.out.println("乙方私钥:/n"+Base64.encodeBase64String(privateKey2));
//组装甲方的本地加密密钥,由乙方的公钥和甲方的私钥组合而成
byte[] key1=DH.getSecretKey(publicKey2, privateKey1);
System.out.println("甲方的本地密钥:/n"+Base64.encodeBase64String(key1));
//组装乙方的本地加密密钥,由甲方的公钥和乙方的私钥组合而成
byte[] key2=DH.getSecretKey(publicKey1, privateKey2);
System.out.println("乙方的本地密钥:/n"+Base64.encodeBase64String(key2));
System.out.println("================密钥对构造完毕,开始进行加密数据的传输=============");
String str="密码交换算法";
System.out.println("/n===========甲方向乙方发送加密数据==============");
System.out.println("原文:"+str);
System.out.println("===========使用甲方本地密钥对进行数据加密==============");
//甲方进行数据的加密
byte[] code1=DH.encrypt(str.getBytes(), key1);
System.out.println("加密后的数据:"+Base64.encodeBase64String(code1));
System.out.println("===========使用乙方本地密钥对数据进行解密==============");
//乙方进行数据的解密
byte[] decode1=DH.decrypt(code1, key2);
System.out.println("乙方解密后的数据:"+new String(decode1)+"/n/n");
System.out.println("===========反向进行操做,乙方向甲方发送数据==============/n/n");
str="乙方向甲方发送数据DH";
System.out.println("原文:"+str);
//使用乙方本地密钥对数据进行加密
byte[] code2=DH.encrypt(str.getBytes(), key2);
System.out.println("===========使用乙方本地密钥对进行数据加密==============");
System.out.println("加密后的数据:"+Base64.encodeBase64String(code2));
System.out.println("=============乙方将数据传送给甲方======================");
System.out.println("===========使用甲方本地密钥对数据进行解密==============");
//甲方使用本地密钥对数据进行解密
byte[] decode2=DH.decrypt(code2, key1);
System.out.println("甲方解密后的数据:"+new String(decode2));
}
}
import org.apache.commons.codec.binary.Base64; import java.io.DataInputStream; import java.io.DataOutputStream; import java.net.Socket; import java.util.Map; import java.util.Scanner; public class ClientDH { public static void main(String args[]) { String cipherText, plainText, answer; Scanner reader = new Scanner (System.in); System.out.println ("客户输入一个中缀表达式: "); String str = reader.nextLine (); Socket mysocket; DataInputStream in = null; DataOutputStream out = null; try { mysocket = new Socket ("127.0.0.1", 2010); in = new DataInputStream (mysocket.getInputStream ( )); out = new DataOutputStream (mysocket.getOutputStream ( )); //设立AES算法的32字符密钥,输入密文与密钥 String AES_Key = "20175223yaomingyushidashuaibi111"; //将中缀表达式变形为后缀表达式 plainText = MyBC.toSuffix (str); System.out.println ("后缀表达式明文:\n" + plainText); //将后缀表达式明文经过AES加密,并将后缀表达式密文发往客户端 cipherText = AES.ecodes (plainText, AES_Key); System.out.println ("后缀表达式密文:\n" + cipherText + "\n"); //out发送信息 out.writeUTF (cipherText); //对AES算法的32字符密钥进行DH算法加密 //生成客户端的密钥对 MapkeyMap1 = DH.initKey ( ); //客户端的公钥 byte[] publicKey1 = DH.getPublicKey (keyMap1); //客户端的私钥 byte[] privateKey1 = DH.getPrivateKey (keyMap1); System.out.println ("客户端公钥:/n" + Base64.encodeBase64String (publicKey1)); System.out.println ("客户端私钥:/n" + Base64.encodeBase64String (privateKey1)); String tempKey1 = Base64.encodeBase64String (publicKey1); //out发送信息 out.writeUTF (tempKey1); //组装客户端的本地加密密钥,由服务器的公钥和客户端的私钥组合而成 //in读取信息,堵塞状态 String tempKey2 = in.readUTF ( ); byte[] publicKey2 = Base64.decodeBase64 (tempKey2); System.out.println ("服务器公钥:/n" + Base64.encodeBase64String (publicKey1)); byte[] key1 = DH.getSecretKey (publicKey2, privateKey1); System.out.println ("客户端的本地密钥:/n" + Base64.encodeBase64String (key1)); //客户端使用本地密钥对AES_Key进行消息加密,并发给服务器 byte[] code1 = DH.encrypt (AES_Key.getBytes ( ), key1); System.out.println ("客户端使用本地密钥对AES_Key进行加密后的数据:" + Base64.encodeBase64String (code1)); //out发送信息,333333 out.writeUTF (Base64.encodeBase64String (code1)); //接受服务器的计算结果 answer = in.readUTF ( ); System.out.println ("\n**计算由服务器进行**\n\n客户收到服务器的计算结果:\n" + answer); Thread.sleep (500); } catch (Exception e) { System.out.println ("服务器已断开" + e); } } }
import org.apache.commons.codec.binary.Base64; import java.io.DataInputStream; import java.io.DataOutputStream; import java.io.IOException; import java.net.ServerSocket; import java.net.Socket; import java.util.Map; public class ServerDH { public static void main(String args[]) { String cipherText, plainText, answer; MyDC mydc = new MyDC ( ); 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 ( )); // in读取信息,堵塞状态 cipherText = in.readUTF ( ); System.out.println ("服务器收到客户的后缀表达式密文:\n" + cipherText + "\n"); //由客户端的公钥产生的密钥对 // in读取信息,堵塞状态 String tempKey1 = in.readUTF ( ); byte[] publicKey1 = Base64.decodeBase64 (tempKey1); System.out.println ("客户端公钥:/n" + Base64.encodeBase64String (publicKey1)); MapkeyMap2 = DH.initKey (publicKey1); byte[] publicKey2 = DH.getPublicKey (keyMap2); byte[] privateKey2 = DH.getPrivateKey (keyMap2); System.out.println ("服务器公钥:/n" + Base64.encodeBase64String (publicKey2)); System.out.println ("服务器私钥:/n" + Base64.encodeBase64String (privateKey2)); //为组装客户端的本地加密密钥,将服务器的公钥发给客户端 String tempKey2 = Base64.encodeBase64String (publicKey2); //out发送信息 out.writeUTF (tempKey2); //组装服务器的本地加密密钥,由客户端的公钥和服务器的私钥组合而成 byte[] key2 = DH.getSecretKey (publicKey1, privateKey2); System.out.println ("服务器的本地密钥:/n" + Base64.encodeBase64String (key2)); //接受客户端的AES_Key的加密信息,对其解密 byte[] code1 = Base64.decodeBase64 (in.readUTF ( )); byte[] decode1 = DH.decrypt (code1, key2); String AES_Key = new String (decode1); System.out.println ("\n服务器解密后的AES_Key数据:" + AES_Key); //使用解密后的AES_Key对后缀表达式密文解密,并算出结果 plainText = AES.dcodes (cipherText, AES_Key); System.out.println ("\nAES_Key对后缀表达式密文解密:\n" + plainText); answer = String.valueOf (mydc.evaluate (plainText)); //将计算结果发给客户端 out.writeUTF (answer); System.out.println ("\n**结果由客户端进行输出**" ); Thread.sleep (500); } catch (Exception e) { System.out.println ("客户已断开" + e); } } }
在 网络编程与安全-3
基础上,利用成熟的 DH 算法(实现于 DH.java)实现 AES 密钥客户端和服务器加解密,具体步骤以下:
//生成客户端的密钥对 Map<String,Object> keyMap1=DH.initKey(); //客户端的公钥 byte[] publicKey1=DH.getPublicKey(keyMap1); //客户端的私钥 byte[] privateKey1=DH.getPrivateKey(keyMap1); //由客户端的公钥产生的密钥对 Map<String,Object> keyMap2=DH.initKey(publicKey1); byte[] publicKey2=DH.getPublicKey(keyMap2); byte[] privateKey2=DH.getPrivateKey(keyMap2); //组装客户端的本地加密密钥,由服务器的公钥和客户端的私钥组合而成 byte[] key1=DH.getSecretKey(publicKey2, privateKey1); //组装服务器的本地加密密钥,由客户端的公钥和服务器的私钥组合而成 byte[] key2=DH.getSecretKey(publicKey1, privateKey2); //客户端进行数据的加密 byte[] code1=DH.encrypt(str.getBytes(), key1); //服务器进行数据的解密 byte[] decode1=DH.decrypt(code1, key2); //使用服务器本地密钥对数据进行加密 byte[] code2=DH.encrypt(str.getBytes(), key2); //客户端使用本地密钥对数据进行解密 byte[] decode2=DH.decrypt(code2, key1);
完整性校验结对编程:1人负责客户端,一人负责服务器
(代码已折叠)
import java.security.MessageDigest;public class MD5 {
public static String numberMD5(String plainText) throws Exception {
String x = plainText;
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);
}return result; }}return result; }
import org.apache.commons.codec.binary.Base64; import java.io.DataInputStream; import java.io.DataOutputStream; import java.net.Socket; import java.util.Map; import java.util.Scanner; public class ClientMD5 { public static void main(String args[]) { String cipherText, plainText, answer; Scanner reader = new Scanner (System.in); System.out.println ("客户输入一个中缀表达式: "); String str = reader.nextLine (); Socket mysocket; DataInputStream in = null; DataOutputStream out = null; try { mysocket = new Socket ("127.0.0.1", 2010); in = new DataInputStream (mysocket.getInputStream ( )); out = new DataOutputStream (mysocket.getOutputStream ( )); //设立AES算法的32字符密钥,输入密文与密钥 String AES_Key = "20175223yaomingyushidashuaibi111"; //将中缀表达式变形为后缀表达式 plainText = MyBC.toSuffix (str); System.out.println ("后缀表达式明文:\n" + plainText); //将后缀表达式明文经过AES加密,并将后缀表达式密文发往服务器 cipherText = AES.ecodes (plainText, AES_Key); System.out.println ("后缀表达式密文:\n" + cipherText + "\n"); //out发送信息 out.writeUTF (cipherText); //对AES算法的32字符密钥进行DH算法加密 //生成客户端的密钥对 MapkeyMap1 = DH.initKey ( ); //客户端的公钥 byte[] publicKey1 = DH.getPublicKey (keyMap1); //客户端的私钥 byte[] privateKey1 = DH.getPrivateKey (keyMap1); System.out.println ("客户端公钥:/n" + Base64.encodeBase64String (publicKey1)); System.out.println ("客户端私钥:/n" + Base64.encodeBase64String (privateKey1)); String tempKey1 = Base64.encodeBase64String (publicKey1); //out发送信息 out.writeUTF (tempKey1); //组装客户端的本地加密密钥,由服务器的公钥和客户端的私钥组合而成 //in读取信息,堵塞状态 String tempKey2 = in.readUTF ( ); byte[] publicKey2 = Base64.decodeBase64 (tempKey2); System.out.println ("服务器公钥:/n" + Base64.encodeBase64String (publicKey1)); byte[] key1 = DH.getSecretKey (publicKey2, privateKey1); System.out.println ("客户端的本地密钥:/n" + Base64.encodeBase64String (key1)); //客户端使用本地密钥对AES_Key进行消息加密,并发给服务器 byte[] code1 = DH.encrypt (AES_Key.getBytes ( ), key1); System.out.println ("客户端使用本地密钥对AES_Key进行加密后的数据:" + Base64.encodeBase64String (code1)); //out发送信息 out.writeUTF (Base64.encodeBase64String (code1)); //计算后缀表达式明文的MD5值,并发往服务器 String valueMD5 = MD5.numberMD5 (plainText); System.out.println ("\n客户端计算的MD5值:" + valueMD5); //out发送信息 out.writeUTF (valueMD5); //接受服务器的计算结果 answer = in.readUTF ( ); System.out.println ("\n**计算由服务器进行**\n\n客户收到服务器的计算结果:\n" + answer); Thread.sleep (500); } catch (Exception e) { System.out.println ("服务器已断开" + e); } } }
import org.apache.commons.codec.binary.Base64; import java.io.DataInputStream; import java.io.DataOutputStream; import java.io.IOException; import java.net.ServerSocket; import java.net.Socket; import java.util.Map; public class ServerMD5 { public static void main(String args[]) { String cipherText, plainText, answer; MyDC mydc = new MyDC ( ); 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 ( )); // in读取信息,堵塞状态 cipherText = in.readUTF ( ); System.out.println ("服务器收到客户的后缀表达式密文:\n" + cipherText + "\n"); //由客户端的公钥产生的密钥对 // in读取信息,堵塞状态 String tempKey1 = in.readUTF ( ); byte[] publicKey1 = Base64.decodeBase64 (tempKey1); System.out.println ("客户端公钥:/n" + Base64.encodeBase64String (publicKey1)); MapkeyMap2 = DH.initKey (publicKey1); byte[] publicKey2 = DH.getPublicKey (keyMap2); byte[] privateKey2 = DH.getPrivateKey (keyMap2); System.out.println ("服务器公钥:/n" + Base64.encodeBase64String (publicKey2)); System.out.println ("服务器私钥:/n" + Base64.encodeBase64String (privateKey2)); //为组装客户端的本地加密密钥,将服务器的公钥发给客户端 String tempKey2 = Base64.encodeBase64String (publicKey2); //out发送信息 out.writeUTF (tempKey2); //组装服务器的本地加密密钥,由客户端的公钥和服务器的私钥组合而成 byte[] key2 = DH.getSecretKey (publicKey1, privateKey2); System.out.println ("服务器的本地密钥:/n" + Base64.encodeBase64String (key2)); //接受客户端的AES_Key的加密信息,对其解密 byte[] code1 = Base64.decodeBase64 (in.readUTF ( )); byte[] decode1 = DH.decrypt (code1, key2); String AES_Key = new String (decode1); System.out.println ("\n服务器解密后的AES_Key数据:" + AES_Key); //使用解密后的AES_Key对后缀表达式密文解密,并算出结果 plainText = AES.dcodes (cipherText, AES_Key); System.out.println ("\nAES_Key对后缀表达式密文解密:" + plainText); answer = String.valueOf (mydc.evaluate (plainText)); //接受客户端的MD5值,计算解密后后缀表达式的MD5值,并判断是否相同,不一样则中止 String clicetValueMD5 = in.readUTF (); String valueMD5 = MD5.numberMD5 (plainText); if (!clicetValueMD5.equals (valueMD5)) { return; } System.out.println ("\n服务器MD5值:"+valueMD5 +"\n**与客户端相同**"); //将计算结果发给客户端 out.writeUTF (answer); System.out.println ("\n**结果由客户端进行输出**" ); Thread.sleep (500); } catch (Exception e) { System.out.println ("客户已断开" + e); } } }
1.实现 MD5 算法:
将参考代码 public static void main
改成可调用的静态方法(于上 MD5.java):
public static String numberMD5(String plainText)
import java.security.*; public class DigestPass{ public static void main(String args[ ]) throws Exception{ String x=args[0]; 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); } System.out.println(result); } }
2.在 网络编程与安全-4
基础上,客户端将后缀表达式明文的MD5值算出,发往服务器:
String valueMD5 = MD5.numberMD5 (plainText);
。
3.服务器接受客户端MD5值,与自身算出的后缀表达式明文的MD5值比较,若相同则继续:
String clicetValueMD5 = in.readUTF (); String valueMD5 = MD5.numberMD5 (plainText); if (!clicetValueMD5.equals (valueMD5)) { return; }
---使用甲方本地密钥对数据进行加密--- Exception in thread "main" java.security.InvalidKeyException: Illegal key size or default parameters at javax.crypto.Cipher.checkCryptoPerm(Cipher.java:1026) at javax.crypto.Cipher.implInit(Cipher.java:801) at javax.crypto.Cipher.chooseProvider(Cipher.java:864) at javax.crypto.Cipher.init(Cipher.java:1249) at javax.crypto.Cipher.init(Cipher.java:1186) at DHCoder.encrypt(DHCoder.java:101) at DHTest.main(DHTest.java:56) Process finished with exit code 1
由于某些国家的进口管制限制,Java发布的运行环境包中的加解密有必定的限制。好比默认不容许256位密钥的AES加解密,解决方法就是修改策略文件。
下载与JDK或JRE对应版本的jce文件包,当前机器的jdk为1.8,因此下载jce_policy-8.zip。
将解压获得的两个jar文件 local_policy.jar
和 US_export_policy.jar
也放到 %JDK_HOME%\jre\lib\security
下,进行替换。
附 jce_policy-8.zip下载连接
out.writeUTF();
传输后没法正确接收,变为乱码客户端:
//经过 `Base64` 的方法 `encodeBase64String ();` 将数组转化为字符串类型 String tempKey1 = Base64.encodeBase64String (publicKey1); //out发送信息 out.writeUTF (tempKey1);
服务器:
...... //由客户端的公钥产生的密钥对 String tempKey1 = in.readUTF (); byte [] publicKey1 = tempKey1.getBytes (); System.out.println("客户端公钥:/n"+Base64.encodeBase64String(publicKey1)); Map<String,Object> keyMap2=DH.initKey(publicKey1); ......
报错:密钥格式不对。
由于 out.writeUTF(); in.readUTF ();
传输的数据类型为 String
,而不是 byte []
数组,因此不可用 getBytes ();
方法来提取。
要使用 Base64
方法 encodeBase64String ();
的对应的方法 decodeBase64 (tempKey1);
来转换数据类型。
String tempKey1 = in.readUTF ( ); byte[] publicKey1 = Base64.decodeBase64 (tempKey1); System.out.println ("客户端公钥:/n" + Base64.encodeBase64String (publicKey1)); Map <String, Object> keyMap2 = DH.initKey (publicKey1);
码云仓库:YogileOne https://gitee.com/Yogile/YogileOne.git
码云项目网页连接:https://gitee.com/Yogile/YogileOne/tree/master/str/exam_5
步骤 | 耗时 | 百分比 |
---|---|---|
需求分析 | 10min | 7.7% |
设计 | 30min | 23.1% |
代码实现 | 50min | 38.5% |
测试 | 30min | 23.1% |
分析总结 | 10min | 7.6% |