Crypt(1)
October 29, 2019
I was surprised to learn recently that modern Linux systems do not provide a crypt
command, which was common in older Unix systems. So I decided to write one.
The interface to crypt
is simple: it reads from standard input and writes to standard output, requesting a key from the console using a method that doesn’t echo the key to the screen. The program has no command-line arguments.
The cipher is symmetric, so encryption and decryption use the same key; the ciphering algorithm I choose is <a href="“>RC4-drop512, which isn’t exactly state-of-the-art encryption, but is simple and good enough for casual use. The base algorithm is RC4; dropping the first 512 characters of the generated keystream eliminates a potential weakness in the bas RC4 key scheduling algorithm.
Your task is to write a crypt
program as described above. When you are finished, you are welcome to read a suggested solution, or to post your own solution or discuss the exercise in the comments below.
Turning off echoing is inherently system-dependent and involves calling C functions.
If your C library has getpass(), that does the whole job; glibc provides it, but it is not any kind of standard.
Otherwise, on Posix you can call tcgetattr(), turn off the echo flag, and call tcsetaddr() before reading the password, and the same process to turn on the echo flag. Source code for getpass() at https://opensource.apple.com/source/Libc/Libc-167/gen.subproj/getpass.c.auto.html shows how.
The approach in Windows is basically the same using GetConsoleMode() and SetConsoleMode().
If you have a typical Posix environment but don’t have access to the tc* functions, then system(“stty -echo”) and system(“stty echo”) will do the trick.
My apologies if I’m preaching to the choir, and I know this isn’t the point of the post, but ccrypt(1) claims to be a better crypt:
DESCRIPTION
As fd says, there are better alternatives to crypt (which, if https://en.wikipedia.org/wiki/Crypt_(Unix) is anything to go by, was never intended for serious use) – as well as ccrypt, you could use “openssl enc” and have access to a wider range of ciphers (or libressl equivalent, or there’s probably something in GPG).
If you want to roll your own, something more contemporary than RC4 would be better. Here we use Speck, designed by those nice people at the NSA for use in limited resource devices, which is about as simple as modern ciphers come. It’s a block cipher so we use it in counter mode to get a stream cipher. Code somewhat modernized from 128 bit example in Speck paper, the termios code is fairly standard (cf. the link John posted above), proper error checking left as an exercise.
Statutory warning: https://classicprogrammerpaintings.com/post/148027314949/we-rolled-our-own-crypto-pieter-bruegel-the
I found the most interesting part of this exercise to be the reading
of the password from the terminal with no echo, so here is a solution
to just that part, in Kawa Scheme, with java.io.Console.readPassword
doing all the low-level work. It’s essentially the Java equivalent of
the C getpass solution suggested by John Cowan.
[…] the previous exercise I tried to write a replacement for the old Unix crypt(1) program, but never did figure out how to […]
Here’s a solution in Python 3.8.
Example usage (the key is “praxis”):