JAVA加密方案(AES/RSA/MD5)
- 對稱加密和非對稱加密
對稱加密指的就是加密和解密使用同一個祕鑰。對稱加密只有一個祕鑰,作爲私鑰。
常見的對稱加密算法:DES,AES,3DES等等。
非對稱加密指的是加密和解密使用不同的祕鑰,一把作爲公開的公鑰,另一把作爲私鑰。公鑰加密的信息,只有私鑰才能解密。私鑰加密的信息,只有公鑰才能解密。
常見的非對稱加密算法:RSA,ECC
對稱加密和非對稱加密不能說誰好誰不好,主要是要看應用場景,如果可以用對稱加密解決的問題,那麼就沒有必要用非對稱進行加密。因爲非對稱加密的開銷一般比較大,例如RSA 1024的安全性,與AES128的安全性是相當的。
- 對稱加密算法AES
對稱算法以DES和AES爲代表性,其底層原理也有相似之處,都有一個S盒子(可不可以叫做黑盒子),然後通過交換和替換等複雜變換,達到加密的效果。對稱加密算法有個非常重要的特性,就是加密和解密可以互逆。總之呢,算法還是挺複雜的,不過,作爲程序員的我們,可以不去關心這些,我們只要知道,我們可以用他們來做加密。加密的安全性取決於密鑰的長度,密鑰越長,越安全如密鑰長爲128的AES,我們稱之爲AES128,密鑰爲256的AES,我們稱之爲AES256。當前計算機的計算能力下,128的AES基本是安全的,256完全可以放心了。
好了,用java代碼來實現AES加解密吧,這個纔是我們關心的。
加密方法:
public static final String VIPARA = "20179TELIGRR1234";//初始化向量 16位
|
這個加密方法傳入參數是文本內容以及密鑰,注意密鑰長度要爲16byte(與上述的初始化向量是一樣的)。
解密方法類似:
/** |
上訴加密和解密方法,還是有挺多與密碼學相關的知識的,比如初始化向量,以及加密的CBC模式,不過其實,作爲我們應用層的,可以不去關心這些底層的實現,使用就可以完成我們的目標了。不過,使用舊了,自然而且,我們會好奇,它到底怎麼實現的?它爲什麼就是安全的?到時,我們就可以深入去學習了,希望大家這種好奇來的越早越好。
有了上訴的加密和解密方法,我們就可以來進行加解密了,示例如下:
byte[] data1 = aesEncryptToBytes("DW1234567fddddddddddfffffffffff8","aaaaaaaaaaaaaaaa"); |
這上面應用到兩個函數bytesToHexString與hexStringToBytes,這個其實不是加解密的環節,而是編解碼的環節了,它們的作用就是把字節轉成16進制數,以及它的逆操作,具體函數如下:
/**
|
- 非對稱加密算法 RSA
非對稱加密算法都有一個數學依據的,比如RSA的數學依據總結起來可以說:兩個質數相乘得到一個合數是很容易的,而兩個大質數相乘得到的大數難以被因式分解。
對於非對稱加密,你首先先要一對密鑰,一個公鑰,用來發布出去的,一個私鑰,只能自己擁有的。基於java的RSA密鑰生成方法如下:
KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("RSA"); keyPairGenerator.initialize(1024);// 祕鑰長度爲1024,可以改成2048等 KeyPair keyPair = keyPairGenerator.generateKeyPair(); PublicKey publicKey = keyPair.getPublic();//公鑰 PrivateKey privateKey = keyPair.getPrivate();//私鑰 |
現在公鑰和私鑰都有了,首先我們需要把它們保存起來,可以直接保存爲文件,或者生成字符串等等,下面我把他們保存爲文件
byte[] publicKeyByte = publicKey.getEncoded(); byte[] privateKeyByte = privateKey.getEncoded(); BufferedOutputStream pukout = new BufferedOutputStream( new FileOutputStream("src/com/lh/test/publicKey.key")); BufferedOutputStream prkout = new BufferedOutputStream( new FileOutputStream("src/com/lh/test/privateKey.key")); pukout.write(publicKeyByte); prkout.write(privateKeyByte); pukout.flush(); prkout.flush(); |
保存的文件讀出如下:
BufferedInputStream pukIn = new BufferedInputStream( new FileInputStream("src/com/lh/test/publicKey.key")); BufferedInputStream prkIn = new BufferedInputStream( new FileInputStream("src/com/lh/test/privateKey.key")); byte[] puKeyByte = new byte[1024]; byte[] prKeyByte = new byte[1024]; pukIn.read(puKeyByte, 0, 1024); prkIn.read(prKeyByte, 0, 1024); X509EncodedKeySpec x509EncodedKeySpec = new X509EncodedKeySpec( puKeyByte);// 公鑰 KeyFactory keyFactory = KeyFactory.getInstance("RSA"); PublicKey publicKey = keyFactory.generatePublic(x509EncodedKeySpec); PKCS8EncodedKeySpec pkcs8EncodedKeySpec = new PKCS8EncodedKeySpec( prKeyByte);// 私鑰 PrivateKey privateKey = keyFactory .generatePrivate(pkcs8EncodedKeySpec); |
現在我們通過文件讀取(或其它途徑)拿到了公鑰和私鑰,我們就可以用來使用了,如果公鑰加密,那麼需要私鑰進行解密,反之亦然。
公鑰加密:
Cipher cipher = Cipher.getInstance("RSA"); cipher.init(Cipher.ENCRYPT_MODE, publicKey); byte[] resultbytes = cipher.doFinal(plainBytes); //plainBytes 要加密的字節數組 |
私鑰解密:
Cipher cipher = Cipher.getInstance("RSA"); cipher.init(Cipher.DECRYPT_MODE, privateKey); byte[] deBytes = cipher.doFinal(ciperBytes); //ciperBytes要解密的字節數組
|
有了byte[],就可以根據上面的hexStringToBytes,bytesToHexString方法,進行字節數組與字符串的轉換,便於傳輸。
- 安全哈希函數MD5
實際開發中,經常可以聽到我們密碼字段是用MD5加密的,其實這種說法是不對的,MD5(安全哈希函數)只是一串數據指紋,只能用來做數據驗證。即,只能單向認證,只能從明文單向計算出MD5值,而不能從MD5值計算出明文。
安全哈希函數常用於驗證信息完整性以及驗證信息等,比如協議的完整性校驗、驗證密碼。
安全哈希函數有MD5/SHA1/SHA2/SHA3,現在推薦使用SHA2/SHA3
Java實現MD5如下
private static final String md5Key = "MD5";
/**
|