The next approach looks more innocent. First you send a normal looking text and later you send a string of numbers, where each number is an index in the normal text that rebuilds your message ...

''' xmas_letter_crypt101.py hide a message in a boring lengthy xmas letter first you send the xmas letter, later you send an index string where each indexed character in the xmas letter matches a message character (all lower case) ''' import pprint import random def create_index_dict(text): ''' return a character:index_list dictionary of a given text replace newlines with '~~' ''' text = text.lower() index_dict = {} for ix, letter in enumerate(text): index_dict.setdefault(letter, []).append(ix) return index_dict def index_message(index_dict, my_message): ''' create the index string you can send each index matches a message char in the xmas letter ''' # convert to lower case my_message = my_message.lower() index_str = "" n = 1 for ix, c in enumerate(my_message): index_list = index_dict[c] # shuffle the index_list # and pick the first element # adds some randomness to index_str random.shuffle(index_list) index = index_list[0] # add a newline char after 10 indices # else add a space if n % 10 == 0: index_str += str(index) + '

' else: index_str += str(index) + ' ' n += 1 return index_str my_message = "Meet me at four thirty PM at the dog park elm tree" # a typical xmas letter you can receive if you are unlucky # make sure it has all your potential message characters in it xmas_letter = '''\ Dear friends, it is a great pleasure to let you all know what we did in the past year. We are quite sure you are just waiting with high anticipation to read this. In January Zoey and Bruce went with us to see Aunt Lulu in Park City Utah. Should we quickly e-mail you all the interesting slides we took? In August we went to visit Blair and Karen at their new home in zany Texas. That place has five bedrooms and seven bathrooms. One of their children fell off the bike, and we took little Freddy to the local child-clinic! Bob Quackenbush went to the doctor to have the wart on his nose removed. He looks real good now! Attracting the amorous attention of Nancy Trotter who had a heart attack in May, but they fixed her and she survived. We hope you are all very healthy and have a merry Christmas and a prosperous New Year. Greetings to all, Mark, Rita and dog Pluto ''' index_dict = create_index_dict(xmas_letter) #pprint.pprint(index_dict) # test # display content of index dictionary # lists shortened to 10 elements, '``' subs for newline print("Prettified content of the index dictionary:") for key, val in sorted(index_dict.items()): # limit list to 10 elements to print nicely print("{}: {}".format(repr(key), val[:10])) print('-'*72) index_str = index_message(index_dict, my_message) print("Potential index_str =

{}".format(index_str)) print('-'*72) # convert index_str to an index list index_list = [int(index) for index in index_str.split()] #pprint.pprint(index_list) # test # now apply the index list to the lowercase xmas letter msg = "".join(xmas_letter.lower()[index] for index in index_list) print("Hidden message =

{}".format(msg)) ''' # optional character frequency count information print('-'*72) print('') from collections import Counter cntr = Counter(xmas_letter.lower()) # print sorted by count (default) pprint.pprint(cntr.most_common()) ''' ''' result ... Prettified content of the index dictionary: '

': [13, 86, 156, 162, 163, 238, 303, 304, 373, 444] ' ': [4, 16, 19, 21, 27, 36, 39, 43, 47, 51] '!': [524, 622] ',': [12, 471, 704, 848, 855] '-': [258, 517] '.': [85, 161, 237, 379, 430, 598, 741, 829] '?': [302] 'a': [2, 20, 25, 31, 48, 59, 77, 83, 90, 109] 'b': [184, 332, 402, 421, 467, 527, 529, 538, 706] 'c': [140, 187, 228, 252, 390, 445, 508, 512, 518, 523] 'd': [0, 10, 65, 67, 155, 182, 244, 291, 340, 404] 'e': [1, 8, 24, 30, 35, 41, 63, 74, 82, 88] 'f': [5, 397, 437, 454, 460, 461, 492, 659, 715] 'g': [22, 124, 133, 286, 310, 614, 634, 832, 839, 868] 'h': [58, 73, 129, 131, 134, 158, 198, 236, 240, 273] 'i': [7, 14, 17, 66, 69, 96, 120, 122, 127, 132] 'j': [113, 167] 'k': [52, 226, 253, 301, 342, 469, 483, 535, 606, 696] 'l': [29, 40, 49, 50, 215, 217, 243, 254, 262, 269] 'm': [259, 363, 408, 428, 593, 641, 701, 788, 800, 851] 'n': [9, 53, 70, 123, 137, 147, 165, 169, 181, 192] 'o': [38, 45, 54, 106, 146, 150, 176, 204, 241, 265] 'p': [28, 76, 142, 223, 387, 749, 810, 814, 870] 'q': [94, 249, 531] 'r': [3, 6, 23, 34, 84, 91, 102, 110, 152, 172] 's': [11, 18, 32, 78, 100, 115, 160, 201, 206, 239] 't': [15, 26, 37, 42, 60, 72, 79, 97, 116, 121] 'u': [33, 46, 95, 101, 107, 114, 170, 186, 200, 211] 'v': [326, 399, 417, 567, 595, 736, 738, 764, 783] 'w': [55, 57, 62, 87, 118, 126, 190, 195, 246, 295] 'x': [376, 717] 'y': [44, 81, 105, 173, 178, 231, 255, 264, 372, 497] 'z': [175, 369] ------------------------------------------------------------------------ Potential index_str = 701 74 24 577 803 408 822 458 171 671 16 492 812 309 688 27 116 383 522 405 502 775 547 814 851 71 629 203 337 636 541 281 21 617 54 286 787 749 384 609 52 484 319 519 851 728 546 405 758 478 ------------------------------------------------------------------------ Hidden message = meet me at four thirty pm at the dog park elm tree '''