Crypt(1)

October 29, 2019

I thought this would be easy, since we implemented the RC4 cipher in a previous exercise. Unfortunately, I could not figure out how to request the key from the console without echoing it, which I do not want to do.

I’ve asked some people who ought to know. I’ll update this exercise when I figure it out.

Pages: 1 2

5 Responses to “Crypt(1)”

  1. John Cowan said

    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.

  2. fd said

    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

       ccrypt is a utility for encrypting and decrypting files and streams. It was designed to replace the standard unix crypt util‐
       ity, which is notorious for using a very weak encryption algorithm.  ccrypt is based on the Rijndael block cipher, a  version
       of  which was also chosen by the U.S. government as the Advanced Encryption Standard (AES, see http://www.nist.gov/aes). This
       cipher is believed to provide very strong cryptographic security.
    
  3. matthew said

    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

    #include <stdint.h>
    #include <stdio.h>
    #include <string.h>
    #include <unistd.h>
    #include <fcntl.h>
    #include <termios.h>
    #include <x86intrin.h>
    
    static inline void R(uint64_t &x, uint64_t &y, uint64_t k) {
      x = _lrotr(x,8); x += y; x ^= k;
      y = _lrotl(y,3); y ^= x;
    }
    
    void Speck128(const uint64_t pt[2], uint64_t ct[2], const uint64_t K[2]) {
      auto B = K[1], A = K[0];
      ct[0] = pt[0]; ct[1] = pt[1];
      for (auto i = 0; i < 32; i++) {
        R(ct[1], ct[0], A);
        R(B, A, i);
      }
    }
    
    void setpass(void *pass, int N) {
      auto prompt = "Password: ";
      auto fd = open("/dev/tty",O_RDWR);
      write(fd,prompt,strlen(prompt));
      termios term;
      tcgetattr(fd,&term);
      const auto term0 = term;
      term.c_lflag &= ~ECHO;
      tcsetattr(fd,TCSAFLUSH,&term);
      char c, data[N]{0};
      for (int i = 0; ; i++) {
        if (read(fd,&c,1) < 1 || c == '\n') break;
        data[i%N] ^= c; // extra chars wraparound
      }
      write(fd,"\n",1);
      tcsetattr(fd,TCSAFLUSH,&term0);
      memcpy(pass,data,N);
    }
    
    int main() {
      uint64_t pt[2]{0}, ct[2], K[2], data[2];
      auto N = sizeof(pt);
      setpass(K,N);
      while(true) {
        auto nread = read(0,data,N);
        if (nread <= 0) break;
        Speck128(pt,ct,K);
        data[0] ^= ct[0]; data[1] ^= ct[1];
        write(1,data,nread);
        ++pt[0] || ++pt[1];
      }
    }
    
    $ g++ -O3 -Wall crypt.cpp -Wno-unused-result -o crypt
    $ echo Hello World | ./crypt > ct.data
    Password: 
    $ ./crypt < ct.data
    Password: 
    Hello World
    
  4. chaw said

    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.

    (import (scheme base)
            (scheme write)
            (class java.lang System)
            (class java.io Console))
    
    (define (read-line-from-console/no-echo . args)
      (let ((con ::Console
                 (System:console)))
        (and (not (eq? #!null con))
             (let ((carr :: char[]
                         (apply con:readPassword args)))
               (and (not (eq? #!null carr))
                    (String carr))))))
    
    (write (read-line-from-console/no-echo))
    (newline)
    (write (read-line-from-console/no-echo "Enter password: "))
    (newline)
    

  5. […] the previous exercise I tried to write a replacement for the old Unix crypt(1) program, but never did figure out how to […]

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

%d bloggers like this: