大家好。PyCrypto:使用RSA和PKCS#1加密兩次字符串#1
我想知道是否可以用PyCrypto做雙重加密RSA/PKCS#1加密。
我有一個服務器,它有自己的RSA密鑰(在安裝上述服務器時使用openssl
命令生成)以及可以請求服務器密鑰公共部分的客戶端。另外,該客戶端可以要求服務器爲其生成另一個RSA密鑰(或密鑰對)。在這種情況下,服務器還會保留私鑰(或「整個」RSA密鑰)並向客戶端發送其公鑰部分。
我一直在玩RSA/PKCS和AES加密技術。我創建了一個測試Python文件,只用一個RSA密鑰就可以很好地進行加密。它所做的是使用對稱AES系統(使用隨機生成的「隨機」密鑰)對數據進行加密,並使用RSA/PKCS#1系統對用於AES的密碼進行密碼處理,並將結果放入結果中發送:
#!/usr/bin/python
# -*- coding: utf-8 -*-
# Interesting links:
# 1> http://stackoverflow.com/a/9039039/289011
# 2> http://eli.thegreenplace.net/2010/06/25/aes-encryption-of-files-in-python-with-pycrypto/
from Crypto.PublicKey import RSA
import base64
import os
from Crypto.Cipher import AES
import Crypto.Util.number
import random
import struct
import cStringIO
from Crypto.Cipher import PKCS1_OAEP
def encrypt(string):
#Begin RSA Part to get a cypher that uses the server's public key
externKeyFilename="/home/borrajax/rsaKeys/server-key.pub"
externKeyFile = open(externKeyFilename, "r")
rsaKey= RSA.importKey(externKeyFile, passphrase="F00bAr")
pkcs1Encryptor=PKCS1_OAEP.new(rsaKey)
#End RSA Part
#Begin AES Part
iv = ''.join(chr(random.randint(0, 0xFF)) for i in range(16))
thisMessagePassword = os.urandom(16)
aesEncryptor = AES.new(thisMessagePassword, AES.MODE_CBC, iv)
chunksize=64*1024
#End AES Part
#Begin RSA Encription of the AES Key
rsaEncryptedPassword = pkcs1Encryptor.encrypt(thisMessagePassword)
retvalTmp = cStringIO.StringIO()
retvalTmp.write(struct.pack('<Q', len(string)))
retvalTmp.write(struct.pack('<Q', len(rsaEncryptedPassword)))
retvalTmp.write(rsaEncryptedPassword)
retvalTmp.write(iv)
while len(string) > 0:
chunk = string[0:chunksize]
string = string[chunksize:]
if len(chunk) % 16 != 0:
chunk += ' ' * (16 - len(chunk) % 16)
retvalTmp.write(aesEncryptor.encrypt(chunk))
return retvalTmp.getvalue()
def decrypt(string):
stringAsBuffer = cStringIO.StringIO(string)
retval = str()
chunksize=64*1024
externKeyFilename="/home/borrajax/rsaKeys/server-key.pem"
externKey = open(externKeyFilename, "r")
rsaKey = RSA.importKey(externKey, passphrase="F00bAr")
pkcs1Decryptor=PKCS1_OAEP.new(rsaKey)
origsize = struct.unpack('<Q', stringAsBuffer.read(struct.calcsize('Q')))[0]
rsaEncryptedPasswordLength = long(struct.unpack('<Q', stringAsBuffer.read(struct.calcsize('Q')))[0])
rsaEncryptedPassword = stringAsBuffer.read(rsaEncryptedPasswordLength)
thisMessagePassword = pkcs1Decryptor.decrypt(rsaEncryptedPassword)
iv = stringAsBuffer.read(16)
decryptor = AES.new(thisMessagePassword, AES.MODE_CBC, iv)
while True:
chunk = stringAsBuffer.read(chunksize)
if len(chunk) == 0:
break
retval += decryptor.decrypt(chunk)
return retval
if __name__ == "__main__":
encryptedThingy=encrypt(base64.b64encode("Toñóooooañjfl凱蘭;kañañfjaafafs凱蘭pingüiñoo你好to金玉Toñóooooañjfl凱蘭;kañañfjaafafs凱蘭pingüiñoo你好to金玉Toñóooooañjfl凱蘭;kañañfjaafafs凱蘭pingüiñoo你好to金玉Toñóooooañjfl凱蘭;kañañfjaafafs凱蘭pingüiñoo你好to金玉Toñóooooañjfl凱蘭;kañañfjaafafs凱蘭pingüiñoo你好to金玉"))
print "Decrypted thingy: %s" % base64.b64decode(decrypt(encryptedThingy))
如您所見,AES密碼使用服務器的RSA密鑰加密。現在,我想成爲額外的偏執,而且已經加密與客戶的公鑰密碼加密,因此,「加密」的方法是這樣的:
def encrypt(string):
#Begin RSA Part to get a cypher that uses the server's public key
externServerKeyFilename="/home/borrajax/rsaKeys/server-key.pub"
externServerKeyFile = open(externServerKeyFilename, "r")
rsaServerKey= RSA.importKey(externServerKeyFile, passphrase="F00bAr")
pkcs1ServerEncryptor=PKCS1_OAEP.new(rsaServerKey)
#End RSA Part
#Begin RSA Part to get a cypher that uses the client's public key
externClientKeyFilename="/home/borrajax/rsaKeys/client-key.pub"
externClientKeyFile = open(externClientKeyFilename, "r")
rsaClientKey= RSA.importKey(externClientKeyFile, passphrase="F00bAr")
pkcs1ClientEncryptor=PKCS1_OAEP.new(rsaClientKey)
#End RSA Part
#Begin AES Part
iv = ''.join(chr(random.randint(0, 0xFF)) for i in range(16))
thisMessagePassword = os.urandom(16)
aesEncryptor = AES.new(thisMessagePassword, AES.MODE_CBC, iv)
chunksize=64*1024
#End AES Part
#Begin RSA Encription of the AES Key
rsaEncryptedPasswordWithServer = pkcs1ServerEncryptor.encrypt(thisMessagePassword)
rsaEncryptedPasswordWithServerAndClient = pkcs1ClientEncryptor.encrypt(rsaEncryptedPasswordWithServer) #Katacrasssshh here!!
retvalTmp = cStringIO.StringIO()
retvalTmp.write(struct.pack('<Q', len(string)))
retvalTmp.write(struct.pack('<Q', len(rsaEncryptedPasswordWithServerAndClient)))
#...Probably some yadda yadda here with key lengths and stuff so it would help re-build the keys in the server's side...
retvalTmp.write(rsaEncryptedPasswordWithServerAndClient)
retvalTmp.write(iv)
while len(string) > 0:
chunk = string[0:chunksize]
string = string[chunksize:]
if len(chunk) % 16 != 0:
chunk += ' ' * (16 - len(chunk) % 16)
retvalTmp.write(aesEncryptor.encrypt(chunk))
return retvalTmp.getvalue()
但是,當我嘗試重新加密鍵,我得到一個異常。這是有道理的(至少對於幾乎不知道加密的人來說是有意義的),因爲PKCS添加了一個填充,所以當我用服務器的公鑰加密「thisMessagePassword
」時,我得到一個256字節的字符串,這對於第二個字符來說太長了PKCS加密器(我一直在做一些「手動測試」,限制似乎是214個字節......我的意思是...這是最後一個不拋出異常的值)。
我知道這可能是一個奇怪的構造,它可能會更有意義使用服務器的公鑰加密和用客戶端密鑰簽名,但我只是想玩一點加密的東西,並嘗試瞭解他們如何工作以及爲什麼。這就是爲什麼任何提示將不勝感激。
預先感謝您!