圖解密碼技術筆記
v0.1 2019.3.16 Sherlock init
v0.2 2019.4.14 Sherlock add RSA, 認證,簽名,祕鑰,隨機數
這篇文章是《圖解密碼技術》的讀書筆記。希望沒有密碼技術背景的人或是沒有讀過這本
書的人通過這篇文章迅速建立起密碼技術的基本概念。
各種密碼技術就是用來保密,我們從具體的場景看起, 然後引出各種應對的手段。
- 監聽
+-----+ +-----+
| A |------+------> | B |
+-----+ | +-----+
v
+-----+
| C |
+-----+
比如A發送信息給B,可能有C在鏈路上監聽。應對的方法就是對要發送的信息加密, 比如我
們可以把發送的信息碼字都加上1,B減去1就得到A原來發送的信息。這裏就引入了密碼學
上的幾個基本概念, 這裏對發送的信息加密就是原來的信息和額外的信息做運算,我們把
額外的信息叫做祕鑰,把所做的運算叫做加解密算法。祕鑰一般是不公開的,對於加解密
算法,有公開的算法,也有商業公司自己保密的算法,不過公開的算法的安全性要大大高於
私有的算法,現在一般的做法也是密碼相關的行業組織會公開徵集特定用途的算法,大家
通過競爭選出最好的算法。
可以看到上面的例子中,A用來加密的祕鑰和B用來解密的祕鑰是一樣的。這種加解密的
方法叫對稱加解密。實際使用中,祕鑰和加解密算法是很複雜的,C即使聽到了加密信息,
沒有祕鑰也解不出A發出的信息。
但是這樣的加解密方法有一個要解決的問題: 怎麼把一樣的祕鑰分發給A和B(前面我們已經
提到算法是公開的)。A直接傳給B顯然是不靠譜的,因爲C完全可以聽到。引入第三方,也不
靠譜,只要傳輸,C就可以聽到祕鑰。
爲了應對是上面的問題,人們發明了非對稱加解密。也就是說A用來加密的祕鑰和B用來解密
的祕鑰不是同一個。對稱加解密使用的方法就是: 把加密祕鑰發給對方,請對方用這個加密
祕鑰加密信息, 解密祕鑰自己留着,用來解密信息。下面的圖是基本流程:
+-----+ +-----+
| A |--------------------->| B |
+-----+ +-----+
+-------+
|pub key| -->
+-----+ +-------+ +-----+
| A |--------------------->| B |
+-----+ +-----+ +-------+ +---+
|message| + |key| --+
+--------------+ +-------+ +---+ |
<--|crypto message| <-------------------------------+
+-----+ +--------------+ +-----+
| A |--------------------->| B |
+-----+ +-----+
+--------+ +--------------+
|priv key| + |crypto message|
+--------+ | +--------------+
v
+-----------------+
|message sent by B|
+-----------------+
可以看到C即使聽到pub key也沒有用,因爲pub key是用來給發給A的信息加密的。上面又
有幾個新的概念,公鑰是可以公開的祕鑰,私鑰必須保密。
我們平時用的ssh用的就是非對稱加密, 和上面的模型是可以對上的。非對稱加密解決了
對稱加密裏對稱祕鑰分發的問題,我們可以使用非對稱加解密代替對稱加解密。當然,我們
也可以一開始採用非對稱加解密解決對稱加解密祕鑰分發的問題,然後就可以使用對稱
加解密了。
可以看到,非對稱加解密的缺點是C可以拿到給A發信息用的加密祕鑰。這樣C可以把自己的
公鑰發給B,誘導B用C的公鑰加密信息,這樣C監聽B發給A的信息,就可以用C自己的私鑰
解密信息。爲了解決這個問題,就需要B可以確認他收到的是A的公鑰。(to do: how to do)
非對稱加解密還有一個缺點,就是祕鑰生成和加解密都需要很大的算裏。所以很適合做專門
的硬件加速器去offload cpu資源。
這裏可以看下RSA算法步驟,RSA算法是經典的非對稱加解密算法。我們這裏只簡單羅列RSA
算法的步驟,因爲他表現的很簡單有趣。這裏E和N爲加密祕鑰,D和N爲解密祕鑰。加密和
解密做的運算就是:
E D
密文 = 明文 mod N 明文 = 密文 mod N
是不是很簡單? 上面的密文和明文都是數字,加解密完全是一個求冪然後取模運算。但是
E, D是一個很大的數,大到用二進制表示,需要512bit,1024bit,2048bit,4096bit…
不同祕鑰長度,當然密碼的強度是不一樣的。
E, D, N生成的算法是:
-
找兩個很大的素數p, q
-
N = p × q
-
L = 最小公倍數(p - 1, q - 1)
-
E爲和L互質的數 —> (E, N)是加密祕鑰,公鑰
-
(E × D) mod L = 1, 求出D —> (D, N)是解密祕鑰,私鑰
第2,5步的逆運算在數學上很困難,這個是RSA算法保密的根本。
- 篡改
+-----+ +-----+
| A |------+ +----------->| B |
+-----+ | | +-----+
v |
+----++
| C |
+-----+
相比較上面的被動攻擊,C還可以篡改A發給B的數據,然後發給B(其實上面也提到了主動
攻擊, 我們先從簡單的說起)。爲了應對這樣的攻擊,B需要有辦法驗證收到信息的完整性。
一般用單向散列得到A發出信息的hash碼,然後A把這個hash碼也發給B,B對收到的信息做
同樣的單向散列,把得到的hash碼和收到的hash作對比,從而驗證信息的完整性。
這要的算法有SHA3, MD5等。其實,一般我們發送大文件的時候,用md5sum算文件hash碼,
然後在對接收到的文件做校驗,就是一樣的道理。
單向散列算法需要保證的就是防止碰撞發生,簡單說就是不同數據得到的hash碼要不一樣。
單向散列只是單純的驗證數據的完整性,並不能確認數據就是A發出的。C可以把A發給B的
數據和hash值都截獲,修改數據,然後對修改後的數據做下單向散列,然後把修改的數據
和新生成的hash值發給B。
- 認證
+-----+ +-----+
| A |--------------------> | B |
+-----+ +------------> +-----+
|
+--+--+
| C |
+-----+
如上,C也做下單向散列,然後把正確的hash碼發送給B。B需要有辦法確認他收到信息是A
發給他的,而不是別人僞造的。這裏的問題和上面非對稱加解密裏C把自己的公鑰發給B是
一樣的問題。
當A,B有共享祕鑰的時候,解決這個問題的方法是,信息和共享祕鑰一起做單向散列。
但是非對稱加密公鑰配送的問題還是沒有解決
對上面認證(也叫消息認證碼)的攻擊有: 重放攻擊。有了消息認證碼之後C無法篡改A發給B
的信息,但是C可以截獲A發給B的信息,在A發給B信息後,再次發同樣的信息給B。比如,A
給B的信息是請求B向A轉一筆錢,那麼B接收的C的信息後將會再次轉錢給A。不過,應對這種
重放攻擊,A只要在發送的信息加上編號或者是時間戳就好了。
消息認證碼無法解決的問題: 對第三方證明,防止否認。對第三方證明比較好理解, 共享
祕鑰存在於A和B,第三方的機構無法證明信息是A向B發的。防止否認的意思是, B也無法證
明A確實向B發了一條消息。其中的關鍵是消息認證碼用的是共享祕鑰, 比如A向B發了一個信
息說向B借了10萬元錢(相當於A給B寫了一個欠條),這個信息用消息認證碼加密, 當B拿着這
個消息向A去索要錢的時候,A完全可以否認自己發過這個消息,因爲B也有A一樣的祕鑰,完
全是可以自己製造這個消息出來的。爲了解決A否認消息是他發出的,就要引入數字簽名,
就是給自己發出的信息簽上自己的名字。
- 簽名
如何給自己發出的消息上標記上自己無法否認的信息作爲自己的簽名?簽名可以用非對稱
加解密的相反運算實現: 用私鑰加密信息給信息簽名,用公鑰解密加密的信息做驗證。
因爲私鑰只有自己知道,而且用和私鑰不對應的公鑰算出來的數據不是被加密數據(算出
的數據接近隨機值), 所以可以用這樣的辦法實現數字簽名。
可以看出來,簽名和簽名驗證的計算量是很大的,比如用RSA算法做簽名,相當於對數據做
乘冪運算再做取模運算。當然,簽名可以對數據的單向散列值做, 不過即使這樣計算量也大。
可以看出簽名和非對稱加解密是可以用一個硬件加速器來做的。這裏先做單向散列再做簽名
是多個加解密算法級聯使用的一個例子,在實際情況中這種情況很多,這對軟件加解密框架
的設計提出了比較高的要求,關於這部分的設計實現可以參考Linux內核crypto子系統的
設計實現,同時該子系統也是c語言面向對象編程的一個很好的參考實例。
有很多針對簽名的攻擊, 其中利用簽名解密信息的攻擊很有意思。簽名的本質是用私鑰做
運算, 所做的運算如果數據是正好是加密數據,那麼相當於做解密運算。攻擊者如果手上
有一個別人發給簽名者的加密信息(簽名者對應的公鑰加過密), 攻擊者請求籤名者給這段
信息簽名, 如果簽名,實際上簽名者就被攻擊者誘導做了解密運算。不過,一般情況下簽名
者也不會對一段來歷不明的信息做簽名。
簽名還有一個注意的地方是撤銷簽名,類比一下就是撕毀借條。但是數字簽名無法撕毀,
辦法就是再籤一個說之前的簽名無效了。
- 公鑰證書
上面的各種辦法其實還是沒有辦法解決非對稱加解密裏公鑰配送的問題。
引入第三方機構辦法公鑰證書。
- 祕鑰
上面各種加解密算法裏多次提到祕鑰。這裏的祕鑰其實就是一個巨大的數字。除了公鑰
祕鑰必須嚴格保密,因爲加解密算法是公開的,祕鑰的價值非常巨大,他的價值和明文是
相等的。
需要注意的是對稱加解密裏的祕鑰配送還可以用祕鑰配送去實現,比較經典的有DH算法。
直觀的看,就是A和B預定幾個數值(明文傳送,C是可見的),然後用公共的算法得到一個
相同的數值, C即使知道預定的值也無法計算出A和B的共享祕鑰。
DH算法的一般步驟是:
祕鑰管理裏有祕鑰作廢比較有意思,祕鑰作廢之後要徹底銷燬。這樣做的原因是防止之前
的信息被解密,比如C長期截獲並保存A和B之間的信息,如果C的到廢棄的祕鑰,他就可以
把之前的信息解密。
- 隨機數
有些祕鑰使用的是隨機數,所以隨機數是否是真隨機這一點很關鍵。另外,並不是所有使用
隨機數的地方都需要真隨機數,但是加解密中使用的隨機數一定要用真隨機。單純軟件生
成的隨機數一定是僞隨機數。
和加解密類似,隨機數的生成包括算法和種子,隨機數生成算法類比加解密算法,是公開
的,種子類似祕鑰,一定是私密的而且必須是真隨機的。因爲純軟件的種子一定不是隨機
的,所以上面提到單純軟件生成的隨機數一定是僞隨機數。
Intel上硬件上已經提供了真隨機數生成的指令。
- PGP
- SSL/TSL
- 區塊鏈
- 硬件
(未完)