518879bdedbb489cd839430e83a536a24013b292
[tinc] / src / gcrypt / 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 along
16     with this program; if not, write to the Free Software Foundation, Inc.,
17     51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18 */
19
20 #include "system.h"
21
22 #include "cipher.h"
23 #include "logger.h"
24 #include "xalloc.h"
25
26 static struct {
27         const char *name;
28         int algo;
29         int mode;
30         int nid;
31 } ciphertable[] = {
32         {"none", GCRY_CIPHER_NONE, GCRY_CIPHER_MODE_NONE, 0},
33
34         {NULL, GCRY_CIPHER_BLOWFISH, GCRY_CIPHER_MODE_ECB, 92},
35         {"blowfish", GCRY_CIPHER_BLOWFISH, GCRY_CIPHER_MODE_CBC, 91},
36         {NULL, GCRY_CIPHER_BLOWFISH, GCRY_CIPHER_MODE_CFB, 93},
37         {NULL, GCRY_CIPHER_BLOWFISH, GCRY_CIPHER_MODE_OFB, 94},
38
39         {NULL, GCRY_CIPHER_AES, GCRY_CIPHER_MODE_ECB, 418},
40         {"aes", GCRY_CIPHER_AES, GCRY_CIPHER_MODE_CBC, 419},
41         {NULL, GCRY_CIPHER_AES, GCRY_CIPHER_MODE_CFB, 421},
42         {NULL, GCRY_CIPHER_AES, GCRY_CIPHER_MODE_OFB, 420},
43
44         {NULL, GCRY_CIPHER_AES192, GCRY_CIPHER_MODE_ECB, 422},
45         {"aes192", GCRY_CIPHER_AES192, GCRY_CIPHER_MODE_CBC, 423},
46         {NULL, GCRY_CIPHER_AES192, GCRY_CIPHER_MODE_CFB, 425},
47         {NULL, GCRY_CIPHER_AES192, GCRY_CIPHER_MODE_OFB, 424},
48
49         {NULL, GCRY_CIPHER_AES256, GCRY_CIPHER_MODE_ECB, 426},
50         {"aes256", GCRY_CIPHER_AES256, GCRY_CIPHER_MODE_CBC, 427},
51         {NULL, GCRY_CIPHER_AES256, GCRY_CIPHER_MODE_CFB, 429},
52         {NULL, GCRY_CIPHER_AES256, GCRY_CIPHER_MODE_OFB, 428},
53 };
54
55 static bool nametocipher(const char *name, int *algo, int *mode) {
56         size_t i;
57
58         for(i = 0; i < sizeof ciphertable / sizeof *ciphertable; i++) {
59                 if(ciphertable[i].name && !strcasecmp(name, ciphertable[i].name)) {
60                         *algo = ciphertable[i].algo;
61                         *mode = ciphertable[i].mode;
62                         return true;
63                 }
64         }
65
66         return false;
67 }
68
69 static bool nidtocipher(int nid, int *algo, int *mode) {
70         size_t i;
71
72         for(i = 0; i < sizeof ciphertable / sizeof *ciphertable; i++) {
73                 if(nid == ciphertable[i].nid) {
74                         *algo = ciphertable[i].algo;
75                         *mode = ciphertable[i].mode;
76                         return true;
77                 }
78         }
79
80         return false;
81 }
82
83 static bool ciphertonid(int algo, int mode, int *nid) {
84         size_t i;
85
86         for(i = 0; i < sizeof ciphertable / sizeof *ciphertable; i++) {
87                 if(algo == ciphertable[i].algo && mode == ciphertable[i].mode) {
88                         *nid = ciphertable[i].nid;
89                         return true;
90                 }
91         }
92
93         return false;
94 }
95
96 static bool cipher_open(cipher_t *cipher, int algo, int mode) {
97         gcry_error_t err;
98
99         if(!ciphertonid(algo, mode, &cipher->nid)) {
100                 logger(LOG_DEBUG, "Cipher %d mode %d has no corresponding nid!", algo, mode);
101                 return false;
102         }
103
104         if((err = gcry_cipher_open(&cipher->handle, algo, mode, 0))) {
105                 logger(LOG_DEBUG, "Unable to intialise cipher %d mode %d: %s", algo, mode, gcry_strerror(err));
106                 return false;
107         }
108
109         cipher->keylen = gcry_cipher_get_algo_keylen(algo);
110         if(mode == GCRY_CIPHER_MODE_ECB || mode == GCRY_CIPHER_MODE_CBC)
111                 cipher->blklen = gcry_cipher_get_algo_blklen(algo);
112         else
113                 cipher->blklen = 0;
114         cipher->key = xmalloc(cipher->keylen + cipher->blklen);
115
116         return true;
117 }
118
119 bool cipher_open_by_name(cipher_t *cipher, const char *name) {
120         int algo, mode;
121
122         if(!nametocipher(name, &algo, &mode)) {
123                 logger(LOG_DEBUG, "Unknown cipher name '%s'!", name);
124                 return false;
125         }
126
127         return cipher_open(cipher, algo, mode);
128 }
129
130 bool cipher_open_by_nid(cipher_t *cipher, int nid) {
131         int algo, mode;
132
133         if(!nidtocipher(nid, &algo, &mode)) {
134                 logger(LOG_DEBUG, "Unknown cipher ID %d!", nid);
135                 return false;
136         }
137
138         return cipher_open(cipher, algo, mode);
139 }
140
141 bool cipher_open_blowfish_ofb(cipher_t *cipher) {
142         return cipher_open(cipher, GCRY_CIPHER_BLOWFISH, GCRY_CIPHER_MODE_OFB);
143 }
144
145 void cipher_close(cipher_t *cipher) {
146         if(cipher->handle) {
147                 gcry_cipher_close(cipher->handle);
148                 cipher->handle = NULL;
149         }
150
151         if(cipher->key) {
152                 free(cipher->key);
153                 cipher->key = NULL;
154         }
155 }
156
157 size_t cipher_keylength(const cipher_t *cipher) {
158         return cipher->keylen + cipher->blklen;
159 }
160
161 void cipher_get_key(const cipher_t *cipher, void *key) {
162         memcpy(key, cipher->key, cipher->keylen + cipher->blklen);
163 }
164
165 bool cipher_set_key(cipher_t *cipher, void *key, bool encrypt) {
166         memcpy(cipher->key, key, cipher->keylen + cipher->blklen);
167
168         gcry_cipher_setkey(cipher->handle, cipher->key, cipher->keylen);
169         gcry_cipher_setiv(cipher->handle, cipher->key + cipher->keylen, cipher->blklen);
170
171         return true;
172 }
173
174 bool cipher_set_key_from_rsa(cipher_t *cipher, void *key, size_t len, bool encrypt) {
175         memcpy(cipher->key, key + len - cipher->keylen, cipher->keylen + cipher->blklen);
176         memcpy(cipher->key + cipher->keylen, key + len - cipher->keylen - cipher->blklen, cipher->blklen);
177
178         gcry_cipher_setkey(cipher->handle, cipher->key, cipher->keylen);
179         gcry_cipher_setiv(cipher->handle, cipher->key + cipher->keylen, cipher->blklen);
180
181         return true;
182 }
183
184 bool cipher_regenerate_key(cipher_t *cipher, bool encrypt) {
185         gcry_create_nonce(cipher->key, cipher->keylen + cipher->blklen);
186
187         gcry_cipher_setkey(cipher->handle, cipher->key, cipher->keylen);
188         gcry_cipher_setiv(cipher->handle, cipher->key + cipher->keylen, cipher->blklen);
189
190         return true;
191 }
192
193 static bool cipher_add_padding(cipher_t *cipher, void *indata, size_t inlen, size_t *outlen) {
194         size_t reqlen;
195
196         if(cipher->blklen == 1) {
197                 *outlen = inlen;
198                 return true;
199         }
200
201         reqlen = ((inlen + 1) / cipher->blklen) * cipher->blklen;
202         if(reqlen > *outlen)
203                 return false;
204
205         // add padding
206
207         *outlen = reqlen;
208         return true;
209 }
210
211 static bool cipher_remove_padding(cipher_t *cipher, void *indata, size_t inlen, size_t *outlen) {
212         size_t origlen;
213
214         if(cipher->blklen == 1) {
215                 *outlen = inlen;
216                 return true;
217         }
218
219         if(inlen % cipher->blklen)
220                 return false;
221
222         // check and remove padding
223
224         *outlen = origlen;
225         return true;
226 }
227
228 bool cipher_encrypt(cipher_t *cipher, const void *indata, size_t inlen, void *outdata, size_t *outlen, bool oneshot) {
229         gcry_error_t err;
230
231         // To be fixed
232
233         if((err = gcry_cipher_encrypt(cipher->handle, outdata, inlen, indata, inlen))) {
234                 logger(LOG_ERR, "Error while encrypting: %s", gcry_strerror(err));
235                 return false;
236         }
237
238         return true;
239 }
240
241 bool cipher_decrypt(cipher_t *cipher, const void *indata, size_t inlen, void *outdata, size_t *outlen, bool oneshot) {
242         gcry_error_t err;
243
244         // To be fixed
245
246         if((err = gcry_cipher_decrypt(cipher->handle, outdata, inlen, indata, inlen))) {
247                 logger(LOG_ERR, "Error while decrypting: %s", gcry_strerror(err));
248                 return false;
249         }
250
251         return true;
252 }
253
254 int cipher_get_nid(const cipher_t *cipher) {
255         return cipher->nid;
256 }
257
258 bool cipher_active(const cipher_t *cipher) {
259         return cipher->nid != 0;
260 }