Skip to content

Instantly share code, notes, and snippets.

@stavxyz
Last active August 29, 2015 14:26
Show Gist options
  • Save stavxyz/e24f39292e06276f4643 to your computer and use it in GitHub Desktop.
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 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.')
cryptography==0.9.3
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment