]>
Commit | Line | Data |
---|---|---|
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> | |
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 | } |