Create wrappers for the cryptographic operations used in tinc.
[tinc] / src / 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 "cipher.h"
25
26 static struct {
27         const char *name,
28         enum gcry_cipher_algos algo,
29         enum gcry_cipher_modes 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, enum gcry_cipher_algos *algo, enum gcry_cipher_modes *mode) {
56         int 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, enum gcry_cipher_algos *algo, enum gcry_cipher_modes *mode) {
70         int 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(enum gcry_cipher_algos algo, enum gcry_cipher_modes mode, int *nid) {
84         int 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!"), algo, mode);
106                 return false;
107         }
108
109         cipher->keylen = gcry_cipher_get_algo_keylen(algo);
110         if(mode == GCRY_MODE_ECB || mode == GCRY_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 bool cipher_regenerate_key(cipher_t *cipher) {
158         gcry_create_nonce(cipher->key, cipher->keylen + cipher->blklen);
159
160         gcry_cipher_setkey(cipher->handle, cipher->key, cipher->keylen);
161         gcry_cipher_setiv(cipher->handle, cipher->key + keylen, cipher->blklen);
162
163         return true;
164 }
165
166 bool cipher_add_padding(cipher_t *cipher, void *indata, size_t inlen, size_t *outlen) {
167         size_t reqlen;
168
169         if(cipher->blklen == 1) {
170                 *outlen = inlen;
171                 return true;
172
173         reqlen = ((inlen + 1) / cipher->blklen) * cipher->blklen;
174         if(reqlen > outlen)
175                 return false;
176
177         // add padding
178
179         *outlen = reqlen;
180         return true;
181 }
182
183 bool cipher_remove_padding(cipher_t *cipher, void *indata, size_t inlen, size_t *outlen) {
184         size_t origlen;
185
186         if(cipher->blklen == 1) {
187                 *outlen = inlen;
188                 return true;
189         }
190
191         if(inlen % cipher->blklen)
192                 return false;
193
194         // check and remove padding
195
196         *outlen = origlen;
197         return true;
198 }
199
200 bool cipher_encrypt(cipher_t *cipher, void *indata, size_t inlen, void *outdata, size_t *outlen) {
201         gcry_error_t err;
202
203         if((err = gcry_cipher_encrypt(cipher->handle, oudata, inlen, indata, inlen))) {
204                 logger(LOG_ERR, _("Error while encrypting"));
205                 return false;
206         }
207
208         return true;
209 }
210
211 bool cipher_decrypt(cipher_t *cipher, void *indata, size_t inlen, void *outdata, size_t *outlen) {
212         gcry_error_t err;
213
214         if((err = gcry_cipher_decrypt(cipher->handle, oudata, inlen, indata, inlen))) {
215                 logger(LOG_ERR, _("Error while encrypting"));
216                 return false;
217         }
218
219         return true;
220 }
221
222 void cipher_reset(cipher_t *cipher) {
223         gcry_cipher_reset(cipher->handle);
224         gcry_cipher_setiv(cipher->handle, cipher->key + keylen, cipher->blklen);
225 }
226
227 int cipher_get_nid(cipher_t *cipher) {
228         return cipher->nid;
229 }
230