import unittest import onetimepad as OT class TestMod25(unittest.TestCase): msg = ('HOWMUCHCHUCKCOULDAWOODCHUCKCHUCKIFA' 'WOODCHUCKCOULDCHUCKWOOD' * 50) _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): self.assertTrue('J' not in self.m25._as_alpha.values()) def test_mk_as_alpha_dict_has_25_members(self): self.assertEqual(25, len(self.m25._as_alpha.items())) def test_creates_pad_of_desired_length(self): for width in (72, 33, 99, 111): pad = self.m25.create_pad(self._padsize, width=width) lines = [line.strip('.') for line in pad.split()] actual = len(''.join(lines)) self.assertEqual(self._padsize, len(''.join(lines)), 'pad of {0} chars created at width ' '{1}, actual={2}'.format(self._padsize, width, actual)) def test_is_padline(self): for lineno in self.PADLINES: self.assertTrue(self.m25._is_padline(lineno), 'line {0} is padline'.format(lineno)) for lineno in self.TEXTLINES: self.assertFalse(self.m25._is_padline(lineno), 'line {0} is not padline'.format(lineno)) for lineno in self.CIPHERLINES: self.assertFalse(self.m25._is_padline(lineno), 'line {0} is not padline'.format(lineno)) def test_is_textline(self): for lineno in self.TEXTLINES: self.assertTrue(self.m25._is_textline(lineno), 'line {0} is textline'.format(lineno)) for lineno in self.PADLINES: self.assertFalse(self.m25._is_textline(lineno), 'line {0} is not textline'.format(lineno)) for lineno in self.CIPHERLINES: self.assertFalse(self.m25._is_textline(lineno), 'line {0} is not textline'.format(lineno)) def test_is_cipherline(self): for lineno in self.CIPHERLINES: self.assertTrue(self.m25._is_cipherline(lineno), 'line {0} is cipherline'.format(lineno)) for lineno in self.PADLINES: self.assertFalse(self.m25._is_cipherline(lineno), 'line {0} is not cipherline'.format(lineno)) for lineno in self.TEXTLINES: self.assertFalse(self.m25._is_cipherline(lineno), 'line {0} is not cipherline'.format(lineno)) def test_make_cipherline_from_padline_and_textline(self): actual = \ self.m25._cipherline_from_padline_and_textline(self.TEST_PADLINE, self.TEST_TEXTLINE) self.assertEqual(self.TEST_CIPHERLINE, actual) def test_make_textline_from_cipherline_and_padline(self): actual = self.m25._textline_from_cipherline_and_padline( self.TEST_CIPHERLINE, self.TEST_PADLINE) self.assertEqual(self.TEST_TEXTLINE, actual) def test_encode_equals_expected(self): ciphertext = OT.mod25encode(self.TEST_MSG, self.TEST_PAD) self.assertEqual(self.TEST_CIPHER, ciphertext) def test_decode_equals_expected(self): text = OT.mod25decode(self.TEST_CIPHER, self.TEST_PAD) self.assertEqual(self.TEST_MSG, text) class TestOneTimePad(unittest.TestCase): def test_get_randint_on_nonexistent_randomness_file_fails_ioerror(self): OT._DEV_URANDOM['fp'] = None self.assertRaises(IOError, OT._get_randint, 25, randomness_file='/foo/bar/busted/borken', fallback_to_fake=False) def test_get_randint_on_nonexistent_randomness_file_uses_fake(self): OT._DEV_URANDOM['fp'] = None random_int = OT._get_randint(32, randomness_file='/broke/as/joke') self.assertTrue(random_int in range(0, 255)) if __name__ == '__main__': unittest.main()