Index: usr.bin/enigma/enigma.1 =================================================================== --- usr.bin/enigma/enigma.1 +++ usr.bin/enigma/enigma.1 @@ -6,7 +6,7 @@ .\" .\" $FreeBSD$ .\" " -.Dd May 8, 2018 +.Dd September 6, 2019 .Dt ENIGMA 1 .Os .Sh NAME @@ -15,110 +15,105 @@ .Nd very simple file encryption .Sh SYNOPSIS .Nm -.Op Fl s -.Op Fl k +.Op Fl sk .Op Ar password .Nm crypt -.Op Fl s -.Op Fl k +.Op Fl sk .Op Ar password .Sh DESCRIPTION The .Nm utility, also known as -.Nm crypt +.Nm crypt , is a .Em very -simple encryption program, working on a -.Dq secret-key -basis. -It operates as a filter, i.e., -it encrypts or decrypts a -stream of data from standard input, and writes the result to standard -output. -Since its operation is fully symmetrical, feeding the encrypted data -stream again through the engine (using the same secret key) will -decrypt it. +simple encryption program that utilises a secret key. +It encrypts or decrypts data from standard input, +and writes the result to standard output. +Its operation is fully symmetrical; +feeding it encrypted data using the same secret key will decrypt it. .Pp -There are several ways to provide the secret key to the program. -By -default, the program prompts the user on the controlling terminal for -the key, using -.Xr getpass 3 . +By default +.Nm +prompts the user on the controlling terminal for the secret key. This is the only safe way of providing it. -.Pp -Alternatively, the key can be provided as the sole command-line -argument +Alternatively, the key can be set with the .Ar password -when starting the program. -Obviously, this way the key can easily be -spotted by other users running +operand, which can easily be spotted by other users running .Xr ps 1 . -As yet another alternative, -.Nm -can be given the option -.Fl k , -and it will take the key from the environment variable -.Ev CrYpTkEy . -While this at a first glance seems to be more secure than the previous -option, it actually is not since environment variables can also be -examined with +The key can also be provided by setting the environment variable +.Ev CrYpTkEy +and specifying the option +.Fl k . +This option is provided for compatibility with other implementations, +as environment variables can also be examined with .Xr ps 1 . -Thus this option is mainly provided for compatibility with other -implementations of -.Nm . -.Pp -When specifying the option -.Fl s , -.Nm -modifies the encryption engine in a way that is supposed to make it a -little more secure, but incompatible with other implementations. .Pp +When option +.Fl s +is passed, +the encryption engine is modified in a way that is supposedly more +secure, but incompatible with other implementations. .Ss Warning The cryptographic value of .Nm -is rather small. -This program is only provided here for compatibility -with other operating systems that also provide an implementation +is worse than useless; +attacks against its encryption scheme have been documented since 1984, +and there are various tools that can break it in an automated process. +This program is only provided here for compatibility with other +operating systems that also provide an implementation (usually called -.Xr crypt 1 +.Nm crypt there). -For real encryption, refer to +For real encryption, use .Xr openssl 1 , or .Xr gpg 1 Pq Pa security/gnupg1 . .Sh ENVIRONMENT -.Bl -tag -offset indent -width ".Ev CrYpTkEy" +.Bl -tag -width "CrYpTkEy" .It Ev CrYpTkEy used to obtain the secret key when option .Fl k -has been given +has been given. .El .Sh EXAMPLES +Encrypt this manual and store it in the file +.Pa encrypted . .Bd -literal -offset indent man enigma | enigma > encrypted -Enter key: (XXX \(em key not echoed) +Enter key: XXX (key not echoed) .Ed .Pp -This will create an encrypted form of this man page, and store it in -the file -.Pa encrypted . +Decrypt the previously created file. .Bd -literal -offset indent -enigma XXX < encrypted +crypt XXX < encrypted .Ed -.Pp -This displays the previously created file on the terminal. .Sh SEE ALSO .Xr gpg 1 , .Xr openssl 1 , -.Xr ps 1 , -.Xr getpass 3 +.Xr ps 1 +.Rs +.%A J. A. Reeds +.%A P. J. Weinberger +.%J AT&T Bell Laboratories Technical Journal +.%I AT&T Bell Laboratories +.%R File Security and the UNIX System Crypt Command +.%D October 1984 +.%P pp. 1673-1683 +.Re .Sh HISTORY -Implementations of +.An Robert Morris +wrote the original .Nm crypt -are very common among -.Ux -operating systems. -This implementation has been taken from the -.Em Cryptbreakers Workbench +for +.At v3 . +It was later updated by +.An Dennis Richie +and +.An James Reeds +for +.At v7 . +.Sh AUTHORS +This implementation has been taken from +.An Robert W. Baldwin Ap s Dq Crypt Breakers Workbench , which is in the public domain. Index: usr.bin/enigma/enigma.c =================================================================== --- usr.bin/enigma/enigma.c +++ usr.bin/enigma/enigma.c @@ -15,143 +15,191 @@ #include +#include +#include #include #include #include #include -#define MINUSKVAR "CrYpTkEy" - -#define ROTORSZ 256 -#define MASK 0377 -static char t1[ROTORSZ]; -static char t2[ROTORSZ]; -static char t3[ROTORSZ]; -static char deck[ROTORSZ]; -static char buf[13]; - -static void shuffle(char *); -static void setup(char *); +/* Copied from src/lib/libcrypt/crypt.c */ +#define DES_SALT_ALPHABET \ + "./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz" +#define CRYPTKEY_ENV "CrYpTkEy" +#define PASSBUF_SIZE 129 +#define ROTORSZ 256 +#define MASK 0377 + +static char t1[ROTORSZ] = {0}; +static char t2[ROTORSZ] = {0}; +static char t3[ROTORSZ] = {0}; +static char deck[ROTORSZ] = {0}; +static char buf[13] = {0}; + +static void shuffle(char *); +static void setup(void); +static void usage(void) __dead2; static void setup(char *pw) { - int ic, i, k, temp; - char salt[3]; + int ic, i, k; + static int32_t seed = 123; unsigned rnd; - int32_t seed; - char *cryptpw; + char salt[3], *cryptpw, temp; - if (crypt_set_format("des") == 0) { - fprintf(stderr, "crypt_set_format(\"des\") failed.\n"); - exit(1); - } + if (crypt_set_format("des") == 0) + errx(1, "crypt_set_format(\"des\") failed"); strlcpy(salt, pw, sizeof(salt)); - cryptpw = crypt(pw, salt); - if (cryptpw == NULL) { - fprintf(stderr, "crypt(3) failure\n"); - exit(1); - } + if ((cryptpw = crypt(pw, salt)) == NULL); + err(1, "crypt") + memcpy(buf, cryptpw, sizeof(buf)); - seed = 123; - for (i=0; i<13; i++) - seed = seed*buf[i] + i; - for(i=0;i>= 8; + temp = t1[k]; t1[k] = t1[ic]; t1[ic] = temp; - if(t3[k]!=0) continue; - ic = (rnd&MASK) % k; - while(t3[ic]!=0) ic = (ic+1) % k; + + if (t3[k] != 0) + continue; + + ic = (rnd & MASK) % k; + while (t3[ic] != 0) + ic = (ic + 1) % k; + t3[k] = ic; t3[ic] = k; } - for(i=0;i 1 && argv[1][0] == '-') { - if (argv[1][1] == 's') { - argc--; - argv++; - secureflg = 1; - } else if (argv[1][1] == 'k') { - argc--; - argv++; + while ((ch = getopt(argc, argv, "ks")) != -1) { + switch (ch) { + case 'k': kflag = 1; + break; + case 's': + sflag = 1; + break; + case 'h': + default: + usage(); } } + argc -= optind; + argv += optind; + if (kflag) { - if ((cp = getenv(MINUSKVAR)) == NULL) { - fprintf(stderr, "%s not set\n", MINUSKVAR); - exit(1); - } - setup(cp); - } else if (argc != 2) { - setup(getpass("Enter key:")); - } - else - setup(argv[1]); - n1 = 0; - n2 = 0; - nr2 = 0; - - while((i=getchar()) != -1) { - if (secureflg) { - nr1 = deck[n1]&MASK; - nr2 = deck[nr1]&MASK; + if ((cryptkey = getenv(CRYPTKEY_ENV)) == NULL) + errx(1, "%s is unset", CRYPTKEY_ENV); + } else if (argc != 1) { + if (readpassphrase("Enter Key: ", passbuf, sizeof(passbuf), + RPP_REQUIRE_TTY) == NULL) + errx(1, "unable to read password"); + cryptkey = passbuf; + } else { + cryptkey = argv[0]; + } + + /* + * The first two bytes of the key are used as the salt, + * and since we skip the salt check with crypt_set_format(), + * we should check it here. + */ + if (strspn(cryptkey, DES_SALT_ALPHABET) != strlen(cryptkey)) + errx(1, "key contains invalid characters"); + + setup(cryptkey); + + n1 = n2 = nr2 = 0; + + while ((i = getchar()) != EOF) { + if (sflag) { + nr1 = deck[n1] & MASK; + nr2 = deck[nr1] & MASK; } else { nr1 = n1; } + i = t2[(t3[(t1[(i+nr1)&MASK]+nr2)&MASK]-nr2)&MASK]-nr1; - putchar(i); + if (putchar(i) == EOF) + err(1, "putchar"); + n1++; - if(n1==ROTORSZ) { + if (n1 == ROTORSZ) { n1 = 0; n2++; - if(n2==ROTORSZ) n2 = 0; - if (secureflg) { - shuffle(deck); - } else { + + if (n2 == ROTORSZ) + n2 = 0; + + if (sflag) + shuffle(); + else nr2 = n2; - } } } + explicit_bzero(buf, sizeof(buf)); + + if (ferror(stdin)) + err(1, "ferror"); + if (fclose(stdout) == EOF) + err(1, "stdout"); + return 0; } static void -shuffle(char deckary[]) +usage(void) { - int i, ic, k, temp; + + fprintf(stderr, "usage: %s [-ks] password\n", getprogname()); + exit(1); +} + +static void +shuffle(void) +{ + int i, ic, k; unsigned rnd; static int32_t seed = 123; + char temp; - for(i=0;i