glitch in the license text detected by hyazinthe, thank you!
[oweals/gnunet.git] / src / util / crypto_symmetric.c
1 /*
2      This file is part of GNUnet.
3      Copyright (C) 2001, 2002, 2003, 2004, 2005, 2006, 2013 GNUnet e.V.
4
5      GNUnet is free software: you can redistribute it and/or modify it
6      under the terms of the GNU Affero General Public License as published
7      by the Free Software Foundation, either version 3 of the License,
8      or (at your option) any later version.
9
10      GNUnet is distributed in the hope that it will be useful, but
11      WITHOUT ANY WARRANTY; without even the implied warranty of
12      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13      Affero General Public License for more details.
14 */
15
16 /**
17  * @file util/crypto_symmetric.c
18  * @brief Symmetric encryption services; combined cipher AES+TWOFISH (256-bit each)
19  * @author Christian Grothoff
20  * @author Ioana Patrascu
21  */
22
23 #include "platform.h"
24 #include "gnunet_crypto_lib.h"
25 #include <gcrypt.h>
26
27 #define LOG(kind,...) GNUNET_log_from (kind, "util-crypto-symmetric", __VA_ARGS__)
28
29 /**
30  * Create a new SessionKey (for symmetric encryption).
31  *
32  * @param key session key to initialize
33  */
34 void
35 GNUNET_CRYPTO_symmetric_create_session_key (struct GNUNET_CRYPTO_SymmetricSessionKey *key)
36 {
37   gcry_randomize (key->aes_key,
38                   GNUNET_CRYPTO_AES_KEY_LENGTH,
39                   GCRY_STRONG_RANDOM);
40   gcry_randomize (key->twofish_key,
41                   GNUNET_CRYPTO_AES_KEY_LENGTH,
42                   GCRY_STRONG_RANDOM);
43 }
44
45
46 /**
47  * Initialize AES cipher.
48  *
49  * @param handle handle to initialize
50  * @param sessionkey session key to use
51  * @param iv initialization vector to use
52  * @return #GNUNET_OK on success, #GNUNET_SYSERR on error
53  */
54 static int
55 setup_cipher_aes (gcry_cipher_hd_t *handle,
56                   const struct GNUNET_CRYPTO_SymmetricSessionKey *sessionkey,
57                   const struct GNUNET_CRYPTO_SymmetricInitializationVector *iv)
58 {
59   int rc;
60
61   GNUNET_assert (0 ==
62                  gcry_cipher_open (handle, GCRY_CIPHER_AES256,
63                                    GCRY_CIPHER_MODE_CFB, 0));
64   rc = gcry_cipher_setkey (*handle,
65                            sessionkey->aes_key,
66                            sizeof (sessionkey->aes_key));
67   GNUNET_assert ((0 == rc) || ((char) rc == GPG_ERR_WEAK_KEY));
68   rc = gcry_cipher_setiv (*handle,
69                           iv->aes_iv,
70                           sizeof (iv->aes_iv));
71   GNUNET_assert ((0 == rc) || ((char) rc == GPG_ERR_WEAK_KEY));
72   return GNUNET_OK;
73 }
74
75
76 /**
77  * Initialize TWOFISH cipher.
78  *
79  * @param handle handle to initialize
80  * @param sessionkey session key to use
81  * @param iv initialization vector to use
82  * @return #GNUNET_OK on success, #GNUNET_SYSERR on error
83  */
84 static int
85 setup_cipher_twofish (gcry_cipher_hd_t *handle,
86                       const struct GNUNET_CRYPTO_SymmetricSessionKey *sessionkey,
87                       const struct GNUNET_CRYPTO_SymmetricInitializationVector *iv)
88 {
89   int rc;
90
91   GNUNET_assert (0 ==
92                  gcry_cipher_open (handle, GCRY_CIPHER_TWOFISH,
93                                    GCRY_CIPHER_MODE_CFB, 0));
94   rc = gcry_cipher_setkey (*handle,
95                            sessionkey->twofish_key,
96                            sizeof (sessionkey->twofish_key));
97   GNUNET_assert ((0 == rc) || ((char) rc == GPG_ERR_WEAK_KEY));
98   rc = gcry_cipher_setiv (*handle,
99                           iv->twofish_iv,
100                           sizeof (iv->twofish_iv));
101   GNUNET_assert ((0 == rc) || ((char) rc == GPG_ERR_WEAK_KEY));
102   return GNUNET_OK;
103 }
104
105
106 /**
107  * Encrypt a block with a symmetric session key.
108  *
109  * @param block the block to encrypt
110  * @param size the size of the @a block
111  * @param sessionkey the key used to encrypt
112  * @param iv the initialization vector to use, use INITVALUE for streams
113  * @param result the output parameter in which to store the encrypted result
114  *               can be the same or overlap with @c block
115  * @returns the size of the encrypted block, -1 for errors.
116  *          Due to the use of CFB and therefore an effective stream cipher,
117  *          this size should be the same as @c len.
118  */
119 ssize_t
120 GNUNET_CRYPTO_symmetric_encrypt (const void *block,
121                                  size_t size,
122                                  const struct GNUNET_CRYPTO_SymmetricSessionKey *sessionkey,
123                                  const struct GNUNET_CRYPTO_SymmetricInitializationVector *iv,
124                                  void *result)
125 {
126   gcry_cipher_hd_t handle;
127   char tmp[size];
128
129   if (GNUNET_OK != setup_cipher_aes (&handle, sessionkey, iv))
130     return -1;
131   GNUNET_assert (0 == gcry_cipher_encrypt (handle, tmp, size, block, size));
132   gcry_cipher_close (handle);
133   if (GNUNET_OK != setup_cipher_twofish (&handle, sessionkey, iv))
134     return -1;
135   GNUNET_assert (0 == gcry_cipher_encrypt (handle, result, size, tmp, size));
136   gcry_cipher_close (handle);
137   memset (tmp, 0, sizeof (tmp));
138   return size;
139 }
140
141
142 /**
143  * Decrypt a given block with the session key.
144  *
145  * @param block the data to decrypt, encoded as returned by encrypt
146  * @param size the size of the @a block to decrypt
147  * @param sessionkey the key used to decrypt
148  * @param iv the initialization vector to use, use INITVALUE for streams
149  * @param result address to store the result at
150  *               can be the same or overlap with @c block
151  * @return -1 on failure, size of decrypted block on success.
152  *         Due to the use of CFB and therefore an effective stream cipher,
153  *         this size should be the same as @c size.
154  */
155 ssize_t
156 GNUNET_CRYPTO_symmetric_decrypt (const void *block,
157                                  size_t size,
158                                  const struct GNUNET_CRYPTO_SymmetricSessionKey *sessionkey,
159                                  const struct GNUNET_CRYPTO_SymmetricInitializationVector *iv,
160                                  void *result)
161 {
162   gcry_cipher_hd_t handle;
163   char tmp[size];
164
165   if (GNUNET_OK != setup_cipher_twofish (&handle, sessionkey, iv))
166     return -1;
167   GNUNET_assert (0 == gcry_cipher_decrypt (handle, tmp, size, block, size));
168   gcry_cipher_close (handle);
169   if (GNUNET_OK != setup_cipher_aes (&handle, sessionkey, iv))
170     return -1;
171   GNUNET_assert (0 == gcry_cipher_decrypt (handle, result, size, tmp, size));
172   gcry_cipher_close (handle);
173   memset (tmp, 0, sizeof (tmp));
174   return size;
175 }
176
177
178 /**
179  * @brief Derive an IV
180  *
181  * @param iv initialization vector
182  * @param skey session key
183  * @param salt salt for the derivation
184  * @param salt_len size of the @a salt
185  * @param ... pairs of void * & size_t for context chunks, terminated by NULL
186  */
187 void
188 GNUNET_CRYPTO_symmetric_derive_iv (struct GNUNET_CRYPTO_SymmetricInitializationVector *iv,
189                                    const struct GNUNET_CRYPTO_SymmetricSessionKey *skey,
190                                    const void *salt,
191                                    size_t salt_len,
192                                    ...)
193 {
194   va_list argp;
195
196   va_start (argp, salt_len);
197   GNUNET_CRYPTO_symmetric_derive_iv_v (iv, skey, salt, salt_len, argp);
198   va_end (argp);
199 }
200
201
202 /**
203  * @brief Derive an IV
204  *
205  * @param iv initialization vector
206  * @param skey session key
207  * @param salt salt for the derivation
208  * @param salt_len size of the salt
209  * @param argp pairs of void * & size_t for context chunks, terminated by NULL
210  */
211 void
212 GNUNET_CRYPTO_symmetric_derive_iv_v (struct GNUNET_CRYPTO_SymmetricInitializationVector *iv,
213                                      const struct GNUNET_CRYPTO_SymmetricSessionKey *skey,
214                                      const void *salt,
215                                      size_t salt_len,
216                                      va_list argp)
217 {
218   char aes_salt[salt_len + 4];
219   char twofish_salt[salt_len + 4];
220
221   GNUNET_memcpy (aes_salt, salt, salt_len);
222   GNUNET_memcpy (&aes_salt[salt_len], "AES!", 4);
223   GNUNET_memcpy (twofish_salt, salt, salt_len);
224   GNUNET_memcpy (&twofish_salt[salt_len], "FISH", 4);
225   GNUNET_CRYPTO_kdf_v (iv->aes_iv,
226                        sizeof (iv->aes_iv),
227                        aes_salt,
228                        salt_len + 4,
229                        skey->aes_key,
230                        sizeof (skey->aes_key),
231                        argp);
232   GNUNET_CRYPTO_kdf_v (iv->twofish_iv,
233                        sizeof (iv->twofish_iv),
234                        twofish_salt,
235                        salt_len + 4,
236                        skey->twofish_key,
237                        sizeof (skey->twofish_key),
238                        argp);
239 }
240
241 /* end of crypto_symmetric.c */