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