/* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License, Version 1.0 only * (the "License"). You may not use this file except in compliance * with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END */ /* * Copyright 2005 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ #pragma ident "%Z%%M% %I% %E% SMI" /* * DES encrypt/decrypt command * Features: * Hardware or software implementation * Cipher Block Chaining (default) or Electronic Code Book (-b) modes * A word about the key: * The DES standard specifies that the low bit of each of the 8 bytes * of the key is used for odd parity. We prompt the user for an 8 * byte ASCII key and add parity to the high bit and use the result * as the key. The nature of parity is that given any 7 bits you can * figure out what the missing bit should be, so it doesn't matter which * bit is used for parity; the information (in the theoretical sense) is * the same. */ #include #include #include #define DES_CBC 0 #define DES_ECB 1 int ifd=0, ofd=1; /* input and output descriptors */ char *cmdname; /* our command name */ struct des_info { char *key; /* encryption key */ char *ivec; /* initialization vector: CBC mode only */ unsigned flags; /* direction, device flags */ unsigned mode; /* des mode: ecb or cbc */ } g_des; void des_setup(char *key, unsigned int mode, unsigned int flags); void fencrypt(void); void fdecrypt(void); void usage(void); static void putparity(char *p); int main(int argc, char **argv) { char *key = NULL, keybuf[8], *getpass(); unsigned mode = DES_CBC; unsigned flags = DES_HW; int dirset = 0; /* set if dir set */ int fflg = 0; /* suppress warning if H/W DES not available */ unsigned err; cmdname = *argv++; argc--; while (argc > 0 && argv[0][0] == '-') { switch (argv[0][1]) { case 'e': /* encrypt */ flags |= DES_ENCRYPT; dirset++; break; case 'd': /* decrypt */ flags |= DES_DECRYPT; dirset++; break; case 'b': /* use Book mode */ mode = DES_ECB; break; case 'f': /* force silent */ fflg++; break; case 's': /* use software DES */ flags |= DES_SW; break; case 'k': /* key */ if (--argc == 0) usage(); strncpy(keybuf, *++argv, 8); for (key = *argv; *key; ) *key++ = '\0'; key = keybuf; break; default: usage(); } argv++; argc--; } if (!dirset) usage(); if (argc > 0) { ifd = open(*argv, 0); if (ifd < 0) { perror(*argv); exit(1); } argv++; argc--; } if (argc > 0) { ofd = creat(*argv, 0666); if (ofd < 0) { perror(*argv); exit(1); } argv++; argc--; } if (argc) usage(); if (key == NULL) { if ((key = getpass("Enter key: ")) == NULL) { fprintf(stderr, "%s: unable to get key\n", cmdname); exit(1); } strncpy(keybuf, key, 8); } if ((flags & DES_DEVMASK) == DES_HW && no_hwdevice()) { flags &= ~DES_DEVMASK; /* clear device bit */ flags |= DES_SW; /* set device to software */ if (!fflg) { fprintf(stderr, "%s: WARNING: using software DES algorithm\n", cmdname); } } if ((flags & DES_DEVMASK) == DES_SW && no_swdevice()) { fprintf(stderr, "%s: no software encryption available\n", cmdname); exit(1); } des_setup(key, mode, flags); switch (flags & DES_DIRMASK) { case DES_ENCRYPT: fencrypt(); break; case DES_DECRYPT: fdecrypt(); break; } return (0); } int no_hwdevice(void) { char key[8]; char buf[8]; return (ecb_crypt(key,buf,8,DES_ENCRYPT | DES_HW) != 0); } int no_swdevice(void) { char key[8]; char buf[8]; int res; return (ecb_crypt(key,buf,8,DES_ENCRYPT | DES_SW) != 0); } void des_setup(char *key, unsigned int mode, unsigned int flags) { static char ivec[8]; g_des.flags = flags; g_des.mode = mode; putparity(key); g_des.key = key; memset(ivec, 0, 8); g_des.ivec = ivec; } void crypt(char *buf, unsigned int len) { if (g_des.mode == DES_ECB) { ecb_crypt(g_des.key, buf, len, g_des.flags); } else { cbc_crypt(g_des.key, buf, len, g_des.flags, g_des.ivec); } } char buf[DES_MAXDATA]; /* * Encrypt a file: * Takes an arbitrary number of bytes of input and * produces an encrypted output file which is always the * the next multiple of 8 bytes bigger (e.g., 64 -> 72, 71 -> 72) * The last byte, when decrypted, gives the number of actual data bytes * in the last 8 bytes. Other bytes are filled with random values to * make it hard to cryptanalize. */ void fencrypt(void) { int n, k, j; char *cp; while ((n = read(ifd, buf, sizeof buf)) > 0) { j = n; while (n & 7) { k = 8 - (n & 7); if ((j = read(ifd, buf+n, k)) <= 0) break; n += j; } k = n &~ 7; if (k == 0) break; crypt(buf, k); if (write(ofd, buf, k) != k) perror("write"); if (j <= 0) break; } if (n >= 0) { cp = &buf[n]; k = 7 - (n & 7); srand(getpid()); for (j = 0; j < k; j++) *cp++ = rand(); *cp++ = n & 7; cp -= 8; crypt(cp, 8); if (write(ofd, cp, 8) != 8) perror("write"); } else perror("read"); } /* * Decrypt a file: * Look at the last byte of the last 8 byte block decrypted * to determine how many of the last 8 bytes to save. * This also serves as a check to see if the decryption succeeded * with a probability of (256-8)/256. */ void fdecrypt(void) { char last8buf[8], *last8; int n, k, j; last8 = NULL; while ((n = read(ifd, buf, sizeof buf)) > 0) { j = n; while (n & 7) { k = 8 - (n & 7); if ((j = read(ifd, buf+n, k)) <= 0) break; n += j; } if (j <= 0) break; crypt(buf, n); if (last8) write(ofd, last8, 8); last8 = last8buf; n -= 8; memcpy(last8, buf+n, 8); if (n && write(ofd, buf, n) != n) perror("write"); } if (n >= 0) { if (last8 == NULL || n != 0 || ((signed char)last8[7]) < 0 || last8[7] > 7) fprintf(stderr, "%s: decryption failed\n", cmdname); else if (((signed char)last8[7]) > 0) write(ofd, last8, last8[7]); } else perror("read"); } void usage(void) { fprintf(stderr, "Usage: %s -e [-b] [-f] [-k key] [ infile [ outfile ] ]\n", cmdname); fprintf(stderr, " or: %s -d [-b] [-f] [-k key] [ infile [ outfile ] ]\n", cmdname); fprintf(stderr, "Use -e to encrypt, -d to decrypt\n"); exit(2); } /* * Table giving odd parity (in high bit) for ASCII characters * program does not use des_setparity() (which puts parity * in low bit) in order to maintain backward compatibility */ static unsigned char partab[128] = { 0x80, 0x01, 0x02, 0x83, 0x04, 0x85, 0x86, 0x07, 0x08, 0x89, 0x8a, 0x0b, 0x8c, 0x0d, 0x0e, 0x8f, 0x10, 0x91, 0x92, 0x13, 0x94, 0x15, 0x16, 0x97, 0x98, 0x19, 0x1a, 0x9b, 0x1c, 0x9d, 0x9e, 0x1f, 0x20, 0xa1, 0xa2, 0x23, 0xa4, 0x25, 0x26, 0xa7, 0xa8, 0x29, 0x2a, 0xab, 0x2c, 0xad, 0xae, 0x2f, 0xb0, 0x31, 0x32, 0xb3, 0x34, 0xb5, 0xb6, 0x37, 0x38, 0xb9, 0xba, 0x3b, 0xbc, 0x3d, 0x3e, 0xbf, 0x40, 0xc1, 0xc2, 0x43, 0xc4, 0x45, 0x46, 0xc7, 0xc8, 0x49, 0x4a, 0xcb, 0x4c, 0xcd, 0xce, 0x4f, 0xd0, 0x51, 0x52, 0xd3, 0x54, 0xd5, 0xd6, 0x57, 0x58, 0xd9, 0xda, 0x5b, 0xdc, 0x5d, 0x5e, 0xdf, 0xe0, 0x61, 0x62, 0xe3, 0x64, 0xe5, 0xe6, 0x67, 0x68, 0xe9, 0xea, 0x6b, 0xec, 0x6d, 0x6e, 0xef, 0x70, 0xf1, 0xf2, 0x73, 0xf4, 0x75, 0x76, 0xf7, 0xf8, 0x79, 0x7a, 0xfb, 0x7c, 0xfd, 0xfe, 0x7f, }; /* * Add odd parity to high bit of 8 byte key */ static void putparity(char *p) { int i; for (i = 0; i < 8; i++) { *p = partab[*p & 0x7f]; p++; } }