Drop localisation and checkpoint tracing in files not covered by the merge.
[tinc] / src / openssl / cipher.c
1 /*
2     cipher.c -- Symmetric block cipher handling
3     Copyright (C) 2007 Guus Sliepen <guus@tinc-vpn.org>
4
5     This program is free software; you can redistribute it and/or modify
6     it under the terms of the GNU General Public License as published by
7     the Free Software Foundation; either version 2 of the License, or
8     (at your option) any later version.
9
10     This program is distributed in the hope that it will be useful,
11     but WITHOUT ANY WARRANTY; without even the implied warranty of
12     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13     GNU General Public License for more details.
14
15     You should have received a copy of the GNU General Public License
16     along with this program; if not, write to the Free Software
17     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18
19     $Id$
20 */
21
22 #include "system.h"
23
24 #include <openssl/rand.h>
25 #include <openssl/err.h>
26
27 #include "cipher.h"
28 #include "logger.h"
29 #include "xalloc.h"
30
31 static bool cipher_open(cipher_t *cipher) {
32         cipher->keylen = cipher->cipher->key_len;
33         cipher->blklen = cipher->cipher->iv_len;
34
35         cipher->key = xmalloc(cipher->keylen + cipher->blklen);
36
37         EVP_CIPHER_CTX_init(&cipher->ctx);
38
39         return true;
40 }
41
42 bool cipher_open_by_name(cipher_t *cipher, const char *name) {
43         cipher->cipher = EVP_get_cipherbyname(name);
44
45         if(cipher->cipher)
46                 return cipher_open(cipher);
47
48         logger(LOG_DEBUG, "Unknown cipher name '%s'!", name);
49         return false;
50 }
51
52 bool cipher_open_by_nid(cipher_t *cipher, int nid) {
53         cipher->cipher = EVP_get_cipherbynid(nid);
54
55         if(cipher->cipher)
56                 return cipher_open(cipher);
57
58         logger(LOG_DEBUG, "Unknown cipher nid %d!", nid);
59         return false;
60 }
61
62 bool cipher_open_blowfish_ofb(cipher_t *cipher) {
63         cipher->cipher = EVP_bf_ofb();
64         return cipher_open(cipher);
65 }
66
67 void cipher_close(cipher_t *cipher) {
68         EVP_CIPHER_CTX_cleanup(&cipher->ctx);
69
70         if(cipher->key) {
71                 free(cipher->key);
72                 cipher->key = NULL;
73         }
74 }
75
76 size_t cipher_keylength(const cipher_t *cipher) {
77         return cipher->keylen + cipher->blklen;
78 }
79
80 void cipher_get_key(const cipher_t *cipher, void *key) {
81         memcpy(key, cipher->key, cipher->keylen + cipher->blklen);
82 }
83
84 bool cipher_set_key(cipher_t *cipher, void *key, bool encrypt) {
85         memcpy(cipher->key, key, cipher->keylen + cipher->blklen);
86         bool result;
87
88         if(encrypt)
89                 result = EVP_EncryptInit_ex(&cipher->ctx, cipher->cipher, NULL, (unsigned char *)cipher->key, (unsigned char *)cipher->key + cipher->keylen);
90         else
91                 result = EVP_DecryptInit_ex(&cipher->ctx, cipher->cipher, NULL, (unsigned char *)cipher->key, (unsigned char *)cipher->key + cipher->keylen);
92
93         if(result)
94                 return true;
95
96         logger(LOG_ERR, "Error while setting key: %s", ERR_error_string(ERR_get_error(), NULL));
97         return false;
98 }
99
100 bool cipher_set_key_from_rsa(cipher_t *cipher, void *key, size_t len, bool encrypt) {
101         memcpy(cipher->key, key + len - (size_t)cipher->keylen, cipher->keylen);
102         memcpy(cipher->key + cipher->keylen, key + len - (size_t)cipher->keylen - (size_t)cipher->blklen, cipher->blklen);
103         bool result;
104
105         if(encrypt)
106                 result = EVP_EncryptInit_ex(&cipher->ctx, cipher->cipher, NULL, (unsigned char *)cipher->key, (unsigned char *)cipher->key + cipher->keylen);
107         else
108                 result = EVP_DecryptInit_ex(&cipher->ctx, cipher->cipher, NULL, (unsigned char *)cipher->key, (unsigned char *)cipher->key + cipher->keylen);
109
110         if(result)
111                 return true;
112
113         logger(LOG_ERR, "Error while setting key: %s", ERR_error_string(ERR_get_error(), NULL));
114         return false;
115 }
116
117 bool cipher_regenerate_key(cipher_t *cipher, bool encrypt) {
118         bool result;
119
120         RAND_pseudo_bytes((unsigned char *)cipher->key, cipher->keylen + cipher->blklen);
121
122         if(encrypt)
123                 result = EVP_EncryptInit_ex(&cipher->ctx, cipher->cipher, NULL, (unsigned char *)cipher->key, (unsigned char *)cipher->key + cipher->keylen);
124         else
125                 result = EVP_DecryptInit_ex(&cipher->ctx, cipher->cipher, NULL, (unsigned char *)cipher->key, (unsigned char *)cipher->key + cipher->keylen);
126
127         if(result)
128                 return true;
129         
130         logger(LOG_ERR, "Error while regenerating key: %s", ERR_error_string(ERR_get_error(), NULL));
131         return false;
132 }
133
134 bool cipher_encrypt(cipher_t *cipher, const void *indata, size_t inlen, void *outdata, size_t *outlen, bool oneshot) {
135         if(oneshot) {
136                 int len = *outlen, pad;
137                 if(EVP_EncryptInit_ex(&cipher->ctx, NULL, NULL, NULL, NULL)
138                                 &&EVP_EncryptUpdate(&cipher->ctx, outdata, &len, indata, inlen)
139                                 && EVP_EncryptFinal(&cipher->ctx, outdata + len, &pad)) {
140                         *outlen = len + pad;
141                         return true;
142                 }
143         } else {
144                 int len = *outlen;
145                 if(EVP_EncryptUpdate(&cipher->ctx, outdata, &len, indata, inlen)) {
146                         *outlen = len;
147                         return true;
148                 }
149         }
150
151         logger(LOG_ERR, "Error while encrypting: %s", ERR_error_string(ERR_get_error(), NULL));
152         return false;
153 }
154
155 bool cipher_decrypt(cipher_t *cipher, const void *indata, size_t inlen, void *outdata, size_t *outlen, bool oneshot) {
156         if(oneshot) {
157                 int len = *outlen, pad;
158                 if(EVP_DecryptInit_ex(&cipher->ctx, NULL, NULL, NULL, NULL)
159                                 && EVP_DecryptUpdate(&cipher->ctx, outdata, &len, indata, inlen)
160                                 && EVP_DecryptFinal(&cipher->ctx, outdata + len, &pad)) {
161                         *outlen = len + pad;
162                         return true;
163                 }
164         } else {
165                 int len = *outlen;
166                 if(EVP_EncryptUpdate(&cipher->ctx, outdata, &len, indata, inlen)) {
167                         *outlen = len;
168                         return true;
169                 }
170         }
171
172         logger(LOG_ERR, "Error while encrypting: %s", ERR_error_string(ERR_get_error(), NULL));
173         return false;
174 }
175
176 int cipher_get_nid(const cipher_t *cipher) {
177         return cipher->cipher ? cipher->cipher->nid : 0;
178 }
179
180 bool cipher_active(const cipher_t *cipher) {
181         return cipher->cipher && cipher->cipher->nid != 0;
182 }