工作奇谈——使用对称密匙加密数据
1、對稱密匙及對稱加密算法DES簡介
???????? 對稱密鑰加密,又稱私鑰加密,即信息的發送方和接收方用一個密鑰去加密和解密數據。它的最大優勢是加/解密速度快,適合于對大數據量進行加密。
???????? DES算法全稱為Data Encryption Standard,即數據加密算法,它是IBM公司于1975年研究成功并公開發表的。DES算法的入口參數有三個:Key、Data、Mode。其中Key為8個字節共64位,是DES算法的工作密鑰;Data也為8個字節64位,是要被加密或被解密的數據;Mode為DES的工作方式,有兩種:加密或解密。
2、實現思路(防君子不防小人)
??????? 項目里有個活,要求登錄的時候賬號密碼加密傳輸,又不能使用SSL(真的坑),沒辦法,自己想了想,決定使用對稱密匙來加密解密數據。
??????? 但是密匙總不能是固定的吧,萬一別人拿到了我的密匙就可以隨意破解數據了(因為加密算法是固定的),所以我的實現思路是在用戶訪問login頁面的時候,服務端生成一個40位(此算法的密匙必須是八的倍數)的隨機密匙給瀏覽器,然后寫一個JQ在瀏覽器同步加密用戶輸入的用戶名及密碼,當用戶提交表單的時候再將加密好的用戶名密碼及密匙傳到服務端解密出原始數據不就OK了?想到這里說干就干!!!
3、代碼實現
??? 3.1、 加密及解密算法實現
??????????? 加密及解密算法的代碼我已經寫成一個工具類,不太懂的同學可以去百度,百度上一大堆 ?щ(゚Д゚щ) ,代碼如下:我也已經傳到碼云上:https://git.oschina.net/LKWai
package cn.yy.util; import java.security.InvalidKeyException; import java.security.NoSuchAlgorithmException; import java.security.spec.InvalidKeySpecException;import javax.crypto.BadPaddingException; import javax.crypto.Cipher; import javax.crypto.IllegalBlockSizeException; import javax.crypto.NoSuchPaddingException; import javax.crypto.SecretKey; import javax.crypto.SecretKeyFactory; import javax.crypto.spec.DESKeySpec;/*** DES加解密工具類* * @author 二十歲以后** @date 2017年7月27日 */ public class DESUtil {private static final String DES_ALGORITHM = "DES";/*** DES加密* * @param plainData 原始字符串* @param secretKey 加密密鑰* @return 加密后的字符串* @throws Exception*/public static String encryption(String plainData, String secretKey) throws Exception {Cipher cipher = null;try {cipher = Cipher.getInstance(DES_ALGORITHM);cipher.init(Cipher.ENCRYPT_MODE, generateKey(secretKey));} catch (NoSuchAlgorithmException e) {e.printStackTrace();} catch (NoSuchPaddingException e) {e.printStackTrace();} catch (InvalidKeyException e) {}try {// 為了防止解密時報javax.crypto.IllegalBlockSizeException: Input length must// be multiple of 8 when decrypting with padded cipher異常,// 不能把加密后的字節數組直接轉換成字符串byte[] buf = cipher.doFinal(plainData.getBytes());return Base64Utils.encode(buf);} catch (IllegalBlockSizeException e) {e.printStackTrace();throw new Exception("IllegalBlockSizeException", e);} catch (BadPaddingException e) {e.printStackTrace();throw new Exception("BadPaddingException", e);}}/*** DES解密* @param secretData 密碼字符串* @param secretKey 解密密鑰* @return 原始字符串* @throws Exception*/public static String decryption(String secretData, String secretKey) throws Exception {Cipher cipher = null;try {cipher = Cipher.getInstance(DES_ALGORITHM);cipher.init(Cipher.DECRYPT_MODE, generateKey(secretKey));} catch (NoSuchAlgorithmException e) {e.printStackTrace();throw new Exception("NoSuchAlgorithmException", e);} catch (NoSuchPaddingException e) {e.printStackTrace();throw new Exception("NoSuchPaddingException", e);} catch (InvalidKeyException e) {e.printStackTrace();throw new Exception("InvalidKeyException", e);}try {byte[] buf = cipher.doFinal(Base64Utils.decode(secretData.toCharArray()));return new String(buf);} catch (IllegalBlockSizeException e) {e.printStackTrace();throw new Exception("IllegalBlockSizeException", e);} catch (BadPaddingException e) {e.printStackTrace();throw new Exception("BadPaddingException", e);}}/*** 獲得秘密密鑰* * @param secretKey* @return* @throws NoSuchAlgorithmException* @throws InvalidKeySpecException* @throws InvalidKeyException*/private static SecretKey generateKey(String secretKey)throws NoSuchAlgorithmException, InvalidKeySpecException, InvalidKeyException {SecretKeyFactory keyFactory = SecretKeyFactory.getInstance(DES_ALGORITHM);DESKeySpec keySpec = new DESKeySpec(secretKey.getBytes());keyFactory.generateSecret(keySpec);return keyFactory.generateSecret(keySpec);}static private class Base64Utils {static private char[] alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=".toCharArray();static private byte[] codes = new byte[256];static {for (int i = 0; i < 256; i++)codes[i] = -1;for (int i = 'A'; i <= 'Z'; i++)codes[i] = (byte) (i - 'A');for (int i = 'a'; i <= 'z'; i++)codes[i] = (byte) (26 + i - 'a');for (int i = '0'; i <= '9'; i++)codes[i] = (byte) (52 + i - '0');codes['+'] = 62;codes['/'] = 63;}/*** 將原始數據編碼為base64編碼*/static private String encode(byte[] data) {char[] out = new char[((data.length + 2) / 3) * 4];for (int i = 0, index = 0; i < data.length; i += 3, index += 4) {boolean quad = false;boolean trip = false;int val = (0xFF & (int) data[i]);val <<= 8;if ((i + 1) < data.length) {val |= (0xFF & (int) data[i + 1]);trip = true;}val <<= 8;if ((i + 2) < data.length) {val |= (0xFF & (int) data[i + 2]);quad = true;}out[index + 3] = alphabet[(quad ? (val & 0x3F) : 64)];val >>= 6;out[index + 2] = alphabet[(trip ? (val & 0x3F) : 64)];val >>= 6;out[index + 1] = alphabet[val & 0x3F];val >>= 6;out[index + 0] = alphabet[val & 0x3F];}return new String(out);}/*** 將base64編碼的數據解碼成原始數據*/static private byte[] decode(char[] data) {int len = ((data.length + 3) / 4) * 3;if (data.length > 0 && data[data.length - 1] == '=')--len;if (data.length > 1 && data[data.length - 2] == '=')--len;byte[] out = new byte[len];int shift = 0;int accum = 0;int index = 0;for (int ix = 0; ix < data.length; ix++) {int value = codes[data[ix] & 0xFF];if (value >= 0) {accum <<= 6;shift += 6;accum |= value;if (shift >= 8) {shift -= 8;out[index++] = (byte) ((accum >> shift) & 0xff);}}}if (index != out.length)throw new Error("miscalculated data length!");return out;}} }??? 3.2 當用戶訪問登錄頁,向瀏覽器寫入一個40位的密匙
??????? 代碼就不貼了,就是用random生成,然后用model寫回去
? ?? 3.3 使用JQ同步加密數據
??????? 當用戶在文本框輸入賬號密碼的時候,需要向隱藏域中實時的寫入當前用戶輸入數據的加密值。代碼如下:???????
function synchronize(){ var NewUser = $("#um").val();var NewPass = $("#pw").val();var ranDom = $("#random").val();//NewPass是用戶輸入值,ranDom是加密密匙document.getElementById('pw1').value =encryptByDES(NewPass, ranDom); document.getElementById('um1').value =encryptByDES(NewUser, ranDom); } //執行同步 setInterval(synchronize,300);//同步的時間間隔,每0.3秒同步一次??? 然后提交表單的時候,把隱藏域中加密好的用戶名密碼及加密密匙傳回后臺進行解密,再去查數據庫判斷就OK了!
??? 下面是加密數據的效果圖:可以看到所有數據已經加密
????? 然后我再補一張服務端解密的Debug圖:首先可以看到傳來的用戶名密碼都是加密的。
??? 接下來是解密成原始數據,數據已經成功解密!!
轉載于:https://my.oschina.net/u/3637243/blog/1510861
總結
以上是生活随笔為你收集整理的工作奇谈——使用对称密匙加密数据的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 怎么用迅捷PDF转换器在线为PDF文件添
- 下一篇: 一篇文章搞定Shiro权限管理框架