【问题标题】:Decryption from RSA encrypted string from sqlite is not the same从 sqlite 解密 RSA 加密字符串是不一样的
【发布时间】:2019-08-17 08:26:31
【问题描述】:

我正在使用带有私钥/公钥的 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 并再次退出,但是为什么我不能再次解密并获得与 secret 相同的结果?

更新:当我删除 sqlite 数据库时,它会按预期工作。所以问题一定出在存储或检索数据的某个地方。

任何提示表示赞赏。

【问题讨论】:

  • 我认为您不应该使用 RSA 密钥直接加密/解密数据。我在the documentation 中找不到RsaKey.encodeRsa.decode。尝试使用基于 RSA 的混合加密方案,如 here 所示。
  • 对于 RSA,您需要至少 2048 位安全性。这将使您的数据非常庞大。你为什么不使用AES?此外,在您的 RSA 中,您不使用填充方案作为 PKCS#1.5,这将容易受到许多攻击。
  • @kelalaka 我同意这两个,这只是一个例子,可以减少分心来理解为什么它不起作用。

标签: python sqlite cryptography rsa pycrypto


【解决方案1】:

Python base 64 library 在编码时返回一个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")

【讨论】:

  • 哇。这正是问题所在。我没看到。非常感谢。
【解决方案2】:

您在解码时得到了错误的 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)加密数据。

【讨论】:

  • 您好,感谢您指出我缺少的 .read(),但除不使用 sqlite 之外,代码完全相同。当我从我的代码中删除 sqlite 存储时,它也在工作。
  • 哎呀,你是对的......对不起,我似乎读错了......这段代码解密为它应该的......也许你可以添加sqlite并读/写@987654325 @ 并找出你的代码失败的地方。再次抱歉...
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2023-03-14
  • 1970-01-01
  • 2013-06-08
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-07-09
相关资源
最近更新 更多