閱讀443 返回首頁    go 阿裏雲 go 技術社區[雲棲]


凱撒加密+Base64--打造安全又高效的加密算法

博學,切問,近思--詹子知 (https://jameszhan.github.io)


在密碼學中,愷撒密碼(或稱愷撒加密、愷撒變換、變換加密)是一種最簡單且最廣為人知的加密技術。它是一種替換加密的技術,明文中的所有字母都在字母表上向後(或向前)按照一個固定數目進行偏移後被替換成密文。
愷撒密碼的加密、解密方法還能夠通過同餘的數學方法進行計算。首先將字母用數字代替,A=0,B=1,...,Z=25。此時偏移量為n的加密方法即為: E(x) = (x + n) mod 26.
解密就是:
D(x) = (x - n) mod 26.
顯而易見,一旦確定了某兩個字母的對應關係(即n的值),這種移位密碼很容易被破解。
因此,為了使密碼有更高的安全性,單字母替換密碼就出現了。
明碼表:A B C D E F G H I J K L M N O P Q R S T U V W X Y Z
密碼表:T U V W X Y Z A B C D E F G H I J K L M N O P Q R S
但是這種加密方式依然可以破解,根據字母使用頻度表,分析密文中的字母頻率,將其對照即可破解。

不僅如此,凱撒加密對加密數據也是有要求的,一般情況下,它隻支持對基本的英文字母進行加密,如果對中文等亞太地區的文字進行加密,結果可想而知,你的隱私將毫無保留的出現在眾人麵前。有人說,我們可以擴展這個算法,使它支持所有的文字,這麼做是可行的,如果采用同餘式的方式實現,代碼幾乎不怎麼需要改動,隻要字符集本身是Unicode就可以了。但是這種加密的安全性很難滿足應用的要求。如果采用單字母替換的方式,程序將需要構建兩個巨大的字符數組去保存他們的映射關係,而且擴展性也不好,當然也是不可行的。這樣看來,凱撒加密豈不是一無是處了,其實對於一般的應用,凱撒加密還是足以應付的,隻要我們對它稍作改進。

那麼有什麼樣改進的方法呢?試想一下,如果被加密的數據本身就雜亂無章,毫無意義,那麼人們就無法利用字母頻度表來對數據進行破解攻擊。如果有個工具能把我們需要加密的數據轉換成簡單的字符並雜亂無章,這樣不就可以解決我們前麵提到的問題了嗎。看過前文的朋友一定還記得,有個叫Base64的字符編碼工具,它剛好可以勝任這個工作。

到這裏,大家一定知道我們這種加密方法的思路了。分兩步走:

  1. 利用Base64對需要加密的字符串進行編碼,生成毫無意義的Base64 String。
  2. 利用凱撒加密方式對Base64 String進行加密。

這時我們已經得到了加密後的字符串了,這個密文已經很難被破解了,是不是很Cool啊,這種方式已經足以滿足大部分應用的安全需求。有人可能會問,Base64本身不是可以達到一種加密效果嗎,為什麼還要對他進行再次加密呢。這個問題的原因在於,Base64算法本身是公開的,拿到Base64 String後,它隻要使用Base64對其進行解碼就可以看到你的信息。而在這裏,凱撒加密算法是我們自己的定製的,這個映射關係一定需要保密,否則我們的算法將起不到任何的加密效果。

public class CaesarCipher { private static final char[] UC_ENCRYPT_CHARS = { 'M', 'D', 'X', 'U', 'P', 'I', 'B', 'E', 'J', 'C', 'T', 'N', 'K', 'O', 'G', 'W', 'R', 'S', 'F', 'Y', 'V', 'L', 'Z', 'Q', 'A', 'H' }; private static final char[] LC_ENCRYPT_CHARS = { 'm', 'd', 'x', 'u', 'p', 'i', 'b', 'e', 'j', 'c', 't', 'n', 'k', 'o', 'g', 'w', 'r', 's', 'f', 'y', 'v', 'l', 'z', 'q', 'a', 'h' }; private static char[] UC_DECRYPT_CHARS = new char[26]; private static char[] LC_DECRYPT_CHARS = new char[26]; static { for (int i = 0; i < 26; i++) { char b = UC_ENCRYPT_CHARS[i]; UC_DECRYPT_CHARS[b - 'A'] = (char) ('A' + i); b = LC_ENCRYPT_CHARS[i]; LC_DECRYPT_CHARS[b - 'a'] = (char) ('a' + i); } } public static char encrypt(char b) { if (b >= 'A' && b <= 'Z') { return UC_ENCRYPT_CHARS[b - 'A']; } else if (b >= 'a' && b <= 'z') { return LC_ENCRYPT_CHARS[b - 'a']; } else { return b; } } public static char decrypt(char b) { if (b >= 'A' && b <= 'Z') { return UC_DECRYPT_CHARS[b - 'A']; } else if (b >= 'a' && b <= 'z') { return LC_DECRYPT_CHARS[b - 'a']; } else { return b; } } public static String encrypt(String input){ StringBuilder sb = new StringBuilder(); for(int i = 0; i < input.length(); i++){ sb.append(encrypt(input.charAt(i))); } return sb.toString(); } public static String decrypt(String input){ StringBuilder sb = new StringBuilder(); for(int i = 0; i < input.length(); i++){ sb.append(decrypt(input.charAt(i))); } return sb.toString(); } }

關於Base64大家可以參照:Base64算法實現

我們看一個例子:

public static void main(String[] args) throws UnsupportedEncodingException { String plainText = "There is a tree!"; String base64String = Base64.encode(plainText.getBytes("utf-8")); //base64 String = VGhlcmUgaXMgYSB0cmVlIQ== System.out.println(CaesarCipher.encrypt(base64String)); }

這時可以的到加密後的字符串:LBenxkVbmQKbAFD0xkLnJR==

 

解密的過程與之剛好相反。

  1. 利用凱撒加密方式對加密後的數據進行解密,得到Base64 String。
  2. 利用Base64對Base64 String進行解碼,得到最終的明文。

public static void main(String[] args) throws UnsupportedEncodingException { String cipherText = "LBenxkVbmQKbAFD0xkLnJR=="; String base64String = CaesarCipher.decrypt(cipherText); //base64 String = VGhlcmUgaXMgYSB0cmVlIQ== System.out.println(new String(Base64.decode(base64String), "utf-8")); }

得到加密前的明文:There is a tree!

 

同樣,我們也可以采用這種方式對多字節的字符串進行加密:

public static void main(String[] args) throws UnsupportedEncodingException { String plainText = "中華人民共和國萬歲!"; String base64String = Base64.encode(plainText.getBytes("utf-8")); //base64String = 5Lit5Y2O5Lq65rCR5YWx5ZKM5Zu95LiH5bKB77yB System.out.println(CaesarCipher.encrypt(base64String)); }

得到密文:5Njy5A2G5Nr65sXS5AZq5HTK5Hv95NjE5dTD77aD

 

解密過程如下:

public static void main(String[] args) throws UnsupportedEncodingException { String cipherText = "5Njy5A2G5Nr65sXS5AZq5HTK5Hv95NjE5dTD77aD"; String base64String = CaesarCipher.decrypt(cipherText); //base64String = 5Lit5Y2O5Lq65rCR5YWx5ZKM5Zu95LiH5bKB77yB System.out.println(new String(Base64.decode(base64String), "utf-8")); }

得到明文:中華人民共和國萬歲!

 

注意:本文示例的算法中,沒有加入對數字和及一些常用字符的加密支持,如果輸入的明文是純數字串,將不能起到加密效果。當然,你完全可以修改以上代碼,加入對Base64所有64個基本字符的支持。

最後更新:2017-04-02 04:00:25

  上一篇:go How to execute shell script in Java?
  下一篇:go 跨頁投遞和Transfer的區別