Citar...cómo se comprueba que esa clave es o no la correcta?...
Dependiendo del modo que use, y si éste verifica que el mensaje no se haya modificado en transmisión, por lo que le será más sencillo (aunque igual sigue siendo realmente complejo e inviable).
Supongamos que tenemos el siguiente
script:
aes_gcm.py:
#!/usr/bin/env python
from Crypto.Cipher import AES
def _convert2bytes(s):
return s.encode() if not (isinstance(s, bytes)) else s
def encrypt(plaintext, password):
password = _convert2bytes(password)
plaintext = _convert2bytes(plaintext)
cipher = AES.new(password, AES.MODE_GCM)
nonce = cipher.nonce
ciphertext, tag = cipher.encrypt_and_digest(plaintext)
return nonce+tag+ciphertext
def decrypt(ciphertext, password):
password = _convert2bytes(password)
nonce = ciphertext[:16]
tag = ciphertext[16:32]
ciphertext = ciphertext[32:]
descipher = AES.new(password, AES.MODE_GCM, nonce=nonce)
return descipher.decrypt_and_verify(ciphertext, tag)
Ahora ciframos:
>>> import aes_gcm
>>> key = ("1"*32).encode()
>>> plaintext = "Hello world!"
>>> ciphertext = aes_gcm.encrypt(plaintext.encode(), key)
>>> ciphertext
b"{\xf5$'\x08\xc9\xa1\xdb\x0e\xc9D\x1cm#\xf6\x912g@+\xbe\xe1\xce\xc4\xe6\xb9=Q\t\xe5\xbbV\xb6s\xf4\x9c8\xd34\xee\xee\xecP\xed"
>>> decrypted = aes_gcm.decrypt(ciphertext, key)
>>> decrypted
b'Hello world!'
>>> decrypted.decode() == plaintext
True
>>>
Muy bien. Este modo, con el diligente uso, te permite verificar si el mensaje ha sido corrompido o si ha habido un cambio incongruente. Como por ejemplo:
>>> key = b'0' + key[1:]
>>> key
b'01111111111111111111111111111111'
>>> decrypted = aes_gcm.decrypt(ciphertext, key)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "/tmp/aes_gcm.py", line 27, in decrypt
return descipher.decrypt_and_verify(ciphertext, tag)
File "/home/dtxdf/.local/lib/python3.8/site-packages/Crypto/Cipher/_mode_gcm.py", line 567, in decrypt_and_verify
self.verify(received_mac_tag)
File "/home/dtxdf/.local/lib/python3.8/site-packages/Crypto/Cipher/_mode_gcm.py", line 508, in verify
raise ValueError("MAC check failed")
ValueError: MAC check failed
>>>
Si se nota, simplemente cambié una cifra en la contraseña y generó un error; por supuesto que esto depende de la implantación, pero por lo general, generaría una excepción sin importar la librería.
En caso de que los datos cifrados no sean parte del Los enlaces son solo para miembros.
Registrate o
iniciá sesión se complicaría un poco más. Incluso de podría decir que ya no es inviable, sino que está llegando a lo imposible, pero podría hacer lo siguiente:
aes_cbc.py:
#!/usr/bin/env python
from Crypto.Cipher import AES
from Crypto.Util.Padding import pad, unpad
def _convert2bytes(s):
return s.encode() if not (isinstance(s, bytes)) else s
def encrypt(plaintext, password):
password = _convert2bytes(password)
plaintext = _convert2bytes(plaintext)
cipher = AES.new(password, AES.MODE_CBC)
ciphertext = cipher.encrypt(pad(plaintext, AES.block_size))
return cipher.iv + ciphertext
def decrypt(ciphertext, password):
password = _convert2bytes(password)
iv = ciphertext[:16]
ciphertext = ciphertext[16:]
descipher = AES.new(password, AES.MODE_CBC, iv=iv)
return unpad(descipher.decrypt(ciphertext), AES.block_size)
>>> import aes_cbc
>>> key = ("1"*32).encode()
>>> plaintext = "Hello world!"
>>> ciphertext = aes_cbc.encrypt(plaintext, key)
>>> ciphertext
b';\xa4\xd5\xffgd\xe5\x98\x06i\xab\xbal\x19\xb2\xeai\xa8\x07\xca\xbe\x17U\\)\xc1\x1d\xfc\x03\xb9\xc7\x06'
>>> aes_cbc.decrypt(ciphertext, key)
b'Hello world!'
>>> key = b'0' + key[1:]
>>> aes_cbc.decrypt(ciphertext, key)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "/tmp/aes_cbc.py", line 26, in decrypt
return unpad(descipher.decrypt(ciphertext), AES.block_size)
File "/home/dtxdf/.local/lib/python3.8/site-packages/Crypto/Util/Padding.py", line 93, in unpad
raise ValueError("PKCS#7 padding is incorrect.")
ValueError: PKCS#7 padding is incorrect.
>>>
Esta vez, el caballero que nos ayudó fue el Los enlaces son solo para miembros.
Registrate o
iniciá sesión, que por su naturaleza detectó una anomalía. Pero no siempre éste será el que nos ayudará y como mencioné, depende de la implantación. Entones lo que sí podría aliviar un poco la tensión es detectar si los caracteres son o no, imprimibles, pero claro, esto es con caracteres que mayormente usamos los humanos y no son procesados de una forma especial (como
\n,
\r,
\t, etc.) y también puede ser que desencriptemos el mensaje, pero sea un archivo, y como un archivo puede ser cualquier cosa (incluyendo caracteres
no imprimibles) puede que lo que le digo no sea del todo correcto, pero puede probar el siguiente script para ver si le guía por un camino correcto: Los enlaces son solo para miembros.
Registrate o
iniciá sesiónManualmente el script puede posarse de la siguiente manera (eliminando el relleno):
aes_cbc.py (
sin relleno):
#!/usr/bin/env python
from Crypto.Cipher import AES
def _convert2bytes(s):
return s.encode() if not (isinstance(s, bytes)) else s
def encrypt(plaintext, password):
password = _convert2bytes(password)
plaintext = _convert2bytes(plaintext)
cipher = AES.new(password, AES.MODE_CBC)
ciphertext = cipher.encrypt(plaintext)
return cipher.iv + ciphertext
def decrypt(ciphertext, password):
password = _convert2bytes(password)
iv = ciphertext[:16]
ciphertext = ciphertext[16:]
descipher = AES.new(password, AES.MODE_CBC, iv=iv)
return descipher.decrypt(ciphertext)
>>> import aes_cbc
>>> plaintext = "Buen día mundo.".encode()
>>> len(plaintext)
16
>>> key = ("1"*32).encode()
>>> ciphertext = aes_cbc.encrypt(plaintext, key)
>>> ciphertext
b'\xbb\xf4\x016\xd4\xea\xde\x9f\x92\xc7*\xb2]\xc2\xe8\xb4\xeegt\x9dy\xd9\x14\xa8\xb1\xee\x87\x93{&`\xfa'
>>> aes_cbc.decrypt(ciphertext, key)
b'Buen d\xc3\xada mundo.'
>>> key = b'0' + key[1:]
>>> decrypted = aes_cbc.decrypt(ciphertext, key)
>>> decrypted
b'\x05\xa0?IL!\x8dW\xf1<\x97\x85\x7f\xe7\xa98'
>>> decrypted.decode()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
UnicodeDecodeError: 'utf-8' codec can't decode byte 0xa0 in position 1: invalid start byte
>>>
También es realmente útil indagar sobre algunos modos, que se podrían decir como clásicos, y que están en desuso, como:
* Los enlaces son solo para miembros.
Registrate o
iniciá sesión* Los enlaces son solo para miembros.
Registrate o
iniciá sesiónPuede que lo siguiente también sea igual de útil:
* Los enlaces son solo para miembros.
Registrate o
iniciá sesión~ DtxdF