對稱加密和Base64編碼
http://blog.7rule.com/2018/03/09/crypto-base64.html
緣起
前陣子在用golang重構一段php邏輯,那段代碼中用到了mcrypt_encrypt和base64_encode方法,大致如下:
看起來挺簡單的php調用,使用golang重構時發現沒那麼簡單。
無論是mcrypt_encrypt還是base64_encode,在golang中都無法很簡單的用一個現成的方法調用,且看官方包文檔時很多概念都搞不懂。
網上查看了一些資料,感覺理解的還不是很清楚,最終我從這兩個方法的基本概念入手,簡單學習了下,感覺清晰了很多,完成了重構。
本篇文章就是把這次學到的關於對稱加密和base64編碼的基本概念在這裡做個簡單的講解,讓大家能從基本原理中理解這兩個方法的正確使用方式。
對稱加密
簡單說:使用相同密鑰進行加密解密叫做對稱加密。
帶著的問題
加密和解密操作是如何實現的?
DES、AES是什麼意思?AES-128、AES-256又是什麼東西?如何選擇?
加密模式是什麼?多種加密模式應當如何選擇?
初始向量是什麼?
加密和解密的運算本質(XOR)
現代加解密運算都是計算機運算,也就是0和1的位運算,對稱加密中,最重要的當屬XOR運算。
XOR也叫做異或運算,規則如下:
如果是比特序列之間的XOR運算,只需要對其中每個對應的比特進行XOR運算即可,例:
這裡就有了個有趣的地方:
即:
如果A是明文,B是密鑰,那麼 即實現了加密, 即實現了解密。
分組加密的概念
這裡用一個最簡單的示例來說明基本概念。
上面大家看到了,加密需要進行運算,這就需要運算雙方的長度相同,也就是明文和密鑰的長度是相同的。
但是,實際通常要加密的明文長度很長,密鑰通常是相對固定的,那麼如何做呢?
這就需要把明文按照密鑰的長度進行分組,即分成多個,然後對每個分別和密鑰進行迭代的運算,形成最終的密文,其中迭代的方式就稱為。
上面描述的就是最簡單的分組加密的概念,實際中的演算法會複雜很多,這些等。
階段小結
通過上面的解釋,相信大家已經了解了對稱加密的基本原理。
本質上就是一種的對稱加密演算法,但這種演算法現在已經被認為是不安全的,所以後來又出現了,它對DES具備向下兼容性。
則是為了取代DES而生的,它通過公開精選,最終選定了一個叫做的分組密碼演算法。上面提到的,即是指密鑰的長度。
模式
模式指的就是分組加密的迭代方式,主要有如下幾種:
ECB
CBC
CFB
OFB
CTR
先給個結論:
絕對不要使用 ,這個模式是非常不安全的。
現在使用最多的,就是,這也是中在使用的模式。
ECB
ECB模式將明文分組加密之後的結果直接作為密文結果,如下圖:
這個模式最大的問題,就是相同的明文分組會轉換為相同的密文分組。因為只要觀察一下密文,就可以知道明文中存在怎樣的重複組合,並可以藉此攻擊。
舉個例子,假如A要向B轉賬100元,數據由3個分組構成:
付款人A的賬號
收款人B的賬號
轉賬金額
ECB加密後的密文簡單示例如下:
59 7D DE CC
DF 49 2A 1C
CD AF D5 9E
假如攻擊者將1和2的內容進行調換,則變為:
DF 49 2A 1C
59 7D DE CC
CD AF D5 9E
這樣一來,就變為了B向A轉賬100元。
ECB模式的一大漏洞,就是攻擊者可以在不破解密文的情況下操縱明文。
CBC
CBC的全稱是(密文分組鏈接),正如其名,密文分組會像鏈條一樣相互連接起來。
CBC模式首先將明文分組與前一個密文分組進行XOR運算,然後再進行加密,就這樣一直加密完所有分組。
這裡出現了這個概念:當加密第一個明文分組時,由於不存在「前一個密文分組」,因此就需要一個長度為一個分組的比特序列來代替,這個比特序列就叫做初始化向量(IV),ECB中不需要。
CBC模式現在是使用最廣泛的對稱加密模式,TLS協議(https中使用)中即使用此模式。
使用golang重構php的mcrypt_encode
我們這裡使用AES的CBC模式,這裡會涉及到3個重要的值:、、。
密鑰key
key的長度,可選,這是為了對應。
的複雜度最高,所以我們最好選擇這個,這樣就需要,有個最好的辦法就是對自定義的key做md5得到的字元串值即可。
初始化向量iv
iv的長度,需要和分組大小相同,AES的分組大小是,即。我們這裡可以對自定義的iv做md5後得到的字元串值取前16個位元組即可。
明文data
明文會被自動分組,為了能讓每個分組的長度固定,就需要先對明文進行數據填充,再進行分組加密操作。這裡我們使用最常用的一種數據分組填充方式
AES代碼:https://github.com/goinbox/crypto/blob/master/aes.go
PKCS5Padding代碼:https://github.com/goinbox/crypto/blob/master/padding.go
Demo
是不是發現原本php一個方法做的事情,到了golang中需要做這麼多的事。
很多高級語言都做了很多的封裝,讓大家不必了解過多的細節即可使用,但同時我們也失去了學習更多東西的機會。
現在大家可以再回過頭看看之前自己用過的對稱加密方法,對其中的參數是不是就理解了,再想想看是否之前有使用不當的地方,筆者就發現了之前一個重要的業務中使用了ECB模式,趕緊改了,呵呵。
Base64編碼
再來說下Base64編碼。
上面加密後的密文,通常會包含很多不可見字元,這樣通常會對加密後的結果做一次編碼的工作,這樣就可以在各處使用了。
帶著的問題
這裡我遇到的一個問題,就是為什麼要用Base64進行編碼,我看還有Base32啊,為什麼不用那個呢?
有了前面的經驗,我認識到還是要去了解下Base64編碼和Base32編碼的本質是什麼,才能判斷。
詳解
Base64編碼使用64個字元來對任意數據進行編碼,同理Base32編碼會使用32個字元對任意數據進行編碼。
Base64編碼的64個字元為:
編碼的過程,先將數據轉成二進位形式,然後每計算十進位值,再在上面的對應表中轉換為對應字元,最終得到一個字元串,示例:
最後的那些0,是需要進行補齊填充的bit。另外,標準Base64會使用來替代,這是因為不在索引表中,可以作為結束符存在。
小結
使用Base64編碼後的數據長度會增加1/3,Base32因為要使用更少的字元,所以編碼後的長度要增加3/5。
有此可見,Base64在某種程度上來說兼顧了字符集大小和編碼後數據長度,所以它的應用場景也更加廣泛。
TAG:7rule |