从sqlite的RSA加密字符串解密是不一样的
Decryption from RSA encrypted string from sqlite is not the same
我正在使用带有 private/public 密钥的 RSA。我正在尝试加密一个字符串,将其保存在数据库(sqlite)中,然后再次检索并加密。
当数据从 sqlite 中出来时,我无法再次解密数据。字符串是相同的,我有点迷路了。
#!/usr/bin/env python3
from Crypto.PublicKey import RSA
from Crypto import Random
import sqlite3
import base64
# database layout
#
# CREATE TABLE secrets ( id INT, secret TEXT );
# INSERT INTO secrets (id,secret) VALUES (1,"");
# database
conn = sqlite3.connect('database.db')
c = conn.cursor()
# generate keys
private_key = RSA.generate(1024, Random.new().read)
public_key = private_key.publickey()
# save keys
f = open('public.pem', 'wb+')
f.write(public_key.exportKey('PEM'))
f.close()
f = open('private.pem', 'wb+')
f.write(private_key.exportKey('PEM'))
f.close()
# crypt
f = open('public.pem','rb')
encrypt_public_key = RSA.importKey(f.read())
secret = "123456"
enc_secret = encrypt_public_key.encrypt(secret.encode("utf-8"), 32)[0]
enc_secret_encoded = base64.b64encode(enc_secret)
print("Base64: " + str(enc_secret_encoded))
# save in db
c.execute('UPDATE secrets SET secret="%s" WHERE id=1' % (enc_secret_encoded))
conn.commit()
print("--------------- DECRYPTION ------------------------")
# decrypt
p = open('private.pem','rb')
decrypt_private_key = RSA.importKey(p.read())
c.execute('SELECT secret FROM secrets WHERE id=1')
result = c.fetchone()
encoded_secret = result[0]
print("Base64: " + encoded_secret)
decoded_secret = base64.b64decode(encoded_secret)
enc_secret = decrypt_private_key.decrypt(decoded_secret)
print("Decrypted: " + str(enc_secret))
输出:
$ ./stuck.py
Base64: b'bfAERXPFvrDRdr5Pcexu8JgHlKfDaUhkqJrSWZJbLwlKLWY8XHtIlBwrRfP7eMX9PTKo4t2CtpdXS6Fam4B+jR3/bYPxji0rHt1Aed64sLH4xAnxgh5B/qWidcYT5cPmvwMekGbCaMSgGjvNB4Js/yDRrW4+N8dqx3IoUAl8zgA='
--------------- DECRYPTION ------------------------
Base64: b'bfAERXPFvrDRdr5Pcexu8JgHlKfDaUhkqJrSWZJbLwlKLWY8XHtIlBwrRfP7eMX9PTKo4t2CtpdXS6Fam4B+jR3/bYPxji0rHt1Aed64sLH4xAnxgh5B/qWidcYT5cPmvwMekGbCaMSgGjvNB4Js/yDRrW4+N8dqx3IoUAl8zgA='
Decrypted: b'\x90\x07\xa2}\x96w\xda\xd3h\xf1\xd4\xc6z\xa5\xf3\x85\x97\xeb\xcfL\x0e\x1f;\x18\xd5\x98\xb3\xb2\xd0\x93.\xc9z\x1c\xc8\xac\xe4x\xbfT\xe4{\x1b\x19\xda\xfb/?A\xda_\xceHc\xd14X\x94\x8a\x94\xfc\x12\xc4\x86\xc9\x16\xc9b\xbf\xdaJ\xcf\xff\xe1J\x95\x03&\xda\x98\x9f\x10\xb1\tzW\xea\x9b\xd2\x13\xc1\x8d\x19\xe97\xd6\xeay\xf3\x83\xb7\xcf\xd3v\`~\x07\xcea(\x81\xe1c\x08\x0b\x8c\xee\xc2\x87\xed\xc8\x08D\x8e\xe5\x83\xf4'
当你运行我的例子时,你会看到相同的加密字符串进入sqlite并再次退出,但为什么我不能再次解密并得到与[=12=相同的结果]?
更新: 当我删除 sqlite 数据库时,它会按预期工作。所以问题一定出在存储或检索数据的某个地方。
感谢任何提示。
解码时 base64/RSA 的顺序错误。这有效:
#!/usr/bin/env python3
from Crypto.PublicKey import RSA
from Crypto import Random
import base64
key_pair = RSA.generate(1024, Random.new().read(1024 // 8))
public_key = key_pair.publickey()
secret = "123456"
enc_secret = public_key.encrypt(secret.encode("utf-8"), 32)[0]
enc_secret_b64 = base64.b64encode(enc_secret)
print(enc_secret_b64)
enc_secret = base64.b64decode(enc_secret_b64)
secret = key_pair.decrypt(enc_secret)
print(secret.decode("utf-8"))
# 123456
另请注意,您需要调用Random
的.read
方法。
除此之外:这不是 RSA 的本意。如果您想使用 RSA 加密数据,您应该仅将 RSA 用于密钥封装并使用对称加密系统(例如 AES)加密数据。
Python base 64 library returns 一个 bytes
对象而不是编码时的字符串(这有点奇怪,因为 base 64 编码的全部目的是创建一个可打印的字符串) .
这意味着当您将结果转换为字符串以将其保存在 sqlite 中时,它的格式为 b'XXX...XX'
,即它被保存为以 b
开头并带有引号的字符串实际的 base64 编码数据。
解码时,默认丢弃任何非base64字符。所以这会删除引号但不会删除初始 b
。这意味着您正在解码的数据前面有一个额外的 b
,因此您最终会尝试解密错误的密文。
您可以通过将 validate=True
添加到解码 base 64 数据以强制其验证输入的调用来看到这一点。由于 '
字符,这将导致 binascii.Error
。
enc_secret = base64.b64decode(enc_secret_b64, validate=True)
解决方法是在保存到 sqlite 之前将字节对象从 base 64 编码解码为 ASCII 字符串。然后只有“真正的”base 64 字符会保存到数据库中:
enc_secret_encoded = base64.b64encode(enc_secret).decode("ASCII")
我正在使用带有 private/public 密钥的 RSA。我正在尝试加密一个字符串,将其保存在数据库(sqlite)中,然后再次检索并加密。
当数据从 sqlite 中出来时,我无法再次解密数据。字符串是相同的,我有点迷路了。
#!/usr/bin/env python3
from Crypto.PublicKey import RSA
from Crypto import Random
import sqlite3
import base64
# database layout
#
# CREATE TABLE secrets ( id INT, secret TEXT );
# INSERT INTO secrets (id,secret) VALUES (1,"");
# database
conn = sqlite3.connect('database.db')
c = conn.cursor()
# generate keys
private_key = RSA.generate(1024, Random.new().read)
public_key = private_key.publickey()
# save keys
f = open('public.pem', 'wb+')
f.write(public_key.exportKey('PEM'))
f.close()
f = open('private.pem', 'wb+')
f.write(private_key.exportKey('PEM'))
f.close()
# crypt
f = open('public.pem','rb')
encrypt_public_key = RSA.importKey(f.read())
secret = "123456"
enc_secret = encrypt_public_key.encrypt(secret.encode("utf-8"), 32)[0]
enc_secret_encoded = base64.b64encode(enc_secret)
print("Base64: " + str(enc_secret_encoded))
# save in db
c.execute('UPDATE secrets SET secret="%s" WHERE id=1' % (enc_secret_encoded))
conn.commit()
print("--------------- DECRYPTION ------------------------")
# decrypt
p = open('private.pem','rb')
decrypt_private_key = RSA.importKey(p.read())
c.execute('SELECT secret FROM secrets WHERE id=1')
result = c.fetchone()
encoded_secret = result[0]
print("Base64: " + encoded_secret)
decoded_secret = base64.b64decode(encoded_secret)
enc_secret = decrypt_private_key.decrypt(decoded_secret)
print("Decrypted: " + str(enc_secret))
输出:
$ ./stuck.py
Base64: b'bfAERXPFvrDRdr5Pcexu8JgHlKfDaUhkqJrSWZJbLwlKLWY8XHtIlBwrRfP7eMX9PTKo4t2CtpdXS6Fam4B+jR3/bYPxji0rHt1Aed64sLH4xAnxgh5B/qWidcYT5cPmvwMekGbCaMSgGjvNB4Js/yDRrW4+N8dqx3IoUAl8zgA='
--------------- DECRYPTION ------------------------
Base64: b'bfAERXPFvrDRdr5Pcexu8JgHlKfDaUhkqJrSWZJbLwlKLWY8XHtIlBwrRfP7eMX9PTKo4t2CtpdXS6Fam4B+jR3/bYPxji0rHt1Aed64sLH4xAnxgh5B/qWidcYT5cPmvwMekGbCaMSgGjvNB4Js/yDRrW4+N8dqx3IoUAl8zgA='
Decrypted: b'\x90\x07\xa2}\x96w\xda\xd3h\xf1\xd4\xc6z\xa5\xf3\x85\x97\xeb\xcfL\x0e\x1f;\x18\xd5\x98\xb3\xb2\xd0\x93.\xc9z\x1c\xc8\xac\xe4x\xbfT\xe4{\x1b\x19\xda\xfb/?A\xda_\xceHc\xd14X\x94\x8a\x94\xfc\x12\xc4\x86\xc9\x16\xc9b\xbf\xdaJ\xcf\xff\xe1J\x95\x03&\xda\x98\x9f\x10\xb1\tzW\xea\x9b\xd2\x13\xc1\x8d\x19\xe97\xd6\xeay\xf3\x83\xb7\xcf\xd3v\`~\x07\xcea(\x81\xe1c\x08\x0b\x8c\xee\xc2\x87\xed\xc8\x08D\x8e\xe5\x83\xf4'
当你运行我的例子时,你会看到相同的加密字符串进入sqlite并再次退出,但为什么我不能再次解密并得到与[=12=相同的结果]?
更新: 当我删除 sqlite 数据库时,它会按预期工作。所以问题一定出在存储或检索数据的某个地方。
感谢任何提示。
解码时 base64/RSA 的顺序错误。这有效:
#!/usr/bin/env python3
from Crypto.PublicKey import RSA
from Crypto import Random
import base64
key_pair = RSA.generate(1024, Random.new().read(1024 // 8))
public_key = key_pair.publickey()
secret = "123456"
enc_secret = public_key.encrypt(secret.encode("utf-8"), 32)[0]
enc_secret_b64 = base64.b64encode(enc_secret)
print(enc_secret_b64)
enc_secret = base64.b64decode(enc_secret_b64)
secret = key_pair.decrypt(enc_secret)
print(secret.decode("utf-8"))
# 123456
另请注意,您需要调用Random
的.read
方法。
除此之外:这不是 RSA 的本意。如果您想使用 RSA 加密数据,您应该仅将 RSA 用于密钥封装并使用对称加密系统(例如 AES)加密数据。
Python base 64 library returns 一个 bytes
对象而不是编码时的字符串(这有点奇怪,因为 base 64 编码的全部目的是创建一个可打印的字符串) .
这意味着当您将结果转换为字符串以将其保存在 sqlite 中时,它的格式为 b'XXX...XX'
,即它被保存为以 b
开头并带有引号的字符串实际的 base64 编码数据。
解码时,默认丢弃任何非base64字符。所以这会删除引号但不会删除初始 b
。这意味着您正在解码的数据前面有一个额外的 b
,因此您最终会尝试解密错误的密文。
您可以通过将 validate=True
添加到解码 base 64 数据以强制其验证输入的调用来看到这一点。由于 '
字符,这将导致 binascii.Error
。
enc_secret = base64.b64decode(enc_secret_b64, validate=True)
解决方法是在保存到 sqlite 之前将字节对象从 base 64 编码解码为 ASCII 字符串。然后只有“真正的”base 64 字符会保存到数据库中:
enc_secret_encoded = base64.b64encode(enc_secret).decode("ASCII")