Running a numbers station

What is a numbers station?

A numbers station is a broadcast station that sends a list of numbers over shortwave radio. They are probably sending coded messages to spies. This use is referred to as a one-way voice link. Read the Wikipedia article on numbers stations for a general overview. You can find the specifics (frequencies, time of day, etc) for numbers stations at priyom.org. To learn how the encryption probably works read Dirk Rijmenants' pages on One-time Pad and The Manual One-time Pad.

What do I need?

Messages to send

For my target audience I went with quotes from science fiction authors. For example:

Science is magic that works. - Kurt Vonnegut

The next step is encoding your messages. This is not the encryption part. Since I wanted a numbers station and not a letters station I converted the quotes into numbers. I used straddling checkerboard CT-37c (shown on the The Manual One-time Pad page) to convert my quotes into numbers. It is expected that a real message would have any unneccesary spaces removed. I left most in to make things easier for the people decoding the messages.

CODE
0
A
1
E
2
I
3
N
4
O
5
T
6
CT-37c
B
70
C
71
D
72
F
73
G
74
H
75
J
76
K
77
L
78
M
79
P
80
Q
81
R
82
S
83
U
84
V
85
W
86
X
87
Y
88
Z
89
FIG
90
.
91
:
92
'
93
()
94
+
95
-
96
=
97
REQ
98
SPC
99

Science is magic that works.-Kurt Vonnegut
8371324712993839979174371996751699865827783919677848269985544274846

The numbers are arranged in groups of 5. The last group is padded with 9s as needed.

83713 24712 99383 99791 74371 99675 16998 65827 78391 96778 48269 98554 42748 46999

Some random numbers

Where can you get good random numbers?
RANDOM.ORG is a good place to start. They have 2 options that are almost perfect:

Random Intergers - You will need to manually add leading zeros to any group that is less than 5 digits.
Random Strings - These have their leading zeros but it is formatted in 1 column.

If you have access to a hardware RNG you could use that. I would avoid using a pseudorandom number generator (any software based random number generator) but for a puzzle it is probably okay. I bought an RTL-SDR USB dongle for $7 on ebay and used rtl-entropy as my RNG source. If you have a Raspberry Pi lying around you can use its HWRNG. Look at the rng.txt script in the software section below.

Even though this is just for fun do NOT use the same page for more than one message. That would convince your puzzle decoders that you have no idea how any of this is supposed to work.

For our example we will use this page:



98392 92904 19478 62743 75792
95310 31348 12478 57042 01936
87891 50293 55708 42843 12427
32192 98661 11575 24498 29767
45952 53539 34865 61381 72658
88457 19291 09810 97766 14554
52177 98437 70929 66370 13352
65820 49360 26558 57971 09957
26342 90321 87562 03018 70045
52979 97212 52211 62243 96548
62619 51683 25415 07879 79954
       numbers

The first group (98392) will be used to identify this page of random numbers so we will start with the second group (92904). Subtract the random numbers from the message. If the result from subtraction is less than 0, add 10. This is similar to clock math but we are using 10 digits instead of 12. Never ever borrow or carry digits. Each column is handled independently. Look at the first column. 8 - 9 = 9. Obviously 8 - 9 is really -1 but that is less than 0 so add 10. -1 + 10 = 9. Going ahead with the next two colums 3 - 2 = 1, no problem there. 7 - 9 = 8. Again 7 - 9 would normally give -2. Since -2 is less than 0 add 10 to get 8. Once this process is complete we have our encrypted message.

  83713 24712 99383 99791 74371 99675 16998 65827 78391 96778 48269 98554 42748 46999
- 92904 19478 62743 75792 95310 31348 12478 57042 01936 87891 50293 55708 42843 12427
  91819 15344 37640 24009 89061 68337 04520 18885 77465 19987 98076 43856 00905 34572

One-time pads for each recipient

pads Here are 2 one-time pad book examples. The cover is closely modeled after The Manual One-time Pad example booklet. When you cut the pages leave most of the blank space at the top of each page to leave room for a staple.

Example book 416 - Example above comes from this book.
Example book 795

Instruction book - Cut and fold - YouTube directions.

It is really helpful to your puzzle decoders if the one-time pad pages are in order by the page identifier (first group). The example books will end up in order if you cut them a certain way. The sort.txt program in the software section below will put your random blocks into the correct order for cutting.

Depending on how much work you want to put into this you can either use my example files directly or use them as templates. You can print 1 copy of the instruction book and then tape a piece of paper over the frequency and operating times, write in your own information and photocopy it. If you want to edit the original instruction book it is available here. After you have finished editing the file convert it to PDF. Extract and run PDFtoPocketMod.zip (downloaded from PocketMod.com) to convert the PDF file into the foldable form. It always fails the first time. Click 'Save as PocketMod' a second time and it will generate your PDF to print. This is a .NET application and seems to run fine in Mono.

A radio transmitter (online streaming could work)

radio You can buy legal power FM transmitters really really cheap. If that link does not work, search ebay for 'fm transmitter' and sort by price. There should be transmitters for less than $3 including shipping. These will probably only transmit for 20 - 30 feet. Depending on your activity area that might be perfect. If that is not appropriate I suggest looking into an online stream. If you are going to go with FM use radio-locator to find a vacant frequency in your area. Listen to make sure it is not in use. radio-locator is only going to tell you about licensed users.

Choose a message format

Spend some time looking through the formats of real numbers stations at priyom.org. Some are fixed length, some start and end with music, some have test tones and test digits. Listen to some examples to get a feel for the timing.

This is the format I went with: The final message looks like this:

260 260 260           260 260 260           260 260 260           260 260 260           260 260 260           416 416 15 15 98392 98392 91819 91819 15344 15344 37640 37640 24009 24009 89061 89061 68337 68337 04520 04520 18885 18885 77465 77465 19987 19987 98076 98076 43856 43856 00905 00905 34572 34572 0 0 0

Timing: 2 [0.4] 6 [0.4] 0 [0.4] [0.5] 2 [0.4] 6 [0.4] 0 [0.4] [0.5] 2 [0.4] 6 [0.4] 0 [0.4] [0.5] [5.0] (X 5) 4 [0.4] 1 [0.4] 6 [0.4] [0.5] 4 [0.4] 1 [0.4] 6 [0.4] [0.5] 1 [0.4] 5 [0.4] [0.5] 1 [0.4] 5 [0.4] [0.5] 9 [0.4] 8 [0.4] 3 [0.4] 9 [0.4] 2 [0.4] [0.5] ...

Listen to an example.

Download audio packs:
Cognitronics Speechmaker, 205K, 0.80 seconds each, used for E05 (CIA) and E23 (AW), sound files and permission to use them were provided by the Cedar Knoll Telephone and Telegraph Company.
Jane Barbe, 869K, 0.55 seconds each, Bell System, sampled by Elmer Cat, use 6 ID groups instead of 5 to get 90 seconds.
Google Translate, 174K, 0.60 seconds each, translate.google.com, use 6 ID groups instead of 5 to get 90 seconds.
Morse Code - See Below.

Add some complexity

Adding a code book (with carefully chosen words) can reduce the length of your messages. Removing unneccesary spaces can futher reduce the message length. My example directions include the code book from The Manual One-time Pad and CT-37c provides a single digit (0) to switch to the code book.

I do not fear computers.I fear the lack of them.-Isaac Asimov
39972 59945 69973 21829 97157 98084 62828 39139 97321 82996 75299 78171 77995 73996 75279 91963 83117 19918 33795 85999


I do not fear0172s.I fear the lack of them.-Isaac Asimov
39972 59945 69973 21820 17283 91399 73218 29967 52997 81717 79957 39967 52799 19638 31171 99183 37958 59999


Idonotfear0172sIfearthelackofthem-IsaacAsimov
37254 56732 18201 72833 73218 26752 78171 77573 67527 99638 31171 18337 95859


The instruction book does not explain how the codes work. I only used codes in 2 of the 22 messages.

Add some real complexity

This would be a different kind of puzzle but you could use the same key for every message and not provide the one-time pads. With each new message sent discovering the key would become easier. Earlier I said to never do this because it makes the message breakable without the key but that could be the point. The instruction book does not cover this kind of puzzle. Read more here: Breaking a Reused One-time pad. You really need to know your target audience for this one.

Implementation

box You have turned your messages into audio files. Now what?

I set up a transmitter to broadcast on a frequency that was not in use in the area. I set the hours of operation to noon through 10 PM Friday and Saturday. That is enough time for 22 puzzles. If you have an area dedicated to this and it will not cause a disruption to others you could skip the transmitter and just use a speaker. I made a flyer with the frequency and a link to the PDF files. I taped the flyer to a box with instruction books and one-time pad books. 2 one-time pad books fit neatly inside the instruction books. The instruction books have 2 pages that work well as pockets. Printing 1/4 size flyers worked well taped by doors around the convention. 1/16 size worked to leave on tables. The QR code would still scan correctly at that size.

I suggest that you repeat the messages over and over during the hour instead of a single transmission at the top of the hour. The repeat.sh program in the software section below can help with this. The next time I do this I plan to put make the audio files available with the PDF downloads. Just the currently playing file, not all of them at once. This will let people with a laptop or smart phone participate without a radio.

Software

mkpad.py - Python script that will generate new one-time pad books ready for cutting. This script replaces rng.txt and sort.txt below. Edit the script to select your random source and then run it in the same folder as otp-template.odt. A new book (otp-in-xxx.odt) will be created in the same folder.

Example:
$ python mkpad.py

rng.txt - (replaced by mkpad.py) PHP script that will convert a binary RNG stream (/dev/random, /dev/hwrng, /var/run/rtl_entropy.fifo) into formatted digits without introducing bias.
echo PHP_EOL; is commented out. This puts all of the output on one line making it suitable for the one-time pad templates above.

Example:
$ php rng.txt
23553 42054 76368 73848 40076
27952 20777 88992 18641 92343
68454 36112 27668 02377 56183
71052 27762 46482 27812 89638
23437 35615 13827 93262 38483
32990 42370 76772 82439 15912
00297 08511 43121 81612 92501
06582 69115 84332 06603 35251
59158 80723 54031 09417 79072
05741 72873 01253 80517 71293
29814 33721 64026 87611 38650


sort.txt - (replaced by mkpad.py) PHP script that will sort 15 random number blocks and place them in the proper order for pasting into an example book template.

Example:
$ head -5 416.txt
41693 70794 08216 86521 06764 98341 81853 52505 51513 63700 ...
47612 97639 47369 55932 74225 77214 64550 40358 71827 65488 ...
30117 41680 25595 22212 62681 40558 60733 82514 47034 00848 ...
16926 37363 22852 60663 37575 70368 07615 82672 15578 54942 ...
04881 17458 40053 94620 36672 23735 51479 67333 37486 13345 ...

$ php sort.txt <416.txt
31617 00648 57336 60952 03638 40631 61537 49405 76027 27730 ...



62938 35653 13766 84760 54565 65085 25231 53613 98052 44831 ...



98392 92904 19478 62743 75792 95310 31348 12478 57042 01936 ...



04881 17458 40053 94620 36672 23735 51479 67333 37486 13345 ...



23986 73389 18207 12447 98333 74088 37005 30778 52337 75809 ...
...


ct37c.txt - PHP script that will convert STDIN to grouped numbers. Numbers will automatically be triplicated and surrounded by the figure symbol (90). Use * to prefix codes. Use & for REQ.

Example:
$ echo 'I do not fear*172s.I fear the lack of them.-Isaac Asimov' | php ct37c.txt
39972 59945 69973 21820 17283 91399 73218 29967 52997 81717 79957 39967 52799 19638 31171 99183 37958 59999


otp.txt - PHP script that will encrypt a message already converted to numbers. This expects a text file formatted a certain way. Originally I had this script use the one-time pad book number to determine the agent. In the end I decided to go with 1 agent and give all listeners both books so they could decode all of the messages. Set $agent near the top of the script. If you are using an audio pack that needs 6 ID groups set $repeat to 6.

File format:
Line 1: Clear text
Line 2: Text converted to grouped numbers
Line 3: [one-time pad book number] [first code group]
Line 4: Random numbers to be used during encryption

A1.txt - Example file.

Example:
$ php otp.txt <A1.txt | tail -1 >>A1.txt

Output if not redirected:
260 260 260           260 260 260           260 260 260           260 260 260           260 260 260           795 795 19 19 22692 22692 04671 04671 91776 91776 88107 88107 49918 49918 30432 30432 55758 55758 22486 22486 46613 46613 49661 49661 82561 82561 56988 56988 07060 07060 44700 44700 64333 64333 71796 71796 37829 37829 63515 63515 62642 62642 0 0 0

playlist.txt - PHP script to convert the last line of otp.txt's output to a list of audio files. This script expects the wav files to be in a subfolder named sound. If you are not using inflected voice for the last digit of each group then comment out or delete 'counter++' in this file.

Example with an older sox and ffmpeg:
$ tail -1 A1.txt | php playlist.txt >A1.list
$ sox `cat A1.list` A1.wav
$ ffmpeg -i A1.wav A1.mp3
$ rm A1.wav


Example with a newer sox and libsox-fmt-all:
$ tail -1 A1.txt | php playlist.txt >A1.list
$ sox `cat A1.list` A1.mp3


otp.txt and playlist.txt can be chained together to create the list file:
$ php otp.txt <A1.txt | tail -1 | php playlist.txt >A1.list

If sox complains about too many files being open, split the list into smaller chunks and combine the temp files. This example shows the list being split into 3 pieces. You may have more or less. You will need to generate a wav file from each list and then combine them and remove the temp files.
$ split -l 500 R1.list
$ sox `cat xaa` xaa.wav
$ sox `cat xab` xab.wav
$ sox `cat xac` xac.wav
$ sox xaa.wav xab.wav xac.wav R1.wav
$ rm xaa xab xac xaa.wav xab.wav xac.wav


list2mp3.sh - Shell script to automate list splitting and wav combining. See commented out section if you use an older sox.

Example:
$ list2mp3.sh A1

repeat.sh - Shell script to repeat an MP3 over and over until the top of the next hour. There are multiple commented sections for different players and ways to determine the MP3 length. Choose an appropriate option for your system.

Example:
$ repeat.sh V2.mp3

Morse Code

If you are considering morse code instead of spoken letters I have some scripts to help. You will need an audio pack for the numbers and a different playlist program that uses morse spacing.

morse.sh will generate the audio files. You can set the speed (wpm) and tone frequency (freq) near the top of the script. Look through this script. There are some commented out symbols you may need depending on the format you choose. After morse.sh has created the wav files it will display an example command to generate the final mp3. Take note of this output. It includes an appropriate bandpass filter to reduce clicks for the frequency and speed you selected. This requires a new-ish sox and the libsox-fmt-all package.

playlist-morse.txt works like playlist.txt above. It will convert a complete message into a list of audio files with morse spacing instead of voice spacing.

The message format for morse is a bit different than the format for spoken numbers. If you want to use morse I suggest you look at the message formats at priyom.org. I liked the Russian format the best (m01, m01b, m14, m24, m25). For something a bit different Cuban stations m08 and m08a use cut numbers instead of full length numbers.

I went with: For this example I used the non-morse otp.txt script and then manually modified to the morse format (changes highlighted in bold).

260      260      260      260      260      260      260      260      260      260      260      416 416 15 15 b b 98392 98392 91819 91819 15344 15344 37640 37640 24009 24009 89061 89061 68337 68337 04520 04520 18885 18885 77465 77465 19987 19987 98076 98076 43856 43856 00905 00905 34572 34572 b b 416 416 15 15 0 0 0

Listen to an example.

The bandpass echoed by morse.sh is important. Here is the same example without it: V2-morse-clicks.mp3.

Have fun

Enjoy setting up a puzzle for others to work out!

puzzle puzzle puzzle

Contact Me

Questions? Comments? I would love to hear from you. Email Jack Zielke.