Skip to content

Instantly share code, notes, and snippets.

@matburt
Forked from anonymous/ACYNOS (Tomillo)
Created February 10, 2010 23:04
Show Gist options
  • Save matburt/300948 to your computer and use it in GitHub Desktop.
Save matburt/300948 to your computer and use it in GitHub Desktop.
#!/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