-
Notifications
You must be signed in to change notification settings - Fork 5
/
Copy pathpmhsc.py
151 lines (107 loc) · 3.83 KB
/
pmhsc.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
#!/usr/bin/env python
#
# pmhsc - poor man's homophonic substitution cipher
# /~https://github.com/vesche/pmhsc
#
import argparse
import os
import pickle
import random
import sys
import time
from itertools import product
from string import ascii_lowercase
CHARS = ascii_lowercase + ' '
def generate_maps():
start_time = time.time()
# get 7 random non-repeating letters and space
letters = random.sample(CHARS, 8)
# get the 16,777,216 permutations with repetitions and shuffle them
perms = [''.join(_) for _ in product(letters, repeat=8)]
random.shuffle(perms)
perm_dict = {}
for l in CHARS:
l_index = CHARS.index(l)
perm_dict[l] = perms[621378*l_index:621378*(l_index+1)]
with open('mapping.p', 'wb') as f:
pickle.dump(perm_dict, f)
print('Mapping completed in {0:.2f} seconds.'.format(time.time() - start_time))
def check_file(f_name):
if not os.path.isfile(f_name):
print('{}: No such file.'.format(f_name))
sys.exit(1)
def read_map(map_file):
if not os.path.isfile(map_file):
print('Unable to find mapping file, use --genmaps to generate one.')
sys.exit(1)
with open(map_file, 'rb') as f:
return pickle.loads(f.read())
def encrypt(map_file, input_file, output_file):
check_file(input_file)
start_time = time.time()
mapping = read_map(map_file)
with open(input_file) as f:
plaintext = f.read()
with open(output_file, 'w') as f:
for i in plaintext:
if i.isalpha() or (i == ' '):
i = i.lower()
f.write(random.choice(mapping[i]))
print('Encryption completed in {0:.2f} seconds.'.format(time.time() - start_time))
def decrypt(map_file, input_file, output_file):
check_file(input_file)
start_time = time.time()
mapping = read_map(map_file)
def search_mapping(s):
for k, vals in mapping.items():
for v in vals:
if v == s:
return k
with open(input_file) as f:
ciphertext = f.read()
plaintext = ''
enc_letters = [ciphertext[x:x+8] for x in range(0, len(ciphertext), 8)]
for l in enc_letters:
plaintext += search_mapping(l)
with open(output_file, 'w') as f:
f.write(plaintext+'\n')
print('Decryption completed in {0:.2f} seconds.'.format(time.time() - start_time))
def get_parser():
parser = argparse.ArgumentParser(description='poor man\'s homophonic substitution cipher')
parser.add_argument('-g', '--genmaps',
help='generate mapping file', action='store_true')
parser.add_argument('-e', '--encrypt',
help='encrypt a file', action='store_true')
parser.add_argument('-d', '--decrypt',
help='decrypt a file', action='store_true')
parser.add_argument('-m', '--mapping',
help='specify a mapping file to use (default: mapping.p)',
type=str, default='mapping.p')
parser.add_argument('-i', '--input',
help='input file', type=str)
parser.add_argument('-o', '--output',
help='output file', type=str)
return parser
def main():
parser = get_parser()
args = vars(parser.parse_args())
if not (args['genmaps'] or args['encrypt'] or args['decrypt']):
parser.print_help()
return
if args['genmaps']:
generate_maps()
return
if not args['input']:
print('Input file not supplied.')
return
if not args['output']:
print('Output file not supplied.')
return
if args['encrypt']:
encrypt(args['mapping'], args['input'], args['output'])
return
if args['decrypt']:
decrypt(args['mapping'], args['input'], args['output'])
return
if __name__ == '__main__':
main()