66 lines
1.9 KiB
Python
Executable File
66 lines
1.9 KiB
Python
Executable File
#!/usr/bin/env python3
|
|
|
|
# DRACONDI: Dual-key Rotating Alphabet CONDI
|
|
|
|
import sys, re
|
|
from collections import OrderedDict
|
|
from random import randint, choice
|
|
from string import ascii_lowercase
|
|
|
|
def prepmsg(s:str):
|
|
return re.sub(r'[^a-z]', '', s.lower())
|
|
|
|
def dracondi_key(keyphrase:str):
|
|
prekey = ''
|
|
oa = ord('a')
|
|
for c in prepmsg(keyphrase):
|
|
while prekey.find(c) != -1 and len(prekey) < 26:
|
|
c = chr(oa + ((25 + ord(c) - oa) % 26))
|
|
prekey += c
|
|
offs = len(prekey) % 26
|
|
alpha = prekey + ''.join(ascii_lowercase)
|
|
unshifted = ''.join(list(OrderedDict.fromkeys(alpha).keys()))
|
|
return (unshifted + unshifted)[offs:offs+26]
|
|
|
|
def dracondi_enc(msg:str, ka1:str, ka2:str):
|
|
offs = randint(0, 25)
|
|
res = ka1[offs]
|
|
for i,c in enumerate(prepmsg(msg)):
|
|
rc = ka1[(ka1.index(c) + offs) % 26]
|
|
res += rc
|
|
offs = (ka2.index(rc) + i + 1) % 26
|
|
l = len(res) % 5
|
|
if l > 0:
|
|
res += ''.join([choice(ascii_lowercase) for i in range(0, 5 - l)])
|
|
return ' '.join([res[i:i+5] for i in range(0, len(res), 5)])
|
|
|
|
def dracondi_dec(msg:str, ka1:str, ka2:str):
|
|
res = ''
|
|
msg = prepmsg(msg)
|
|
offs = ka1.index(msg[0])
|
|
for i,c in enumerate(msg[1:]):
|
|
res += ka1[(26 + ka1.index(c) - offs) % 26]
|
|
offs = (ka2.index(c) + i + 1) % 26
|
|
return res
|
|
|
|
# entrypoint parameters: [mode] [key1] [key2]
|
|
# modes: e - encrypt, d - decrypt, k - print out keyed alphabets
|
|
def main():
|
|
mode = sys.argv[1].lower()
|
|
kp1 = sys.argv[2]
|
|
kp2 = sys.argv[3]
|
|
ka1 = dracondi_key(kp1)
|
|
ka2 = dracondi_key(kp2)
|
|
if mode.startswith('e'):
|
|
msg = sys.stdin.read()
|
|
print(dracondi_enc(msg, ka1, ka2))
|
|
elif mode.startswith('k'):
|
|
print('Keyed alphabet 1:', ka1)
|
|
print('Keyed alphabet 2:', ka2)
|
|
else:
|
|
msg = sys.stdin.read()
|
|
print(dracondi_dec(msg, ka1, ka2))
|
|
|
|
if __name__ == '__main__':
|
|
main()
|