RSA非對稱加解密演算法的使用
加密金鑰和解密金鑰相同時則稱為對稱加密。由於加密金鑰和解密金鑰相同,它們也被稱為Shared Key。如AES等。
加密金鑰(公鑰)和解密金鑰(私鑰)不相同時則稱為非對稱加密,別稱公鑰密碼。如RSA等。
非對稱加密例子:
假設張三擁有的公鑰Pu和私鑰Pr,其公鑰是公開的,誰想跟張三通訊的話必須用張三的公鑰Pu進行加密後傳輸給張三,張三用自己的私鑰Pr解密後就能檢視通訊內容了。
RSA:建立在分解大數的困難度、公鑰/私鑰長度至少是1024bit。1英文字元=1位元組=8bit位。
對稱加密的優缺點:
1.高效
2.金鑰交換問題
3.不如RSA的加密安全程度高,但是當選擇256bit的AES時,仍然能勝任絕大多數的安全領域
非對稱加密的優缺點:
1.安全性足夠高
2.沒有金鑰交換的問題
3.效率低,對於大資料加密很慢
實際的保密會話應用場景:
1.基於高效的對稱加密演算法對會話進行加密
2.會話金鑰實時產生並週期性變化
3.基於其他足夠安全的方式進行會話金鑰的傳輸和交換
針對上面的第3步,可以利用非對稱加密方法來交換會話金鑰:
1.產生實時隨機的會話金鑰
2.A使用對端B的公鑰對產生的會話金鑰進行加密並傳遞給對端B
3.對端B使用自己的私鑰解密獲取會話金鑰
4.雙方開始基於共享的會話金鑰進行對稱加密的保密會話通訊
點對點通訊使用上面的加解密方法進行通訊,點對多的通訊可以使用下面的方法進行廣播:
5.B向任何人發訊息時,傳送的是使用自己私鑰加密後的內容
6.任何人接收到訊息後使用訊息傳送者B的公鑰進行解密得到B廣播的訊息內容
非對稱加密的兩面性:
A使用B的公鑰加密後,B可以使用自己的私鑰進行解密;
B使用自己的私鑰加密後,A可以使用B的公鑰進行解密。
RSA加密演算法例項:
public class RSA { private static RSA mInstance; private File mPublicKeyFile; private File mPrivateKeyFile; public static RSA getInstance(Context context) { if (mInstance == null) { mInstance = new RSA(context); } return mInstance; } public RSA(Context context) { String path = context.getFilesDir().getAbsolutePath(); mPublicKeyFile = createFile(path + "/publickey.dat"); mPrivateKeyFile = createFile(path + "/privatekey.dat"); generateKeyPair(); } /** * 生成金鑰對 */ private void generateKeyPair() { try { // RSA演算法要求有一個可信任的隨機數源 SecureRandom sr = new SecureRandom(); // 為RSA演算法建立一個KeyPairGenerator物件 KeyPairGenerator kpg = KeyPairGenerator.getInstance("RSA"); // 初始化金鑰長度 kpg.initialize(1024, sr); // 生成金鑰對 KeyPair genKeyPair = kpg.genKeyPair(); // 獲取公鑰 PublicKey publicKey = genKeyPair.getPublic(); // 儲存公鑰 FileOutputStream fos = new FileOutputStream(mPublicKeyFile); ObjectOutputStream oos = new ObjectOutputStream(fos); oos.writeObject(publicKey); oos.close(); // 獲取私鑰 PrivateKey privateKey = genKeyPair.getPrivate(); // 儲存私鑰 FileOutputStream fos1 = new FileOutputStream(mPrivateKeyFile); ObjectOutputStream oos1 = new ObjectOutputStream(fos1); oos1.writeObject(privateKey); oos1.close(); } catch (Exception e) { e.printStackTrace(); } } /** * 公鑰加解密 * isEncrypt: true是利用公鑰加密,false是利用公鑰解密 */ public byte[] encrypt(byte[] source, boolean isEncrypt) { byte[] result = null; try { // 獲取公鑰 FileInputStream fis = new FileInputStream(mPublicKeyFile); ObjectInputStream ois = new ObjectInputStream(fis); RSAPublicKey publicKey = (RSAPublicKey) ois.readObject(); ois.close(); Cipher cipher = Cipher.getInstance("RSA"); if (isEncrypt) { cipher.init(Cipher.ENCRYPT_MODE, publicKey); } else { cipher.init(Cipher.DECRYPT_MODE, publicKey); } if (source != null) { // 加密 result = cipher.doFinal(source); } } catch (Exception e) { e.printStackTrace(); } return result; } /** * 私鑰加解密 * isDecrypt: true是利用私鑰解密,false是利用私鑰加密 */ public byte[] decrypt(byte[] source, boolean isDecrypt) { byte[] result = null; try { // 讀取私鑰 FileInputStream fis = new FileInputStream(mPrivateKeyFile); ObjectInputStream ois = new ObjectInputStream(fis); RSAPrivateKey privateKey = (RSAPrivateKey) ois.readObject(); ois.close(); Cipher cipher = Cipher.getInstance("RSA"); if (isDecrypt) { cipher.init(Cipher.DECRYPT_MODE, privateKey); } else { cipher.init(Cipher.ENCRYPT_MODE, privateKey); } if (source != null) { // 解密 result = cipher.doFinal(source); } } catch (Exception e) { e.printStackTrace(); } return result; } private File createFile(String path) { File file = new File(path); if (!file.exists()) { try { file.createNewFile(); } catch (Exception e) { e.printStackTrace(); } } return file; } }
呼叫:
try {
String source = "哈哈嘻嘻的假短髮接歐文多拉點開機費的";
byte[] encrypt = RSA.getInstance(this).encrypt(source.getBytes("UTF-8"), true);
String result = new String(RSA.getInstance(this).decrypt(encrypt, true), "UTF-8");
System.out.println("zyf 使用公鑰加密,私鑰解密的結果: " + result);
byte[] decrypt = RSA.getInstance(this).decrypt(source.getBytes("UTF-8"), false);
result = new String(RSA.getInstance(this).encrypt(decrypt, false), "UTF-8");
System.out.println("zyf 使用私鑰加密,公鑰解密的結果: " + result);
} catch (Exception e) {
e.printStackTrace();
}
RSA的低效率特性導致即便是簽名也不適合直接對原始資訊進行簽名,可以:
1.先計算出原始訊息的MD5值
2.對MD5值進行基於非對稱加密演算法的簽名
3.簽名一般附著於原始訊息尾部或頭部一起傳送
收到訊息後,先用非對稱加密演算法對簽名進行解密,解密後的MD5值與原始訊息的MD5值進行比對,一致則認為訊息沒有被篡改。