今天來談談加密那些事兒。
先說微信。
微信公眾平臺的服務器配置中,有三種消息加解密方式:明文模式、兼容模式和加密模式。明文模式顧名思義,自不必說,且說兼容模式和加密模式:前者明文密文在一條消息里共存,消息長度可達到通常消息三倍,然而卻一點保密作用也沒有起到,果如文檔所說,純就是為了調試,除此之外的場合,只是掩耳盜鈴,還不如明文來得有效率。加密模式,實際上是利用 AES 和 SHA 對微信消息服務器和你的服務器之間傳遞的 XML 進行認證加密,同時保證了消息的保密性和完整性。
加密模式的具體實現細節是這樣的:微信服務器發送過來的 XML 里攜帶了密文(Encrypt
字段)、時間戳(TimeStamp
)、消息簽名(MsgSignature
)和nonce(Nonce
),而諸如 token
、appid
和 EncodingAESKey
之類的信息是雙方之前就約定好的。
- 接收到微信服務器轉發過來的消息之后,首先要對消息完整性進行校驗:把
token
、TimeStamp
、Nonce
和Encrypt
等字段按字典序排序并拼接成一個字符串,然后算出該字符串的 SHA1 值,與MsgSignature
字段進行比較,一致的話,就是認證成功,反之失敗。 - 認證成功之后,進入解密流程:利用 AES 解密,需要傳遞三個參數:秘鑰、加密模式和 IV (inital vector,應該翻譯成“起始向量”吧)。秘鑰是事先約定的
EncodingAESKey
+ '='并用 base64 解碼后的值,加密模式微信使用的是 CBC,IV 固定是秘鑰的前16字節。按說,IV 不應該多次重復使用,不過騰訊這里用了 PKCS7 算法對明文進行了位填充,或許可以避免 IV 重復使用帶來的安全隱患也未可知,我對密碼學了解不算深入,不能細究。調用 AES 算法解密之后,還要用 base64 對明文進行解碼,去掉填充字符串,從 XML 中恢復出appid
并和約定的值進行比較,如果成功,這才算解密完成,可以進行下一步操作了。
如果要向微信服務器回復消息,就需要對消息進行加密。加密過程完全是解密過程的逆操作:先用 PKCS7 算法進行位填充,再用 AES 算法 CBC 模式對明文進行加密,然后用 base64 對密文進行編碼;再然后,用前述的 SHA1 算法計算消息簽名 MsgSignature
,其中,時間戳取當前時間,nonce 可隨機生成;最后,把 Encrypt
、MsgSignature
、TimeStamp
、Nonce
等字段填充進 XML ,發送給微信服務器。
微信的開發者文檔提供了多種語言的參考代碼,修修改改就能用在自己的項目上。不想自己實現也沒關系,如果你用 Python,wechat-python-sdk 這款開發包自帶了消息加解密的實現,安裝使用即可。不管你用何種方法實現,都千萬不要自己實現 AES 和 SHA 算法,必須調用經過廣泛驗證過的第三方庫(Python 的話,就是 PyCrypto),否則你自己的實現100%會存在安全隱患。