1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
|
import sys
import struct
from hashlib import sha256, sha512
def checksum_stdin(hashalg='sha256'):
if hashalg == 'sha256':
d = sha256()
elif hashalg == 'sha512':
d = sha512()
else:
return None
while True:
buf = sys.stdin.buffer.read()
if not buf:
break
d.update(buf)
return d.digest()
def ssh_to_sign(namespace, hashalg, checksum):
if hashalg == 'sha256':
hashlen = 32
elif hashalg == 'sha512':
hashlen = 64
else:
return None
s = struct.pack('!6sI{}sII6sI{}s'.format(len(namespace), hashlen),
b'SSHSIG',
len(namespace), bytes(namespace, 'ascii'),
0,
6, bytes(hashalg, 'ascii'),
hashlen, checksum)
return s
# Adapted from https://stackoverflow.com/questions/65684414/how-to-use-ssh-keygen-ed25519-keys-for-encryption-in-python
# Author: LJHW
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,
cls.__key_length,
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, file_name):
with open(file_name, '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()
|