如何在 Python 中使用 ssh-keygen ed25519 密钥进行加密?

如何解决如何在 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_keyextract_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 举报,一经查实,本站将立刻删除。

相关推荐


Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其他元素将获得点击?
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。)
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbcDriver发生异常。为什么?
这是用Java进行XML解析的最佳库。
Java的PriorityQueue的内置迭代器不会以任何特定顺序遍历数据结构。为什么?
如何在Java中聆听按键时移动图像。
Java“Program to an interface”。这是什么意思?
Java在半透明框架/面板/组件上重新绘画。
Java“ Class.forName()”和“ Class.forName()。newInstance()”之间有什么区别?
在此环境中不提供编译器。也许是在JRE而不是JDK上运行?
Java用相同的方法在一个类中实现两个接口。哪种接口方法被覆盖?
Java 什么是Runtime.getRuntime()。totalMemory()和freeMemory()?
java.library.path中的java.lang.UnsatisfiedLinkError否*****。dll
JavaFX“位置是必需的。” 即使在同一包装中
Java 导入两个具有相同名称的类。怎么处理?
Java 是否应该在HttpServletResponse.getOutputStream()/。getWriter()上调用.close()?
Java RegEx元字符(。)和普通点?