Last active
August 29, 2015 14:26
-
-
Save stavxyz/e24f39292e06276f4643 to your computer and use it in GitHub Desktop.
ssh public key serialization -- a step towards resolving https://github.com/pyca/cryptography/issues/1744
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
"""This should work with python 2 & 3 | |
Something curious: if private_bytes() is | |
called with a format other than | |
serialization.PrivateFormat.TraditionalOpenSSL, | |
the generated key will prompt for a password | |
when running `ssh-keygen -f test-key -e` even when | |
encryption is set to serialization.NoEncryption() | |
There's a hunch that this ^^ only occurs on mac os x. | |
""" | |
import base64 | |
import functools | |
import operator | |
import os | |
import struct | |
import sys | |
from cryptography.hazmat.backends import default_backend | |
from cryptography.hazmat.primitives import serialization | |
from cryptography.hazmat.primitives.asymmetric import rsa | |
if sys.version_info > (3,): | |
long = int | |
def generate_private_key(): | |
return rsa.generate_private_key( | |
public_exponent=65537, | |
key_size=2048, | |
backend=default_backend() | |
) | |
def multiple_precision(number): | |
if number == 0: | |
return b'\000' * 4 | |
assert number > 0 | |
bn = b'' | |
number = long(number) | |
while number > 0: | |
bn = struct.pack('>I', number & long('FFFFFFFF', base=16)) + bn | |
#bn = struct.pack('>I', long(number)) + bn | |
number = number >> 32 | |
# strip off leading zeros | |
for i in range(len(bn)): | |
if bn[i] != b'\000'[0]: | |
break | |
else: | |
# only happens when n == 0 | |
bn = b'\000' | |
i = 0 | |
bn = bn[i:] | |
if ord(bn.decode('latin-1')[0]) & 128: | |
bn = b'\000' + bn | |
return struct.pack('>L', len(bn)) + bn | |
def blob(pubkey): | |
assert isinstance(pubkey, rsa.RSAPublicKeyWithNumbers) | |
numbers = pubkey.public_numbers() | |
items = [ | |
struct.pack('!L', len('ssh-rsa')) + b'ssh-rsa', | |
multiple_precision(numbers.e), | |
multiple_precision(numbers.n), | |
] | |
cat = functools.reduce(operator.add, items) | |
return base64.standard_b64encode(cat) | |
if __name__ == '__main__': | |
private = generate_private_key() | |
serialized = private.private_bytes( | |
encoding=serialization.Encoding.PEM, | |
format=serialization.PrivateFormat.TraditionalOpenSSL, | |
encryption_algorithm=serialization.NoEncryption(), | |
) | |
with open('test-key', 'wb+') as k: | |
k.write(serialized) | |
os.chmod(k.name, 0o600) | |
pub = private.public_key() | |
data = blob(pub) | |
output = 'ssh-rsa {}'.format(data.decode('latin-1')).strip() | |
with open('test-key.pub', 'w+') as k: | |
k.write(output) | |
# now read it back in | |
with open('test-key.pub', 'rb') as p: | |
pub = serialization.load_ssh_public_key(p.read(), default_backend()) | |
assert pub.public_numbers() == private.public_key().public_numbers() | |
print('Good.') | |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
cryptography==0.9.3 |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment