如何解决如何在 Python 中使用 ssh-keygen ed25519 密钥进行加密?
我花了大约 2 天的时间试图完成这项工作,并在谷歌上搜索了有关加密、pynacl 和 paramiko 等软件包的信息。
解决方法
最后我在 https://gist.github.com/R-VdP/b7ac0106a4fd395ee1c37bfe6f552a36 找到了一些示例代码 sealing.py,感谢 GitHub https://github.com/R-VdP 的 Ramses。
您可以读取使用 ssh-keygen 生成的 id_ed25519 和 id_ed25519.pub 文件并打开,将密钥剥离为文本,然后使用 extract_curve_private_key 和 extract_curve_public_key 来自密封.py这些键可用于从 PyNaCl 构造 Box 类。因此,您可以使用 Ramses 代码和 PyNaCl 完成对称、非对称和签名操作。
希望这能帮助一些人花在谷歌上的时间比我少。
编辑:根据 Kenster 的建议添加了包装类和客户端代码。 data/ 中的文件是通过 ssh-keygen -t ed25519 生成的,没有密码。请注意,这是 Ramses 代码的瘦类包装器,值得称赞。
from nacl.public import Box
from nacl.utils import random as nacl_random
from nacl.secret import SecretBox
from nacl.exceptions import BadSignatureError
from base64 import b64decode
from nacl.encoding import RawEncoder
from nacl.signing import SigningKey,VerifyKey
class C25519:
# Adapted from https://gist.github.com/R-VdP/b7ac0106a4fd395ee1c37bfe6f552a36 sealing.py
# Author: Ramses https://github.com/R-VdP
__key_length = 32
__private_key_signature = b'\x00\x00\x00\x40'
__public_key_signature = b'\x00\x00\x00\x20'
@classmethod
def __bytes_after(cls,signature,length,bytestr):
start = bytestr.find(signature) + len(signature)
return bytestr[start:start+length]
@classmethod
def __extract_signing_key(cls,private_data):
openssh_bytes = b64decode(private_data)
private_bytes = cls.__bytes_after(
cls.__private_key_signature,cls.__key_length,openssh_bytes
)
signing_key = SigningKey(seed=private_bytes,encoder=RawEncoder)
return signing_key
@classmethod
def __extract_verify_key(cls,public_data):
openssh_bytes = b64decode(public_data)
public_bytes = cls.__bytes_after(
cls.__public_key_signature,openssh_bytes
)
verify_key = VerifyKey(key=public_bytes,encoder=RawEncoder)
return verify_key
@classmethod
def __private_data_from_file(cls,file_name):
with open(file_name,'r') as file:
contents = file.read()
contents = contents.split('\n')
private_data = ''
for line in contents:
if 'PRIVATE KEY' in line:
continue
if not line:
continue
private_data += line
return private_data
@classmethod
def __public_data_from_file(cls,'r') as file:
contents = file.read()
contents = contents.split(' ')
# assert contents[0] == 'ssh-ed25519'
public_data = contents[1].strip(' ')
return public_data
@classmethod
def signingKey(cls,private_ed25519_file):
private_data = cls.__private_data_from_file(private_ed25519_file)
signing_key = cls.__extract_signing_key(private_data)
return signing_key
@classmethod
def verifyKey(cls,public_ed25519_file):
public_data = cls.__public_data_from_file(public_ed25519_file)
verify_key = cls.__extract_verify_key(public_data)
return verify_key
@classmethod
def privateKey(cls,private_ed25519_file):
signing_key = cls.signingKey(private_ed25519_file)
return signing_key.to_curve25519_private_key()
@classmethod
def publicKey(cls,public_ed25519_file):
verify_key = cls.verifyKey(public_ed25519_file)
return verify_key.to_curve25519_public_key()
def asymmetric():
# Alice and Bob exchange public keys
public_key_alice = C25519.publicKey('data/id_ed25519_alice.pub')
public_key_bob = C25519.publicKey('data/id_ed25519_bob.pub')
private_key_alice = C25519.privateKey('data/id_ed25519_alice')
private_key_bob = C25519.privateKey('data/id_ed25519_bob')
bob_box = Box(private_key_bob,public_key_alice)
message = 'Asymmetric secret message from Bob to Alice'
message_bytes = message.encode('utf-8')
encrypted = bob_box.encrypt(message_bytes)
alice_box = Box(private_key_alice,public_key_bob)
plaintext_bytes = alice_box.decrypt(encrypted)
plaintext = plaintext_bytes.decode('utf-8')
assert message == plaintext
def symmetric():
# Alice and Bob exchange public keys
public_key_alice = C25519.publicKey('data/id_ed25519_alice.pub')
public_key_bob = C25519.publicKey('data/id_ed25519_bob.pub')
private_key_alice = C25519.privateKey('data/id_ed25519_alice')
private_key_bob = C25519.privateKey('data/id_ed25519_bob')
symmetric_key_bytes = nacl_random(SecretBox.KEY_SIZE)
bob_box_assymetric = Box(private_key_bob,public_key_alice)
encrypted = bob_box_assymetric.encrypt(symmetric_key_bytes)
alice_box_assymetric = Box(private_key_alice,public_key_bob)
plaintext_bytes = alice_box_assymetric.decrypt(encrypted)
assert symmetric_key_bytes == plaintext_bytes
bob_box_symmetric = SecretBox(symmetric_key_bytes)
message = 'Symmetric secret message from Bob to Alice'
message_bytes = message.encode('utf-8')
encrypted_message = bob_box_symmetric.encrypt(message_bytes)
alice_box_symmetric = SecretBox(symmetric_key_bytes)
plaintext_bytes = alice_box_symmetric.decrypt(encrypted_message)
plaintext = plaintext_bytes.decode('utf-8')
assert plaintext == message
def signing():
signingKey = C25519.signingKey('data/id_ed25519_bob')
message = 'Document signed with private key'
message_bytes = message.encode('utf-8')
signed = signingKey.sign(message_bytes)
signed_message = signed.message
signed_signature = signed.signature
verifyKey = C25519.verifyKey('data/id_ed25519_bob.pub')
verifyKey.verify(signed_message,signed_signature)
forged = signed[:-1] + bytes([int(signed[-1]) ^ 1])
try:
verifyKey.verify(forged)
except BadSignatureError as exc:
print(exc.args)
if __name__ == "__main__":
asymmetric()
symmetric()
signing()
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。