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