Spaces:
Sleeping
Sleeping
Create substitution_cipher.py
Browse files- substitution_cipher.py +81 -0
substitution_cipher.py
ADDED
|
@@ -0,0 +1,81 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#!/usr/bin/env python3
|
| 2 |
+
"""
|
| 3 |
+
Cifrado de sustituci贸n estilo AES (solo confusi贸n/ofuscaci贸n).
|
| 4 |
+
Autor: Denisse Aguilar (ejemplo para maestr铆a en Criptograf铆a)
|
| 5 |
+
------------------------------------------------------------------
|
| 6 |
+
Descripci贸n:
|
| 7 |
+
- Genera una S-box (sustituci贸n 1 a 1 de bytes) derivada de una clave.
|
| 8 |
+
- Cifra y descifra texto usando solo sustituci贸n (sin difusi贸n).
|
| 9 |
+
- Basado en la idea del paso SubBytes del AES.
|
| 10 |
+
------------------------------------------------------------------
|
| 11 |
+
Uso (en terminal o Hugging Face):
|
| 12 |
+
>>> from substitution_cipher import encrypt, decrypt
|
| 13 |
+
>>> texto_cifrado = encrypt("Hola mundo", "miClave")
|
| 14 |
+
>>> decrypt(texto_cifrado, "miClave")
|
| 15 |
+
"""
|
| 16 |
+
|
| 17 |
+
import hashlib
|
| 18 |
+
import base64
|
| 19 |
+
import random
|
| 20 |
+
|
| 21 |
+
# ==============================================================
|
| 22 |
+
# 馃攼 Generaci贸n de S-box e inversa
|
| 23 |
+
# ==============================================================
|
| 24 |
+
|
| 25 |
+
def generate_sbox_from_key(key: str):
|
| 26 |
+
"""
|
| 27 |
+
Genera una tabla de sustituci贸n (S-box) de 256 valores 煤nicos basada en la clave.
|
| 28 |
+
"""
|
| 29 |
+
# Deriva una semilla num茅rica de la clave usando SHA-256
|
| 30 |
+
key_hash = hashlib.sha256(key.encode("utf-8")).digest()
|
| 31 |
+
seed = int.from_bytes(key_hash, "big")
|
| 32 |
+
|
| 33 |
+
# Usa PRNG determinista (semilla derivada)
|
| 34 |
+
rng = random.Random(seed)
|
| 35 |
+
|
| 36 |
+
sbox = list(range(256))
|
| 37 |
+
rng.shuffle(sbox) # Permutaci贸n aleatoria 0..255
|
| 38 |
+
inv_sbox = [0] * 256
|
| 39 |
+
for i, v in enumerate(sbox):
|
| 40 |
+
inv_sbox[v] = i
|
| 41 |
+
return sbox, inv_sbox
|
| 42 |
+
|
| 43 |
+
# ==============================================================
|
| 44 |
+
# 馃攣 Funciones de cifrado y descifrado
|
| 45 |
+
# ==============================================================
|
| 46 |
+
|
| 47 |
+
def encrypt(plaintext: str, password: str) -> str:
|
| 48 |
+
"""
|
| 49 |
+
Cifra un texto (string) usando sustituci贸n de bytes.
|
| 50 |
+
Devuelve el resultado en base64.
|
| 51 |
+
"""
|
| 52 |
+
sbox, _ = generate_sbox_from_key(password)
|
| 53 |
+
data = plaintext.encode("utf-8")
|
| 54 |
+
encrypted_bytes = bytes([sbox[b] for b in data])
|
| 55 |
+
return base64.b64encode(encrypted_bytes).decode("utf-8")
|
| 56 |
+
|
| 57 |
+
def decrypt(ciphertext_b64: str, password: str) -> str:
|
| 58 |
+
"""
|
| 59 |
+
Descifra un texto cifrado en base64 usando la misma clave.
|
| 60 |
+
"""
|
| 61 |
+
_, inv_sbox = generate_sbox_from_key(password)
|
| 62 |
+
encrypted_bytes = base64.b64decode(ciphertext_b64)
|
| 63 |
+
decrypted_bytes = bytes([inv_sbox[b] for b in encrypted_bytes])
|
| 64 |
+
return decrypted_bytes.decode("utf-8", errors="ignore")
|
| 65 |
+
|
| 66 |
+
# ==============================================================
|
| 67 |
+
# 馃И Ejemplo de uso
|
| 68 |
+
# ==============================================================
|
| 69 |
+
|
| 70 |
+
if __name__ == "__main__":
|
| 71 |
+
import argparse
|
| 72 |
+
parser = argparse.ArgumentParser(description="Cifrado por sustituci贸n (solo confusi贸n).")
|
| 73 |
+
parser.add_argument("mode", choices=["encrypt", "decrypt"], help="Modo: encrypt o decrypt")
|
| 74 |
+
parser.add_argument("text", help="Texto a cifrar o descifrar")
|
| 75 |
+
parser.add_argument("--key", required=True, help="Clave secreta")
|
| 76 |
+
args = parser.parse_args()
|
| 77 |
+
|
| 78 |
+
if args.mode == "encrypt":
|
| 79 |
+
print(encrypt(args.text, args.key))
|
| 80 |
+
else:
|
| 81 |
+
print(decrypt(args.text, args.key))
|