課程: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% |