beginning process of "making it right", enclosing mod 25 one-time pad stuff in its own class
This commit is contained in:
parent
e0d5e608f9
commit
b932174e34
@ -2,20 +2,117 @@ import unittest
|
|||||||
import onetimepad as OT
|
import onetimepad as OT
|
||||||
|
|
||||||
|
|
||||||
class TestOneTimePad(unittest.TestCase):
|
class TestMod25(unittest.TestCase):
|
||||||
msg = ('HOWMUCHCHUCKCOULDAWOODCHUCKCHUCKIFA'
|
msg = ('HOWMUCHCHUCKCOULDAWOODCHUCKCHUCKIFA'
|
||||||
'WOODCHUCKCOULDCHUCKWOOD' * 50)
|
'WOODCHUCKCOULDCHUCKWOOD' * 50)
|
||||||
_padsize = 2000
|
_padsize = 2000
|
||||||
|
PADLINES = (1, 4, 7, 10, 13, 16, 19, 22, 25)
|
||||||
|
TEXTLINES = (2, 5, 8, 11, 14, 17, 20, 23, 26)
|
||||||
|
CIPHERLINES = (3, 6, 9, 12, 15, 18, 21, 24, 27)
|
||||||
|
|
||||||
|
TEST_PADLINE = 'HUCHUGGHOBUXADDHOHPGQBKXQKAOLRL'
|
||||||
|
TEST_TEXTLINE = 'THISCAKEISUNSATISFACTORYTOMEYES'
|
||||||
|
TEST_CIPHERLINE = 'BCMAXHRNXUPLTEXRGOQKKQBWKYNTKWD'
|
||||||
|
|
||||||
|
TEST_MSG = \
|
||||||
|
'HOWMUCHCHUCKCOULDAWOODCHUCKCHUCKIFAWOODCHUCKCOULDCHUCKWOOD' \
|
||||||
|
'HOWMUCHCHUCKCOULDAWOODCHUCKCHUCKIFAWOODCHUCKCOULDCHUCKWOOD' \
|
||||||
|
'HOWMUCHCHUCKCOULDAWOODCHUCKCHUCKIFAWOODCHUCKCOULDCHUCKWOOD' \
|
||||||
|
'HOWMUCHCHUCKCOULDAWOODCHUCKCHUCKIFAWOODCHUCKCOULDCHUCKWOOD' \
|
||||||
|
'HOWMUCHCHUCKCOULDAWOODCHUCKCHUCKIFAWOODCHUCKCOULDCHUCKWOOD' \
|
||||||
|
'HOWMUCHCHUCKCOULDAWOODCHUCKCHUCKIFAWOODCHUCKCOULDCHUCKWOOD' \
|
||||||
|
'HOWMUCHCHUCKCOULDAWOODCHUCKCHUCKIFAWOODCHUCKCOULDCHUCKWOOD' \
|
||||||
|
'HOWMUCHCHUCKCOULDAWOODCHUCKCHUCKIFAWOODCHUCKCOULDCHUCKWOOD' \
|
||||||
|
'HOWMUCHCHUCKCOULDAWOODCHUCKCHUCKIFAWOODCHUCKCOULDCHUCKWOOD' \
|
||||||
|
'HOWMUCHCHUCKCOULDAWOODCHUCKCHUCKIFAWOODCHUCKCOULDCHUCKWOOD' \
|
||||||
|
'HOWMUCHCHUCKCOULDAWOODCHUCKCHUCKIFAWOODCHUCKCOULDCHUCKWOOD' \
|
||||||
|
'HOWMUCHCHUCKCOULDAWOODCHUCKCHUCKIFAWOODCHUCKCOULDCHUCKWOOD' \
|
||||||
|
'HOWMUCHCHUCKCOULDAWOODCHUCKCHUCKIFAWOODCHUCKCOULDCHUCKWOOD' \
|
||||||
|
'HOWMUCHCHUCKCOULDAWOODCHUCKCHUCKIFAWOODCHUCKCOULDCHUCKWOOD' \
|
||||||
|
'HOWMUCHCHUCKCOULDAWOODCHUCKCHUCKIFAWOODCHUCKCOULDCHUCKWOOD' \
|
||||||
|
'HOWMUCHCHUCKCOULDAWOODCHUCKCHUCKIFAWOODCHUCKCOULDCHUCKWOOD' \
|
||||||
|
'HOWMUCHCHUCKCOULDAWOODCHUCKCHUCKIFAWOODCHUCKCOULDCHUCKWOOD' \
|
||||||
|
'HOWMUCHCHUCKCOULDAWOODCHUCKCHUCKIFAWOO'
|
||||||
|
|
||||||
|
TEST_CIPHER = \
|
||||||
|
'FMHZRGHRITAMHVAOLBANWMNYPBYDCFCAVXAEEKXUTYXLUCYQVYPWZFSKYI' \
|
||||||
|
'LWKCHZSXLFCMZIEFHXKVUXVNBIQVSNYPTFVIZHSVTDCKWUSZHEHUPLZSUY' \
|
||||||
|
'BTPSMEISGTYDWCXVUCPGHHKXDOUHGCVDTDUQVKFDRDCHFIKTNFGDFODCQS' \
|
||||||
|
'RIWGZBLPTCSXLMPQODYLHQNGWNSCTHNDOZEUXWCEQAZMRGZIQUTUYSKOGW' \
|
||||||
|
'YGYPEDNUZDWBEPUHLWWBHLGADYTCNGEUFKPLQSAMMXCTXWQEOYBNKQAHBV' \
|
||||||
|
'PDKTMQSHDFCFBCVKXVTRSXRTBHAGKNLFASNVNENHHRNGCKXALMIBNZKOTL' \
|
||||||
|
'BZMWGSNMTLDNPXKVQZZUAZCSPWFNRKAMTNMCPHWGLGBVSNFDXSKVUFBZBW' \
|
||||||
|
'WICBUPCWZDUXCZTXHKQBMQNTBHAAGMBPKUIDTHITUEWEPPMACPXERXRYND' \
|
||||||
|
'RWQSBQQMSQRVWZMAQQKUGHLELKFLKHGNFFDHIWUZPDIMIOELSIHMUIZQCW' \
|
||||||
|
'KLPZQIFAXNDRRIIIHOYBGSCIYBIVSRTECEOZSBLYTNCXGQXEWMGIXHKBIL' \
|
||||||
|
'TOKWHGABPMXNAHEWFKIMOQPHVHSYZABWLMLSSDEHQIBNEMEMHCWOUBIIZS' \
|
||||||
|
'XPFWXMQNOTEANYGQBVMZAXNPAMWSUOGFAFFYUTKDZYHFTPYGOMDHESKOZI' \
|
||||||
|
'IPDXAMSAQOTGAQKYPYWWUYGHSBVODAHDSKDVPMLWRCXQXGAXQZBFNKXFKU' \
|
||||||
|
'WUDRWNRKECIQIUEEMQNCAZDDDOQOEGUVFVCTKLTISNOQILEKUYXCYZNHHZ' \
|
||||||
|
'OFHCSLOPPQAFLHHDZANGTXNQSDZSAFLLSGWULVHIDERMTZZHTDHTZPHEFN' \
|
||||||
|
'ORDEIYOVTTAWVTOOXSLZBOPMRCCKSMHQOVFERCOVUMWXFSNEMFALNWGRQC' \
|
||||||
|
'NLWELLXNCHZGXQEUGEVNCWMHRNGUTBKTVEXGASBRCEBSFITOEFSNIBTLME' \
|
||||||
|
'MERMOFVBNTFCTTWEGAIGRZQBBFOKOPXNCWXFBK'
|
||||||
|
|
||||||
|
TEST_PAD = """\
|
||||||
|
XXLNWDZOAYXBEGFCGADYHHKQUYOAULZQMRZHQVTRLDUARODERVGBWVVVKECHNQNWKUCLZBWU
|
||||||
|
|
||||||
|
|
||||||
|
KUDWNGFTSEGFFSKSVEKZUMLTOSLIZZTFXODBZZMACDFUTESFRBAPYYVTTOCKQBSSTDGPILKE
|
||||||
|
|
||||||
|
|
||||||
|
YHSTKXTTGVBAIIZXCUPHICYICDGOBOIUZUEYCMLHPNHXUEKCBWTMKYBKHZLNKTETDXIHYBHF
|
||||||
|
|
||||||
|
|
||||||
|
WBOSEXMRLZVHNZSSQSBCKAERRITRBAZWGVZNTGDSIVIZEMBKWDOOBDWIDCZIUHVTKVTSGFDT
|
||||||
|
|
||||||
|
|
||||||
|
NRGPNGRNKEVLZVYOAYTUWCDTOLGEQDBSHVRMMYYQIEZWKWZVCPGIAGKPNZEGTLPKMPEILQAC
|
||||||
|
|
||||||
|
|
||||||
|
MIPKMYCFMVZKUTVKIPXBKGLFATSDCMYLPYLSTPBARVELNSOUFPZMUTRIRNZLYMDITNXMKLGE
|
||||||
|
|
||||||
|
|
||||||
|
QXYRYEAOHGETEQMKTUMARPYMPKONUKYZIHTFGNHIKVOLTLRPMPNFSDHWQGVHBNDCWZCLUHQW
|
||||||
|
|
||||||
|
|
||||||
|
GIFBFZKZOFZRRYCBOSBWSNVFXXPSAGOUOXDNBNSOZADYYSKWQUTYNCDNGVLSZNDBCTSIYOUX
|
||||||
|
|
||||||
|
|
||||||
|
NNUGLZNKNDSYGRUCXTKLBIMXZMMZAEHVRFYMBFKVDPAEHOYCBXKADZOTRRMULOPAIKCIHKFY
|
||||||
|
|
||||||
|
|
||||||
|
BQKKMEXUPLMTKGFIMPMTDVRZEBFEFARDEVQADVKIVNBHNZLEAAGLFIKXHTQWXBPNLXZHFUDZ
|
||||||
|
|
||||||
|
|
||||||
|
XYLLVFETIDCYAXGTIHUFUSFMMWTLKZARVQOFGEBKIGWHFFFFKTHPQOMVAVILFLWMRLWPBWVW
|
||||||
|
|
||||||
|
|
||||||
|
PFKSLFFWKYQVPHVPQTTVFRLQXHFMGVXVHTNSVZQSETKHXAPPSLHAIAVXWGDFVKOBQLEWPAZY
|
||||||
|
|
||||||
|
|
||||||
|
WELQRIFCGSOVFSLYXMSETCTROLNKMDWZSGKREFEPEHCOKSMRTNCDSTHCSQKMKCBYEWZSQHPK
|
||||||
|
|
||||||
|
|
||||||
|
UNWWUBKICDYYOSIZWKWRLGGIMYWKMDXOUKYHCUYCACKSFRWWXADQUZTCNYEYCSQEBTCZMSCV
|
||||||
|
|
||||||
|
|
||||||
|
NTGCDGFUUCTQWINV........................................................
|
||||||
|
|
||||||
|
"""
|
||||||
|
|
||||||
|
def setUp(self):
|
||||||
|
self.m25 = OT.Mod25()
|
||||||
|
|
||||||
def test_mk_as_alpha_excludes_j(self):
|
def test_mk_as_alpha_excludes_j(self):
|
||||||
self.assertTrue('J' not in OT._AS_ALPHA.values())
|
self.assertTrue('J' not in self.m25._as_alpha.values())
|
||||||
|
|
||||||
def test_mk_as_alpha_dict_has_25_members(self):
|
def test_mk_as_alpha_dict_has_25_members(self):
|
||||||
self.assertEqual(25, len(OT._AS_ALPHA.items()))
|
self.assertEqual(25, len(self.m25._as_alpha.items()))
|
||||||
|
|
||||||
def test_creates_pad_of_desired_length(self):
|
def test_creates_pad_of_desired_length(self):
|
||||||
for width in (72, 33, 99, 111):
|
for width in (72, 33, 99, 111):
|
||||||
pad = OT.create_pad(self._padsize, width=width)
|
pad = self.m25.create_pad(self._padsize, width=width)
|
||||||
lines = [line.strip('.') for line in pad.split()]
|
lines = [line.strip('.') for line in pad.split()]
|
||||||
actual = len(''.join(lines))
|
actual = len(''.join(lines))
|
||||||
self.assertEqual(self._padsize, len(''.join(lines)),
|
self.assertEqual(self._padsize, len(''.join(lines)),
|
||||||
@ -23,163 +120,71 @@ class TestOneTimePad(unittest.TestCase):
|
|||||||
'{1}, actual={2}'.format(self._padsize,
|
'{1}, actual={2}'.format(self._padsize,
|
||||||
width, actual))
|
width, actual))
|
||||||
|
|
||||||
def test_get_randint_on_nonexistent_randomness_file_fails_ioerror(self):
|
|
||||||
OT._DEV_RANDOM['fp'] = None
|
|
||||||
self.assertRaises(IOError, OT._get_randint,
|
|
||||||
randomness_file='/foo/bar/busted/borken',
|
|
||||||
fallback_to_fake=False)
|
|
||||||
|
|
||||||
def test_get_randint_on_nonexistent_randomness_file_uses_fake(self):
|
|
||||||
OT._DEV_RANDOM['fp'] = None
|
|
||||||
random_int = OT._get_randint(randomness_file='/broke/as/joke')
|
|
||||||
self.assertTrue(random_int in range(0, 255))
|
|
||||||
|
|
||||||
def test_is_padline(self):
|
def test_is_padline(self):
|
||||||
for lineno in PADLINES:
|
for lineno in self.PADLINES:
|
||||||
self.assertTrue(OT._is_padline(lineno),
|
self.assertTrue(self.m25._is_padline(lineno),
|
||||||
'line {0} is padline'.format(lineno))
|
'line {0} is padline'.format(lineno))
|
||||||
for lineno in TEXTLINES:
|
for lineno in self.TEXTLINES:
|
||||||
self.assertFalse(OT._is_padline(lineno),
|
self.assertFalse(self.m25._is_padline(lineno),
|
||||||
'line {0} is not padline'.format(lineno))
|
'line {0} is not padline'.format(lineno))
|
||||||
for lineno in CIPHERLINES:
|
for lineno in self.CIPHERLINES:
|
||||||
self.assertFalse(OT._is_padline(lineno),
|
self.assertFalse(self.m25._is_padline(lineno),
|
||||||
'line {0} is not padline'.format(lineno))
|
'line {0} is not padline'.format(lineno))
|
||||||
|
|
||||||
def test_is_textline(self):
|
def test_is_textline(self):
|
||||||
for lineno in TEXTLINES:
|
for lineno in self.TEXTLINES:
|
||||||
self.assertTrue(OT._is_textline(lineno),
|
self.assertTrue(self.m25._is_textline(lineno),
|
||||||
'line {0} is textline'.format(lineno))
|
'line {0} is textline'.format(lineno))
|
||||||
for lineno in PADLINES:
|
for lineno in self.PADLINES:
|
||||||
self.assertFalse(OT._is_textline(lineno),
|
self.assertFalse(self.m25._is_textline(lineno),
|
||||||
'line {0} is not textline'.format(lineno))
|
'line {0} is not textline'.format(lineno))
|
||||||
for lineno in CIPHERLINES:
|
for lineno in self.CIPHERLINES:
|
||||||
self.assertFalse(OT._is_textline(lineno),
|
self.assertFalse(self.m25._is_textline(lineno),
|
||||||
'line {0} is not textline'.format(lineno))
|
'line {0} is not textline'.format(lineno))
|
||||||
|
|
||||||
def test_is_cipherline(self):
|
def test_is_cipherline(self):
|
||||||
for lineno in CIPHERLINES:
|
for lineno in self.CIPHERLINES:
|
||||||
self.assertTrue(OT._is_cipherline(lineno),
|
self.assertTrue(self.m25._is_cipherline(lineno),
|
||||||
'line {0} is cipherline'.format(lineno))
|
'line {0} is cipherline'.format(lineno))
|
||||||
for lineno in PADLINES:
|
for lineno in self.PADLINES:
|
||||||
self.assertFalse(OT._is_cipherline(lineno),
|
self.assertFalse(self.m25._is_cipherline(lineno),
|
||||||
'line {0} is not cipherline'.format(lineno))
|
'line {0} is not cipherline'.format(lineno))
|
||||||
for lineno in TEXTLINES:
|
for lineno in self.TEXTLINES:
|
||||||
self.assertFalse(OT._is_cipherline(lineno),
|
self.assertFalse(self.m25._is_cipherline(lineno),
|
||||||
'line {0} is not cipherline'.format(lineno))
|
'line {0} is not cipherline'.format(lineno))
|
||||||
|
|
||||||
def test_make_cipherline_from_padline_and_textline(self):
|
def test_make_cipherline_from_padline_and_textline(self):
|
||||||
actual = OT._cipherline_from_padline_and_textline(TEST_PADLINE,
|
actual = \
|
||||||
TEST_TEXTLINE)
|
self.m25._cipherline_from_padline_and_textline(self.TEST_PADLINE,
|
||||||
self.assertEqual(TEST_CIPHERLINE, actual)
|
self.TEST_TEXTLINE)
|
||||||
|
self.assertEqual(self.TEST_CIPHERLINE, actual)
|
||||||
|
|
||||||
def test_make_textline_from_cipherline_and_padline(self):
|
def test_make_textline_from_cipherline_and_padline(self):
|
||||||
actual = OT._textline_from_cipherline_and_padline(TEST_CIPHERLINE,
|
actual = self.m25._textline_from_cipherline_and_padline(
|
||||||
TEST_PADLINE)
|
self.TEST_CIPHERLINE, self.TEST_PADLINE)
|
||||||
self.assertEqual(TEST_TEXTLINE, actual)
|
self.assertEqual(self.TEST_TEXTLINE, actual)
|
||||||
|
|
||||||
def test_encode_equals_expected(self):
|
def test_encode_equals_expected(self):
|
||||||
ciphertext = OT.encode(TEST_MSG, TEST_PAD)
|
ciphertext = OT.mod25encode(self.TEST_MSG, self.TEST_PAD)
|
||||||
self.assertEqual(TEST_CIPHER, ciphertext)
|
self.assertEqual(self.TEST_CIPHER, ciphertext)
|
||||||
|
|
||||||
def test_decode_equals_expected(self):
|
def test_decode_equals_expected(self):
|
||||||
text = OT.decode(TEST_CIPHER, TEST_PAD)
|
text = OT.mod25decode(self.TEST_CIPHER, self.TEST_PAD)
|
||||||
self.assertEqual(TEST_MSG, text)
|
self.assertEqual(self.TEST_MSG, text)
|
||||||
|
|
||||||
|
|
||||||
PADLINES = (1, 4, 7, 10, 13, 16, 19, 22, 25)
|
class TestOneTimePad(unittest.TestCase):
|
||||||
TEXTLINES = (2, 5, 8, 11, 14, 17, 20, 23, 26)
|
|
||||||
CIPHERLINES = (3, 6, 9, 12, 15, 18, 21, 24, 27)
|
|
||||||
|
|
||||||
TEST_PADLINE = 'HUCHUGGHOBUXADDHOHPGQBKXQKAOLRL'
|
def test_get_randint_on_nonexistent_randomness_file_fails_ioerror(self):
|
||||||
TEST_TEXTLINE = 'THISCAKEISUNSATISFACTORYTOMEYES'
|
OT._DEV_URANDOM['fp'] = None
|
||||||
TEST_CIPHERLINE = 'BCMAXHRNXUPLTEXRGOQKKQBWKYNTKWD'
|
self.assertRaises(IOError, OT._get_randint,
|
||||||
|
25, randomness_file='/foo/bar/busted/borken',
|
||||||
|
fallback_to_fake=False)
|
||||||
|
|
||||||
TEST_MSG = \
|
def test_get_randint_on_nonexistent_randomness_file_uses_fake(self):
|
||||||
'HOWMUCHCHUCKCOULDAWOODCHUCKCHUCKIFAWOODCHUCKCOULDCHUCKWOOD' \
|
OT._DEV_URANDOM['fp'] = None
|
||||||
'HOWMUCHCHUCKCOULDAWOODCHUCKCHUCKIFAWOODCHUCKCOULDCHUCKWOOD' \
|
random_int = OT._get_randint(32, randomness_file='/broke/as/joke')
|
||||||
'HOWMUCHCHUCKCOULDAWOODCHUCKCHUCKIFAWOODCHUCKCOULDCHUCKWOOD' \
|
self.assertTrue(random_int in range(0, 255))
|
||||||
'HOWMUCHCHUCKCOULDAWOODCHUCKCHUCKIFAWOODCHUCKCOULDCHUCKWOOD' \
|
|
||||||
'HOWMUCHCHUCKCOULDAWOODCHUCKCHUCKIFAWOODCHUCKCOULDCHUCKWOOD' \
|
|
||||||
'HOWMUCHCHUCKCOULDAWOODCHUCKCHUCKIFAWOODCHUCKCOULDCHUCKWOOD' \
|
|
||||||
'HOWMUCHCHUCKCOULDAWOODCHUCKCHUCKIFAWOODCHUCKCOULDCHUCKWOOD' \
|
|
||||||
'HOWMUCHCHUCKCOULDAWOODCHUCKCHUCKIFAWOODCHUCKCOULDCHUCKWOOD' \
|
|
||||||
'HOWMUCHCHUCKCOULDAWOODCHUCKCHUCKIFAWOODCHUCKCOULDCHUCKWOOD' \
|
|
||||||
'HOWMUCHCHUCKCOULDAWOODCHUCKCHUCKIFAWOODCHUCKCOULDCHUCKWOOD' \
|
|
||||||
'HOWMUCHCHUCKCOULDAWOODCHUCKCHUCKIFAWOODCHUCKCOULDCHUCKWOOD' \
|
|
||||||
'HOWMUCHCHUCKCOULDAWOODCHUCKCHUCKIFAWOODCHUCKCOULDCHUCKWOOD' \
|
|
||||||
'HOWMUCHCHUCKCOULDAWOODCHUCKCHUCKIFAWOODCHUCKCOULDCHUCKWOOD' \
|
|
||||||
'HOWMUCHCHUCKCOULDAWOODCHUCKCHUCKIFAWOODCHUCKCOULDCHUCKWOOD' \
|
|
||||||
'HOWMUCHCHUCKCOULDAWOODCHUCKCHUCKIFAWOODCHUCKCOULDCHUCKWOOD' \
|
|
||||||
'HOWMUCHCHUCKCOULDAWOODCHUCKCHUCKIFAWOODCHUCKCOULDCHUCKWOOD' \
|
|
||||||
'HOWMUCHCHUCKCOULDAWOODCHUCKCHUCKIFAWOODCHUCKCOULDCHUCKWOOD' \
|
|
||||||
'HOWMUCHCHUCKCOULDAWOODCHUCKCHUCKIFAWOO'
|
|
||||||
|
|
||||||
TEST_CIPHER = \
|
|
||||||
'FMHZRGHRITAMHVAOLBANWMNYPBYDCFCAVXAEEKXUTYXLUCYQVYPWZFSKYI' \
|
|
||||||
'LWKCHZSXLFCMZIEFHXKVUXVNBIQVSNYPTFVIZHSVTDCKWUSZHEHUPLZSUY' \
|
|
||||||
'BTPSMEISGTYDWCXVUCPGHHKXDOUHGCVDTDUQVKFDRDCHFIKTNFGDFODCQS' \
|
|
||||||
'RIWGZBLPTCSXLMPQODYLHQNGWNSCTHNDOZEUXWCEQAZMRGZIQUTUYSKOGW' \
|
|
||||||
'YGYPEDNUZDWBEPUHLWWBHLGADYTCNGEUFKPLQSAMMXCTXWQEOYBNKQAHBV' \
|
|
||||||
'PDKTMQSHDFCFBCVKXVTRSXRTBHAGKNLFASNVNENHHRNGCKXALMIBNZKOTL' \
|
|
||||||
'BZMWGSNMTLDNPXKVQZZUAZCSPWFNRKAMTNMCPHWGLGBVSNFDXSKVUFBZBW' \
|
|
||||||
'WICBUPCWZDUXCZTXHKQBMQNTBHAAGMBPKUIDTHITUEWEPPMACPXERXRYND' \
|
|
||||||
'RWQSBQQMSQRVWZMAQQKUGHLELKFLKHGNFFDHIWUZPDIMIOELSIHMUIZQCW' \
|
|
||||||
'KLPZQIFAXNDRRIIIHOYBGSCIYBIVSRTECEOZSBLYTNCXGQXEWMGIXHKBIL' \
|
|
||||||
'TOKWHGABPMXNAHEWFKIMOQPHVHSYZABWLMLSSDEHQIBNEMEMHCWOUBIIZS' \
|
|
||||||
'XPFWXMQNOTEANYGQBVMZAXNPAMWSUOGFAFFYUTKDZYHFTPYGOMDHESKOZI' \
|
|
||||||
'IPDXAMSAQOTGAQKYPYWWUYGHSBVODAHDSKDVPMLWRCXQXGAXQZBFNKXFKU' \
|
|
||||||
'WUDRWNRKECIQIUEEMQNCAZDDDOQOEGUVFVCTKLTISNOQILEKUYXCYZNHHZ' \
|
|
||||||
'OFHCSLOPPQAFLHHDZANGTXNQSDZSAFLLSGWULVHIDERMTZZHTDHTZPHEFN' \
|
|
||||||
'ORDEIYOVTTAWVTOOXSLZBOPMRCCKSMHQOVFERCOVUMWXFSNEMFALNWGRQC' \
|
|
||||||
'NLWELLXNCHZGXQEUGEVNCWMHRNGUTBKTVEXGASBRCEBSFITOEFSNIBTLME' \
|
|
||||||
'MERMOFVBNTFCTTWEGAIGRZQBBFOKOPXNCWXFBK'
|
|
||||||
|
|
||||||
TEST_PAD = """\
|
|
||||||
XXLNWDZOAYXBEGFCGADYHHKQUYOAULZQMRZHQVTRLDUARODERVGBWVVVKECHNQNWKUCLZBWU
|
|
||||||
|
|
||||||
|
|
||||||
KUDWNGFTSEGFFSKSVEKZUMLTOSLIZZTFXODBZZMACDFUTESFRBAPYYVTTOCKQBSSTDGPILKE
|
|
||||||
|
|
||||||
|
|
||||||
YHSTKXTTGVBAIIZXCUPHICYICDGOBOIUZUEYCMLHPNHXUEKCBWTMKYBKHZLNKTETDXIHYBHF
|
|
||||||
|
|
||||||
|
|
||||||
WBOSEXMRLZVHNZSSQSBCKAERRITRBAZWGVZNTGDSIVIZEMBKWDOOBDWIDCZIUHVTKVTSGFDT
|
|
||||||
|
|
||||||
|
|
||||||
NRGPNGRNKEVLZVYOAYTUWCDTOLGEQDBSHVRMMYYQIEZWKWZVCPGIAGKPNZEGTLPKMPEILQAC
|
|
||||||
|
|
||||||
|
|
||||||
MIPKMYCFMVZKUTVKIPXBKGLFATSDCMYLPYLSTPBARVELNSOUFPZMUTRIRNZLYMDITNXMKLGE
|
|
||||||
|
|
||||||
|
|
||||||
QXYRYEAOHGETEQMKTUMARPYMPKONUKYZIHTFGNHIKVOLTLRPMPNFSDHWQGVHBNDCWZCLUHQW
|
|
||||||
|
|
||||||
|
|
||||||
GIFBFZKZOFZRRYCBOSBWSNVFXXPSAGOUOXDNBNSOZADYYSKWQUTYNCDNGVLSZNDBCTSIYOUX
|
|
||||||
|
|
||||||
|
|
||||||
NNUGLZNKNDSYGRUCXTKLBIMXZMMZAEHVRFYMBFKVDPAEHOYCBXKADZOTRRMULOPAIKCIHKFY
|
|
||||||
|
|
||||||
|
|
||||||
BQKKMEXUPLMTKGFIMPMTDVRZEBFEFARDEVQADVKIVNBHNZLEAAGLFIKXHTQWXBPNLXZHFUDZ
|
|
||||||
|
|
||||||
|
|
||||||
XYLLVFETIDCYAXGTIHUFUSFMMWTLKZARVQOFGEBKIGWHFFFFKTHPQOMVAVILFLWMRLWPBWVW
|
|
||||||
|
|
||||||
|
|
||||||
PFKSLFFWKYQVPHVPQTTVFRLQXHFMGVXVHTNSVZQSETKHXAPPSLHAIAVXWGDFVKOBQLEWPAZY
|
|
||||||
|
|
||||||
|
|
||||||
WELQRIFCGSOVFSLYXMSETCTROLNKMDWZSGKREFEPEHCOKSMRTNCDSTHCSQKMKCBYEWZSQHPK
|
|
||||||
|
|
||||||
|
|
||||||
UNWWUBKICDYYOSIZWKWRLGGIMYWKMDXOUKYHCUYCACKSFRWWXADQUZTCNYEYCSQEBTCZMSCV
|
|
||||||
|
|
||||||
|
|
||||||
NTGCDGFUUCTQWINV........................................................
|
|
||||||
|
|
||||||
"""
|
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
|
331
onetimepad.py
331
onetimepad.py
@ -1,62 +1,177 @@
|
|||||||
from itertools import izip
|
from itertools import izip
|
||||||
|
|
||||||
PAD_MODULO = 3
|
|
||||||
PADLINE_OFFSET = -2
|
|
||||||
TEXTLINE_OFFSET = -1
|
|
||||||
DEFAULT_PAD_WIDTH = 72
|
DEFAULT_PAD_WIDTH = 72
|
||||||
CIPHER_FLOOR = 1
|
|
||||||
CIPHER_CEIL = 25
|
|
||||||
NULLCHAR = '.'
|
|
||||||
|
|
||||||
|
|
||||||
def encode(msg, pad):
|
def mod25encode(msg, pad):
|
||||||
ret = []
|
mod25 = Mod25(pad=pad)
|
||||||
filled = list(_text_padfill(msg, pad))
|
return mod25.encode(msg)
|
||||||
for i, line in enumerate(_text_cipherfill(filled)):
|
|
||||||
lineno = i + 1
|
|
||||||
if _is_cipherline(lineno):
|
|
||||||
ret.append(line)
|
|
||||||
return ''.join(ret).strip(NULLCHAR)
|
|
||||||
|
|
||||||
|
|
||||||
def decode(ciphertext, pad):
|
def mod25decode(msg, pad):
|
||||||
ret = []
|
mod25 = Mod25(pad=pad)
|
||||||
filled = list(_cipher_padfill(ciphertext, pad))
|
return mod25.decode(msg)
|
||||||
for i, line in enumerate(_cipher_textfill(filled)):
|
|
||||||
lineno = i + 1
|
|
||||||
if _is_textline(lineno):
|
|
||||||
ret.append(line)
|
|
||||||
return ''.join(ret).strip(NULLCHAR)
|
|
||||||
|
|
||||||
|
|
||||||
def create_pad(length, width=DEFAULT_PAD_WIDTH):
|
class Mod25(object):
|
||||||
return '\n'.join(create_pad_lines(length, width=width))
|
_pad_modulo = 3
|
||||||
|
_padline_offset = -2
|
||||||
|
_textline_offset = -1
|
||||||
|
_cipher_floor = 1
|
||||||
|
_cipher_ceil = 25
|
||||||
|
_nullchar = '.'
|
||||||
|
|
||||||
|
def __init__(self, pad=''):
|
||||||
|
self.pad = pad
|
||||||
|
self._as_alpha = {}
|
||||||
|
self._as_nums = {}
|
||||||
|
self._mk_as_alpha_as_nums()
|
||||||
|
|
||||||
|
def _mk_as_alpha_as_nums(self):
|
||||||
|
as_alpha = {}
|
||||||
|
as_nums = {}
|
||||||
|
a_chr = ord('A')
|
||||||
|
past_j = False
|
||||||
|
|
||||||
|
for char in range(self._cipher_ceil + 1):
|
||||||
|
letter = chr(a_chr + char)
|
||||||
|
if letter != 'J':
|
||||||
|
key = char + (1 if not past_j else 0)
|
||||||
|
as_alpha[key] = letter
|
||||||
|
else:
|
||||||
|
past_j = True
|
||||||
|
|
||||||
|
for key, val in as_alpha.iteritems():
|
||||||
|
as_nums[val] = key
|
||||||
|
|
||||||
|
self._as_alpha.update(as_alpha)
|
||||||
|
self._as_nums.update(as_nums)
|
||||||
|
|
||||||
|
def encode(self, msg):
|
||||||
|
ret = []
|
||||||
|
filled = list(self._text_padfill(msg))
|
||||||
|
for i, line in enumerate(self._text_cipherfill(filled)):
|
||||||
|
lineno = i + 1
|
||||||
|
if self._is_cipherline(lineno):
|
||||||
|
ret.append(line)
|
||||||
|
return ''.join(ret).strip(self._nullchar)
|
||||||
|
|
||||||
|
def decode(self, ciphertext):
|
||||||
|
ret = []
|
||||||
|
filled = list(self._cipher_padfill(ciphertext))
|
||||||
|
for i, line in enumerate(self._cipher_textfill(filled)):
|
||||||
|
lineno = i + 1
|
||||||
|
if self._is_textline(lineno):
|
||||||
|
ret.append(line)
|
||||||
|
return ''.join(ret).strip(self._nullchar)
|
||||||
|
|
||||||
|
def create_pad(self, length, width=DEFAULT_PAD_WIDTH):
|
||||||
|
return '\n'.join(self.create_pad_lines(length, width=width))
|
||||||
|
|
||||||
|
def create_pad_lines(self, length, width=DEFAULT_PAD_WIDTH):
|
||||||
|
chars = self._create_chars_for_pad(length)
|
||||||
|
lines = _chunk_chars_into_lines(chars, self._nullchar, width=width)
|
||||||
|
for line in lines:
|
||||||
|
yield line
|
||||||
|
yield ''
|
||||||
|
yield ''
|
||||||
|
|
||||||
|
def _create_chars_for_pad(self, length):
|
||||||
|
chars = []
|
||||||
|
for char in range(length):
|
||||||
|
chars.append(self._as_alpha[_get_randint(self._cipher_ceil)])
|
||||||
|
return ''.join(chars)
|
||||||
|
|
||||||
|
def _ensure_pad_is_lines(self):
|
||||||
|
if isinstance(self.pad, basestring):
|
||||||
|
self.pad = self.pad.splitlines()
|
||||||
|
|
||||||
|
def _text_padfill(self, text):
|
||||||
|
self._ensure_pad_is_lines()
|
||||||
|
padlines = [line.strip() for line in self.pad if line.strip()]
|
||||||
|
textlines = _chunk_chars_into_lines(text, self._nullchar,
|
||||||
|
_get_textwidth(padlines))
|
||||||
|
for textline, padline in izip(textlines, padlines):
|
||||||
|
yield padline
|
||||||
|
yield textline
|
||||||
|
yield ''
|
||||||
|
|
||||||
|
def _cipher_padfill(self, ciphertext):
|
||||||
|
self._ensure_pad_is_lines()
|
||||||
|
padlines = [line.strip() for line in self.pad if line.strip()]
|
||||||
|
cipherlines = _chunk_chars_into_lines(ciphertext, self._nullchar,
|
||||||
|
_get_textwidth(padlines))
|
||||||
|
for cipherline, padline in izip(cipherlines, padlines):
|
||||||
|
yield padline
|
||||||
|
yield ''
|
||||||
|
yield cipherline
|
||||||
|
|
||||||
|
def _text_cipherfill(self, padfilled_text_lines):
|
||||||
|
for i, line in enumerate(padfilled_text_lines):
|
||||||
|
lineno = i + 1
|
||||||
|
if self._is_cipherline(lineno):
|
||||||
|
padline = padfilled_text_lines[i - abs(self._padline_offset)]
|
||||||
|
textline = padfilled_text_lines[i - abs(self._textline_offset)]
|
||||||
|
yield padline
|
||||||
|
yield textline
|
||||||
|
yield self._cipherline_from_padline_and_textline(padline,
|
||||||
|
textline)
|
||||||
|
|
||||||
|
def _cipher_textfill(self, padfilled_cipher_lines):
|
||||||
|
for i, line in enumerate(padfilled_cipher_lines):
|
||||||
|
lineno = i + 1
|
||||||
|
if self._is_cipherline(lineno):
|
||||||
|
padline = padfilled_cipher_lines[i - abs(self._padline_offset)]
|
||||||
|
textline = \
|
||||||
|
padfilled_cipher_lines[i - abs(self._textline_offset)]
|
||||||
|
yield padline
|
||||||
|
yield self._textline_from_cipherline_and_padline(line, padline)
|
||||||
|
yield line
|
||||||
|
|
||||||
|
def _cipherline_from_padline_and_textline(self, padline, textline):
|
||||||
|
ret = []
|
||||||
|
for padchar, textchar in izip(padline, textline):
|
||||||
|
if textchar == self._nullchar:
|
||||||
|
ret.append(self._nullchar)
|
||||||
|
continue
|
||||||
|
charnum = self._as_nums[padchar] + self._as_nums[textchar]
|
||||||
|
idx = charnum if charnum <= self._cipher_ceil else \
|
||||||
|
charnum % self._cipher_ceil
|
||||||
|
ret.append(self._as_alpha[idx])
|
||||||
|
return ''.join(ret)
|
||||||
|
|
||||||
|
def _textline_from_cipherline_and_padline(self, cipherline, padline):
|
||||||
|
ret = []
|
||||||
|
for ciphercar, padchar in izip(cipherline, padline):
|
||||||
|
if ciphercar == self._nullchar:
|
||||||
|
ret.append(self._nullchar)
|
||||||
|
continue
|
||||||
|
charnum = self._as_nums[ciphercar] - self._as_nums[padchar]
|
||||||
|
idx = charnum if charnum <= self._cipher_ceil else \
|
||||||
|
charnum % self._cipher_ceil
|
||||||
|
if idx < 0:
|
||||||
|
idx = self._cipher_ceil + idx
|
||||||
|
ret.append(self._as_alpha[idx])
|
||||||
|
return ''.join(ret)
|
||||||
|
|
||||||
|
def _is_padline(self, lineno):
|
||||||
|
return self._is_cipherline(lineno + abs(self._padline_offset))
|
||||||
|
|
||||||
|
def _is_textline(self, lineno):
|
||||||
|
return self._is_cipherline(lineno + abs(self._textline_offset))
|
||||||
|
|
||||||
|
def _is_cipherline(self, lineno):
|
||||||
|
return not lineno % self._pad_modulo
|
||||||
|
|
||||||
|
|
||||||
def create_pad_lines(length, width=DEFAULT_PAD_WIDTH):
|
def _chunk_chars_into_lines(chars, nullchar, width=DEFAULT_PAD_WIDTH):
|
||||||
chars = _create_chars_for_pad(length)
|
|
||||||
lines = _chunk_chars_into_lines(chars, width=width)
|
|
||||||
for line in lines:
|
|
||||||
yield line
|
|
||||||
yield ''
|
|
||||||
yield ''
|
|
||||||
|
|
||||||
|
|
||||||
def _create_chars_for_pad(length):
|
|
||||||
chars = []
|
|
||||||
for char in range(length):
|
|
||||||
chars.append(_AS_ALPHA[_get_randint()])
|
|
||||||
return ''.join(chars)
|
|
||||||
|
|
||||||
|
|
||||||
def _chunk_chars_into_lines(chars, width=DEFAULT_PAD_WIDTH):
|
|
||||||
lines = []
|
lines = []
|
||||||
for chunk in _as_line_chunks(chars, width=width):
|
for chunk in _as_line_chunks(chars, nullchar, width=width):
|
||||||
lines.append(chunk)
|
lines.append(chunk)
|
||||||
return lines
|
return lines
|
||||||
|
|
||||||
|
|
||||||
def _as_line_chunks(chars, width=DEFAULT_PAD_WIDTH):
|
def _as_line_chunks(chars, nullchar, width=DEFAULT_PAD_WIDTH):
|
||||||
chunk = []
|
chunk = []
|
||||||
for char in chars.replace('\n', ''):
|
for char in chars.replace('\n', ''):
|
||||||
chunk.append(char)
|
chunk.append(char)
|
||||||
@ -64,142 +179,42 @@ def _as_line_chunks(chars, width=DEFAULT_PAD_WIDTH):
|
|||||||
yield ''.join(chunk)
|
yield ''.join(chunk)
|
||||||
chunk = []
|
chunk = []
|
||||||
if len(chunk) < width:
|
if len(chunk) < width:
|
||||||
chunk += ([NULLCHAR] * (width - len(chunk)))
|
chunk += ([nullchar] * (width - len(chunk)))
|
||||||
yield ''.join(chunk)
|
yield ''.join(chunk)
|
||||||
|
|
||||||
|
|
||||||
def _text_padfill(text, padlines):
|
|
||||||
if isinstance(padlines, basestring):
|
|
||||||
padlines = padlines.splitlines()
|
|
||||||
padlines = [line.strip() for line in padlines if line.strip()]
|
|
||||||
textlines = _chunk_chars_into_lines(text, _get_textwidth(padlines))
|
|
||||||
for textline, padline in izip(textlines, padlines):
|
|
||||||
yield padline
|
|
||||||
yield textline
|
|
||||||
yield ''
|
|
||||||
|
|
||||||
|
|
||||||
def _cipher_padfill(ciphertext, padlines):
|
|
||||||
if isinstance(padlines, basestring):
|
|
||||||
padlines = padlines.splitlines()
|
|
||||||
padlines = [line.strip() for line in padlines if line.strip()]
|
|
||||||
cipherlines = _chunk_chars_into_lines(ciphertext, _get_textwidth(padlines))
|
|
||||||
for cipherline, padline in izip(cipherlines, padlines):
|
|
||||||
yield padline
|
|
||||||
yield ''
|
|
||||||
yield cipherline
|
|
||||||
|
|
||||||
|
|
||||||
def _text_cipherfill(padfilled_text_lines):
|
|
||||||
for i, line in enumerate(padfilled_text_lines):
|
|
||||||
lineno = i + 1
|
|
||||||
if _is_cipherline(lineno):
|
|
||||||
padline = padfilled_text_lines[i - abs(PADLINE_OFFSET)]
|
|
||||||
textline = padfilled_text_lines[i - abs(TEXTLINE_OFFSET)]
|
|
||||||
yield padline
|
|
||||||
yield textline
|
|
||||||
yield _cipherline_from_padline_and_textline(padline, textline)
|
|
||||||
|
|
||||||
|
|
||||||
def _cipher_textfill(padfilled_cipher_lines):
|
|
||||||
for i, line in enumerate(padfilled_cipher_lines):
|
|
||||||
lineno = i + 1
|
|
||||||
if _is_cipherline(lineno):
|
|
||||||
padline = padfilled_cipher_lines[i - abs(PADLINE_OFFSET)]
|
|
||||||
textline = padfilled_cipher_lines[i - abs(TEXTLINE_OFFSET)]
|
|
||||||
yield padline
|
|
||||||
yield _textline_from_cipherline_and_padline(line, padline)
|
|
||||||
yield line
|
|
||||||
|
|
||||||
|
|
||||||
def _cipherline_from_padline_and_textline(padline, textline):
|
|
||||||
ret = []
|
|
||||||
for padchar, textchar in izip(padline, textline):
|
|
||||||
if textchar == NULLCHAR:
|
|
||||||
ret.append(NULLCHAR)
|
|
||||||
continue
|
|
||||||
charnum = _AS_NUMS[padchar] + _AS_NUMS[textchar]
|
|
||||||
idx = charnum if charnum <= CIPHER_CEIL else charnum % CIPHER_CEIL
|
|
||||||
ret.append(_AS_ALPHA[idx])
|
|
||||||
return ''.join(ret)
|
|
||||||
|
|
||||||
|
|
||||||
def _textline_from_cipherline_and_padline(cipherline, padline):
|
|
||||||
ret = []
|
|
||||||
for ciphercar, padchar in izip(cipherline, padline):
|
|
||||||
if ciphercar == NULLCHAR:
|
|
||||||
ret.append(NULLCHAR)
|
|
||||||
continue
|
|
||||||
charnum = _AS_NUMS[ciphercar] - _AS_NUMS[padchar]
|
|
||||||
idx = charnum if charnum <= CIPHER_CEIL else charnum % CIPHER_CEIL
|
|
||||||
if idx < 0:
|
|
||||||
idx = CIPHER_CEIL + idx
|
|
||||||
ret.append(_AS_ALPHA[idx])
|
|
||||||
return ''.join(ret)
|
|
||||||
|
|
||||||
|
|
||||||
def _get_textwidth(textlines):
|
def _get_textwidth(textlines):
|
||||||
return max([len(line) for line in textlines])
|
return max([len(line) for line in textlines])
|
||||||
|
|
||||||
|
|
||||||
def _is_padline(lineno):
|
def _get_randint(modulo, randomness_file='/dev/urandom',
|
||||||
return _is_cipherline(lineno + abs(PADLINE_OFFSET))
|
fallback_to_fake=True):
|
||||||
|
if not _DEV_URANDOM.get('fp'):
|
||||||
|
|
||||||
def _is_textline(lineno):
|
|
||||||
return _is_cipherline(lineno + abs(TEXTLINE_OFFSET))
|
|
||||||
|
|
||||||
|
|
||||||
def _is_cipherline(lineno):
|
|
||||||
return not lineno % PAD_MODULO
|
|
||||||
|
|
||||||
|
|
||||||
def _get_randint(randomness_file='/dev/urandom', fallback_to_fake=True):
|
|
||||||
if not _DEV_RANDOM.get('fp'):
|
|
||||||
_get_urandom_fp(randomness_file=randomness_file,
|
_get_urandom_fp(randomness_file=randomness_file,
|
||||||
fallback_to_fake=fallback_to_fake)
|
fallback_to_fake=fallback_to_fake)
|
||||||
ret = ord(_DEV_RANDOM['fp'].read(1)) % CIPHER_CEIL
|
ret = ord(_DEV_URANDOM['fp'].read(1)) % modulo
|
||||||
return ret if ret != 0 else _get_randint()
|
return ret if ret != 0 else _get_randint(modulo)
|
||||||
|
|
||||||
|
|
||||||
class _FakeDevUrandom(object):
|
class _FakeDevUrandom(object):
|
||||||
|
|
||||||
def read(self, nchars):
|
@staticmethod
|
||||||
|
def read(nchars):
|
||||||
import random
|
import random
|
||||||
return ''.join([chr(random.randint(0, 255)) for i in range(0, nchars)])
|
ret = []
|
||||||
|
for i in range(0, nchars):
|
||||||
|
ret.append(chr(random.randint(0, 255)))
|
||||||
|
return ''.join(ret)
|
||||||
|
|
||||||
|
|
||||||
def _get_urandom_fp(randomness_file='/dev/urandom', fallback_to_fake=True):
|
def _get_urandom_fp(randomness_file='/dev/urandom', fallback_to_fake=True):
|
||||||
try:
|
try:
|
||||||
_DEV_RANDOM['fp'] = open(randomness_file)
|
_DEV_URANDOM['fp'] = open(randomness_file)
|
||||||
except (OSError, IOError):
|
except (OSError, IOError):
|
||||||
if fallback_to_fake:
|
if fallback_to_fake:
|
||||||
_DEV_RANDOM['fp'] = _FakeDevUrandom()
|
_DEV_URANDOM['fp'] = _FakeDevUrandom()
|
||||||
else:
|
else:
|
||||||
raise
|
raise
|
||||||
|
|
||||||
|
|
||||||
_DEV_RANDOM = {}
|
_DEV_URANDOM = {}
|
||||||
|
|
||||||
|
|
||||||
def _mk_as_alpha_as_nums():
|
|
||||||
as_alpha = {}
|
|
||||||
as_nums = {}
|
|
||||||
a_chr = ord('A')
|
|
||||||
past_j = False
|
|
||||||
|
|
||||||
for char in range(CIPHER_CEIL + 1):
|
|
||||||
letter = chr(a_chr + char)
|
|
||||||
if letter != 'J':
|
|
||||||
key = char + (1 if not past_j else 0)
|
|
||||||
as_alpha[key] = letter
|
|
||||||
else:
|
|
||||||
past_j = True
|
|
||||||
|
|
||||||
for key, val in as_alpha.iteritems():
|
|
||||||
as_nums[val] = key
|
|
||||||
|
|
||||||
return as_alpha, as_nums
|
|
||||||
|
|
||||||
|
|
||||||
_AS_ALPHA, _AS_NUMS = _mk_as_alpha_as_nums()
|
|
||||||
|
Loading…
Reference in New Issue
Block a user