python中的RSA加密與解密


什么是RSA:

RSA公開密鑰密碼體制。所謂的公開密鑰密碼體制就是使用不同的加密密鑰與解密密鑰,是一種“由已知加密密鑰推導出解密密鑰在計算上是不可行的”密碼體制。

在公開密鑰密碼體制中,加密密鑰(即公開密鑰)PK是公開信息,而解密密鑰(即秘密密鑰)SK是需要保密的。加密算法E和解密算法D也都是公開的。雖然解密密鑰SK是由公開密鑰PK決定的,但卻不能根據PK計算出SK。

正是基於這種理論,1978年出現了著名的RSA算法,它通常是先生成一對RSA 密鑰,其中之一是保密密鑰,由用戶保存;另一個為公開密鑰,可對外公開,甚至可在網絡服務器中注冊。為提高保密強度,RSA密鑰至少為500位長,一般推薦使用1024位。這就使加密的計算量很大。為減少計算量,在傳送信息時,常采用傳統加密方法與公開密鑰加密方法相結合的方式,即信息采用改進的DES或IDEA密鑰加密,然后使用RSA密鑰加密對話密鑰和信息摘要。對方收到信息后,用不同的密鑰解密並可核對信息摘要。

RSA算法是第一個能同時用於加密和數字簽名的算法,也易於理解和操作。RSA是被研究得最廣泛的公鑰算法,從提出到現今的三十多年里,經歷了各種攻擊的考驗,逐漸為人們接受,截止2017年被普遍認為是最優秀的公鑰方案之一。
SET(Secure Electronic Transaction)協議中要求CA采用2048bits長的密鑰,其他實體使用1024比特的密鑰。RSA密鑰長度隨着保密級別提高,增加很快。下表列出了對同一安全級別所對應的密鑰長度。

python實現對RSA的加密和解密

Python密碼庫--Pycrypto
Python良好的生態,對於加密解密技術都有成熟的第三方庫。大名鼎鼎的M2Crypto和Pycrypto,前者非常容易使用,可是安裝卻非常頭疼,不同的系統依賴軟件的版本還有影響。后者則比較方面,直接使用pip安裝即可。

密碼技術
為了進行加密以及通信,人們發明了很多公開的算法。對稱與非對稱算法等。常見的加密方式有RSA, AES等算法。對於選擇加密算法,一個常識就是使用公開的算法。一方面是這些算法經過實踐檢驗,另一方面對於破譯難度和破譯條件破譯時間都有預估。對於任何加密算法,都是能破解的,不同在於時間上的投入。

Python密碼庫--Pycrypto
Python良好的生態,對於加密解密技術都有成熟的第三方庫。大名鼎鼎的M2Crypto和Pycrypto,前者非常容易使用,可是安裝卻非常頭疼,不同的系統依賴軟件的版本還有影響。后者則比較方面,直接使用pip安裝即可。

安裝

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生成秘鑰對很簡單,我們分別為 Server和Client各生成一對屬於自己的秘鑰對。

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)
 
# Server的秘鑰對的生成
private_pem = rsa.exportKey()
with open("server-private.pem", "w") as f:
  f.write(private_pem)
 
public_pem = rsa.publickey().exportKey()
with open("server-public.pem", "w") as f:
  f.write(public_pem)
 
# Client的秘鑰對的生成
private_pem = rsa.exportKey()
with open("client-private.pem", "w") as f:
  f.write(private_pem)
 
public_pem = rsa.publickey().exportKey()
with open("client-public.pem", "w") as f:
  f.write(public_pem)

  

所生成的私鑰和公鑰大概是這樣的:

-----BEGIN RSA PRIVATE KEY-----
MIICXQIBAAKBgQC26X6A0WCWiVxdxq3jtm42yDdGbf+99v2zyi0UMVGZfowlnkcW
eMvpz8NBm2UVlrjZpnFr8wFkdHyjFFkq/ilclH3AN4+Xw8Ap7CGJ2jVMyS5h9RRB
Uyf3F4D5Og8789Ywh9HXYyvD/6J62EtbbkhGPxg3aa8n2kfKZ9N6Q7DqrwIDAQAB
AoGBAJn5qu1D1FxE24Vxl7ZGPzdMigN227+NaPptak9CSR++gLm2KL+JBpcXt5XF
+20WCRvnWjl2QijPSpB5s6pWdHezEa1cl6WrqB1jDJd1U99WNCL5+nfEVD9IF+uE
ig0pnj+wAT5fu78Z0UjxD9307f9S7BLC8ou3dWVkIqob6W95AkEAuPGTNlTkquu/
wBJTb4/+/2ZCf7Ci9qvsN3+RcrzFkKa3uTtBOa6Xk2R61zBkucUgY6cQHPbxhFLN
TVmXdbwxTQJBAP0wGenVOq4dCPdz3NhyghkKT6SL2w/SgbrROiJ1mG9MoBq58/0g
k85I91R7nuvOYTKTUkhWdPYITpDarmPJzesCQGRBmOMgHCHH0NfHV3Gn5rz+61eb
IoyD4Hapceh4CsWCiyAfzhj9229sTecvdbr68Lb0zphVCdIIrQCca63IShUCQGYI
e3jzmHlQdCudArQruWgz8pKiVf7TW7qY1O/MKkk4PRFoPP6WoVoxp5LhWtM20Y7b
Nf628N2xzU+tAThvvE8CQQCI1C7GO3I5EMfqPbTSq2oZq8thvGlyFyI7SNNuvAHj
hj2+0217B9CcTZqloYln01CNDVuaoUgEvFSw1OdRB1tC
-----END RSA PRIVATE KEY-----

-----BEGIN PUBLIC KEY-----
MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQC26X6A0WCWiVxdxq3jtm42yDdG
bf+99v2zyi0UMVGZfowlnkcWeMvpz8NBm2UVlrjZpnFr8wFkdHyjFFkq/ilclH3A
N4+Xw8Ap7CGJ2jVMyS5h9RRBUyf3F4D5Og8789Ywh9HXYyvD/6J62EtbbkhGPxg3
aa8n2kfKZ9N6Q7DqrwIDAQAB
-----END PUBLIC KEY-----

  

加密與解密
通常通信的時候,發送者使用接受者的公鑰加密,接受者使用接受者私鑰解密。

簡而言之,Server給Client通信,需要加密內容,那么Client會生成一個秘鑰對,Client的公鑰client-public.pem和私鑰client-private.pem 。Client把公鑰公開給發送者,任何人都可以用來加密,然后Server使用client-public.pem進行加密,然后把內容發給Client,Client再使用私鑰client-private.pem進行解密。

1.加密(encrypt)

# Server使用Client的公鑰對內容進行rsa 加密
 
message = "hello client, this is a message"
with open("client-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.encode('utf-8')))
    print(cipher_text.decode('utf-8'))
 
#加密結果: 
HYQPGB+axWCbPp7PPGNTJEAhVPW0TX5ftvUN2v40ChBLB1pS+PVM3YGT5vfcsvmPZhW8NKVSBp8FwjLUnMn6yXP1O36NaunUzyHwI+cpjlkTwZs3DfCY/32EzeuKuJABin1FHBYUMTOKtHy+eEDOuaJTnZTC7ZBkdha+J88HXSc=

cipher_text 即 Master加密后將要發送給Client的密文。

2.解密(decrypt)

# Client使用自己的私鑰對內容進行rsa 解密 
 
with open("client-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)
    print(text.decode('utf-8'))

#解密結果:
hello client, this is a message

 這樣Client就能看到Server所發的內容了,當然,如果Client想要給Server發消息,就需要Server先把其的公鑰給Client,后者再使用公鑰加密,然后發送給Server,最后Server使用自己的私鑰解密。

簽名與驗簽
當然,對於竊聽者,有時候也可以對偽造Server給Client發送內容。為此出現了數字簽名。也就是Server給Client發送消息的時候,先對消息進行簽名,表明自己的身份,並且這個簽名無法偽造。具體過程即Server使用自己的私鑰對內容簽名,然后Client使用Server的公鑰進行驗簽。

簽名

# Server使用自己的私鑰對內容進行簽名

with open("server-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)
    print signature

#簽名結果:
jVUcAYfgF5Pwlpgrct3IlCX7KezWqNI5tD5OIFTrfCOQgfyCrOkN+/gRLsMiSDOHhFPj2LnfY4Cr5u4eG2IiH8+uSF5z4gUX48AqCQlqiOTLk2EGvyp+w+iYo2Bso1MUi424Ebkx7SnuJwLiPqNzIBLfEZLA3ov69aDArh6hQiw=

  

驗簽

#Client使用Server的公鑰對內容進行驗簽

with open("server-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秘鑰算法中,加密主要用對方的公鑰,解密用自己的私鑰。簽名用自己的私鑰,驗簽用對方的公鑰。

  • 加密解密:公鑰加密,私鑰解密
  • 簽名驗簽:私鑰簽名,公鑰驗簽

無論是加密解密還是簽名驗簽都使用同一對秘鑰對。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM