Imported Upstream version 0.3
[debian/uanytun.git] / src / cipher.c
1 /*
2  *  uAnytun
3  *
4  *  uAnytun is a tiny implementation of SATP. Unlike Anytun which is a full
5  *  featured implementation uAnytun has no support for multiple connections
6  *  or synchronisation. It is a small single threaded implementation intended
7  *  to act as a client on small platforms.
8  *  The secure anycast tunneling protocol (satp) defines a protocol used
9  *  for communication between any combination of unicast and anycast
10  *  tunnel endpoints.  It has less protocol overhead than IPSec in Tunnel
11  *  mode and allows tunneling of every ETHER TYPE protocol (e.g.
12  *  ethernet, ip, arp ...). satp directly includes cryptography and
13  *  message authentication based on the methodes used by SRTP.  It is
14  *  intended to deliver a generic, scaleable and secure solution for
15  *  tunneling and relaying of packets of any protocol.
16  *  
17  *
18  *  Copyright (C) 2007-2008 Christian Pointner <equinox@anytun.org>
19  *
20  *  This file is part of uAnytun.
21  *
22  *  uAnytun is free software: you can redistribute it and/or modify
23  *  it under the terms of the GNU General Public License version 3 as
24  *  published by the Free Software Foundation.
25  *
26  *  uAnytun is distributed in the hope that it will be useful,
27  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
28  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
29  *  GNU General Public License for more details.
30  *
31  *  You should have received a copy of the GNU General Public License
32  *  along with uAnytun. If not, see <http://www.gnu.org/licenses/>.
33  */
34
35 #include "datatypes.h"
36
37 #include "plain_packet.h"
38 #include "encrypted_packet.h"
39
40 #include "cipher.h"
41
42 #include "log.h"
43
44 #include <stdlib.h>
45 #include <string.h>
46
47 int cipher_init(cipher_t* c, const char* type)
48 {
49   if(!c) 
50     return -1;
51
52   c->key_length_ = 0;
53
54   c->type_ = c_unknown;
55   if(!strcmp(type, "null"))
56     c->type_ = c_null;
57 #ifndef NO_CRYPT
58   else if(!strncmp(type, "aes-ctr", 7)) {
59     c->type_ = c_aes_ctr;
60     if(type[7] == 0) {
61       c->key_length_ = C_AESCTR_DEFAULT_KEY_LENGTH;
62     }
63     else if(type[7] != '-') 
64       return -1;
65     else {
66       const char* tmp = &type[8];
67       c->key_length_ = atoi(tmp);
68     }
69   }
70 #endif
71   else {
72     log_printf(ERROR, "unknown cipher type");
73     return -1;
74   }
75
76   c->params_ = NULL;
77
78   c->key_.buf_ = NULL;
79   c->key_.length_ = 0;
80
81   c->salt_.buf_ = NULL;
82   c->salt_.length_ = 0;
83
84   int ret = 0;
85 #ifndef NO_CRYPT
86   if(c->type_ == c_aes_ctr)
87     ret = cipher_aesctr_init(c);
88 #endif
89
90   if(ret)
91     cipher_close(c);
92
93   return ret;
94 }
95
96 void cipher_close(cipher_t* c)
97 {
98   if(!c)
99     return;
100
101 #ifndef NO_CRYPT
102   if(c->type_ == c_aes_ctr)
103     cipher_aesctr_close(c);
104 #endif
105
106   if(c->key_.buf_)
107     free(c->key_.buf_);
108   if(c->salt_.buf_)
109     free(c->salt_.buf_);
110 }
111
112
113 int cipher_encrypt(cipher_t* c, key_derivation_t* kd, key_derivation_dir_t dir, plain_packet_t* in, encrypted_packet_t* out, seq_nr_t seq_nr, sender_id_t sender_id, mux_t mux)
114 {
115   if(!c) 
116     return -1;
117
118         int32_t len;
119   if(c->type_ == c_null)
120     len = cipher_null_crypt(plain_packet_get_packet(in), plain_packet_get_length(in), 
121                             encrypted_packet_get_payload(out), encrypted_packet_get_payload_length(out));
122 #ifndef NO_CRYPT
123   else if(c->type_ == c_aes_ctr)
124     len = cipher_aesctr_crypt(c, kd, dir, plain_packet_get_packet(in), plain_packet_get_length(in),
125                               encrypted_packet_get_payload(out), encrypted_packet_get_payload_length(out),
126                               seq_nr, sender_id, mux);
127 #endif
128   else {
129     log_printf(ERROR, "unknown cipher type");
130     return -1;
131   }
132
133   if(len < 0)
134     return 0;
135
136         encrypted_packet_set_sender_id(out, sender_id);
137   encrypted_packet_set_seq_nr(out, seq_nr);
138   encrypted_packet_set_mux(out, mux);
139
140   encrypted_packet_set_payload_length(out, len);
141
142   return 0;
143 }
144
145 int cipher_decrypt(cipher_t* c, key_derivation_t* kd, key_derivation_dir_t dir, encrypted_packet_t* in, plain_packet_t* out)
146 {
147   if(!c) 
148     return -1;
149
150         int32_t len;
151   if(c->type_ == c_null)
152     len = cipher_null_crypt(encrypted_packet_get_payload(in), encrypted_packet_get_payload_length(in),
153                             plain_packet_get_packet(out), plain_packet_get_length(out));
154 #ifndef NO_CRYPT
155   else if(c->type_ == c_aes_ctr)
156     len = cipher_aesctr_crypt(c, kd, dir, encrypted_packet_get_payload(in), encrypted_packet_get_payload_length(in),
157                               plain_packet_get_packet(out), plain_packet_get_length(out),
158                               encrypted_packet_get_seq_nr(in), encrypted_packet_get_sender_id(in),
159                               encrypted_packet_get_mux(in));
160 #endif
161   else {
162     log_printf(ERROR, "unknown cipher type");
163     return -1;
164   }
165   
166   if(len < 0)
167     return 0;
168
169         plain_packet_set_length(out, len);
170
171   return 0;
172 }
173
174 /* ---------------- NULL Cipher ---------------- */
175
176 int32_t cipher_null_crypt(u_int8_t* in, u_int32_t ilen, u_int8_t* out, u_int32_t olen)
177 {
178         memcpy(out, in, (ilen < olen) ? ilen : olen);
179   return (ilen < olen) ? ilen : olen;
180 }
181
182 #ifndef NO_CRYPT
183 /* ---------------- AES-Ctr Cipher ---------------- */
184
185 int cipher_aesctr_init(cipher_t* c)
186 {
187   if(!c)
188     return -1;
189
190   if(c->key_.buf_)
191     free(c->key_.buf_);
192
193   c->key_.length_ = c->key_length_/8;
194   c->key_.buf_ = malloc(c->key_.length_);
195   if(!c->key_.buf_)
196     return -2;
197
198   if(c->salt_.buf_)
199     free(c->salt_.buf_);
200
201   c->salt_.length_ = C_AESCTR_SALT_LENGTH;
202   c->salt_.buf_ = malloc(c->salt_.length_);
203   if(!c->salt_.buf_)
204     return -2;
205
206   if(c->params_)
207     free(c->params_);
208   c->params_ = malloc(sizeof(cipher_aesctr_param_t));
209   if(!c->params_)
210     return -2;
211
212   cipher_aesctr_param_t* params = c->params_;
213
214 #ifndef USE_SSL_CRYPTO
215   int algo;
216   switch(c->key_length_) {
217   case 128: algo = GCRY_CIPHER_AES128; break;
218   case 192: algo = GCRY_CIPHER_AES192; break;
219   case 256: algo = GCRY_CIPHER_AES256; break;
220   default: {
221     log_printf(ERROR, "cipher key length of %d Bits is not supported", c->key_length_);
222     return -1;
223   }
224   }
225
226   gcry_error_t err = gcry_cipher_open(&params->handle_, algo, GCRY_CIPHER_MODE_CTR, 0);
227   if(err) {
228     log_printf(ERROR, "failed to open cipher: %s", gcry_strerror(err));
229     return -1;
230   } 
231 #endif
232
233   return 0;
234 }
235
236 void cipher_aesctr_close(cipher_t* c)
237 {
238   if(!c)
239     return;
240
241   if(c->params_) {
242     cipher_aesctr_param_t* params = c->params_;
243
244 #ifndef USE_SSL_CRYPTO
245     if(params->handle_)
246       gcry_cipher_close(params->handle_);
247 #endif
248
249     free(c->params_);
250   }
251 }
252
253 int cipher_aesctr_calc_ctr(cipher_t* c, key_derivation_t* kd, key_derivation_dir_t dir, seq_nr_t seq_nr, sender_id_t sender_id, mux_t mux)
254 {
255   if(!c || !c->params_)
256     return -1;
257   
258   cipher_aesctr_param_t* params = c->params_;
259
260   int ret = key_derivation_generate(kd, dir, LABEL_SALT, seq_nr, c->salt_.buf_, C_AESCTR_SALT_LENGTH);
261   if(ret < 0)
262     return ret;
263
264   memcpy(params->ctr_.salt_.buf_, c->salt_.buf_, C_AESCTR_SALT_LENGTH);
265   params->ctr_.salt_.zero_ = 0;
266   params->ctr_.params_.mux_ ^= MUX_T_HTON(mux);
267   params->ctr_.params_.sender_id_ ^= SENDER_ID_T_HTON(sender_id);
268   params->ctr_.params_.seq_nr_ ^= SEQ_NR_T_HTON(seq_nr);
269
270   return 0;
271 }
272
273 int32_t cipher_aesctr_crypt(cipher_t* c, key_derivation_t* kd, key_derivation_dir_t dir, u_int8_t* in, u_int32_t ilen, u_int8_t* out, u_int32_t olen, seq_nr_t seq_nr, sender_id_t sender_id, mux_t mux)
274 {
275   if(!c || !c->params_) {
276     log_printf(ERROR, "cipher not initialized");
277     return -1;
278   }
279
280   if(!kd) {
281     log_printf(ERROR, "no key derivation supplied");
282     return -1;
283   }
284
285   cipher_aesctr_param_t* params = c->params_;
286
287   int ret = key_derivation_generate(kd, dir, LABEL_ENC, seq_nr, c->key_.buf_, c->key_.length_);
288   if(ret < 0)
289     return ret;
290   
291 #ifdef USE_SSL_CRYPTO
292   ret = AES_set_encrypt_key(c->key_.buf_, c->key_length_, &params->aes_key_);
293   if(ret) {
294     log_printf(ERROR, "failed to set cipher ssl aes-key (code: %d)", ret);
295     return -1;
296   }
297 #else
298   gcry_error_t err = gcry_cipher_setkey(params->handle_, c->key_.buf_, c->key_.length_);
299   if(err) {
300     log_printf(ERROR, "failed to set cipher key: %s", gcry_strerror(err));
301     return -1;
302   }
303 #endif
304
305   ret = cipher_aesctr_calc_ctr(c, kd, dir, seq_nr, sender_id, mux);
306   if(ret < 0) {
307     log_printf(ERROR, "failed to calculate cipher CTR");
308     return ret;
309   }
310   
311 #ifndef USE_SSL_CRYPTO
312   err = gcry_cipher_setctr(params->handle_, params->ctr_.buf_, C_AESCTR_CTR_LENGTH);
313   if(err) {
314     log_printf(ERROR, "failed to set cipher CTR: %s", gcry_strerror(err));
315     return -1;
316   }
317
318   err = gcry_cipher_encrypt(params->handle_, out, olen, in, ilen);
319   if(err) {
320     log_printf(ERROR, "failed to de/encrypt packet: %s", gcry_strerror(err));
321     return -1;
322   }
323 #else
324   if(C_AESCTR_CTR_LENGTH != AES_BLOCK_SIZE) {
325     log_printf(ERROR, "failed to set cipher CTR: size don't fits");
326     return -1;
327   }
328   u_int32_t num = 0;
329   memset(params->ecount_buf_, 0, AES_BLOCK_SIZE);
330   AES_ctr128_encrypt(in, out, (ilen < olen) ? ilen : olen, &params->aes_key_, params->ctr_.buf_, params->ecount_buf_, &num);
331 #endif
332
333   return (ilen < olen) ? ilen : olen;  
334 }
335 #endif