Wevos yisus
Algo xd
Proyecto 1: Simulación de Cifrado y Firma
Yisus
Materia
Profesor
Fecha
1. Introducción
En este proyecto se tiene como objetivo principal la implementación práctica y demostrativa a
través del lenguaje de programación Python. Mediante la simulación de algoritmos criptográficos
estándar de la industria, se busca comprender el funcionamiento interno de la protección de datos.
1.1. Conceptos Básicos y Herramientas Utilizadas
Para el desarrollo de este proyecto, se abordaron tres actividades, cada una centrada en un meca-
nismo de seguridad especı́fico:
1.1.1. 1. Confidencialidad a través de Cifrado Simétrico (AES)
La confidencialidad garantiza que la información solo sea accesible para las entidades autorizadas.
Para esta actividad se utiliza el algoritmo AES (Advanced Encryption Standard ) en modo CBC.
Cifrado Simétrico: Se emplea una única clave secreta tanto para cifrar como para descifrar
el mensaje.
Vector de Inicialización (IV): Un valor aleatorio que asegura que el mismo mensaje cifrado
dos veces produzca resultados diferentes, aumentando la seguridad contra ataques de patrones.
1.1.2. 2. Integridad y Autenticación (Funciones Hash y HMAC)
La integridad asegura que los datos no han sido alterados, mientras que la autenticación verifica
la identidad del origen.
Hash (SHA-256): Una función matemática unidireccional que genera una ”huella digital”
única del archivo. Cualquier cambio, por mı́nimo que sea (incluso un bit), altera drásticamente
el hash resultante, permitiendo detectar modificaciones no autorizadas.
HMAC (Hash-based Message Authentication Code): Combina una función hash con una clave
secreta compartida, permitiendo verificar no solo que el mensaje está ı́ntegro, sino que proviene
de alguien que posee la clave legı́tima.
1.1.3. 3. No Repudio mediante Firma Digital (RSA)
El No Repudio evita que una entidad niegue haber realizado una acción (como enviar un mensaje
o firmar un contrato).
Cifrado Asimétrico: Utiliza un par de claves matemáticamente vinculadas: una Privada (se-
creta, usada para firmar) y una Pública (compartida, usada para verificar).
Firma Digital: Un mecanismo criptográfico que valida la autenticidad e integridad de un do-
cumento, garantizando que fue generado por el propietario de la clave privada correspondiente.
1
2. Desarrollo
En esta sección se documenta la ejecución de los tres scripts desarrollados, analizando los resultados
obtenidos en la consola para validar los conceptos de Confidencialidad, Integridad, Autenticación
y No Repudio.
2.1. Cifrado Simétrico (Confidencialidad)
Para esta actividad se implementó el algoritmo AES (Advanced Encryption Standard ) en modo
CBC utilizando la librerı́a PyCryptodome. El objetivo fue demostrar que sin la clave secreta generada
aleatoriamente, el mensaje es ilegible.
2.1.1. Librerı́as Criptográficas de Python
from Crypto . Cipher import AES
from Crypto . Util . Padding import pad , unpad
from Crypto . Random import g e t _ r a n d o m _ b y t e s
import os # Para generar el vector de i n i c i a l i z a c i n ( IV )
A continuación, se detallan las funciones de la librerı́a PyCryptodome y estándar de Python utili-
zadas en la simulación:
from [Link] import AES
Permite crear objetos para cifrar y descifrar mensajes usando el algoritmo AES, que es el método
principal utilizado en la simulación.
[Image of AES encryption and decryption process]
from [Link] import pad, unpad
Proporciona funciones para agregar y quitar padding (relleno) al mensaje. Esto es necesario
porque AES solo puede cifrar datos en bloques de tamaño fijo (16 bytes).
from [Link] import get random bytes
Se usa para generar valores aleatorios seguros, como la clave secreta y el vector de inicialización
(IV), garantizando seguridad y entropı́a en el cifrado.
import os
Sirve como apoyo para manejar funciones del sistema, pero en este caso principalmente se men-
ciona para posible generación o gestión de archivos o el IV (aunque get random bytes es más
especı́fico para criptografı́a).
2.1.2. Presentación y Generación de la Clave Secreta
clave_secreta = g e t _ r a n d o m _ b y t e s (16)
print ( f " Clave ␣ secreta ␣ generada :{ clave_secreta . hex () } " )
clave secreta = get random bytes(16)
Genera una clave aleatoria de 16 bytes (128 bits), que es el tamaño estándar para AES-128.
Este valor se obtiene de forma segura y aleatoria, lo que es esencial para la fortaleza criptográfica.
print(fÇlave secreta generada: {clave [Link]()}")
Muestra la clave generada en la consola, pero la convierte a formato hexadecimal (.hex()),
que es una representación más legible y manejable que los bytes crudos.
2
2.1.3. Definición y Codificación del Mensaje
m e n s a j e _ o r i g i n a l = " Este ␣ es ␣ un ␣ mensaje ␣ secreto ␣ para ␣ la ␣ clase . "
print ( f " Mensaje ␣ original :{ m e n s a j e _ o r i g i n a l } " )
# Convertimos el mensaje a bytes , que es lo que requiere el cifrador
mensaje_bytes = m e n s a j e _ o r i g i n a l . encode ( ’utf -8 ’)
mensaje original = .Este es un mensaje secreto para la clase."
Se define la cadena de texto (string) que representa el mensaje que queremos proteger mediante
cifrado.
mensaje bytes = mensaje [Link](’utf-8’)
Se transforma el mensaje a bytes, utilizando la codificación UTF-8. Esta conversión es necesaria
porque el algoritmo AES solo acepta y procesa datos en formato binario para poder cifrarlo.
2.1.4. Proceso de Cifrado del Mensaje
# Proceso de Cifrado
print ( " \ n [ Cifrando ␣ el ␣ mensaje ...] " )
# Creamos un objeto cifrador AES en modo Cipher Block Chaining
iv = g e t _ r a n d o m_ b y t e s ( AES . block_size ) # IV es del t a m a o de 16 bytes
cifrador_aes = AES . new ( clave_secreta , AES . MODE_CBC , iv )
# Padding
mensa je_padd ed = pad ( mensaje_bytes , AES . block_size )
# Ciframos el mensaje
m en sa je _ ci fr ad o = cifrador_aes . encrypt ( mensaje_ padded )
print ( f " Mensaje ␣ cifrado ␣ ( hex ) : ␣ { m en sa je _ ci fr ad o . hex () } " )
print ( f " IV ␣ utilizado ␣ ( hex ) : ␣ { iv . hex () } " )
Generación del Vector de Inicialización (IV)
Se genera un vector de inicialización (IV) aleatorio, necesario en el modo CBC para asegurar
que, aunque se cifre el mismo mensaje varias veces con la misma clave, el resultado sea diferente,
proporcionando mayor seguridad. El IV no es secreto, pero sı́ debe ser único y aleatorio.
Creación del objeto cifrador AES
Se crea el objeto cifrador configurado con la clave secreta, el modo de cifrado CBC y el
IV generado previamente. Este objeto es el encargado de realizar el proceso de cifrado del
mensaje.
Aplicación del Padding
Debido a que AES trabaja con bloques de 16 bytes, si el tamaño del mensaje no es múltiplo
de dicho valor, se le aplica un relleno (padding) para ajustarlo al tamaño requerido.
Cifrado del mensaje
Una vez preparado y rellenado, el mensaje es cifrado mediante el objeto AES. El resultado es un
texto cifrado completamente ilegible, que suele mostrarse en formato hexadecimal.
Elementos necesarios para el descifrado
Para poder recuperar el mensaje original, se requieren dos elementos imprescindibles:
• La clave secreta
• El IV utilizado durante el cifrado
El IV puede enviarse junto con el mensaje cifrado, ya que no es secreto, pero sı́ es indispen-
sable para el descifrado correcto.
3
2.1.5. Descifrado y Verificación (Receptor)
print ( " \ n [ Proceso ␣ de ␣ Descifrado : ␣ ] " )
try :
d es ci fr a do r_ ae s = AES . new ( clave_secreta , AES . MODE_CBC , iv )
# Desciframos el mensaje
m e n s a j e _ d e s c i f r a d o _ p a d d e d = d es ci fr a do r_ ae s . decrypt ( m en sa j e_ ci fr a do )
# Unpadding para obtener el mensaje original
m e n s a j e _ d e s c i f r a d o _ b y t e s = unpad ( mensaje_descifrado_padded , AES . block_size )
# Convertimos de bytes a string
mensaje_final = m e n s a j e _ d e s c i f r a d o _ b y t e s . decode ( ’utf -8 ’)
print ( f " Mensaje ␣ descifrado : ␣ { mensaje_final } " )
# Comprobamos que es igual al original
assert m e n s a j e _ or i g i n a l == mensaje_final
print ( " El ␣ mensaje ␣ se ␣ d e s c i f r ␣ correctamente . " )
except ( ValueError , KeyError ) :
print ( " La ␣ clave ␣ o ␣ el ␣ IV ␣ son ␣ incorrectos . ␣ No ␣ se ␣ pudo ␣ descifrar . " )
En esta sección se simula el proceso de descifrado realizado por el receptor
Se simula el papel del receptor, quien debe tener la misma clave secreta y el mismo IV usados
durante el cifrado. Con estos elementos crea un nuevo objeto descifrador AES.
Se aplica el proceso de descifrado sobre el mensaje cifrado. El resultado aún no es legible porque
contiene el relleno (padding) agregado durante el cifrado.
Se elimina ese relleno usando la función unpad, obteniendo ası́ los bytes del mensaje original.
Luego, esos bytes se convierten nuevamente a un texto legible (string) con el mensaje original.
Se realiza una verificación automática para comprobar que el mensaje recuperado es exacta-
mente igual al que se envió al inicio. Si coincide, se muestra el mensaje de éxito; si la clave o el
IV son incorrectos, el descifrado falla y se muestra un mensaje de error de padding,
4
2.1.6. Prueba de Robustez (Descifrado con Clave Incorrecta)
print ( " \ n [ Simulando ␣ una ␣ clave ␣ incorrecta : ␣ ] " )
try :
c l a v e _ i n c o r r e ct a = g e t _ ra n d o m _ b y t e s (16)
d e s c i f r a d o r _ f a l l i d o = AES . new ( clave_incorrecta , AES . MODE_CBC , iv )
datos_basura = d e s c i f r a d o r _ f a l l i d o . decrypt ( m e ns aj e_ c if ra do )
unpad ( datos_basura , AES . block_size )
except ValueError :
print ( " El ␣ descifrado ␣ f a l l . " )
Esta sección simula un intento de acceso no autorizado, demostrando que la Confidencialidad se
mantiene ante la ausencia de la clave correcta:
Primero, se genera una clave diferente a la utilizada durante el cifrado, simulando ser la clave
de un atacante.
Con esa clave equivocada (pero usando el mismo IV correcto), se crea un nuevo objeto descifrador.
El intento de descifrado se envuelve en un bloque de manejo de errores (try...except) para
capturar el fallo esperado.
El resultado del descifrado es un conjunto de datos basura, ya que la clave no coincide con la
original.
Al intentar quitar el padding (relleno), el sistema detecta que el contenido resultante no es
válido criptográficamente, lo que provoca un error de tipo ValueError o de padding.
Este error es capturado y se muestra el mensaje indicando que el descifrado falló, demostrando
que sin la clave correcta no es posible recuperar el mensaje original (pilar de la Confidencialidad).
2.1.7. Resultados:
Figura 1: Generación de Claves y Entrada
En esta primera etapa se establece la seguridad del sistema. Se genera aleatoriamente una clave
de 128 bits (representada por 32 caracteres hexadecimales). Esta clave es el componente crı́tico de la
Simetrı́a: la misma secuencia c3a4... será necesaria tanto para cifrar como para descifrar la información.
Mientras que mensaje se muestra en texto plano, siendo legible antes de aplicar el algoritmo.
Figura 2: Proceso de Cifrado
Criptograma: El mensaje original ha sido transformado en una cadena hexadecimal ininteligible
(669d...). Esto demuestra el principio de Confidencialidad: si un atacante intercepta esta
cadena, no podrá obtener información útil sin la clave.
Vector de Inicialización (IV): Se muestra el IV aleatorio (2477...) utilizado para iniciar
el encadenamiento de bloques (en modo CBC). Este valor asegura que, aunque cifremos
el mismo mensaje varias veces, el resultado cifrado siempre sea diferente, evitando ataques de
análisis de patrones.
5
Figura 3: Verificación de Descifrado
Este bloque valida la Disponibilidad y corrección del algoritmo. Al aplicar la función de descifra-
do utilizando la clave correcta (c3a4...) y el IV original, el sistema es capaz de revertir el proceso
matemático y recuperar el mensaje original sin pérdida de datos ni errores de codificación.
Figura 4: Prueba de Seguridad
Esta es la prueba definitiva de robustez. Se intentó descifrar el criptograma utilizando una clave dis-
tinta a la original. El sistema, al no poder validar el relleno (padding) correcto debido a la clave errónea,
rechaza la operación. Esto confirma que es matemáticamente imposible acceder a la información sin
poseer la credencial exacta, garantizando la seguridad del sistema frente a accesos no autorizados.
2.2. Funciones Hash y MAC (Integridad y Autenticación)
2.2.1. Librerı́as para Integridad y Autenticación
import hashlib # Para SHA -256
import hmac # Para HMAC
import os
import hashlib
Permite usar funciones hash como SHA-256, que se usan para verificar la integridad de archivos
o mensajes detectando cualquier modificación.
import hmac
Se utiliza para generar y verificar códigos de autenticación de mensajes (MAC), que
garantizan integridad y autenticidad, ya que requieren una clave secreta compartida.
import os
Se usa para operaciones relacionadas con el sistema, como crear, modificar o eliminar ar-
chivos, lo cual es necesario para los ejemplos prácticos de hash donde se simula la alteración de
un archivo.
6
2.2.2. Cálculo del Hash SHA-256 (Integridad)
# Creamos un archivo de texto de ejemplo
nombr e_archi vo = " me n sa je _s e cr et o . txt "
c o n t e n i d o _ o r i g i n a l = " Este ␣ es ␣ el ␣ contenido ␣ original ␣ del ␣ archivo . ␣ No ␣ debe ␣ ser ␣
modificado . "
with open ( nombre_archivo , " w " , encoding = " utf -8 " ) as f :
f . write ( c o n t e n i d o _ o r i g i n a l )
print ( f " Archivo ␣ ’{ nombre_a rchivo } ’ ␣ creado ␣ con ␣ contenido ␣ original . " )
def c a l c u l a r _ h a s h _ a r c h i v o ( filepath ) :
" " " Calcula ␣ el ␣ hash ␣ SHA -256 ␣ de ␣ un ␣ archivo . " " "
sha256_hash = hashlib . sha256 ()
try :
with open ( filepath , " rb " ) as f : # Abrir en modo binario ’ rb ’
# Leer y actualizar el hash en bloques para no sobrecargar la memoria
for byte_block in iter ( lambda : f . read (4096) , b " " ) :
sha256_hash . update ( byte_block )
return sha256_hash . hexdigest ()
except F i l e N o t F o u n d E r r o r :
return None
nombre archivo = "mensaje [Link]"
with open(nombre archivo, ’w’) as f: [Link](Çontenido original...")
Primero, se crea un archivo llamado mensaje [Link] con un contenido especı́fico. Este
archivo sirve como ejemplo para comprobar la integridad, es decir, verificar si su contenido
cambia o no.
def calcular hash archivo(nombre archivo): ...
Luego, se define la función calcular hash archivo, que calcula el hash SHA-256 del archivo
que se le indique.
Proceso de la Función Hash:
• Abre el archivo en modo binario (’rb’), como lo requiere SHA-256.
• Lee el contenido por bloques (chunks), lo que permite procesar archivos grandes sin con-
sumir mucha memoria.
• Va actualizando el hash con cada bloque leı́do.
• Al finalizar, devuelve el hash final en formato hexadecimal, que es la “huella digital”
única del archivo.
• Si el archivo no existe, devuelve None.
2.2.3. Simulación de Alteración (Efecto Avalancha)
# 1. Calculamos y mostramos el hash original
hash_original = c a l c u l a r _ h a s h _ a r c h i v o ( nom bre_arc hivo )
print ( f " Hash ␣ SHA -256 ␣ original : ␣ { hash_original } " )
# 2. S i m u l a c i n de Ataque de Integridad
print ( " \ n [ Simulando ␣ ataque : ␣ modificando ␣ 1 ␣ byte ␣ del ␣ archivo ...] " )
try :
with open ( nombre_archivo , " r + b " ) as f : # Abrir en modo lectura / escritura binaria
f . seek (10) # Moverse al byte 10
f . write ( b " X " ) # Sobrescribir ese byte
print ( " Archivo ␣ modificado ! " )
except Exception as e :
print ( f " Error ␣ al ␣ modificar ␣ archivo : ␣ { e } " )
# 3. Recalculamos el hash
h as h_ mo d if ic ad o = c a l c u l a r _ h a s h _ a r c h i v o ( nombre _archivo )
print ( f " Hash ␣ SHA -256 ␣ nuevo :{ h as h_ m od if ic a do } " )
7
Esta sección demuestra cómo un cambio mı́nimo en un archivo modifica completamente su hash,
evidenciando una alteración en la integridad (Efecto Avalancha).
hash original = calcular hash archivo(nombre archivo)
Primero, se calcula el hash original del archivo, que representa su estado inicial y correcto.
with open(nombre archivo, ’a’) as f: [Link](¡")
Luego, se simula un ataque de integridad, modificando solo un byte del archivo (por ejemplo,
añadiendo un ¡" al final). Aunque el cambio es mı́nimo, se hace para demostrar que incluso una
pequeña alteración afecta drásticamente el hash.
hash modificado = calcular hash archivo(nombre archivo)
Después de la modificación, se vuelve a calcular el hash del archivo.
if hash original != hash modificado: ...
Este nuevo hash es totalmente diferente al original, lo cual es detectado por el script, con-
firmando que el archivo fue alterado y se ha perdido la integridad.
2.2.4. Verificación y Limpieza
# 4. Comparamos los hashes
if hash_original != h as h_ mo d if ic ad o :
print ( " ALERTA ␣ DE ␣ INTEGRIDAD ! ␣ El ␣ hash ␣ ha ␣ cambiado ␣ d r s t i c a m e n t e . ␣ El ␣ archivo ␣ fue ␣
alterado . " )
else :
print ( " El ␣ hash ␣ es ␣ i d n t i c o ␣ ( esto ␣ no ␣ d e b e r a ␣ pasar ) . " )
# Limpiamos el archivo
os . remove ( n ombre_a rchivo )
if hash original != hash modificado: ...
Se comparan el hash original y el hash modificado.
• Si son diferentes, significa que el archivo fue alterado y se muestra una alerta de pérdida
de integridad.
• Si fueran iguales (lo cual solo es posible si no hubo cambios), significarı́a que no hubo
alteraciones.
[Link](nombre archivo)
Finalmente, se elimina el archivo de prueba (mensaje [Link]) utilizado, dejando limpia la
carpeta de trabajo.
2.2.5. Generación del HMAC (Autenticación)
# --- Parte B : MAC ( HMAC ) para Integridad y Autenticidad ---
print ( " \n - - - ␣ Parte ␣ B : ␣ HMAC - SHA256 ␣ para ␣ Integridad ␣ y ␣ Autenticidad ␣ ---" )
# El emisor y el receptor deben compartir una clave secreta
c l a v e _ c o m p a r t i d a _ m a c = b ’ m i _ c l a v e _ s e c r e t a _ p a r a _ h m a c ’ # b ’ indica bytes
# Mensaje que e n v a el emisor
mensaje_mac = b " Este ␣ es ␣ un ␣ mensaje ␣ que ␣ debe ␣ ser ␣ autenticado . "
# 1. Emisor : Calcula el HMAC
# Se usa la clave , el mensaje y una f u n c i n hash ( SHA -256)
hmac_ calcula do = hmac . new ( clave_compartida_mac , mensaje_mac , hashlib . sha256 )
mac_d el_emis or = hma c_calcu lado . hexdigest ()
print ( f " Mensaje : ␣ { mensaje_mac . decode () } " )
print ( f " MAC ␣ enviado ␣ por ␣ el ␣ emisor : ␣ { ma c_del_e misor } " )
Esta sección simula el proceso de generación de un Código de Autenticación de Mensaje
(HMAC) que garantiza tanto la Integridad como la Autenticidad del mensaje.
8
clave mac = [Link](16)
Primero, se define una clave secreta compartida entre el emisor y el receptor. Esta clave
asegura que solo quienes la conocen puedan generar o verificar el MAC.
mensaje autenticacion = [Link] mensaje debe ser autentico."
Luego, se establece el mensaje que será autenticado. Se utiliza el prefijo b para indicar que es
un literal de bytes, ya que HMAC trabaja directamente con este formato.
mac = [Link](clave mac, mensaje autenticacion, hashlib.sha256)
El emisor usa la clave secreta, el mensaje y el algoritmo SHA-256 para generar un HMAC
(Hash-based Message Authentication Code).
mac final = [Link]().hex()
El resultado es un código único (MAC) que funciona como una firma digital del mensaje. Si
el mensaje o la clave cambian, ese código será diferente.
print("Mensaje:", mensaje [Link]())
print("HMAC generado:", mac final)
Finalmente, se muestra el mensaje original y su MAC, que será enviado al receptor a través de
un canal potencialmente inseguro.
2.2.6. Verificación del HMAC (Receptor)
# El receptor tiene el mensaje , el MAC recibido y la clave compartida
print ( " \ n [ Receptor ␣ verificando ␣ el ␣ mensaje ...] " )
def verificar_mac ( clave_recibida , mensaje_recibido , mac_recibido ) :
# El receptor recalcula el MAC con su clave y el mensaje recibido
hmac_receptor = hmac . new ( clave_recibida , mensaje_recibido , hashlib . sha256 )
m ac _r ec a lc ul ad o = hmac_receptor . hexdigest ()
if hmac . co mpare_d igest ( mac_recalculado , mac_recibido ) :
print ( " V E R I F I C A C I N ␣ EXITOSA : ␣ El ␣ mensaje ␣ es ␣ ntegro ␣ y ␣ a u t n t i c o ␣ ( proviene ␣
del ␣ emisor ␣ correcto ) . " )
else :
print ( " V E R I F I C A C I N ␣ FALLIDA : ␣ El ␣ mensaje ␣ fue ␣ alterado ␣ o ␣ la ␣ clave ␣ es ␣ incorrecta
.")
Esta parte del código simula el proceso de verificación del mensaje por parte del receptor,
utilizando el HMAC recibido para validar la Integridad y Autenticidad.
def verificar mac(clave, mensaje, mac recibido): ...
Se define la función verificar mac, que recibe como parámetros:
1. La clave secreta compartida.
2. El mensaje recibido.
3. El MAC recibido.
mac recalculado = [Link](clave, mensaje, hashlib.sha256)
El receptor recalcula el MAC usando su propia clave y el mensaje recibido. Si el mensaje o la
clave han sido alterados, el MAC recalculado será diferente al MAC que recibió.
[Link] digest(mac [Link](), [Link](mac recibido))
Se utiliza [Link] digest, que es una forma segura y resistente a ataques de temporiza-
ción, para comparar el MAC original con el MAC recalculado.
• Si ambos coinciden =⇒ el mensaje es auténtico y no fue alterado.
• Si no coinciden =⇒ el mensaje fue modificado o la clave no es válida, indicando un fallo
en la autenticación.
9
2.2.7. Simulación de Escenarios HMAC
# S i m u l a c i n 1: V e r i f i c a c i n correcta
verificar_mac ( clave_compartida_mac , mensaje_mac , mac_del _emisor )
# S i m u l a c i n 2: Falla por mensaje alterado ( Ataque de Integridad )
print ( " \ n [ Simulando ␣ mensaje ␣ alterado ...] " )
m e n s a j e _ a l t e r a d o = b " Este ␣ es ␣ un ␣ mensaje ␣ que ␣ HA ␣ SIDO ␣ alterado . "
verificar_mac ( clave_compartida_mac , mensaje_alterado , mac_del _emisor )
# S i m u l a c i n 3: Falla por clave incorrecta ( Ataque de Autenticidad )
print ( " \ n [ Simulando ␣ clave ␣ incorrecta ...] " )
clave _atacan te = b ’ c l a v e _ i n c o r r e c t a _ d e l _ a t a c a n t e ’
verificar_mac ( clave_atacante , mensaje_mac , ma c_del_em isor )
print ( " -" * 40 + " \ n " )
Esta sección realiza tres simulaciones para comprobar cómo funciona la autenticación con HMAC
en diferentes escenarios de ataque y verificación.
Simulación 1: Verificación Correcta
verificar mac(clave mac, mensaje autenticacion, mac final)
• Se usan el mensaje original, la clave correcta y el MAC generado por el emisor.
• Resultado: La verificación es exitosa, confirmando la integridad y la autenticidad del
mensaje.
Simulación 2: Ataque de Integridad (Mensaje Alterado)
mensaje alterado = [Link] mensaje fue modificado."
• Se modifica el contenido del mensaje (mensaje alterado), pero se mantiene la misma
clave y el mismo MAC.
• Resultado: La verificación falla porque el mensaje fue alterado. Esto demuestra que el
HMAC detecta cambios aunque sean mı́nimos.
Simulación 3: Ataque de Autenticidad (Clave Incorrecta)
clave incorrecta = [Link](16)
• Se usa el mensaje original, pero con una clave diferente a la usada para generar el
MAC.
• Resultado: La verificación falla, demostrando que sin la clave correcta (secreta) no se
puede autenticar el mensaje.
10
2.2.8. Resultados:
Figura 5: Detección de Integridad
En la primera parte del experimento, se calcula el hash SHA-256 de un archivo original y se guarda
como referencia. Luego se simula un ataque de integridad, modificando intencionalmente solo un
byte del archivo.
Aunque el cambio es mı́nimo, el nuevo hash obtenido es completamente diferente al original
(Efecto Avalancha). Esto demuestra que:
Los hashes son extremadamente sensibles: una mı́nima modificación genera un hash total-
mente distinto.
Sirven como mecanismo de detección de integridad: si el hash cambia, significa que el
archivo fue alterado.
El sistema correctamente alerta: “El archivo fue alterado.”
Figura 6: Integridad y Autenticidad (HMAC)
Esta salida muestra cómo funciona la verificación de integridad y autenticidad usando HMAC-
SHA256:
Primero, se calcula un código MAC usando una clave secreta compartida y el mensaje. Este
MAC actúa como una firma digital que garantiza que el mensaje no fue modificado y que
proviene del emisor legı́timo.
Verificación Exitosa: En la primera verificación, el receptor obtiene el mismo resultado, lo que
confirma que:
El mensaje está intacto (Integridad).
El emisor es auténtico (Autenticidad).
Fallo por Alteración del Mensaje: Luego se simula una modificación del mensaje. Aunque
el MAC recibido es el mismo, al recalcularlo el receptor obtiene un valor diferente, indicando:
11
× Integridad rota → el mensaje fue alterado.
Fallo por Clave Incorrecta: Finalmente, se prueba con una clave incorrecta. Aunque el
mensaje es el original, el MAC generado por el receptor no coincide con el MAC recibido:
× Falla de autenticidad → el emisor no es confiable (no tiene la clave real).
2.3. Firma Digital (No Repudio)
Se utilizó el algoritmo RSA (criptografı́a asimétrica) para generar un par de claves. El objetivo fue
demostrar el ”No Repudio”, es decir, que el emisor no puede negar haber firmado el documento.
2.3.1. Librerı́as para Firma Digital RSA (No Repudio)
from cryptography . hazmat . primitives import hashes
from cryptography . hazmat . primitives . asymmetric import rsa , padding
from cryptography . hazmat . primitives . serialization import (
load_pem_private_key , load_pem_public_key ,
PrivateFormat , PublicFormat , NoEncryption
)
from cryptography . exceptions import I n v al i d S i g n a t u r e
Este bloque importa las herramientas de la librerı́a cryptography que se usan en la actividad de
Firma Digital con RSA (Criptografı́a Asimétrica).
from [Link] import hashes
Proporciona funciones de resumen criptográfico (p. ej. SHA-256). Se usan para hashear el
mensaje antes de firmarlo o verificar la firma.
from [Link] import rsa
Contiene utilidades para generar y manipular claves RSA (creación de la clave privada, deriva-
ción de la pública, operaciones asociadas).
from [Link] import padding
Incluye esquemas de relleno seguros para operaciones asimétricas (por ejemplo, PSS para
firmas). El padding evita vulnerabilidades matemáticas y estandariza el proceso de firma/verifi-
cación.
from [Link] import ...
load pem private key, load pem public key: Funciones para cargar claves desde datos en
formato PEM (texto codificado). Se usan si quieres leer claves desde archivos o cadenas PEM en
vez de generarlas en memoria.
from [Link] import ...
PrivateFormat, PublicFormat, NoEncryption: Constantes/formatos usados al serializar cla-
ves (convertirlas a bytes/PEM). Permiten elegir el formato de salida para la clave privada o
pública y si la clave privada se encripta al guardarla (NoEncryption indica que no usar cifrado).
from [Link] import InvalidSignature
Excepción que se lanza cuando la verificación de una firma falla. Permite capturar y manejar
de forma clara el caso en que la firma no coincide con el mensaje y la clave pública.
2.3.2. Generación del Par de Claves RSA
print ( " [ Generando ␣ par ␣ de ␣ claves ␣ RSA ␣ ( P b l i c a ␣ y ␣ Privada ) ...] " )
clave_privada = rsa . g e n e r a t e _ p r i v a t e _ k e y (
p ub li c_ e xp on en t =65537 ,
key_size =2048 , # T a m a o de la clave en bits
)
# La clave p b l i c a se deriva de la clave privada
clave_publica = clave_privada . public_key ()
print ( " Claves ␣ generadas . ␣ La ␣ CLAVE ␣ PRIVADA ␣ se ␣ mantiene ␣ secreta . ␣ La ␣ CLAVE ␣ P B L I C A ␣ se ␣
comparte . " )
12
Este fragmento genera un par de claves RSA (Asimétricas) y establece su propósito fundamental
para el No Repudio:
private key = [Link] private key(...)
Generación de claves: Se crea una clave privada RSA usando el método [Link] private key()
con:
• public exponent=65537: Valor estándar y seguro utilizado en RSA.
• key size=2048: Tamaño de la clave (nivel de seguridad fuerte).
public key = private [Link] key()
Obtención de la clave pública: A partir de la clave privada, se obtiene la clave pública con
.public key(). En RSA, la clave pública siempre se deriva matemáticamente de la privada.
Uso de las claves:
• La clave privada permite firmar digitalmente (debe mantenerse secreta).
• La clave pública se usa para verificar la firma (puede ser compartida públicamente).
2.3.3. Firma Digital del Mensaje (Emisor)
print ( " \ n [ Emisor : ␣ Firmando ␣ un ␣ documento ...] " )
m e n s a j e _ o r i g i n a l = b " Yo , ␣ el ␣ emisor , ␣ me ␣ comprometo ␣ a ␣ cumplir ␣ este ␣ contrato . "
print ( f " Mensaje : ␣ { m e n s a j e _ o r i g i n a l . decode () } " )
firma_digital = clave_privada . sign (
mensaje_original ,
padding . PSS (
mgf = padding . MGF1 ( hashes . SHA256 () ) ,
salt_length = padding . PSS . MAX_LENGTH
),
hashes . SHA256 ()
)
print ( f " Firma ␣ generada ␣ ( hex ) : ␣ { firma_digital . hex () } " )
Este bloque representa el proceso de Firma Digital realizado por el emisor, estableciendo el
compromiso y garantizando el No Repudio.
mensaje = [Link] es el mensaje que se va a firmar."
Mensaje a firmar: Se define el mensaje original en formato de bytes, que es el contenido que
el emisor quiere certificar digitalmente.
signature = private [Link](...)
Firma con la clave privada: El emisor utiliza su clave privada RSA para generar una firma
digital. El proceso sign() realiza dos pasos internamente:
1→ Aplica un hash SHA-256 al mensaje (resumen único).
2→ Cifra ese hash con la clave privada, generando la firma digital.
[Link](...)
Uso de padding PSS: Se utiliza [Link] (Probabilistic Signature Scheme), que es un
estándar moderno y seguro que evita ataques criptográficos y hace la firma más robusta.
Resultado: Se genera la firma digital (una cadena en hexadecimal), que sirve como prueba de
autenticidad y compromiso del emisor.
⋄ Envı́o: La firma, junto con el mensaje y la clave pública del emisor, se envı́an al receptor para
que pueda verificar su autenticidad.
13
2.3.4. Verificación de la Firma Digital (Receptor)
# --- 3. Proceso de V e r i f i c a c i n ( Receptor / P b l i c o ) ---
print ( " \ n [ Receptor : ␣ Verificando ␣ la ␣ firma ...] " )
# El receptor usa la CLAVE P B L I C A del emisor para verificar .
def v er if ic a r_ fi rm a ( public_key , mensaje , firma ) :
try :
# El m t o d o ’ verify ’ descifra la firma con la clave p b l i c a ,
# recalcula el hash del mensaje y los compara .
public_key . verify (
firma ,
mensaje ,
padding . PSS (
mgf = padding . MGF1 ( hashes . SHA256 () ) ,
salt_length = padding . PSS . MAX_LENGTH
),
hashes . SHA256 ()
)
print ( " V E R I F I C A C I N ␣ EXITOSA : ␣ La ␣ firma ␣ es ␣ v l i d a . ␣ El ␣ mensaje ␣ es ␣ a u t n t i c o ␣ y ␣
el ␣ emisor ␣ no ␣ puede ␣ negarlo ␣ ( No ␣ Repudio ) . " )
return True
except I n v a l i d S ig n a t u r e :
print ( " V E R I F I C A C I N ␣ FALLIDA : ␣ La ␣ firma ␣ no ␣ es ␣ v l i d a ! ␣ El ␣ mensaje ␣ fue ␣
alterado ␣ o ␣ la ␣ firma ␣ es ␣ falsa . " )
return False
except Exception as e :
print ( f " O c u r r i ␣ un ␣ error ␣ en ␣ la ␣ v e r i f i c a c i n : ␣ { e } " )
return False
Este bloque representa el proceso de verificación de la firma digital por parte del receptor,
asegurando la Integridad y el No Repudio.
Propósito: El receptor usa la clave pública del emisor para comprobar si la firma digital es
válida y si el mensaje no ha sido modificado.
try: public [Link](...) except InvalidSignature: ...
Proceso de la Función verify():
1. La función verify() recibe tres datos: la clave pública, el mensaje recibido y la firma
digital.
2. El método verify() realiza dos operaciones claves:
• Descifra la firma usando la clave pública para obtener el hash original que generó el
emisor.
• Calcula nuevamente el hash del mensaje recibido usando SHA-256 y lo compara
con el hash obtenido de la firma.
Resultado Exitoso: Si ambos hashes coinciden, el bloque try se ejecuta con éxito:
La firma es válida.
El mensaje es auténtico (no fue alterado).
La firma pertenece al emisor, garantizando el No Repudio.
Resultado Fallido: Si los hashes no coinciden o la firma no corresponde a la clave pública, se
captura la excepción InvalidSignature:
× Se muestra un mensaje de VERIFICACIÓN FALLIDA, indicando alteración del men-
saje o firma falsa.
14
2.3.5. Resultados:
Figura 7: Inicio del proceso de Firma Digital con RSA)
En los resultados se observa cómo se generan las claves RSA y cómo el emisor firma un documento
usando su clave privada. El programa muestra el mensaje original y su firma digital correspondiente
(en formato hexadecimal). Esta firma es única para ese mensaje y permite que cualquier receptor,
usando la clave pública, pueda verificar su autenticidad, integridad y origen.
Figura 8: Verificación de la firma digital
En esta etapa, se verifica la firma digital utilizando la clave pública del emisor. Cuando el mensaje
y la firma son auténticos, la verificación es exitosa, lo que confirma la autenticidad, integridad y
no repudio. Sin embargo, si el mensaje se altera o se utiliza una firma falsa, la verificación falla,
demostrando que la firma digital protege contra modificaciones y falsificaciones.
3. Conclusión
A través de las tres actividades desarrolladas, fue posible comprender de manera práctica cómo
funcionan los mecanismos de seguridad en la comunicación digital. En primer lugar, se analizó el
uso del hash, observando cómo permite identificar cualquier cambio en un mensaje gracias a que
genera un valor único e irrepetible. Posteriormente, se trabajó con el cifrado simétrico, donde se
evidenció cómo la información puede mantenerse confidencial siempre que la clave usada para cifrar
y descifrar permanezca protegida. Finalmente, en la actividad de firma digital, se demostró cómo se
puede garantizar no solo la integridad y autenticidad del mensaje, sino también evitar que el emisor
pueda negar su participación (no repudio).
En conjunto, estas actividades permitieron comprender que los sistemas de seguridad no funcionan
aislados, sino que se complementan para proteger la información desde diferentes ángulos: confiden-
cialidad, integridad, autenticidad y no repudio. Además, se logró ver de forma aplicada cómo estos
conceptos, que a veces pueden parecer abstractos, son fundamentales para asegurar la confianza y
validez en los sistemas y comunicaciones digitales actuales.
Referencias
1. Al-Komah, F. (2024). Authenticate and Verification Source Files using SHA256 and HMAC
Algorithms. Preprints, 2024070075. [Link]
15