密碼與通訊
密碼技術是一門歷史悠久的技術。資訊傳播離不開加密與解密。密碼技術的用途主要源於兩個方面,加密/解密和簽名/驗籤
在資訊傳播中,通常有傳送者,接受者和竊聽者三個角色。假設傳送者Master想要寫信給接受者Ghost,可是又不想信的內容被別人看到,因此Master需要先對信加密,而Ghost收到信之後又能解密。這樣別的人即使竊聽盜取了密文也無法解密。其次,如果竊聽者並不像破譯內容,而是偽造Master發訊息給Ghost,那麼Master發訊息前就得先對機密內容進行簽名。
密碼技術
為了進行加密以及通訊,人們發明了很多公開的演算法。對稱與非對稱演算法等。常見的加密方式有RSA
, AES
等演算法。對於選擇加密演算法,一個常識就是使用公開的演算法。一方面是這些演算法經過實踐檢驗,另一方面對於破譯難度和破譯條件破譯時間都有預估。對於任何加密演算法,都是能破解的,不同在於時間上的投入。
Python密碼庫–Pycrypto
Python良好的生態,對於加密解密技術都有成熟的第三方庫。大名鼎鼎的M2Crypto
和Pycrypto
,前者非常容易使用,可是安裝卻非常頭疼,不同的系統依賴軟體的版本還有影響。後者則比較方面,直接使用pip安裝即可。
安裝
1 |
pip install pycrypto |
RSA 密碼演算法與簽名
RSA是一種公鑰密碼演算法,RSA的密文是對程式碼明文的數字的 E 次方求mod N 的結果。也就是將明文和自己做E次乘法,然後再將其結果除以 N 求餘數,餘數就是密文。RSA是一個簡潔的加密演算法。E 和 N 的組合就是公鑰(public key
)。
對於RSA的解密,即密文的數字的 D 次方求mod N 即可,即密文和自己做 D 次乘法,再對結果除以 N 求餘數即可得到明文。D 和 N 的組合就是私鑰(private key
)。
演算法的加密和解密還是很簡單的,可是公鑰和私鑰的生成演算法卻不是隨意的。本文在於使用,對生成祕鑰對的演算法就暫時忽略。使用 Pycrypto生成祕鑰對很簡單,我們分別為 Master和Ghost各生成一對屬於自己的祕鑰對。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 |
from Crypto import Random from Crypto.Hash import SHA from Crypto.Cipher import PKCS1_v1_5 as Cipher_pkcs1_v1_5 from Crypto.Signature import PKCS1_v1_5 as Signature_pkcs1_v1_5 from Crypto.PublicKey import RSA # 偽隨機數生成器 random_generator = Random.new().read # rsa演算法生成例項 rsa = RSA.generate(1024, random_generator) # master的祕鑰對的生成 private_pem = rsa.exportKey() with open('master-private.pem', 'w') as f: f.write(private_pem) public_pem = rsa.publickey().exportKey() with open('master-public.pem', 'w') as f: f.write(public_pem) # ghost的祕鑰對的生成 private_pem = rsa.exportKey() with open('master-private.pem', 'w') as f: f.write(private_pem) public_pem = rsa.publickey().exportKey() with open('master-public.pem', 'w') as f: f.write(public_pem) |
所生成的私鑰和公鑰大概是這樣的:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
-----BEGIN RSA PRIVATE KEY----- MIICXQIBAAKBgQDR4Wq9l44lw/thTPyFmSi2hII92EPh90yGXQNL5e7zJPD16j6Q tr+tIPNSQaVrnmNwrtqyEC2x4Meyp3tdCWPYUF11r2GgDgxKfUByetNG4XqJeUKk kJ6D6C706mTf/2zsm8KFoNYCYPX1GhvpiTOikHcNlHLCnOD7jbMAovJg/QIDAQAB AoGBAIz8V6+0NxC3bg4WoSs9j1PL/5F7zV3lucoogSZi9vjuP89x40Vi/a9XCxye bHi2lSYEz3P92jQ7QuqIBx6gSCi3p2HLjD5LyQeSSMbPe8KSlf52dBUaPthbBceA IJSBDrE8MKGpulTQKAJ7K3zQUOP2ZZgcKxq2jcQgS6iTENIBAkEA5r7emvwuL0Ob Maav4o1Ovb5c6OL7bSm1tuLPSKl05WuNYfE6LkqiwOOn5lPvsqhwyI1dJeywVeQz E+PvcTUR7QJBAOjZ8PxnP5T14fuhbfko4d24Ev+iiTBdq3pMXWvobEFL1ljV6aYE 2JAiMjO/Fzd1WgZhWPa3P+diyTs9mART6VECQQC0LeEXdsn9oDYEbFu1dZBB++8C 75NTJ5m8iJlB7QjZyMUq8Ln0wdUa9+n4ohxvDraa9EADSDJdr4bvBjLH3J/1AkBr 9QfO7kvDU5DXqoujVnoJ4xsj3IbAnt0vEZLKwfLW/0M84si2SU7i3IfsB+/KraT0 ilPF50ZAkEN+LNt7PjBRAkAHBBPME7IbFqxi5Cc/6R12DOMiJbOLDTS12b1J1cwG p8WMIERsvwWdJw+4NdqjbJcjzeGrXhDBi//JU902TAwy -----END RSA PRIVATE KEY----- -----BEGIN PUBLIC KEY----- MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDR4Wq9l44lw/thTPyFmSi2hII9 2EPh90yGXQNL5e7zJPD16j6Qtr+tIPNSQaVrnmNwrtqyEC2x4Meyp3tdCWPYUF11 r2GgDgxKfUByetNG4XqJeUKkkJ6D6C706mTf/2zsm8KFoNYCYPX1GhvpiTOikHcN lHLCnOD7jbMAovJg/QIDAQAB -----END PUBLIC KEY----- |
加密與解密
通常通訊的時候,傳送者使用接受者的公鑰加密,接受者使用接受者私鑰解密。
簡而言之,Master給Ghost通訊,需要加密內容,那麼Ghost會生成一個祕鑰對,Ghost的公鑰ghost-public.pem
和私鑰ghost-private.pem
。Ghost 把公鑰公開給傳送者,任何人都可以用來加密,然後Master使用ghost-public.pem
進行加密,然後把內容發給Ghost,Ghost再使用ghost-private.pem
進行解密。
加密(encrypt)
1 2 3 4 5 6 7 8 9 10 11 |
# Master使用Ghost的公鑰對內容進行rsa 加密 In [12]: message = 'hello ghost, this is a plian text' In [13]: with open('ghost-public.pem') as f: ....: key = f.read() ....: rsakey = RSA.importKey(key) ....: cipher = Cipher_pkcs1_v1_5.new(rsakey) ....: cipher_text = base64.b64encode(cipher.encrypt(message)) ....: print cipher_text ....: HYQPGB+axWCbPp7PPGNTJEAhVPW0TX5ftvUN2v40ChBLB1pS+PVM3YGT5vfcsvmPZhW8NKVSBp8FwjLUnMn6yXP1O36NaunUzyHwI+cpjlkTwZs3DfCY/32EzeuKuJABin1FHBYUMTOKtHy+eEDOuaJTnZTC7ZBkdha+J88HXSc= |
cipher_text 即 Master加密後將要傳送給Ghost的密文。
解密(decrypt)
1 2 3 4 5 6 7 8 9 10 11 |
# Ghost使用自己的私鑰對內容進行rsa 解密 In [14]: with open('ghost-private.pem') as f: ....: key = f.read() ....: rsakey = RSA.importKey(key) ....: cipher = Cipher_pkcs1_v1_5.new(rsakey) ....: text = cipher.decrypt(base64.b64decode(encrypt_text), random_generator) ....: In [15]: print text hello ghost, this is a plian text In [16]: assert text == message, 'decrypt falied' |
這樣Ghost就能看到Master所發的內容了,當然,如果Ghost想要給Master發訊息,就需要Master先把其的公鑰給Ghost,後者再使用公鑰加密,然後傳送給Master,最後Master使用自己的私鑰解密。
簽名與驗籤
當然,對於竊聽者,有時候也可以對偽造Master給Ghost傳送內容。為此出現了數字簽名。也就是Master給Ghost傳送訊息的時候,先對訊息進行簽名,表明自己的身份,並且這個簽名無法偽造。具體過程即Master使用自己的私鑰對內容簽名,然後Ghost使用Master的公鑰進行驗籤。
簽名
1 2 3 4 5 6 7 8 9 10 11 |
# Master 使用自己的公鑰對內容進行簽名 In [17]: with open('master-private.pem') as f: ....: key = f.read() ....: rsakey = RSA.importKey(key) ....: signer = Signature_pkcs1_v1_5.new(rsakey) ....: digest = SHA.new() ....: digest.update(message) ....: sign = signer.sign(digest) ....: signature = base64.b64encode(sign) In [18]: print signature jVUcAYfgF5Pwlpgrct3IlCX7KezWqNI5tD5OIFTrfCOQgfyCrOkN+/gRLsMiSDOHhFPj2LnfY4Cr5u4eG2IiH8+uSF5z4gUX48AqCQlqiOTLk2EGvyp+w+iYo2Bso1MUi424Ebkx7SnuJwLiPqNzIBLfEZLA3ov69aDArh6hQiw= |
驗籤
1 2 3 4 5 6 7 8 9 10 11 |
In [22]: with open('master-public.pem') as f: ....: key = f.read() ....: rsakey = RSA.importKey(key) ....: verifier = Signature_pkcs1_v1_5.new(rsakey) ....: digest = SHA.new() ....: # Assumes the data is base64 encoded to begin with ....: digest.update(message) ....: is_verify = signer.verify(digest, base64.b64decode(signature)) ....: print is_verify ....: True |
總結
Pycrypto提供了比較完善的加密演算法。RSA廣泛用於加密與解密,還有數字簽名通訊領域。使用Publick/Private祕鑰演算法中,加密主要用對方的公鑰,解密用自己的私鑰。簽名用自己的私鑰,驗籤用對方的公鑰。
加密解密:公鑰加密,私鑰解密
簽名驗籤:私鑰簽名,公鑰驗籤
無論是加密機密還是簽名驗籤都使用同一對祕鑰對,