tutorial - Cómo generar pares de claves SSH con Python
todo sobre elasticsearch (10)
¡Usa la cryptography
! pycrypto
ya no está en desarrollo activo y, si es posible, debería estar usando criptografía. Desde junio también es posible generar claves públicas SSH:
from cryptography.hazmat.primitives import serialization as crypto_serialization
from cryptography.hazmat.primitives.asymmetric import rsa
from cryptography.hazmat.backends import default_backend as crypto_default_backend
key = rsa.generate_private_key(
backend=crypto_default_backend(),
public_exponent=65537,
key_size=2048
)
private_key = key.private_bytes(
crypto_serialization.Encoding.PEM,
crypto_serialization.PrivateFormat.PKCS8,
crypto_serialization.NoEncryption())
public_key = key.public_key().public_bytes(
crypto_serialization.Encoding.OpenSSH,
crypto_serialization.PublicFormat.OpenSSH
)
Nota: Necesita al menos la versión 1.4.0
.
Estoy intentando escribir un script para generar pares de claves de identidad SSH para mí.
from M2Crypto import RSA
key = RSA.gen_key(1024, 65337)
key.save_key("/tmp/my.key", cipher=None)
El archivo /tmp/my.key
ve muy bien ahora.
Al ejecutar ssh-keygen -y -f /tmp/my.key > /tmp/my.key.pub
puedo extraer la clave pública.
Mi pregunta es ¿cómo puedo extraer la clave pública de Python? Usar key.save_pub_key("/tmp/my.key.pub")
guarda algo como:
-----BEGIN PUBLIC KEY-----
MFwwDQYJKoZIhvcNAQEBBQADASDASDASDASDBarYRsmMazM1hd7a+u3QeMP
...
FZQ7Ic+BmmeWHvvVP4Yjyu1t6vAut7mKkaDeKbT3yiGVUgAEUaWMXqECAwEAAQ==
-----END PUBLIC KEY-----
Cuando estoy buscando algo como:
ssh-rsa AAAABCASDDBM$%3WEAv/3%$F ..... OSDFKJSL43$%^DFg==
¿Puedes sacar la cadena AAAA ... Dfg == mientras es un objeto? Si es así, simplemente puede abrir un archivo usted mismo y guardarlo en lugar de usar la función incorporada save_pub_key.
¿Qué hay de usar subprocess
para invocar ssh-keygen
?
from subprocess import Popen, PIPE
import shlex
def get_pub_key(path):
args = shlex.split(''ssh-keygen -y -f'')
args.append(path)
p = Popen(args, stdout=PIPE)
stdout = p.communicate()[0]
if p.returncode != 0:
raise Exception("Error handling would be nice, eh?")
return stdout.strip()
print get_pub_key(''/tmp/my.key'')
El pequeño programa anterior producirá un resultado como este:
ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAQEA ... 9Jbn6D74JOKpaOU050ltyNRw==
Aquí hay un ejemplo usando la biblioteca Twisted Conch que aprovecha PyCrypto debajo de las cubiertas. Puede encontrar la documentación de API en http://twistedmatrix.com/documents/current/api/twisted.conch.ssh.keys.html :
from twisted.conch.ssh import keys
# one-time use key
k="""-----BEGIN RSA PRIVATE KEY-----
PRIVATE KEY STUFF
-----END RSA PRIVATE KEY-----"""
# create pycrypto RSA object
rsa = keys.RSA.importKey(k)
# create `twisted.conch.ssh.keys.Key` instance which has some nice helpers
key = keys.Key(rsa)
# pull the public part of the key and export an openssh version
ssh_public = key.public().toString("openssh")
print ssh_public
Editar 05/09/2012:
Me acabo de dar cuenta de que pycrypto ya tiene esto:
import os
from Crypto.PublicKey import RSA
key = RSA.generate(2048, os.urandom)
print key.exportKey(''OpenSSH'')
Este código funciona para mí:
import os
from Crypto.PublicKey import RSA
key = RSA.generate(2048, os.urandom)
# Create public key.
ssh_rsa = ''00000007'' + base64.b16encode(''ssh-rsa'')
# Exponent.
exponent = ''%x'' % (key.e, )
if len(exponent) % 2:
exponent = ''0'' + exponent
ssh_rsa += ''%08x'' % (len(exponent) / 2, )
ssh_rsa += exponent
modulus = ''%x'' % (key.n, )
if len(modulus) % 2:
modulus = ''0'' + modulus
if modulus[0] in ''89abcdef'':
modulus = ''00'' + modulus
ssh_rsa += ''%08x'' % (len(modulus) / 2, )
ssh_rsa += modulus
public_key = ''ssh-rsa %s'' % (
base64.b64encode(base64.b16decode(ssh_rsa.upper())), )
En caso de que haya viajeros futuros que quieran hacer esto. El módulo RSA admite la escritura de la clave pública en formato OpenSSH ahora (posiblemente no en el momento de las publicaciones anteriores). Entonces creo que puedes hacer lo que necesitas con:
from os import chmod
from Crypto.PublicKey import RSA
key = RSA.generate(2048)
with open("/tmp/private.key", ''w'') as content_file:
chmod("/tmp/private.key", 0600)
content_file.write(key.exportKey(''PEM''))
pubkey = key.publickey()
with open("/tmp/public.key", ''w'') as content_file:
content_file.write(pubkey.exportKey(''OpenSSH''))
Obviamente, no almacene su clave privada en / tmp ...
La clave utilizada por ssh está codificada en base64, no conozco mucho M2Crypto, pero después de una breve descripción, parece que puedes hacer lo que quieras de esta manera:
import os
from base64 import b64encode
from M2Crypto import RSA
key = RSA.gen_key(1024, 65537)
raw_key = key.pub()[1]
b64key = b64encode(raw_key)
username = os.getlogin()
hostname = os.uname()[1]
keystring = ''ssh-rsa %s %s@%s'' % (b64key, username, hostname)
with open(os.getenv(''HOME'')+''/.ssh/id_rsa.pub'') as keyfile:
keyfile.write(keystring)
No probé la clave generada con SSH, así que avíseme si funciona (debería pensar)
La versión decodificada de base64 de la salida de ssh-keygen a los contenidos de key.pub () el formato del archivo de claves es
b64encode(''/x00/x00/x00/x07ssh-rsa%s%s'' % (key.pub()[0], key.pub()[1]))
No sé de una biblioteca así en Python.
Puede encontrar útil la biblioteca de paramiko (también disponible en PyPI ). Implementa el protocolo SSH, y tiene funcionalidad para manejar claves existentes, pero no las genera.
La generación de claves puede ser una adición útil a esa biblioteca (podría trabajar con los desarrolladores para incorporarla a la biblioteca), y un inicio más fácil que hacerlo desde cero.
Solo adivinando ... ¿pero has probado algo como esto ?:
print "ssh-rsa " + "".join([ l.strip() for l in open(''/tmp/my.key.pub'') if not l.startswith(''-----'')])