Procedimiento correcto para cifrar datos con clave pública y proteger con contraseña la clave privada

2

Me veo en la necesidad de usar PKI en un programa en Linux.

El siguiente código resume el enfoque que tomaría.

Genere un par de claves, guárdelo en el disco. La clave privada se encripta con AES para el cifrado en reposo (la clave privada sin cifrar también se almacena con fines de prueba)

¿Esto refleja los estándares actuales de la comunidad de seguridad?

import os
import json
import base64
import getpass
from Cryptodome.Cipher import AES
from Cryptodome.PublicKey import RSA

print '################################################'

if True:
  PASSWORD = '01234567'[:32].ljust(32)
else:
  print 'Enter password (max 32 chars)'
  PASSWORD = getpass.getpass()[:32].ljust(32)

print '################################################'

GENERATE = False
if not os.path.isfile('private-key-2048.pem.encrypted'):
  GENERATE = True
  print 'GENERATING KEY PAIR'

print '################################################'
print '   CREATE / LOAD THE PRIVATE KEY'
print '################################################'

if GENERATE:

  # store the private key
  private_key = RSA.generate(2048)

  with open('private-key-2048.pem','wb') as f:
    f.write(private_key.exportKey('PEM'))

  with open('private-key-2048.pem.encrypted','wb') as f:
    cipher = AES.new(PASSWORD, AES.MODE_EAX)
    ciphertext, tag = cipher.encrypt_and_digest(private_key.exportKey('PEM'))
    print repr(tag)
    f.write(json.dumps({
        'ciphertext': base64.b64encode(ciphertext),
        'nonce': base64.b64encode(cipher.nonce),
        'tag': base64.b64encode(tag)
      }, indent=1))

else:

  # already generated, read the private key
  private_key = RSA.importKey(open('private-key-2048.pem','rb').read())
  with open('private-key-2048.pem.encrypted','rb') as f:
    data = json.loads(f.read())
    cipher = AES.new(PASSWORD, AES.MODE_EAX, base64.b64decode(data['nonce']))
    ciphertext = cipher.decrypt(base64.b64decode(data['ciphertext']))
    try:
      cipher.verify(base64.b64decode(data['tag']))
    except ValueError:
      print 'password incorrect or message corrupted'
  private_key = RSA.importKey(ciphertext)

print private_key.exportKey('PEM')

print '################################################'
print '   SAVE / LOAD THE PUBLIC KEY'
print '################################################'

if GENERATE:

  # store the public key      
  public_key = private_key.publickey()
  with open('public-key-2048.pem','wb') as f:
    f.write(public_key.exportKey('PEM'))

else:

  # already generated, read the public key      
  public_key = RSA.importKey(open('public-key-2048.pem','rb').read())

print public_key.exportKey('PEM')


print '################################################'
print '   ENCRYPT WITH PUBLIC KEY'
print '################################################'


from Cryptodome.Cipher import PKCS1_OAEP
encryptor = PKCS1_OAEP.new(public_key)
encrypted = encryptor.encrypt('this is a test')
print repr(encrypted)

print '################################################'
print '   DECRYPT WITH PRIVATE KEY'
print '################################################'

decryptor = PKCS1_OAEP.new(private_key)
decrypted = decryptor.decrypt(encrypted)
print decrypted

print '################################################'
    
pregunta Daniel F 28.02.2018 - 16:52
fuente

2 respuestas

1

¿Cuál es el sistema operativo de destino?

Solo he estado leyendo en Windows DPAPI, que se usa para este proceso y la forma en que se realiza se basa en la clave maestra y la frase de contraseña de los usuarios actuales para generar material clave. A continuación, utiliza una función de estiramiento de la clave para generar la clave que le falta. En lugar de eso, agregue la contraseña directamente al AES y la limite a 32 caracteres.

O si su objetivo son ventanas, simplemente use el DPAPI directo para proteger sus claves.

    
respondido por el McMatty 01.03.2018 - 02:45
fuente
1

Generalmente, el método de generar claves y proteger la clave privada con una contraseña se usa comúnmente. Hasta ahora tan bueno.

Sin embargo, no se recomienda usar su propio esquema para el cifrado. Ha habido muchas vulnerabilidades causadas por eso.

La mayoría de los sistemas pueden manejar algunos de los métodos de cifrado de clave privada estándar, lo que garantiza, por ejemplo, que la clave derivada de la contraseña use una buena función de derivación de clave. Los dos métodos más comunes que conozco son PKCS # 12, como los usan las ventanas, los navegadores, etc., y el PEM, como los usa OpenSSL.

El uso de cualquiera de estos métodos te lo hará más fácil. Probablemente será más seguro, será interoperable con los sistemas estándar, y podrá fácilmente transferir su código entre diferentes lenguajes de programación, solo buscando cómo usar este estándar específico en el nuevo idioma.

    
respondido por el primetomas 05.04.2018 - 08:05
fuente

Lea otras preguntas en las etiquetas