Tuesday, February 14, 2023

Afternoon Project: CryptMaster 2001

This is another quick and quirky project I put together for my two younger kids : a pair of simple, handheld devices that let them enter text and then write down the its encrypted representation on a piece of paper. The recipient of this coded message can then enter it on their device to recover the original text.

CryptMaster 2001: secure communications at the palm of your hand.

The interface is simple: turning the decorative knob on the right lets you cycle through the alphabet. A short press of the small tactile button on the left advances the cursor to the next position. A longer press erases all previously entered text.

The circuit is similarly uncomplicated. A popular ATmega328P microcontroller is interfaced to a 16x2 text OLED module from Newhaven Display (NHD-0216CW-AR3); this particular module is now out of production, but most other devices from Newhaven and other vendors share the same interface. The module aside, the MCU is also connected to a switch and an incremental rotary encoder (possibly PEC12R):

The entirety of the CryptMaster circuit.

Incremental rotary encoders are a modern-day replacement for potentiometers, offering longer service life and built-in haptic feedback, usually with 24 detents per turn. Internally, the encoder has two offset contacts (A and B) and a common terminal. Depending on the direction of rotation, the encoder produces two different waveforms:

Rotary encoder signals, by author.

If there is a rising edge on output A but output B is low, the encoder must be turning in one direction; if the opposite is true, it’s going the other way round; the speed can be inferred from the frequency of pulses. The scheme might sound simple, but it’s easy to make mistakes. I encountered a fair share of electronics with wonky-feeling encoders, and it’s usually not a mechanical fault, just bad coding. For example, insufficient sampling rates cause sluggish or reversed movement when the dial is being rotated quickly; while excessive sample rates cause problems due to debounce artifacts.

As for the remaining parts of the circuit, there’s not much to note. Like virtually all text display modules, the NHD-0216CW-AR3 superficially adheres to the ancient Hitachi HD44780 spec. Pins 17-19 (BS0-BS2) set the input mode; in this case, we’re using the familiar “8080” protocol. There are small gotchas here and there — for example, the spec gives an incorrect memory offset for the second line of the display — but nothing to write home about.

The most interesting part of the project is probably the cipher. For simplicity, I wanted it to be self-reciprocal, so that no separate algorithm or UI setting would be needed to decrypt received messages. A well-known scheme with this property is ROT13, where every letter of the alphabet is shifted by 13 positions (“A” becomes “N”, “Q” becomes “D”, etc). Because the English alphabet has 26 letters, another identical shift restores the original string. Alas, ROT13 is a bit too trivial and too well-known. Meanwhile, shifts by other values lack the requisite symmetry.

Another well-known self-reciprocal operation is XOR: it flips a subset of bits and flips them back again when you XOR the result with the same value once again. But 26 isn’t near any power of two, so we would either need to pad the alphabet to get to 32 symbols, or accept some inelegant bias.

In the end, I settled on another trick: I took the standard 26-character alphabet and then divided in into 13 randomly-selected pairs, swapping nominal alphabet positions for the members of each pair. This way, no letter in the ciphertext stays the same as in the plaintext message, but the mapping is symmetric: if “F” is in the position of “A”, then “A” is in the position of “F”.

To further slow down their cryptanalysis without making the scheme entirely child-proof, I generated different mappings for each character position (11 total); this way, repeating letters in the input don’t produce repeating letters in the ciphertext:

const uint8_t* lookup_table[11] = {
  "NXKEDJTZRFCOWALQPIYGVUMBSH",
  "DSVAZRYNJIUQOHMTLFBPKCXWGE",
  "HSTUZJXAMFYRIONWVLBCDQPGKE",
  "PFEQCBUMZWNSHKXADYLVGTJORI",
  "NVZRFEPTUXLKYASGWDOHIBQJMC",
  "YCBTFEZPMKJQIRSHLNODWXUVAG",
  "RPGTFECXWLUJOYMBZAVDKSIHNQ",
  "ICBRWMUQAVTNFLXZHDYKGJEOSP",
  "WRFLUCHGPOXDVZJISBQYEMAKTN",
  "BAWIYRZUDNSVPJXMTFKQHLCOEG",
  "VKDCJSNOQEBYUGHXIWFZMARPLT"
};

Of course, an enemy who captures the device could recreate this entire table by cycling through the alphabet at each position — which is precisely what my eldest son did.

You can see the source code for CryptMaster 2001 here.

PS. It’s called “CryptMaster” and not “CryptoMaster” because it doesn’t mine dogecoin.



from Hacker News https://ift.tt/hngWuRG

No comments:

Post a Comment

Note: Only a member of this blog may post a comment.