網絡營銷策略內容廈門seo俱樂部
需要考慮哪些問題?
在進行報文傳輸時,有兩個問題需要考慮:
- 消息防篡改
- 加密報文
定義消息結構
為了方便后面使用,這里定義消息結構:
public static class Message {public String data; //消息public String sign; //簽名public Message(String data, String sign) {this.data = data;this.sign = sign;}
}
對報文進行簽名
首先我們假設消息是一個字符串:String msg = "Hello, message encryption!"
然后我們對這個報文計算摘要:byte[] msgHash = md5(msg)
。只要兩個字符串計算出的摘要相同,我們認為這兩個字符串是相等的(即沒有被篡改過)。
然而如果直接傳輸 msg 及其摘要,那么很容易被別人篡改,這時就需要對摘要進行加密,也就是所謂的簽名。也就是防止篡改的核心。下面給出一個完整的實現(xiàn):
這里只放主要流程,輔助方法見附錄:
// 生成RSA密鑰對
KeyPair keyPair = generateKeyPair();// 獲取公鑰和私鑰
PublicKey publicKey = keyPair.getPublic();
PrivateKey privateKey = keyPair.getPrivate();// 要加密的原始數(shù)據
String originalMessage = "Hello, message encryption!";//發(fā)送端簽名
Message message = sign(originalMessage, privateKey);
System.out.println("加密后的消息簽名: " + message.sign);//接收端校驗簽名
boolean checkResult = checkSign(message, publicKey);
System.out.println("合法:" + checkResult);
對報文進行加密
在發(fā)送端: 首先生成 AES 密鑰,使用AES對報文進行加密,然后使用 RSA 對 AES 密鑰進行加密。(考慮到報文本身可能較大,而非對稱RSA加密效率較差)
在接收端:使用 RSA解密 AES 密鑰,使用解密的 AES 密鑰解密報文。
// 生成RSA密鑰對
KeyPair keyPair = generateKeyPair();// 獲取公鑰和私鑰
PublicKey publicKey = keyPair.getPublic();
PrivateKey privateKey = keyPair.getPrivate();//生成 aes 密鑰
byte[] aesKey = generateAesKey();
//使用公鑰對 aes 密鑰進行加密
byte[] encryptedAesKey = encrypt(aesKey, publicKey);//報文
String originalMessage = "Hello, message encryption!";// 使用AES密鑰加密報文
byte[] encryptedMessage = encryptWithAes(originalMessage.getBytes(), aesKey);//將encryptedAesKey和encryptedMessage傳給接收端
// 使用私鑰解密AES密鑰
byte[] decryptedAesKey = decrypt(encryptedAesKey, privateKey);// 使用AES密鑰解密消息
String decryptedMessage = new String(decryptWithAes(encryptedMessage, decryptedAesKey));
附錄
//公鑰簽名
public static Message sign(String originalMessage, PublicKey publicKey) throws Exception {byte[] bytes = calculateMD5(originalMessage);byte[] encryptedHash = encrypt(bytes, publicKey);String signStr = bytesToHex(encryptedHash);return new Message(originalMessage, signStr);
}//私鑰簽名
public static Message sign(String originalMessage, PrivateKey privateKey) throws Exception {byte[] bytes = calculateMD5(originalMessage);byte[] encryptedHash = encrypt(bytes, privateKey);String signStr = bytesToHex(encryptedHash);return new Message(originalMessage, signStr);
}//公鑰驗簽
public static boolean checkSign(Message message, PublicKey publicKey) throws Exception {byte[] sign = hexToBytes(message.sign);byte[] md5Hash = decrypt(sign, publicKey);byte[] calcMd5Hash = calculateMD5(message.data);return Arrays.equals(md5Hash, calcMd5Hash);
}//私鑰驗簽
public static boolean checkSign(Message message, PrivateKey privateKey) throws Exception {byte[] sign = hexToBytes(message.sign);byte[] md5Hash = decrypt(sign, privateKey);byte[] calcMd5Hash = calculateMD5(message.data);return Arrays.equals(md5Hash, calcMd5Hash);
}// 生成RSA密鑰對
public static KeyPair generateKeyPair() throws Exception {KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("RSA");SecureRandom secureRandom = new SecureRandom();keyPairGenerator.initialize(2048, secureRandom);return keyPairGenerator.generateKeyPair();
}// 計算MD5哈希值
public static byte[] calculateMD5(String message) throws Exception {MessageDigest md = MessageDigest.getInstance("MD5");md.update(message.getBytes());return md.digest();
}// 使用公鑰加密數(shù)據
public static byte[] encrypt(byte[] data, PublicKey publicKey) throws Exception {Cipher cipher = Cipher.getInstance("RSA");cipher.init(Cipher.ENCRYPT_MODE, publicKey);return cipher.doFinal(data);
}// 使用私鑰加密數(shù)據
public static byte[] encrypt(byte[] data, PrivateKey privateKey) throws Exception {Cipher cipher = Cipher.getInstance("RSA");cipher.init(Cipher.ENCRYPT_MODE, privateKey);return cipher.doFinal(data);
}// 使用公鑰解密數(shù)據
public static byte[] decrypt(byte[] data, PublicKey publicKey) throws Exception {Cipher cipher = Cipher.getInstance("RSA");cipher.init(Cipher.DECRYPT_MODE, publicKey);return cipher.doFinal(data);
}// 使用私鑰解密數(shù)據
public static byte[] decrypt(byte[] data, PrivateKey privateKey) throws Exception {Cipher cipher = Cipher.getInstance("RSA");cipher.init(Cipher.DECRYPT_MODE, privateKey);return cipher.doFinal(data);
}// 生成AES密鑰
public static byte[] generateAesKey() throws Exception {SecureRandom secureRandom = new SecureRandom();byte[] key = new byte[16];secureRandom.nextBytes(key);return key;
}// 使用AES密鑰加密數(shù)據
public static byte[] encryptWithAes(byte[] data, byte[] key) throws Exception {Cipher cipher = Cipher.getInstance("AES");cipher.init(Cipher.ENCRYPT_MODE, new SecretKeySpec(key, "AES"));return cipher.doFinal(data);
}// 使用AES密鑰解密數(shù)據
public static byte[] decryptWithAes(byte[] encryptedData, byte[] key) throws Exception {Cipher cipher = Cipher.getInstance("AES");cipher.init(Cipher.DECRYPT_MODE, new SecretKeySpec(key, "AES"));return cipher.doFinal(encryptedData);
}// 將字節(jié)數(shù)組轉換為十六進制字符串
public static String bytesToHex(byte[] bytes) {StringBuilder hexString = new StringBuilder();for (byte b : bytes) {String hex = Integer.toHexString(0xff & b);if (hex.length() == 1) {hexString.append('0');}hexString.append(hex);}return hexString.toString();
}public static byte[] hexToBytes(String hex) {int len = hex.length();byte[] data = new byte[len / 2];for (int i = 0; i < len; i += 2) {data[i / 2] = (byte) ((Character.digit(hex.charAt(i), 16) << 4)+ Character.digit(hex.charAt(i + 1), 16));}return data;
}