Notas de lectura "Programación de criptografía en Python" (2)

Capítulo 4 Cifrado asimétrico

A través de una contraseña, se genera una clave pública y una clave privada,
y luego la clave pública cifra el texto para formar un texto cifrado, y la clave privada descifra el texto cifrado para obtener el texto.

RSAComo uno de los algoritmos de cifrado asimétrico clásicos, está casi desactualizado, pero puede comprender algunos conceptos básicos aprendiendo RSA

from cryptography.hazmat.primitives import serialization
from cryptography.hazmat.primitives.asymmetric import rsa
from cryptography.hazmat.backends import default_backend

# 生成一个私钥
private_key = rsa.generate_private_key(public_exponent=65537,key_size=2048,backend=default_backend())# 参数就这样设定,文档建议
# 从私钥中提取公钥
public_key = private_key.public_key()
# 把私钥转成字节,这一次不加密它
private_key_bytes = private_key.private_bytes(encoding=serialization.Encoding.PEM,
                                              format=serialization.PrivateFormat.TraditionalOpenSSL,
                                              encryption_algorithm=serialization.NoEncryption()
                                            )
# 把公钥转成字节
public_key_bytes = public_key.public_bytes(encoding=serialization.Encoding.PEM,
                                           format=serialization.PublicFormat.SubjectPublicKeyInfo)

# 把私钥字节转回key
private_key = serialization.load_pem_private_key(private_key_bytes,backend=default_backend(),password=None)
public_key = serialization.load_pem_public_key(public_key_bytes,backend=default_backend())

inserte la descripción de la imagen aquí
La clave pública se deriva de la clave privada.

4.2 Errores RSA

La fórmula del modelo matemático encriptado ces el texto cifrado y mel mensaje, y los parámetros restantes son la clave pública y la clave privada.

  c ≡ yo ( mod n ) \ c ≡ m^e(mod\space n) Cmetroe (modn)__ 

  metro ≡ cd ( mod n ) \ m ≡ c^d(mod\space n) metroCLa conversión de d (modn) 
a código se puede denominar de la siguiente manera

El siguiente código es solo para pruebas y no se puede usar en ningún entorno de producción.

import gmpy2, os, binascii
from cryptography.hazmat.backends import default_backend
from cryptography.hazmat.primitives.asymmetric import rsa
from cryptography.hazmat.primitives import serialization

def simple_rsa_encrypt(m, publickey):
    numbers = publickey.public_numbers()
    return gmpy2.powmod(m, numbers.e, numbers.n)

def simple_rsa_decrypt(c, privatekey):
    numbers = privatekey.private_numbers()
    return gmpy2.powmod(c, numbers.d, numbers.public_numbers.n)
    
def int_to_byte(i):
    i = int(i)
    return i.to_bytes((i.bit_length()+7)//8,byteorder='big')

def bytes_to_int(b):
    return int.from_bytes(b,byteorder='big')

to_bytesHay 3 parámetros en el método,

bytesEl primer numero es para especificar cuantos bytes convertir,
y el segundo es byteorder, que se especifica bigo littlesi
inserte la descripción de la imagen aquí

El tercer signedparámetro indica que este bytescorresponde a un número con signo o un número sin signo int, este es booleanun valor que se puede omitir
junto con el código anterior

def main():
    public_key_file = None
    private_key_file = None
    public_key = None
    private_key = None
    while True:
        print("Simple RSA Crypto")
        print("--------------------")
        print("\tprviate key file: {}".format(private_key_file))
        print("\tpublic key file: {}".format(public_key_file))
        print("\t1. Encrypt Message.")
        print("\t2. Decrypt Message.")
        print("\t3. Load public key file.")
        print("\t4. Load private key file.")
        print("\t5. Create and load new public and private key files.")
        print("\t6. Quit.\n")
        choice = input(">> ")
        if choice == '1':
            if not public_key:
                print("\nNo public key loaded\n")
            else:
                message = input("\nPlaintext: ").encode()# 字符串encode之后可以转为一个整数
                message_as_int = bytes_to_int(message)
                cipher_as_int = simple_rsa_encrypt(message_as_int, public_key)
                cipher = int_to_bytes(cipher_as_int)
                print("\nCiphertext (hexlified): {}\n".format(binascii.hexlify(cipher)))# binascii.hexlify返回一个数据的16进制表示
        elif choice == '2':
            if not private_key:
                print("\nNo private key loaded\n")
            else:
                cipher_hex = input("\nCiphertext (hexlified): ").encode()
                cipher = binascii.unhexlify(cipher_hex)
                cipher_as_int = bytes_to_int(cipher)
                message_as_int = simple_rsa_decrypt(cipher_as_int, private_key)
                message = int_to_bytes(message_as_int)
                print("\nPlaintext: {}\n".format(message))
        elif choice == '3':
            public_key_file_temp = input("\nEnter public key file: ")
            if not os.path.exists(public_key_file_temp):
                print("File {} does not exist.")
            else:
                with open(public_key_file_temp, "rb") as public_key_file_object:
                    public_key = serialization.load_pem_public_key(
                                     public_key_file_object.read(),
                                     backend=default_backend())
                    public_key_file = public_key_file_temp
                    print("\nPublic Key file loaded.\n")

                    # unload private key if any
                    private_key_file = None
                    private_key = None
        elif choice == '4':
            private_key_file_temp = input("\nEnter private key file: ")
            if not os.path.exists(private_key_file_temp):
                print("File {} does not exist.")
            else:
                with open(private_key_file_temp, "rb") as private_key_file_object:
                    private_key = serialization.load_pem_private_key(
                                     private_key_file_object.read(),
                                     backend=default_backend(),
                                     password=None)
                    private_key_file = private_key_file_temp
                    print("\nPrivate Key file loaded.\n")

                    # load public key for private key
                    # (unload previous public key if any)
                    public_key = private_key.public_key()
                    public_key_file = None
        elif choice == '5':
            private_key_file_temp = input("\nEnter a file name for new private key: ")
            public_key_file_temp  = input("\nEnter a file name for a new public key: ")
            if os.path.exists(private_key_file_temp) or os.path.exists(public_key_file_temp):
                print("File already exists.")
            else:
                with open(private_key_file_temp, "wb+") as private_key_file_obj:
                    with open(public_key_file_temp, "wb+") as public_key_file_obj:

                        private_key = rsa.generate_private_key(
                                          public_exponent=65537,
                                          key_size=2048,
                                          backend=default_backend()
                                      )
                        public_key = private_key.public_key()

                        private_key_bytes = private_key.private_bytes(
                            encoding=serialization.Encoding.PEM,
                            format=serialization.PrivateFormat.TraditionalOpenSSL,
                            encryption_algorithm=serialization.NoEncryption()
                        )
                        private_key_file_obj.write(private_key_bytes)
                        public_key_bytes = public_key.public_bytes(
                            encoding=serialization.Encoding.PEM,
                            format=serialization.PublicFormat.SubjectPublicKeyInfo
                        )
                        public_key_file_obj.write(public_key_bytes)

                        public_key_file = None
                        private_key_file = private_key_file_temp
        elif choice == '6':
            print("\n\nTerminaing. This program will self destruct in 5 seconds.\n")
            break
        else:
            print("\n\nUnknown option {}.\n".format(choice))

if __name__ == '__main__':
    main()

Pasos:
1. Seleccione 5, ingrese el nombre del archivo, my_private_key_file.pem, my_public_key_file.pemy guarde la clave pública y la clave privada en estos dos archivos.
2. Después de que A obtenga el archivo de clave pública, seleccione 3para cargar el archivo de clave pública
. 3. Seleccione 1, A necesita para responder Ba hot dogs", usará la clave pública anterior para cifrar este mensaje y devolverá el texto cifrado. Estos mensajes están cifrados por A , pero no se pueden descifrar porque A no tiene una clave privada. A envía el texto cifrado generado a B

Ciphertext (hexlified): b'a8d6b19f7661fa7bcc11476df13c7c0a151db81967308afc083d9223d2492b3e139fab519b419b7dcf14c8a856ec8ff3701d9ebdf520ec4584172acd34d9d2c9e216d6abbf9697e641185104c52dedf72115ecfcf6ee34a504ed983c7bce463d5e8963d1d4111bced4c937816e52e7ce986e57bedfe5896a5d5a133c29f3f2006ac480dca589f5938092b0ac8bbad91fb20572429d079be4a8d2583c187ba3f22a6cd7b5779d6589fef39b3595363427c4c19e1a4ac78b3e62d56d17810fff1f74385f03db4051841cd6d48ff70dfc406954e50fd4aa33f392aaf510c4bb3341e3f406f68ff8b97db34821add1464f85f770b12303fa3d207650561ed3a81ab3'

4. Seleccione 4, B cargue el archivo de clave privada
5. Seleccione 2, solo ingrese el contenido entre las comillas de texto cifrado anteriores

4.6 Relleno de pase

4.6.2 Ataque de texto cifrado elegido (CCA)

Esta sección significa que el método anterior es fácil de descifrar, de acuerdo con un montón de fórmulas matemáticas, bla, bla, bla, bla,

4.6.3 Ataque en modo común

nEl parámetro es el módulo, si el mismo RSAmensaje se cifra con dos nclaves públicas diferentes con el mismo módulo, se puede descifrar sin usar la clave privada

4.7 Acolchado

cryptographyEl uso de ningún relleno está prohibido en RSA, pero la biblioteca OpenSSL le permite
usar OAEPun relleno óptimo para el cifrado asimétrico.

from cryptography.hazmat.backends import default_backend
from cryptography.hazmat.primitives.asymmetric import rsa
from cryptography.hazmat.primitives import hashes
from cryptography.hazmat.primitives.asymmetric import padding

def main():
    message = b'test'
    
    private_key = rsa.generate_private_key(
          public_exponent=65537,
          key_size=2048,
          backend=default_backend()
      )
    public_key = private_key.public_key()
    
    ciphertext1 = public_key.encrypt(
        message,
        padding.OAEP(
            mgf=padding.MGF1(algorithm=hashes.SHA256()),
            algorithm=hashes.SHA256(),
            label=None # rarely used. Just leave it 'None'
        )
    )
    
    ###
    # WARNING: PKCS #1 v1.5 is obsolete and has vulnerabilities
    # DO NOT USE EXCEPT WITH LEGACY PROTOCOLS
    ciphertext2 = public_key.encrypt(
        message,
        padding.PKCS1v15()
    )
    
    recovered1 = private_key.decrypt(
    ciphertext1,
     padding.OAEP(
         mgf=padding.MGF1(algorithm=hashes.SHA256()),
         algorithm=hashes.SHA256(),
         label=None # rarely used. Just leave it 'None'
     ))
       
    recovered2 = private_key.decrypt(
    ciphertext2,
     padding.PKCS1v15()
 )
    
    print("Plaintext: {}".format(message))
    print("Ciphertext with PKCS #1 v1.5 padding (hexlified): {}".format(ciphertext1.hex()))
    print("Ciphertext with OAEP padding (hexlified): {}".format(ciphertext2.hex()))
    print("Recovered 1: {}".format(recovered1))
    print("Recovered 2: {}".format(recovered2))
    if ciphertext1 != ciphertext2 and recovered1 == message and recovered2 == message:
        print("[PASS]")
    
if __name__=="__main__":
    main()

padding.PKCS1v15()Insecure
se ejecuta repetidamente, el texto cifrado para ambos esquemas de relleno cambiará cada vez que
el relleno garantice que la entrada siempre tenga un tamaño fijo: la entrada al módulo de bits
RSAcifrado (tamaño de módulo 2048) siempre será 256bytes. Dos discusiones
sobre (1) Los parámetros generalmente son , el uso no aumentará la seguridad, por lo tanto, ignore temporalmente (2) es necesario usar el algoritmo hash, más seguroOAEP
labelNonelabel
OAEPSHA256

Se acerca la computación cuántica, ahora la mayoría de los algoritmos asimétricos serán fáciles de descifrar, RSA será descifrado

Capítulo 5 Integridad de mensajes, firmas y certificados

5.2 MAC, HMAC, CBC-MAC

MAC (Message Authentication Code) es un mecanismo de autenticación utilizado por entidades de comunicación y una herramienta para garantizar la integridad de los datos del mensaje. Aquí hay 2 métodos

5.2.1 HMAC

HMAC es un código de autenticación de mensajes basado en hash
Algoritmo hash, para la misma entrada, la salida es la misma, la misma en cada computadora
Para el algoritmo sin clave, la misma entrada siempre da la misma salida, usando la clave se gana 't porque la salida depende tanto de la entrada como de la clave

Supongo que te gusta

Origin blog.csdn.net/weixin_44831720/article/details/123201112
Recomendado
Clasificación