別怕,咱們的聊天消息,沒人能偷看

別怕,咱們的聊天消息,沒人能偷看
別怕,咱們的聊天消息,沒人能偷看html

攝影:產品經理
炸魚剩下的油,我跟產品經理吃了一週
因爲衆所周知的緣由,國內的各大郵箱、聊天 App 都會監控你接收和發送的信息。若是你須要傳遞一些絕密內容,顯然你須要對你的內容進行加密。算法

可是加密的密碼你怎麼告訴別人呢?打電話說嗎?若是是一對一的溝通,這種方式確實沒有問題。安全

但若是如今是單向聯繫,多我的給你發信息。你想讓全部聯繫你的人,都把信息加密之後才能發給你,而且只有你能解密怎麼辦?若是隻使用一個密碼,那麼 A 發給你的消息可能會被 B 偷看。難道你須要和每一個人都設置一個各自的專用密碼?微信

爲了解決這個問題,咱們就可使用非對稱加密。非對稱加密的加密密鑰與解密密鑰是分開的。加密密鑰能夠公開,全部人都能看到。全部人都能使用同一個加密密鑰加密信息發送給你。但只有你本身手上的解密密鑰能把這個密文解開。ide

RSA 算法就是一種非對稱加密算法。工具

這種算法很是可靠,密鑰越長,它就越難破解。根據已經披露的文獻,目前被破解的最長RSA密鑰是768個二進制位。也就是說,長度超過768位的密鑰,還沒法破解(至少沒人公開宣佈)。所以能夠認爲,1024位的RSA密鑰基本安全,2048位的密鑰極其安全。——《RSA算法原理(一)》[1]」

RSA 算法中的加密密鑰,咱們稱爲公鑰(Public Key),解密密鑰,稱爲私鑰(Private Key)。你只須要保管好私鑰便可。公鑰能夠放在博客上,想給你發信息的人, 只須要用公鑰加密信息再發給你便可。ui

在 Python 中咱們如何使用 RSA 算法進行加密解密呢?能夠安裝一個第三方庫,叫作rsa:編碼

pip install rsa

安裝完成之後,咱們試着交密一段中文:今晚8點老地方碰頭.加密

第一步,建立公鑰和私鑰3d

import rsa

public_key, private_key = rsa.newkeys(1024)

咱們如今打印一下這兩個密鑰,以下圖所示:
別怕,咱們的聊天消息,沒人能偷看

其中的數字1024表示生成1024位的密鑰。你也能夠寫2048或者4096……,只要是 且 n>4便可。位數越多越安全,可是加密解密速度越慢。

生成的密鑰是 Python 對象,不方便發送給別人。因此咱們能夠把它們轉換爲pem格式:

public_key_str = public_key.save_pkcs1()
private_key_str = private_key.save_pkcs1()

以下圖所示:
別怕,咱們的聊天消息,沒人能偷看

如今,咱們獲得了兩個字符串。這是 pem 格式的公鑰和私鑰,公鑰以BEGIN RSA PUBLIC KEY開頭,較短;私鑰以BEGIN RSA PRIVATE KEY開頭,較長。

其中,私鑰你本身保管好不要泄露。公鑰你能夠用 QQ 微信郵箱短信等等任意通訊工具發送給別人。

密鑰只須要生成一次,之後就不須要執行上面的代碼了。

有了公鑰和私鑰之後,咱們就能夠開始發送信息了。

注意如下代碼都是使用 pem 格式的公鑰和私鑰。

首先咱們使用公鑰加密信息。

public_key_str = '''
-----BEGIN RSA PUBLIC KEY-----
MIGJAoGBAIWmLWCvb3kSJ7+ys9JZ/rqqgIcYwf9bcEl9/BQd4XnsSHHoyAyG+bPI
1YRGaAnmKLGeEcgrJE1sQIqIMdeHLHVTWUNh4Wr8o+1fyTrlpK0fCNmLb3qRabsg
wRxoSEflXAchBLlHWQoHkaMjcfR7zTFe5I/ogx5gtSX0TQCSmLANAgMBAAE=
-----END RSA PUBLIC KEY-----
'''
msg = '今晚8點老地方碰頭'
public_key = rsa.PublicKey.load_pkcs1(public_key_str.encode())
encryptd_msg = rsa.encrypt(msg.encode(), public_key)

加密之後,咱們得到是一個 bytes 型的數據,以下圖所示:
別怕,咱們的聊天消息,沒人能偷看

注意,這裏的這個 bytes 型數據是不能.decode()成字符串的。那麼應該如何把它發送給別人呢?

這個時候,就能夠在它的外層套一層 base64編碼,讓他變成字符串:

import base64

encryptd_msg_str = base64.b64encode(encryptd_msg).decode()

以下圖所示:
別怕,咱們的聊天消息,沒人能偷看

如今,你能夠把密文

RzwfgCFUhLKYiXM7frOcBL7VyLIh1M7pJ8Gpaz9j7HksjYqsw8DzreFziBNi/S0GGciIfWsvr5pUvYFA7wacOjHqluZ7KVx1oEOdg/x6wyeb1UdQ9cR6PzMlgpidpzUknhsGIAmxjtt6EUL+tJVUbzfXHgs5wETxFZQtRHLcKag=」

經過任何一個公開渠道發送給別人了。這就是密文。

擁有私鑰的人,拿到密文之後如何解密呢?也很簡單:

import rsa
import base64

encryptd_msg_str = '''
RzwfgCFUhLKYiXM7frOcBL7VyLIh1M7pJ8Gpaz9j7HksjYqsw8DzreFziBNi/S0GGciIfWsvr5pUvYFA7wacOjHqluZ7KVx1oEOdg/x6wyeb1UdQ9cR6PzMlgpidpzUknhsGIAmxjtt6EUL+tJVUbzfXHgs5wETxFZQtRHLcKag=
'''

private_key_str = '''
-----BEGIN RSA PRIVATE KEY-----
MIICXwIBAAKBgQCFpi1gr295Eie/srPSWf66qoCHGMH/W3BJffwUHeF57Ehx6MgM
hvmzyNWERmgJ5iixnhHIKyRNbECKiDHXhyx1U1lDYeFq/KPtX8k65aStHwjZi296
kWm7IMEcaEhH5VwHIQS5R1kKB5GjI3H0e80xXuSP6IMeYLUl9E0AkpiwDQIDAQAB
AoGAYNu2N0PtfcjylbNlLyWZvp6i10XSEsap8hkj/1BIgJwFRMh3cty/StRaKar8
62+qPk9Yg8EAZjv16nAZjRcVQ031/F57FGR3JdZ43fuT/no0gV+mEIc72ypNuhUl
M9iccyhEq0xX4eixex3nUALBcPY17ElhvaD8cDZoW2QGFAECRQCHR4RHmgOzoyuM
Wnov7/WetV8Eqxy1/XQOkvSTWEv6Gyc1vlc/xsRGLwXiUt0BFoOnMRCOAQJwjxSn
EbbRzey3YdzX4QI9APzqPCqiEZ4eNnh8F7eOmQYSRurx2b5eyEg3zrVgJHCNOE1i
8uidT4mLBx4nfIwV8/ttw7TjzvhQtnBtrQJEaAzyCcDEqB8RF9tfsA95dKE8fHLA
mppf8fXGeK6pga3w8r18jmlr/i+c7v+dTYDrsmVivla4casbz4UogSdKs6JqIwEC
PGkUdO0Nqx4z1VPX0w7Lq15vZ5Gj7GEBBlui/Do1eM5ejj7w1pW5DlvKLKnlpASb
9mPHZiGY6NwYxMQPfQJEGg5vG+TN7G4PxbCzeInxxIScpmDE8TBPixrIy9qM/cjb
Excc1vCiR8+Kbhr/RhYveaGuKIKaXrVBhzQJZDYd8298mmA=
-----END RSA PRIVATE KEY-----
'''

private_key = rsa.PrivateKey.load_pkcs1(private_key_str.encode())
encryptd_msg = base64.b64decode(encryptd_msg_str.encode())
msg = rsa.decrypt(encryptd_msg, private_key).decode()
print(msg)

運行效果以下圖所示:

別怕,咱們的聊天消息,沒人能偷看
RSA 加密對被加密的內容(明文)是有長度限制的。由於最終的密文中會有11 bytes 的內容用來存放加密相關的元信息,因此對於1024位的密鑰來講,能加密的明文長度爲 bytes。

若是計算一個字符串的字節長度呢?可使用以下代碼:

msg = '今晚8點老地方碰頭'
print(len(msg.encode()))

運行效果以下圖所示:
別怕,咱們的聊天消息,沒人能偷看

說明這8個漢字加1個數字長度爲25bytes(由於在 Python 裏面,一個漢字佔3bytes,數字和字母佔1bytes,)

若是要發送一段很長的字符串,就須要把字符串先轉成 bytes 型數據,再按照117 bytes 一組拆分紅不少組,對每一組分別加密。解密的時候,以密鑰位數/8bytes一組先切分密文,再逐一解密,最後拼出明文的 bytes 型數據之後再.decode()轉成字符串。

咱們先來實現加密的代碼:

def encrypt(msg, public_key):
    msg_bytes = msg.encode()
    encryptd_msg = b''
    chunk_size = len(msg_bytes) // 117 + 1
    for chunk_index in range(chunk_size + 1):
        chunk = msg_bytes[chunk_index * 117: (chunk_index + 1) * 117]
        encryptd_msg += rsa.encrypt(chunk, public_key)
    encryptd_msg_str = base64.b64encode(encryptd_msg).decode()
    return encryptd_msg_str

在這段代碼中,咱們是先把明文轉成 bytes 型的數據後,再進行切片。這裏有可能會把一箇中文對應的三個 bytes 從中切開。不過這影響不大。以117bytes 爲一個明文塊進行加密。把加密後生成的 bytes 型數據拼接成長字符串,再總體使用 Base64進行編碼。最後把編碼生成的密文發送給別人便可。以下圖所示:
別怕,咱們的聊天消息,沒人能偷看

咱們在這裏生成的密文爲:

K2Tb9tDQPXBiuCBuWxOR9zBTbDSN2WaF+n+P2RUA9CHdIKvIHvqfMZ60xTsJ7UqZlB4ykzu/ccsTEmp8vqiVaJSSwg5TgDYLdPmk5/6leZaBW4BqyJ2g0PcyCcUvhjxc7P4AIC6MKYZ+74qTgm+Pf8qnY/riOeEZUuxoq0KaFZQOpvGpwnAgpCad8a6MJ7TbyZpepkZr+GbFDdbmegrA6HN9zCIw30c4g0RCiD01PwerUtbK9YXr/aO8hrFEim8bWDos3bpNrQtk8ST4fM9OczXKEoTSuv+f+Ue2s1YFJ00tAyD4GF8QeZ5mUc2ydNyovkvEfhwhy1eOcI/HQQZn2DPxLb3gB4tgE/Hoo4Xblj8ZWpeMe5BrAdT4Dk1qduOJ/A3RnfvhEbojwx30pEU+JipW4AqCPxK26Q+WsYyqVCBM29vWWgxttthxBidpM0GYII1OIfZvWG8GAAMPvotTwrdGOF/Nk355qLlwiHJhsjz0uN0p9PjyUY+xHobDrmuggBHejM69PwelnG5ubxjhBoqKtbBttU4IWfDZq+d3LZdhwZMp2PsXkSzu+IIgpAn0+F/5bZkRAv8XTAv1YFnYLwJI9vyXfMIyoo4wcqDpNmJrMoaW0hvpJ8jMPna0lI9/Up2JO8GRhq+C+pgeM37OUE70UGrqw1R25yO8Y60of69HqfdFgLalhD7egJ42gRt9Lman7dsokWrpySp6Tq7jFJ/h/OL2Kma8Tqeodd1B0/bINNBkK2hb5EIq7cu6xEd5LevieYllEw0LNK03aWERMfkIuOSabzDfn1kedZnK4PlZ+DiXaoe8uUlAlfZsWNBNV94C3+Ji/a1jYk+ZEUZMxA==」

接下來咱們來編寫解密程序:

def decrypt(encryptd_msg_str, private_key):
    encryptd_msg = base64.b64decode(encryptd_msg_str.encode())
    chunk_size = len(encryptd_msg) // 128
    msg_bytes = b''
    for chunk_index in range(chunk_size):
        chunk = encryptd_msg[chunk_index * 128: (chunk_index + 1) * 128]
        msg_bytes += rsa.decrypt(chunk, private_key)
    return msg_bytes.decode()

在解密程序中,咱們先把 Base64編碼的字符串解碼爲 bytes 型的數據,而後以128bytes 爲一組進行拆分。分別對每一組進行解密。再把每次解密生成的 bytes 型數據拼接。最後把拼接完成的數據使用.decode()轉換爲字符串。

特別要注意,對每一塊密文,在解密完成之後不能直接.decode()。由於它末尾可能只有半個中文,直接轉字符串會致使報錯,必須先拼接完解密後的全部 bytes 數據,再轉成字符串。更多關於 bytes 型數據切片的問題,請參閱我之前的公衆號:一日一技:Python 的 bytes 型數據的迭代特徵一文。

解密程序運行效果以下圖所示:
別怕,咱們的聊天消息,沒人能偷看

你們注意,若是你的密鑰是2048位的,那麼加密時一個明文會以245bytes 一組先切分再加密;解密時,密文會以256bytes 一組先切分再解密。

最後,你們若是有任何不但願被衆所周知的組織看到的信息想發送給我,可使用下面這個公鑰對信息進行加密,而後把密文發送給我:

-----BEGIN RSA PUBLIC KEY-----
MIIBCgKCAQEApQSWvu/C5NH3aEGMqFTeiJrXbOM2Qi+uXc+FiApEWDYdyEMPQWKH
exJiFoyAa+JJ8OfmkTIVktkx0VqEcvfjfKxrGPk9JuQ6WL4/UUYs8/F+2ArDnMyR
lWcqaf1658QjrWYbFHxQ0eEOZ6RcRKME3p431mDMqeDpQtqlDyeMKGp7hSv5gnpd
Qjlyl1Jgoa4lAzyPv66IM1PD207qjLFCTY0udiWSFDiUlvgXcBHDypUqWGOUUSLE
vVXIE+KYNbR2g23iRa1IJGSCEz1xllt7QpygCwwd+vVGD8zaCHOEE7Fex0K/ybhi
Nvdt19qgxE8aIwGt0ln71DNpn+yZsq4fIwIDAQAB
-----END RSA PUBLIC KEY-----

參考資料

[1]
《RSA算法原理(一)》: https://www.ruanyifeng.com/blog/2013/06/rsa_algorithm_part_one.html

別怕,咱們的聊天消息,沒人能偷看

kingname攢錢給產品經理買房。

相關文章
相關標籤/搜索