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