summaryrefslogtreecommitdiffstats
path: root/src/lib/crypto/symmetric.h
blob: a50fe9a1849f1efde5c13573df380b64595064f2 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
/*
 * Copyright (c) 2017, 2021 [Ribose Inc](https://www.ribose.com).
 * Copyright (c) 2009 The NetBSD Foundation, Inc.
 * All rights reserved.
 *
 * This code is originally derived from software contributed to
 * The NetBSD Foundation by Alistair Crooks (agc@netbsd.org), and
 * carried further by Ribose Inc (https://www.ribose.com).
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS
 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 */
/*
 * Copyright (c) 2005-2008 Nominet UK (www.nic.uk)
 * All rights reserved.
 * Contributors: Ben Laurie, Rachel Willmer. The Contributors have asserted
 * their moral rights under the UK Copyright Design and Patents Act 1988 to
 * be recorded as the authors of this copyright work.
 *
 * Licensed under the Apache License, Version 2.0 (the "License"); you may not
 * use this file except in compliance with the License.
 *
 * You may obtain a copy of the License at
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#ifndef SYMMETRIC_CRYPTO_H_
#define SYMMETRIC_CRYPTO_H_

#include <repgp/repgp_def.h>
#include "crypto/rng.h"
#include "config.h"
#ifdef CRYPTO_BACKEND_OPENSSL
#include <openssl/evp.h>
#include "mem.h"
#endif

/* Nonce len for AEAD/EAX */
#define PGP_AEAD_EAX_NONCE_LEN 16

/* Nonce len for AEAD/OCB */
#define PGP_AEAD_OCB_NONCE_LEN 15

/* Maximum AEAD nonce length */
#define PGP_AEAD_MAX_NONCE_LEN 16

/* Authentication tag len for AEAD/EAX and AEAD/OCB */
#define PGP_AEAD_EAX_OCB_TAG_LEN 16

/* Maximal size of symmetric key */
#define MAX_SYMM_KEY_SIZE 32

/* Maximum AEAD tag length */
#define PGP_AEAD_MAX_TAG_LEN 16

/* Maximum authenticated data length for AEAD */
#define PGP_AEAD_MAX_AD_LEN 32

struct pgp_crypt_cfb_param_t {
#ifdef CRYPTO_BACKEND_BOTAN
    struct botan_block_cipher_struct *obj;
#endif
#ifdef CRYPTO_BACKEND_OPENSSL
    EVP_CIPHER_CTX *obj;
#endif
    size_t  remaining;
    uint8_t iv[PGP_MAX_BLOCK_SIZE];
};

struct pgp_crypt_aead_param_t {
#ifdef CRYPTO_BACKEND_BOTAN
    struct botan_cipher_struct *obj;
#endif
#ifdef CRYPTO_BACKEND_OPENSSL
    EVP_CIPHER_CTX *             obj;
    const EVP_CIPHER *           cipher;
    rnp::secure_vector<uint8_t> *key;
    uint8_t                      ad[PGP_AEAD_MAX_AD_LEN];
    size_t                       ad_len;
    size_t                       n_len;
#endif
    pgp_aead_alg_t alg;
    bool           decrypt;
    size_t         granularity;
    size_t         taglen;
};

/** pgp_crypt_t */
typedef struct pgp_crypt_t {
    union {
        struct pgp_crypt_cfb_param_t cfb;
#if defined(ENABLE_AEAD)
        struct pgp_crypt_aead_param_t aead;
#endif
    };

    pgp_symm_alg_t alg;
    size_t         blocksize;
    rnp::RNG *     rng;
} pgp_crypt_t;

unsigned pgp_block_size(pgp_symm_alg_t);
unsigned pgp_key_size(pgp_symm_alg_t);
bool     pgp_is_sa_supported(int alg, bool silent = false);
size_t   pgp_cipher_block_size(pgp_crypt_t *crypt);

/**
 * Initialize a cipher object.
 * @param iv if null an all-zero IV is assumed
 */
bool pgp_cipher_cfb_start(pgp_crypt_t *  crypt,
                          pgp_symm_alg_t alg,
                          const uint8_t *key,
                          const uint8_t *iv);

// Deallocate all storage
int pgp_cipher_cfb_finish(pgp_crypt_t *crypt);
// CFB encryption/decryption
int pgp_cipher_cfb_encrypt(pgp_crypt_t *crypt, uint8_t *out, const uint8_t *in, size_t len);
int pgp_cipher_cfb_decrypt(pgp_crypt_t *crypt, uint8_t *out, const uint8_t *in, size_t len);

void pgp_cipher_cfb_resync(pgp_crypt_t *crypt, const uint8_t *buf);

#if defined(ENABLE_AEAD)
/** @brief Initialize AEAD cipher instance
 *  @param crypt pgp crypto object
 *  @param ealg symmetric encryption algorithm to use together with AEAD cipher mode
 *  @param aalg AEAD cipher mode. Only EAX is supported now
 *  @param key key buffer. Number of key bytes is determined by ealg.
 *  @param decrypt true for decryption, or false for encryption
 *  @return true on success or false otherwise.
 */
bool pgp_cipher_aead_init(pgp_crypt_t *  crypt,
                          pgp_symm_alg_t ealg,
                          pgp_aead_alg_t aalg,
                          const uint8_t *key,
                          bool           decrypt);

/** @brief Return the AEAD cipher update granularity. Botan FFI will consume chunks which are
 *         multiple of this value. See the description of pgp_cipher_aead_update()
 *  @param crypt initialized AEAD crypto
 *  @return Update granularity value in bytes
 */
size_t pgp_cipher_aead_granularity(pgp_crypt_t *crypt);
#endif

/** @brief Return the AEAD cipher tag length
 *  @param aalg OpenPGP AEAD algorithm
 *  @return length of authentication tag in bytes, or 0 for unknown algorithm
 */
size_t pgp_cipher_aead_tag_len(pgp_aead_alg_t aalg);

/** @brief Return the AEAD cipher nonce and IV length
 *  @param aalg OpenPGP AEAD algorithm
 *  @return length of nonce in bytes, or 0 for unknown algorithm
 */
size_t pgp_cipher_aead_nonce_len(pgp_aead_alg_t aalg);

#if defined(ENABLE_AEAD)
/** @brief Set associated data
 *  @param crypt initialized AEAD crypto
 *  @param ad buffer with data. Cannot be NULL.
 *  @param len number of bytes in ad
 *  @return true on success or false otherwise.
 */
bool pgp_cipher_aead_set_ad(pgp_crypt_t *crypt, const uint8_t *ad, size_t len);

/** @brief Start the cipher operation, using the given nonce
 *  @param crypt initialized AEAD crypto
 *  @param nonce buffer with nonce, cannot be NULL.
 *  @param len number of bytes in nonce. Must conform to the cipher properties.
 *  @return true on success or false otherwise.
 */
bool pgp_cipher_aead_start(pgp_crypt_t *crypt, const uint8_t *nonce, size_t len);

/** @brief Update the cipher. This should be called for non-final data, respecting the
 *         update granularity of underlying botan cipher. Now it is 256 bytes.
 *  @param crypt initialized AEAD crypto
 *  @param out buffer to put processed data. Cannot be NULL, and should be large enough to put
 *             len bytes
 *  @param in buffer with input, cannot be NULL
 *  @param len number of bytes to process. Should be multiple of update granularity.
 *  @return true on success or false otherwise. On success exactly len processed bytes will be
 *          stored in out buffer
 */
bool pgp_cipher_aead_update(pgp_crypt_t *crypt, uint8_t *out, const uint8_t *in, size_t len);

/** @brief Do final update on the cipher. For decryption final chunk should contain at least
 *         authentication tag, for encryption input could be zero-size.
 *  @param crypt initialized AEAD crypto
 *  @param out buffer to put processed data. For decryption it should be large enough to put
 *             len bytes minus authentication tag, for encryption it should be large enough to
 *             put len byts plus a tag.
 *  @param in buffer with input, if any. May be NULL for encryption, then len should be zero.
 *            For decryption it should contain at least authentication tag.
 *  @param len number of input bytes bytes
 *  @return true on success or false otherwise. On success for decryption len minus tag size
 *               bytes will be stored in out, for encryption out will contain len bytes plus
 *               tag size.
 */
bool pgp_cipher_aead_finish(pgp_crypt_t *crypt, uint8_t *out, const uint8_t *in, size_t len);

/** @brief Reset the AEAD cipher's state, calling the finish() and ignoring the result
 *  @param crypt initialized AEAD crypto
 */
void pgp_cipher_aead_reset(pgp_crypt_t *crypt);

/** @brief Destroy the cipher object, deallocating all the memory.
 *  @param crypt initialized AEAD crypto
 */
void pgp_cipher_aead_destroy(pgp_crypt_t *crypt);

/** @brief Helper function to set AEAD nonce for the chunk by its index.
 *         iv and nonce should be large enough to hold max nonce bytes
 *  @param aalg AEAD algorithm used
 *  @param iv Initial vector for the message, must have 16 bytes of data
 *  @param nonce Nonce to fill up, should have space for 16 bytes of data
 *  @param index Chunk's index
 *  @return Length of the nonce, or 0 if algorithm is unknown
 */
size_t pgp_cipher_aead_nonce(pgp_aead_alg_t aalg,
                             const uint8_t *iv,
                             uint8_t *      nonce,
                             size_t         index);
#endif // ENABLE_AEAD

#endif