課程:Java程序設計 班級:1751 班 姓名:謝文航 學號:20175126html
指導教師:婁嘉鵬java
實驗日期:2019年5月29日git
實驗序號:實驗五算法
實驗名稱:網絡編程與安全編程
實驗內容:數組
實驗要求:安全
兩人一組結對編程:
0. 參考http://www.cnblogs.com/rocedu/p/6766748.html#SECDSA
1. 結對實現中綴表達式轉後綴表達式的功能 MyBC.java
2. 結對實現從上面功能中獲取的表達式中實現後綴表達式求值的功能,調用MyDC.java
3. 上傳測試代碼運行結果截圖和碼雲連接服務器
知識點:網絡
棧的一個應用是用來對四則運算表達式進行求值。dom
表達式Exp = S1 + OP + S2
(S1 ,S2是兩個操做數,OP爲運算符)有三種標識方法:
例如:Exp = a * b + (c - d / e) * f
咱們能夠看出:
實驗步驟:
import java.util.Stack; public class MyDC { static Stack<Character> op = new Stack<>(); public static Float getv(char op, Float f1, Float f2) { if (op == '+') { return f2 + f1; } else if (op == '-') { return f2 - f1; } else if (op == '*') { return f2 * f1; } else if (op == '/') { return f2 / f1; } else { return Float.valueOf(-0); } } public static float calrp(String rp) { Stack<Float> v = new Stack<>(); char[] arr = rp.toCharArray(); int len = arr.length; for (int i = 0; i < len; i++) { Character ch = arr[i]; if (ch >= '0' && ch <= '9') { v.push(Float.valueOf(ch - '0')); } else { v.push(getv(ch, v.pop(), v.pop())); } } return v.pop(); } }
import java.util.Stack; public class MyBC { static Stack<Character> op = new Stack<>(); public static String getrp(String s){ char[] arr = s.toCharArray(); int len = arr.length; String out = ""; for(int i =0;i<len;i++){ char ch = arr[i]; if(ch == ' ') continue; if(ch>='0'&&ch<='9'){ out +=ch; continue; } if(ch =='(') op.push(ch); if(ch == '+'|| ch=='-'){ while(!op.empty()&&(op.peek()!='(')) out +=op.pop(); op.push(ch); continue; } if(ch=='*'||ch=='/'){ while(!op.empty()&&(op.peek()=='*'||op.peek()=='/')) out+=op.pop(); op.push(ch); continue; } if(ch == ')'){ while(!op.empty()&&op.peek()!='(') out += op.pop(); op.pop(); continue; } } while(!op.empty()) out += op.pop(); return out; } }
import java.util.Scanner; public class Main { public static void main(String[] args){ Scanner in = new Scanner(System.in); System.out.println("請輸入運算式:"); String s = in.nextLine(); String s2 = MyBC.getrp(s); System.out.println("轉換爲後綴表達式:"+s2); System.out.println(MyDC.calrp(s2)); } }
運行效果截圖:
實驗要求:
結對編程:1人負責客戶端,一人負責服務器
0. 注意責任歸宿,要會經過測試證實本身沒有問題
1. 基於Java Socket實現客戶端/服務器功能,傳輸方式用TCP
2. 客戶端讓用戶輸入中綴表達式,而後把中綴表達式調用MyBC.java的功能轉化爲後綴表達式,把後綴表達式經過網絡發送給服務器
3. 服務器接收到後綴表達式,調用MyDC.java的功能計算後綴表達式的值,把結果發送給客戶端
4. 客戶端顯示服務器發送過來的結果
5. 上傳測試結果截圖和碼雲連接
實驗步驟:
該任務須要利用Socket實現用客戶端和用戶端。
import javax.crypto.Cipher; import javax.crypto.KeyGenerator; import javax.crypto.SecretKey; import javax.crypto.spec.SecretKeySpec; import java.io.*; import java.security.Key; import java.util.Scanner; import java.net.*; public class SocketClient { // 搭建客戶端 public static void main(String[] args) throws IOException { try { // 一、建立客戶端Socket,指定服務器地址和端口 //下面是你要傳輸到另外一臺電腦的IP地址和端口 Socket socket = new Socket("192.168.56.1", 5209); System.out.println("客戶端啓動成功"); // 二、獲取輸出流,向服務器端發送信息 // 向本機的52000端口發出客戶請求 BufferedReader br = new BufferedReader(new InputStreamReader(System.in)); // 由系統標準輸入設備構造BufferedReader對象 PrintWriter write = new PrintWriter(socket.getOutputStream()); // 由Socket對象獲得輸出流,並構造PrintWriter對象 //三、獲取輸入流,並讀取服務器端的響應信息 BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream())); // 由Socket對象獲得輸入流,並構造相應的BufferedReader對象 String readline; readline = br.readLine(); // 從系統標準輸入讀入一字符串 readline = MyBC.getrp(readline); while (!readline.equals("end")) { // 若從標準輸入讀入的字符串爲 "end"則中止循環 write.println(readline); // 將從系統標準輸入讀入的字符串輸出到Server write.flush(); // 刷新輸出流,使Server立刻收到該字符串 System.out.println("客戶:" + readline); // 在系統標準輸出上打印讀入的字符串 System.out.println("服務:" + in.readLine()); // 從Server讀入一字符串,並打印到標準輸出上 readline = br.readLine(); // 從系統標準輸入讀入一字符串 } // 繼續循環 //四、關閉資源 write.close(); // 關閉Socket輸出流 in.close(); // 關閉Socket輸入流 socket.close(); // 關閉Socket } catch (Exception e) { System.out.println("can not listen to:" + e);// 出錯,打印出錯信息 } } }
import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; import java.io.PrintWriter; import java.net.ServerSocket; import java.net.Socket; public class SocketService { //搭建服務器端 public static void main(String[] args) throws IOException{ SocketService socketService = new SocketService(); //一、a)建立一個服務器端Socket,即SocketService socketService.oneServer(); } public void oneServer(){ try{ ServerSocket server=null; try{ //下面是端口,端口能夠和客戶端代碼裏面的端口同樣 server=new ServerSocket(5209); //b)指定綁定的端口,並監聽此端口。 System.out.println("服務器啓動成功"); //建立一個ServerSocket在端口5209監聽客戶請求 }catch(Exception e) { System.out.println("沒有啓動監聽:"+e); //出錯,打印出錯信息 } Socket socket=null; try{ socket=server.accept(); //二、調用accept()方法開始監聽,等待客戶端的鏈接 //使用accept()阻塞等待客戶請求,有客戶 //請求到來則產生一個Socket對象,並繼續執行 }catch(Exception e) { System.out.println("Error."+e); //出錯,打印出錯信息 } //三、獲取輸入流,並讀取客戶端信息 String line; BufferedReader in=new BufferedReader(new InputStreamReader(socket.getInputStream())); //由Socket對象獲得輸入流,並構造相應的BufferedReader對象 PrintWriter writer=new PrintWriter(socket.getOutputStream()); //由Socket對象獲得輸出流,並構造PrintWriter對象 BufferedReader br=new BufferedReader(new InputStreamReader(System.in)); //由系統標準輸入設備構造BufferedReader對象 Float m1=MyDC.calrp(in.readLine()); System.out.println("Client:"+m1); //在標準輸出上打印從客戶端讀入的字符串 line = m1.toString(); //從標準輸入讀入一字符串 //四、獲取輸出流,響應客戶端的請求 while(!line.equals("end")){ //若是該字符串爲 "bye",則中止循環 writer.println(line); //向客戶端輸出該字符串 writer.flush(); //刷新輸出流,使Client立刻收到該字符串 System.out.println("服務:"+line); //在系統標準輸出上打印讀入的字符串 System.out.println("客戶:"+in.readLine()); //從Client讀入一字符串,並打印到標準輸出上 line=br.readLine(); //從系統標準輸入讀入一字符串 } //繼續循環 //五、關閉資源 writer.close(); //關閉Socket輸出流 in.close(); //關閉Socket輸入流 socket.close(); //關閉Socket server.close(); //關閉ServerSocket }catch(Exception e) {//出錯,打印出錯信息 System.out.println("Error."+e); } } }
運行效果截圖:
實驗要求:
加密結對編程:1人負責客戶端,一人負責服務器
0. 注意責任歸宿,要會經過測試證實本身沒有問題
1. 基於Java Socket實現客戶端/服務器功能,傳輸方式用TCP
2. 客戶端讓用戶輸入中綴表達式,而後把中綴表達式調用MyBC.java的功能轉化爲後綴表達式,把後綴表達式用3DES或AES算法加密後經過網絡把密文發送給服務器
3. 服務器接收到後綴表達式表達式後,進行解密(和客戶端協商密鑰,能夠用數組保存),而後調用MyDC.java的功能計算後綴表達式的值,把結果發送給客戶端
4. 客戶端顯示服務器發送過來的結果
5. 上傳測試結果截圖和碼雲連接
實驗步驟:
該任務須要使用AES加密算法。
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); } }
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; public class Encoder { public static String AESEncode(String encodeRules,String content){ try { KeyGenerator keygen=KeyGenerator.getInstance("AES"); keygen.init(128, new SecureRandom(encodeRules.getBytes())); SecretKey original_key=keygen.generateKey(); byte [] raw=original_key.getEncoded(); SecretKey key=new SecretKeySpec(raw, "AES"); Cipher cipher=Cipher.getInstance("AES"); cipher.init(Cipher.ENCRYPT_MODE, key); byte [] byte_encode=content.getBytes("utf-8"); byte [] byte_AES=cipher.doFinal(byte_encode); 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(); } return null; } public static String AESDncode(String encodeRules,String content){ try { KeyGenerator keygen=KeyGenerator.getInstance("AES"); keygen.init(128, new SecureRandom(encodeRules.getBytes())); SecretKey original_key=keygen.generateKey(); byte [] raw=original_key.getEncoded(); SecretKey key=new SecretKeySpec(raw, "AES"); Cipher cipher=Cipher.getInstance("AES"); cipher.init(Cipher.DECRYPT_MODE, key); 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(); } return null; } }
import java.io.*; import java.net.*; import java.lang.*; import java.util.Scanner; public class Client { 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();//輸入算式 str = MyBC.getrp(str); String secret=Encoder.AESEncode(key,str);//客戶端進行加密 System.out.println("已加密:"+secret); 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); } } }
import java.io.*; import java.net.*; public class Server { public static void main (String args[]) throws Exception { 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=Encoder.AESDncode(key,s); System.out.println("解密後:"+clear); float answer=MyDC.calrp(clear); out.writeUTF(answer+""); Thread.sleep(500); } catch(Exception e) { System.out.println("客戶已斷開"+e); } } }
運行效果截圖:
客戶端:
服務器端:
實驗要求:
任務詳情
密鑰分發結對編程:1人負責客戶端,一人負責服務器 0. 注意責任歸宿,要會經過測試證實本身沒有問題 1. 基於Java Socket實現客戶端/服務器功能,傳輸方式用TCP 2. 客戶端讓用戶輸入中綴表達式,而後把中綴表達式調用MyBC.java的功能轉化爲後綴表達式,把後綴表達式用3DES或AES算法加密經過網絡把密文發送給服務器 3. 客戶端和服務器用DH算法進行3DES或AES算法的密鑰交換 4. 服務器接收到後綴表達式表達式後,進行解密,而後調用MyDC.java的功能計算後綴表達式的值,把結果發送給客戶端 5. 客戶端顯示服務器發送過來的結果 6. 上傳測試結果截圖和碼雲連接
實驗步驟:
該任務須要用到密鑰對生成器、公鑰及私鑰:
KeyPairGenerator kpg=KeyPairGenerator.getInstance("RSA");
kpg.initialize(1024);
KeyPair kp=kpg.genKeyPair( );
PublicKey pbkey=kp.getPublic( );
碼雲連接:https://gitee.com/Apollo20175126/java-besti-20175126/tree/master/20175126/test10
運行效果截圖:
客戶端:
服務器端:
實驗要求:
完整性校驗結對編程:1人負責客戶端,一人負責服務器
0. 注意責任歸宿,要會經過測試證實本身沒有問題
1. 基於Java Socket實現客戶端/服務器功能,傳輸方式用TCP
2. 客戶端讓用戶輸入中綴表達式,而後把中綴表達式調用MyBC.java的功能轉化爲後綴表達式,把後綴表達式用3DES或AES算法加密經過網絡把密文和明文的MD5値發送給服務器
3. 客戶端和服務器用DH算法進行3DES或AES算法的密鑰交換
4. 服務器接收到後綴表達式表達式後,進行解密,解密後計算明文的MD5值,和客戶端傳來的MD5進行比較,一致則調用MyDC.java的功能計算後綴表達式的值,把結果發送給客戶端
5. 客戶端顯示服務器發送過來的結果
6. 上傳測試結果截圖和碼雲連接
實驗步驟:
該任務須要使用DH算法:
import javax.crypto.spec.DHParameterSpec; import java.io.FileOutputStream; import java.io.ObjectOutputStream; import java.math.BigInteger; import java.security.KeyPair; import java.security.KeyPairGenerator; import java.security.PrivateKey; import java.security.PublicKey; public class DH { private static final byte SKIP1024_MODULUS_BYTES[] = { (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 }; private static final BigInteger SKIP1024_MODULES = new BigInteger(1, SKIP1024_MODULUS_BYTES); private static final BigInteger SKIP1024_BASE = BigInteger.valueOf(2); public static void createPubAndPriKey(String inpub,String inpri) throws Exception{ DHParameterSpec dhp = new DHParameterSpec(SKIP1024_MODULES, SKIP1024_BASE); KeyPairGenerator kpg = KeyPairGenerator.getInstance("DH"); kpg.initialize(dhp); KeyPair kp = kpg.generateKeyPair(); PublicKey pbk = kp.getPublic(); PrivateKey prk = kp.getPrivate(); FileOutputStream f1 = new FileOutputStream(inpub); ObjectOutputStream b1 = new ObjectOutputStream(f1); b1.writeObject(pbk); FileOutputStream f2 = new FileOutputStream(inpri); ObjectOutputStream b2 = new ObjectOutputStream(f2); b2.writeObject(prk); } }
import java.io.*; import java.security.*; import javax.crypto.*; public class SEnc{ public static void main(String args[]) throws Exception{ String s="Hello World!"; FileInputStream f=new FileInputStream("key1.dat"); ObjectInputStream b=new ObjectInputStream(f); Key k=(Key)b.readObject( ); Cipher cp=Cipher.getInstance("DESede"); cp.init(Cipher.ENCRYPT_MODE, k); byte ptext[]=s.getBytes("UTF8"); for(int i=0;i<ptext.length;i++){ System.out.print(ptext[i]+","); } System.out.println(""); byte ctext[]=cp.doFinal(ptext); for(int i=0;i<ctext.length;i++){ System.out.print(ctext[i] +","); } FileOutputStream f2=new FileOutputStream("SEnc.dat"); f2.write(ctext); } }
運行效果截圖:
客戶端:
服務器端:
問題一:
服務器調用MyDC時出現錯誤:
問題一解決辦法:
這是因爲MyDC.calrp的返回值是float,因此應該將String改成Float型:
問題二:
編譯運行時,出現找不到文件的錯誤:
問題二解決辦法:
這是因爲敲代碼時把文件名字寫錯致使,改回來便可:
問題三:
出現javax.crypto.IllegalBlockSizeException: Input length must be multiple of 16 when decrypting with padded cipher
報錯
問題三解決辦法:
產生的密文是byte[]數組,可是傳送給服務器時所使用的參數應該是String類型,我是直接使用了String s = new String(ctext);,因此就出現了錯誤。因此只用將ctext[]二進制轉化成十六進制傳送給服務器,服務器接收後再將十六進制轉爲二進制便可。
本次實驗是JAVA課程最後一次實驗,五個任務都是按部就班一個接一個的遞進關係,感受本身學會了不少,但在AES加解密的部分仍是有點欠缺,須要再增強!
https://gitee.com/Apollo20175126/java-besti-20175126/tree/master/20175126