]> git.wh0rd.org - dump.git/blob - rmt/cipher.c
Fixed negative size displays in restore
[dump.git] / rmt / cipher.c
1 #include <sys/types.h>
2 #include <fcntl.h>
3 #include <unistd.h>
4 #include <stdlib.h>
5 #include <stdio.h>
6 #include <syslog.h>
7 #include <strings.h>
8 #include <errno.h>
9 #include <openssl/evp.h>
10
11 /*
12 * Encrypt or decrypt buf, returning a pointer to the transformed data,
13 * or NULL on error.
14 * The returned data is the same size as the input data,
15 * which means we must turn off cipher padding, and require that buflen
16 * be a multiple of the cipher block size (8 for Blowfish).
17 * To keep things simple, the return value is a malloc'd
18 * buffer that is overwritten on each call.
19 *
20 * Ken Lalonde <ken@globalremit.com>, 2003
21 */
22 char *
23 cipher(char *buf, int buflen, int do_encrypt)
24 {
25 static EVP_CIPHER_CTX ctx;
26 static char *out = NULL; /* return value, grown as necessary */
27 static int outlen = 0;
28 static int init = 0, which, blocksize;
29 int n;
30
31 if (!init) {
32 static const EVP_CIPHER *cipher;
33 unsigned char key[EVP_MAX_KEY_LENGTH], iv[EVP_MAX_IV_LENGTH];
34 // Read key from $HOME/.ermt.key
35 char *keyfile = ".ermt.key";
36 unsigned char buf[128];
37 FILE *fp;
38 int i;
39
40 openlog("ermt", LOG_PID, LOG_DAEMON);
41 // Not needed: OpenSSL_add_all_algorithms();
42 // Not needed: ERR_load_crypto_strings();
43 cipher = EVP_bf_cbc(); // or: EVP_aes_{128,192,256}_cbc()
44 // We want the ability to decrypt the output
45 // using "openssl enc -d -kfile K -nopad -nosalt", which
46 // means we must read the key file the same way
47 // openssl does. But be careful: if the key contains
48 // \0 or \r or \n, the effective size will be reduced.
49 if ((fp = fopen(keyfile, "r")) == NULL) {
50 syslog(LOG_ERR, "Can't open key file %s: %m", keyfile);
51 return NULL;
52 }
53 buf[0] = '\0';
54 fgets(buf, sizeof buf, fp);
55 fclose(fp);
56 i = strlen(buf);
57 if ((i > 0) &&
58 ((buf[i-1] == '\n') || (buf[i-1] == '\r')))
59 buf[--i]='\0';
60 if ((i > 0) &&
61 ((buf[i-1] == '\n') || (buf[i-1] == '\r')))
62 buf[--i]='\0';
63 if (i < 1) {
64 syslog(LOG_ERR, "zero length key");
65 errno = EINVAL;
66 return NULL;
67 }
68 EVP_BytesToKey(cipher, EVP_md5(), NULL,
69 buf, strlen(buf), 1, key, iv);
70 EVP_CIPHER_CTX_init(&ctx);
71 EVP_CipherInit_ex(&ctx, cipher, NULL, key, iv, do_encrypt);
72 EVP_CIPHER_CTX_set_padding(&ctx, 0); // -nopad
73 OPENSSL_cleanse(buf, sizeof buf);
74 OPENSSL_cleanse(key, sizeof key);
75 OPENSSL_cleanse(iv, sizeof iv);
76 blocksize = EVP_CIPHER_CTX_block_size(&ctx);
77 which = do_encrypt;
78 init = 1;
79 }
80 if (which != do_encrypt) {
81 syslog(LOG_ERR, "Cannot switch modes");
82 errno = EINVAL;
83 return NULL;
84 }
85 if ((buflen % blocksize) != 0) {
86 syslog(LOG_ERR, "Buffer size is not a multiple of cipher block size");
87 errno = EINVAL;
88 return NULL;
89 }
90 if (outlen < buflen+blocksize) {
91 outlen = (buflen+blocksize) * 2;
92 out = realloc(out, outlen);
93 }
94 if (!EVP_CipherUpdate(&ctx, out, &n, buf, buflen)) {
95 syslog(LOG_ERR, "EVP_CipherUpdate failed");
96 errno = EINVAL;
97 return NULL;
98 }
99 if (n != buflen) {
100 syslog(LOG_ERR, "EVP_CipherUpdate: %d != %d", n, buflen);
101 errno = EINVAL;
102 return NULL;
103 }
104 // assert(ctx->buf_len == 0);
105 return out;
106 }
107
108 /* Decrypt stdin to stdout, and exit */
109 int
110 decrypt()
111 {
112 char buf[8*1024], *cp;
113 int n;
114
115 while ((n = fread(buf, 1, sizeof buf, stdin)) > 0) {
116 if ((cp = cipher(buf, n, 0)) == NULL) {
117 fprintf(stderr, "ermt: Error decoding input; see daemon.err syslog\n");
118 exit(1);
119 }
120 fwrite(cp, 1, n, stdout);
121 }
122 if (ferror(stdin)) {
123 perror("ermt: stdin: read");
124 exit(1);
125 }
126 if (fflush(stdout)) {
127 perror("ermt: stdout: write");
128 exit(1);
129 }
130 exit(0);
131 }