欧美性猛交XXXX免费看蜜桃,成人网18免费韩国,亚洲国产成人精品区综合,欧美日韩一区二区三区高清不卡,亚洲综合一区二区精品久久

打開(kāi)APP
userphoto
未登錄

開(kāi)通VIP,暢享免費電子書(shū)等14項超值服

開(kāi)通VIP
循序漸進(jìn)學(xué)加密
作者:張京
鏈接:https://segmentfault.com/a/1190000019437132

還記得上初二的那年夏天,班里來(lái)了一個(gè)新同學(xué),他就住在我家對面的樓里,于是我們一起上學(xué)放學(xué),很快便成了最要好的朋友。我們決定發(fā)明一套神秘的溝通方式,任何人看到都不可能猜到它的真實(shí)含義。我們第一個(gè)想到的就是漢語(yǔ)拼音,但很顯然光把一個(gè)句子變成漢語(yǔ)拼音是不夠的,于是我們把26個(gè)英文字母用簡(jiǎn)譜的方式從低音到高音排起來(lái),就得到了一個(gè)簡(jiǎn)單的密碼本:

把“ 我們都是好朋友”用這個(gè)密碼本變換之后就得到了這樣的結果:

小時(shí)候玩這個(gè)游戲樂(lè )此不疲,覺(jué)得非常有趣。上大學(xué)后,有幸聽(tīng)盧開(kāi)澄教授講《計算機密碼學(xué)》,才知道原來(lái)我們小時(shí)候玩的這個(gè)游戲遠遠不能稱(chēng)之為加密。那么到底什么是加密呢?

什么是加密?

把字符串 123456經(jīng)過(guò) base64變換之后,得到了 MTIzNDU2,有人說(shuō)這是 base64加密。

把字符串 123456經(jīng)過(guò) md5變換之后,得到了 E10ADC3949BA59ABBE56E057F20F883E,有人說(shuō)這是 md5加密。

從嚴格意義上來(lái)說(shuō),不管是 base64還是 md5甚至更復雜一些的 sha256都不能稱(chēng)之為加密。

一句話(huà),沒(méi)有密鑰的算法都不能叫加密。

編碼(Encoding)是把字符集中的字符編碼為指定集合中某一對象(例如:比特模式、自然數序列、8位字節或者電脈沖),以便文本在計算機中存儲和通過(guò)通信網(wǎng)絡(luò )的傳遞的方法,常見(jiàn)的例子包括將拉丁字母表編碼成摩爾斯電碼和 ASCII。 base64只是一種編碼方式。

雜湊(Hashing)是電腦科學(xué)中一種對資料的處理方法,通過(guò)某種特定的函數/算法(稱(chēng)為雜湊函數/算法)將要檢索的項與用來(lái)檢索的索引(稱(chēng)為雜湊,或者雜湊值)關(guān)聯(lián)起來(lái),生成一種便于搜索的資料結構(稱(chēng)為雜湊表)。雜湊算法常被用來(lái)保護存在資料庫中的密碼字符串,由于雜湊算法所計算出來(lái)的雜湊值具有不可逆(無(wú)法逆向演算回原本的數值)的性質(zhì),因此可有效的保護密碼。常用的雜湊算法包括 md5sha1sha256等。

加密(Encryption)是將明文信息改變?yōu)殡y以讀取的密文內容,使之不可讀的過(guò)程。只有擁有解密方法的對象,經(jīng)由解密過(guò)程,才能將密文還原為正??勺x的內容。加密分為對稱(chēng)加密和非對稱(chēng)加密,對稱(chēng)加密的常用算法包括 DESAES等,非對稱(chēng)加密算法包括 RSA,橢圓曲線(xiàn)算法等。

在古典加密算法當中,加密算法和密鑰都是不能公開(kāi)的,一旦泄露就有被破解的風(fēng)險,我們可以用詞頻推算等方法獲知明文。 1972年美國 IBM公司研制的 DES算法( Data Encryption Standard)是人類(lèi)歷史上第一個(gè)公開(kāi)加密算法但不公開(kāi)密鑰的加密方法,后來(lái)成為美國軍方和政府機構的標準加密算法。 2002年升級成為 AES算法( AdvancedEncryption Standard),我們今天就從 AES開(kāi)始入手學(xué)習加密和解密。

準備工具

通常情況下,加解密都只需要在服務(wù)端完成就夠了,這也是網(wǎng)上大多數教程和樣例代碼的情況,但在某種特殊情況下,你需要用一種語(yǔ)言加密而用另一種語(yǔ)言解密的時(shí)候,最好有一個(gè)中立的公正的第三方結果集來(lái)驗證你的加密結果,否則一旦出錯,你都不知道是加密算法出錯了,還是解密算法出錯了,對此我們是有慘痛教訓的,特別是如果一個(gè)公司里,寫(xiě)加密的是前端,用的是 js語(yǔ)言,而寫(xiě)解密的是后端,用的是 java語(yǔ)言或者 php語(yǔ)言或者 go語(yǔ)言,則雙方更需要有這樣一個(gè)客觀(guān)公正的平臺,否則你們之間必然會(huì )陷入永無(wú)休止的互相指責的境地,前端說(shuō)自己沒(méi)有錯,是后端解密解錯了,后端說(shuō)解密沒(méi)有錯,是前端加密寫(xiě)錯了,而事實(shí)上是雙方都是菜鳥(niǎo),對密碼學(xué)一知半解,在這種情況下浪費的時(shí)間就更多。

在線(xiàn)AES加密解密就是這樣的一個(gè)工具網(wǎng)站,你可以在上面驗證你的加密結果,如果你加密得到的結果和它的結果完全一致,就說(shuō)明你的加密算法沒(méi)有問(wèn)題,否則你就去調整,直到和它的結果完全一致為止。反之亦然,如果它能從一個(gè)密文解密解出來(lái),而你的代碼解不出來(lái),那么一定是你的算法有問(wèn)題,而不可能是數據的問(wèn)題。

我們先在這個(gè)網(wǎng)站上對一個(gè)簡(jiǎn)單的字符串 123456進(jìn)行加密。

下面我們對網(wǎng)站上的所有選項逐個(gè)解釋一下:

  1. AES加密模式:這里我們選擇的是 ECBee cc block)模式。這是 AES所有模式中最簡(jiǎn)單也是最不被人推薦的一種模式,因為它的固定的明文對應的是固定的密文,很容易被破解。但是既然是練習的話(huà),就讓我們先從最簡(jiǎn)單的開(kāi)始。

  2. 填充:在這里我們選擇 pkcs標準的 pkcs7padding。

  3. 數據塊:我們選擇 128位,因為 java端解密算法目前只支持 AES128,所以我們先從 128位開(kāi)始。

  4. 密鑰:因為我們前面選擇了 128位的數據塊,所以這里我們用 128 / 8 = 16個(gè)字節來(lái)處理,我們先簡(jiǎn)單地填入 16個(gè)0,其實(shí)你也可以填寫(xiě)任意字符,比如 abcdefg1234567ab或者其它,只要是 16個(gè)字節即可。理論上來(lái)說(shuō),不是16個(gè)字節也可以用來(lái)當密鑰,優(yōu)秀的算法會(huì )自動(dòng)補齊,但是為了簡(jiǎn)單起見(jiàn),我們先填入 16個(gè) 0。

  5. 偏移量:置空。因為是 ECB模式,不需要 iv偏移量。

  6. 輸出:我們選擇 base64編碼方式。

  7. 字符集:這里因為我們只加密英文字母和阿拉伯數字,所以選擇 utf-8和 gb2312都是一樣的。

好了,現在我們知道按照以上選項設置好之后的代碼如果加密 123456的話(huà),應該輸出 DoxDHHOjfol/2WxpaXAXgQ==,如果不是這個(gè)結果,那就是加密端的問(wèn)題。

AES-ECB

AES-ECB的Javascript加密

為了完成 AES加密,我們并不需要自己手寫(xiě)一個(gè) AES算法,不需要去重復造輪子。但如何選擇 js的加密庫是個(gè)很有意思的挑戰。我們嘗試了很多方法,一開(kāi)始我們嘗試了aes-js這個(gè)庫,但它不支持 RSA算法,后來(lái)我們看到Web Crypto API這種瀏覽器自帶的加密庫,原生支持 AES和 RSA,但它的 RSA實(shí)現和 Java不兼容,最終我們還是選擇了Forge這個(gè)庫,它天生支持 AES的各種子集,并且它的 RSA也能和 Java完美配合。

使用 forge編寫(xiě)的 js代碼實(shí)現 AES-ECB加密的代碼就是下面這些:

const cipher = forge.cipher.createCipher('AES-ECB''這里是16字節密鑰');
cipher.start();
cipher.update(forge.util.createBuffer('這里是明文'));
cipher.finish();
const result = forge.util.encode64(cipher.output.getBytes())

forge的 AES缺省就是 pkcs7padding,所以不用特別設置。運行它之后你就會(huì )得到正確的加密結果。

AES-ECB的Java解密

接下來(lái)我們看看Java端的解密代碼該如何寫(xiě):

try {
    Cipher cipher = Cipher.getInstance('AES/ECB/PKCS5Padding');
    cipher.init(Cipher.DECRYPT_MODE, new SecretKeySpec('這里是16字節密鑰'.getBytes(), 'AES'));
    String plaintext = new String(cipher.doFinal(Base64.getDecoder().decode('這里是明文'.getBytes())), 'UTF-8');
    System.out.println(plaintext);
catch (Exception e) {
    System.out.println('解密出錯:' + e.toString());
}

注意這里我們用到的是 PKCS5Padding,上面加密的時(shí)候不是用的是 pkcs7padding嗎?怎么這里變成 5了呢?

我們先來(lái)了解一下什么是 pkcs。 pkcs的全稱(chēng)是 Public Key Cryptography Standards公鑰加密標準),這是 RSA實(shí)驗室制定的一系列的公鑰密碼編譯標準,比較著(zhù)名的有 pkcs1pkcs5pkcs7pkcs8這四個(gè),它們分別管理的是不同的內容。在這里我們只是用它來(lái)填充,所以我們只關(guān)注 pkcs5和 pkcs7就夠了。那么 pkcs5和 pkcs7有什么區別呢?其實(shí)在填充方面它們兩個(gè)的算法是一樣的, pkcs5是 pkcs7的一個(gè)子集,區別在于 pkcs5是 8字節固定的,而 pkcs7可以是 1到 255之間的任意字節。但用在 AES算法上,因為 AES標準規定塊大小必須是 16字節或者 24字節或者 32字節,不可能用 pkcs5的 8字節,所以 AES算法只能用 pkcs7填充。但是由于 java早期工程師犯的一個(gè)命名上的錯誤,他們把 AES填充算法的名稱(chēng)設定為 pkcs5,而實(shí)際實(shí)現中實(shí)現的是 pkcs7,所以我們在 java端開(kāi)發(fā)解密的時(shí)候需要使用 pkcs5。

AES-CBC

談完了不安全的 AES-ECB,我們來(lái)做一下相對安全一些的 AES-CBC模式。

AES-CBC的Javascript加密

直接上代碼:

const cipher = forge.cipher.createCipher('AES-CBC''這里是16字節密鑰');
cipher.start({ iv: '這里是16字節偏移量' });
cipher.update(forge.util.createBuffer('這里是明文'));
cipher.finish();
const result = forge.util.encode64(cipher.output.getBytes());

跟上面的 AES-ECB差不多,唯一區別只是在 start函數里定義了一個(gè) iv。

AES-CBC的Java解密

下面是 Java代碼:

try {
    Cipher cipher = Cipher.getInstance('AES/CBC/PKCS5Padding');
    cipher.init(Cipher.DECRYPT_MODE, new SecretKeySpec('這里是16字節密鑰'.getBytes(), 'AES'), new IvParameterSpec('這里是16字節偏移量'.getBytes()));
    String plaintext = new String(cipher.doFinal(Base64.getDecoder().decode('這里是明文'.getBytes())), 'UTF-8');
    System.out.println(plaintext);
catch (Exception e) {
    System.out.println('解密出錯:' + e.toString());
}

也是同樣,跟上面用 AES-ECB時(shí)的模式幾乎一模一樣,只是增加了一個(gè) IvParameterSpec,用來(lái)生成 iv,在 cipher.init里面增加了一個(gè) iv參數,除此之外完全相同,就這樣我們就已經(jīng)實(shí)現了一個(gè)簡(jiǎn)單的 CBC模式。

RSA

但是以上兩種做法都明顯是非常不安全的,因為我們把加密用的密鑰和 iv參數都直接暴露在了前端,為此我們需要一種更加安全的加密方法—— RSA。因為 RSA是非對稱(chēng)加密,即使我們把加密用的公鑰完全暴露在前端也不必擔心,別人即使截獲了我們的密文,但因為他們沒(méi)有解密密鑰,是無(wú)法解出我們的明文的。

生成密鑰對

要用 RSA加密,首先我們需要生成一個(gè)公鑰和一個(gè)私鑰,我們可以直接執行命令 ssh-keygen。它會(huì )問(wèn)我們密鑰文件保存的文件夾,注意一定要單獨找一個(gè)文件夾存放,不要放在缺省文件夾下,否則你日常使用的 ssh公鑰和私鑰就都被覆蓋了。

得到公鑰文件之后,由于這個(gè)公鑰文件是 rfc4716格式的,而我們的 forge庫要求一個(gè) pkcs1格式的公鑰,所以這里我們需要把它轉換成 pem格式(也就是 pkcs1格式):

ssh-keygen -f 公鑰文件名 -m pem -e

RSA的Javascript加密

得到 pem格式的公鑰之后,我們來(lái)看一下 js的代碼:

forge.util.encode64(forge.pki.publicKeyFromPem('-----BEGIN RSA PUBLIC KEY-----MIIBCfdsafasfasfafsdaafdsaAB-----END RSA PUBLIC KEY-----').encrypt('這里是明文''RSA-OAEP', { md: forge.md.sha256.create(), mgf1: { md: forge.md.sha1.create() } });

一句話(huà)就完成整個(gè)加密過(guò)程了,這就是 forge的強大之處。

RSA的Java解密

接下來(lái)我們看解密。

對于私鑰,因為 Java只支持 PKCS8,而我們用 ssh-keygen生成的私鑰是 pkcs1的,所以還需要用以下命令把 pkcs1的私鑰轉換為 pkcs8的私鑰:

openssl pkcs8 -topk8 -inform PEM -outform PEM -nocrypt -in 私鑰文件名 -out 導出文件名

得到 pkcs8格式的私鑰之后,我們把這個(gè)文件的頭和尾去掉,然后放入以下 Java代碼:

try {
    Cipher cipher = Cipher.getInstance('RSA/ECB/OAEPWithSHA-256AndMGF1Padding');
    cipher.init(Cipher.DECRYPT_MODE, KeyFactory.getInstance('RSA').generatePrivate(new PKCS8EncodedKeySpec(Base64.getDecoder().decode('這里是私鑰'))));
    String plaintext = new String(cipher.doFinal(Base64.getDecoder().decode('這里是密文'.getBytes())), 'UTF-8');
    System.out.println(plaintext);
catch (Exception e) {
    System.out.println('解密出錯:' + e.toString());
}

和上面的 AES解密類(lèi)似,只是增加了 KeyFactory讀取 PKCS8格式私鑰的部分,這樣我們就完成了 Java端的 RSA解密。

以上我們用最簡(jiǎn)單的方式實(shí)現了 js端加密, java端解密的過(guò)程,感興趣的朋友可以在這里下載完整的代碼親自驗證一下:

https://github.com/fengerzh/encdec


●編號891,輸入編號直達本文

●輸入m獲取文章目錄

本站僅提供存儲服務(wù),所有內容均由用戶(hù)發(fā)布,如發(fā)現有害或侵權內容,請點(diǎn)擊舉報。
打開(kāi)APP,閱讀全文并永久保存 查看更多類(lèi)似文章
猜你喜歡
類(lèi)似文章
Java使用Cipher類(lèi)實(shí)現加密,包括DES,DES3,AES和RSA加密
python筆記43-加解密AES/CBC/pkcs7padding
網(wǎng)絡(luò )安全加密——DES、AES、RSA、Base64、MD5加密原理介紹,代碼實(shí)現
密碼類(lèi)庫Crypto++? Library 5.1的研究與應用
JAVA中怎么搞定DES算法 完整頁(yè)
程序員必須知道的加密、解密和簽名算法
更多類(lèi)似文章 >>
生活服務(wù)
分享 收藏 導長(cháng)圖 關(guān)注 下載文章
綁定賬號成功
后續可登錄賬號暢享VIP特權!
如果VIP功能使用有故障,
可點(diǎn)擊這里聯(lián)系客服!

聯(lián)系客服

欧美性猛交XXXX免费看蜜桃,成人网18免费韩国,亚洲国产成人精品区综合,欧美日韩一区二区三区高清不卡,亚洲综合一区二区精品久久