Created
February 10, 2010 22:49
-
-
Save anonymous/300930 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/python | |
""" | |
Criptosistema ACYMOS2 por Agustin, Kriptopolis | |
Notas: | |
"~" representa la "enye" | |
Los comentarios estan sin acentos y caracteres especiales | |
by xiscu [en] email [punto] de | |
""" | |
import re | |
from decimal import * | |
from math import * | |
############################################################################### | |
# CONFIGURACION Y CONSTANTES | |
## El alfabeto basico | |
ALFABETO_BASE = list('ABCDEFGHIJKLMN~OPQRSTUVWXYZ_') | |
ALFA_N = len(ALFABETO_BASE) | |
## Traducciones | |
espacio = re.compile(' ') # 1 | |
enye = re.compile('\xc3\x91') # 2 | |
retorno = re.compile('\n') # 3 | |
## Numero de Cifras decimales | |
ND = 10 | |
DIEZ_DECIMALES = Decimal(10) ** -ND | |
## Fichero con numeros primeros | |
FICHERO_PRIMOS = '100000_primos.txt' | |
PRIMOS=[] | |
############################################################################### | |
# FUNCIONES INTERNAS | |
def lee_primos(): | |
f=None | |
try: | |
f=open(FICHERO_PRIMOS) | |
for linea in f: | |
primos_texto=linea.split() | |
for p in primos_texto: | |
PRIMOS.append(int(p)) | |
except: | |
raise | |
finally: | |
if f: | |
f.close() | |
## Lee los primos | |
lee_primos() | |
## Constante PI_DECIMAL | |
PI_DEC = Decimal('3.1415926536') | |
############################################################################### | |
# FUNCIONES EXPORTADAS | |
def texto_a_ascii(texto): | |
"""Traduce un texto a ascii | |
""" | |
tt = espacio.sub('_', texto) # 1 | |
tt = enye.sub('~', tt) # 2 | |
tt = retorno.sub('', tt) # 3 | |
return tt | |
def lan(alfabeto, letras): | |
"""Traduce una o una lista de letras a numeros segun el orden del alfabeto | |
""" | |
index_mas1 = lambda letra: alfabeto.index(letra) + 1 | |
if len(letras)==1: | |
return index_mas1(letras) | |
else: | |
return map(index_mas1, letras) | |
def primo_n(n): | |
"""Retorna el primo numero n, empezando a contar por 0 | |
""" | |
return PRIMOS[n] | |
def s_alfa(clave): | |
"""Calcula la semilla para contruir el alfabeto derivado con la clave dada | |
""" | |
s=Decimal(0) | |
pn=0 | |
for c in clave: | |
n=lan(ALFABETO_BASE, c) | |
s+=n * Decimal(primo_n(pn)).log10() | |
pn+=1 | |
# Desplazamiento | |
d=s.adjusted()+1 | |
s=s/Decimal(10**d) | |
return s.quantize(DIEZ_DECIMALES) | |
def s_cifra(clave): | |
"""Calcula la semilla para contruir el cifrado (Ai) con la clave dada | |
""" | |
s=Decimal(0) | |
alfa_derivado=alfa_k(clave) | |
pn=0 | |
for c in clave: | |
n=lan(alfa_derivado, c) | |
s+=n * Decimal(primo_n(pn)).log10() | |
pn+=1 | |
# Desplazamiento | |
d=s.adjusted()+1 | |
s=s/Decimal(10**d) | |
return s.quantize(DIEZ_DECIMALES) | |
def pseudo(s): | |
"""Calcula el siguiente numero pseudo aleatorio | |
""" | |
resto = divmod((PI_DEC + s)**2, Decimal(1))[1] | |
return resto.quantize(DIEZ_DECIMALES) | |
def fn_a(l, s): | |
"""Funcion A para el calculo de la siguiente letra en el alfabeto | |
derivado | |
""" | |
n = s * (l-1)+1 | |
# Solo la parte entera | |
return int(n.quantize(1)) | |
def alfa_k(clave): | |
"""Calcula el alfabeto derivado para la clave dada | |
""" | |
s = s_alfa(clave) | |
alfa_act = list(ALFABETO_BASE) | |
alfa_derivado = [] | |
for n in range(ALFA_N): | |
# Numero pseudoaleatorio | |
s = pseudo(s) | |
# L (Longitud restante) | |
l = ALFA_N - n | |
# Funcion A (el "-1" es para el siguiente indexado) | |
p = fn_a(l, s) - 1 | |
# Nueva letra | |
alfa_derivado.append(alfa_act[p]) | |
# Resto alfabeto | |
alfa_act = alfa_act[0:p] + alfa_act[p+1::] | |
return alfa_derivado | |
def ldist(letra, pos): | |
"""Toma una letra a distancia "x" del alfabeto base | |
""" | |
nueva_letra = (ALFABETO_BASE.index(letra) + pos) % NUM_LETRAS | |
return ALFABETO_BASE[nueva_letra] | |
def codifica(clave, texto, formato_s='t'): | |
"""Codifica un texto con la clave | |
Uso: codifica(clave, texto, formato) | |
Donde los parametros son: | |
- clave: clave usada para cifrar (en mayusculas) | |
- texto: texto a cifrar (en mayusculas y ya traducido) | |
- formato_s: formato de salida. 't' texto (por defecto) y 'n' numerico | |
""" | |
# Alfabeto derivado | |
alfa_d = alfa_k(clave) | |
# Tamano de la clave | |
clave_n = len(clave) | |
# Posiciones de las letras de la clave en el alfabeto derivado | |
clave_ki = lan(alfa_d, clave) | |
# Semilla aleatoria para la el calculo del cifrado | |
s0 = s_cifra(clave) | |
# Cifrado | |
cifra = [] | |
sa = s0 | |
for n, ca in enumerate(texto): | |
sa = pseudo(sa) | |
a = fn_a(ALFA_N, sa) | |
k = clave_ki[n % clave_n] | |
p = lan(alfa_d, ca) | |
c = (a + p + k) % ALFA_N | |
if c == 0: | |
c = ALFA_N | |
cifra.append(c) | |
# Formato de salida en texto ? | |
if formato_s == 't': | |
pos_menos1 = lambda pos: alfa_d.__getitem__(pos-1) | |
return ''.join(map(pos_menos1, cifra)) | |
return cifra | |
def decodifica(clave, texto, formato_s='t'): | |
""" Decodifica un texto con la clave | |
Uso: decodifica(clave, texto, formato) | |
Donde los parametros son: | |
- clave: clave para descifrar (en mayusculas) | |
- texto: texto a descifrar (en mayusculas) | |
- formato_s: formato de salida. 't' texto (por defecto) y 'n' numerico | |
""" | |
# Alfabeto derivado | |
alfa_d = alfa_k(clave) | |
# Tamano de la clave | |
clave_n = len(clave) | |
# Posiciones de las letras de la clave en el alfabeto derivado | |
clave_ki = lan(alfa_d, clave) | |
# Semilla aleatoria para la el calculo del cifrado | |
s0 = s_cifra(clave) | |
# Cifrado | |
claro = '' | |
sa = s0 | |
for n, ca in enumerate(texto): | |
sa = pseudo(sa) | |
a = fn_a(ALFA_N, sa) | |
k = clave_ki[n % clave_n] | |
c = lan(alfa_d, ca) | |
p = (c - a - k) % ALFA_N | |
p = p % ALFA_N | |
if p == 0: | |
p = ALFA_N | |
claro += alfa_d[p-1] | |
# Formato de salida numerico ? | |
if formato_s == 'n': | |
index_mas1 = lambda pos: ALFABETO_BASE.index(pos) + 1 | |
claro = map(index_mas1, claro) | |
return claro | |
############################################################################### | |
# Ejecucion directa del modulo: Ejecuta los tests | |
# | |
if __name__ == '__main__' : | |
import unittest | |
########################################################################### | |
# Definicion de los tests | |
class TestACYNOS2(unittest.TestCase): | |
def test_letra_a_numero(self): | |
self.assertEqual(lan('ABC', 'A'), 1) | |
self.assertEqual(lan('ABC', 'C'), 3) | |
self.assertRaises(ValueError, lan, 'ABC', 'D') | |
def test_traduccion(self): | |
self.assertEqual(texto_a_ascii('ABCDE'), 'ABCDE') | |
self.assertEqual(texto_a_ascii(''), '') | |
self.assertEqual(texto_a_ascii('\xc3\x91'), '~') | |
self.assertEqual(texto_a_ascii(' '), '_') | |
self.assertEqual(texto_a_ascii('\n'), '') | |
def test_lee_primos(self): | |
self.assertEqual(primo_n(0), 2) | |
self.assertEqual(primo_n(1), 3) | |
self.assertEqual(primo_n(100007), 1299827) | |
def test_semilla_alfabeto(self): | |
self.assertEqual(s_alfa(''), Decimal(0)) | |
self.assertEqual(s_alfa('VALE'), Decimal("0.2001394141")) | |
def test_pi_decimal(self): | |
self.assertEqual(PI_DEC, Decimal("3.1415926536")) | |
def test_pseudo(self): | |
self.assertEqual( | |
pseudo(Decimal("0.2001394141")), | |
Decimal("0.1671732123")) | |
self.assertEqual( | |
pseudo(Decimal("0.1671732123")), | |
Decimal("0.9479315553")) | |
sa=Decimal("0.2001394141") | |
for s in range(28): | |
sa=pseudo(sa) | |
self.assertEqual(sa, Decimal("0.3376494172")) | |
def test_fn_a(self): | |
s = Decimal("0.1671732123") | |
self.assertEqual(fn_a(28, s), 6) | |
s = Decimal("0.9479315553") | |
self.assertEqual(fn_a(27, s), 26) | |
s = Decimal("0.7242082552") | |
self.assertEqual(fn_a(26, s), 19) | |
s = Decimal("0.9444166665") | |
self.assertEqual(fn_a(25, s), 24) | |
def test_alfa_derivado(self): | |
alfa_derivado = alfa_k('VALE') | |
self.assertEqual(ALFA_N, len(alfa_derivado)) | |
self.assertEqual( | |
alfa_derivado, | |
list('FZSYQRXNDAVGBWLUKHEPOMIJT~_C')) | |
def test_semilla_cifrado(self): | |
self.assertEqual(s_cifra(''), Decimal(0)) | |
s0_cifrado=Decimal("0.3462395532") | |
self.assertEqual(s_cifra('VALE'), s0_cifrado) | |
s115 = Decimal("0.4232082654") | |
si = s0_cifrado | |
for i in range(115): | |
si=pseudo(si) | |
self.assertEqual(si, s115) | |
def test_de_claro_a_pi(self): | |
clave = 'VALE' | |
claro = "LA_HEROICA_CIUDAD_DORMIA" | |
pi = [15,10,27,18,19,06,21,23,28,10,\ | |
27,28,23,16, 9,10, 9,27, 9,21,\ | |
06,22,23,10] | |
r = lan(alfa_k(clave), claro) | |
for n, (c, p) in enumerate(zip(r, pi)): | |
self.assertEqual(c, p, "C: %d, P: %d, N: %d"% (c, p, n)) | |
def test_cifrado(self): | |
# cifrado vacio | |
self.assertEqual('', codifica('', '')) | |
self.assertEqual([], codifica('', '', 'n')) | |
clave = 'VALE' | |
claro = 'LA_HEROICA_CIUDAD_DORMIA' | |
cin = [ 3,18, 3,11, 6, 7,20, 1,22, 2,\ | |
13,16,11,18,19,18,23,16, 8, 4,\ | |
14,10,13,13] | |
cit = 'SHSVRXPFMZBUVHEHIUNYWABB' | |
r = codifica(clave, claro, 'n') | |
self.assertEqual(len(r), len(claro)) | |
for n, (c, p) in enumerate(zip(r, cin)): | |
self.assertEqual(c, p, "C: %d, P: %d, N: %d"% (c, p, n)) | |
r = codifica(clave, claro) | |
for n, (c, p) in enumerate(zip(r, cit)): | |
self.assertEqual(c, p, "C: %s, P: %s, N: %d"% (c, p, n)) | |
def test_descifrado(self): | |
# cifrado vacio | |
self.assertEqual('', decodifica('', '')) | |
self.assertEqual([], decodifica('', [], 'n')) | |
clave = 'VALE' | |
claro = 'LA_HEROICA_CIUDAD_DORMIA' | |
lan_alfabase = lambda letra: lan(ALFABETO_BASE, letra) | |
claro_num = map(lan_alfabase, claro) | |
cit = 'SHSVRXPFMZBUVHEHIUNYWABB' | |
# Formato de salida numerico | |
r = decodifica(clave, cit, 'n') | |
self.assertEqual(len(r), len(claro)) | |
for n, (c_desc, c_claro) in enumerate(zip(r, claro_num)): | |
self.assertEqual(c_desc, c_claro, | |
"Caracter descifrado: %s, Caracter claro: %s, N: %d" % | |
(c_desc, c_claro, n)) | |
# Formato de salida texto | |
r = decodifica(clave, cit) | |
self.assertEqual(len(r), len(claro)) | |
for n, (c_desc, c_claro) in enumerate(zip(r, claro)): | |
self.assertEqual(c_desc, c_claro, | |
"Caracter descifrado: %s, Caracter claro: %s, N: %d" % | |
(c_desc, c_claro, n)) | |
########################################################################### | |
# Ejecucion de los tests | |
unittest.main() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment