Project

General

Profile

Statistics
| Branch: | Tag: | Revision:

gdp / ep / ep_crypto_cipher.c @ master

History | View | Annotate | Download (6.66 KB)

1
/* vim: set ai sw=8 sts=8 ts=8 :*/
2

    
3
/***********************************************************************
4
**  ----- BEGIN LICENSE BLOCK -----
5
**        LIBEP: Enhanced Portability Library (Reduced Edition)
6
**
7
**        Copyright (c) 2008-2019, Eric P. Allman.  All rights reserved.
8
**        Copyright (c) 2015-2019, Regents of the University of California.
9
**        All rights reserved.
10
**
11
**        Permission is hereby granted, without written agreement and without
12
**        license or royalty fees, to use, copy, modify, and distribute this
13
**        software and its documentation for any purpose, provided that the above
14
**        copyright notice and the following two paragraphs appear in all copies
15
**        of this software.
16
**
17
**        IN NO EVENT SHALL REGENTS BE LIABLE TO ANY PARTY FOR DIRECT, INDIRECT,
18
**        SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, INCLUDING LOST
19
**        PROFITS, ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION,
20
**        EVEN IF REGENTS HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
21
**
22
**        REGENTS SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT
23
**        LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
24
**        FOR A PARTICULAR PURPOSE. THE SOFTWARE AND ACCOMPANYING DOCUMENTATION,
25
**        IF ANY, PROVIDED HEREUNDER IS PROVIDED "AS IS". REGENTS HAS NO
26
**        OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS,
27
**        OR MODIFICATIONS.
28
**  ----- END LICENSE BLOCK -----
29
***********************************************************************/
30

    
31
/*
32
**  Symmetric cipher support.
33
*/
34

    
35
#include <ep/ep.h>
36
#include <ep/ep_crypto.h>
37

    
38
struct ep_crypto_cipher_ctx
39
{
40
        EP_CRYPTO_KEY        *key;                // symmetric encryption/decryption key
41
        EVP_CIPHER_CTX        *ctx;                // OpenSSL cipher context
42
//        uint8_t                iv[EVP_MAX_IV_LENGTH];
43
};
44

    
45

    
46
/*
47
**  Convert EP cipher code to OpenSSL cipher (helper routine)
48
*/
49

    
50
static const EVP_CIPHER *
51
evp_cipher_type(uint32_t cipher)
52
{
53
        switch (cipher)
54
        {
55
          case EP_CRYPTO_SYMKEY_AES128 | EP_CRYPTO_MODE_CBC:
56
                return EVP_aes_128_cbc();
57
          case EP_CRYPTO_SYMKEY_AES128 | EP_CRYPTO_MODE_CFB:
58
                return EVP_aes_128_cfb();
59
          case EP_CRYPTO_SYMKEY_AES128 | EP_CRYPTO_MODE_OFB:
60
                return EVP_aes_128_ofb();
61

    
62
          case EP_CRYPTO_SYMKEY_AES192 | EP_CRYPTO_MODE_CBC:
63
                return EVP_aes_192_cbc();
64
          case EP_CRYPTO_SYMKEY_AES192 | EP_CRYPTO_MODE_CFB:
65
                return EVP_aes_192_cfb();
66
          case EP_CRYPTO_SYMKEY_AES192 | EP_CRYPTO_MODE_OFB:
67
                return EVP_aes_192_ofb();
68

    
69
          case EP_CRYPTO_SYMKEY_AES256 | EP_CRYPTO_MODE_CBC:
70
                return EVP_aes_256_cbc();
71
          case EP_CRYPTO_SYMKEY_AES256 | EP_CRYPTO_MODE_CFB:
72
                return EVP_aes_256_cfb();
73
          case EP_CRYPTO_SYMKEY_AES256 | EP_CRYPTO_MODE_OFB:
74
                return EVP_aes_256_ofb();
75
        }
76

    
77
        (void) _ep_crypto_error(EP_STAT_CRYPTO_KEYTYPE,
78
                        "ep_crypto_cipher_new: unknown cipher type 0x%x",
79
                        cipher);
80
        return NULL;
81
}
82

    
83

    
84
/*
85
**  Create a new cipher context.  This is used by most of the
86
**  rest of the cipher routines.
87
**
88
**        The 'enc' parameter tells whether this is an encryption or a
89
**        description operation (true == encrypt).
90
**
91
**        XXX need to explain iv.
92
*/
93

    
94
EP_CRYPTO_CIPHER_CTX *
95
ep_crypto_cipher_new(
96
                uint32_t cipher,
97
                uint8_t *key,
98
                uint8_t *iv,
99
                bool enc)
100
{
101
        EP_CRYPTO_CIPHER_CTX *ctx;
102
        const EVP_CIPHER *ciphertype;
103
        ENGINE *engine = NULL;
104

    
105
        ciphertype = evp_cipher_type(cipher);
106
        if (ciphertype == NULL)
107
                return NULL;
108

    
109
        ctx = (EP_CRYPTO_CIPHER_CTX *) ep_mem_zalloc(sizeof *ctx);
110
#if OPENSSL_VERSION_NUMBER >= 0x10100000        // version 1.1.0
111
        ctx->ctx = EVP_CIPHER_CTX_new();
112
#else
113
        ctx->ctx = ep_mem_malloc(sizeof *ctx->ctx);
114
        EVP_CIPHER_CTX_init(ctx->ctx);
115
#endif
116
        if (EVP_CipherInit_ex(ctx->ctx, ciphertype, engine, key, iv, enc) <= 0)
117
        {
118
                ep_crypto_cipher_free(ctx);
119
                (void) _ep_crypto_error(EP_STAT_CRYPTO_CIPHER,
120
                                "ep_crypto_cipher_new: "
121
                                "cannot initialize for encryption");
122
                return NULL;
123
        }
124

    
125
        return ctx;
126
}
127

    
128

    
129
/*
130
**  Free a cipher context
131
**
132
**        This makes sure that sensitive information is cleared from
133
**        memory before it is released.
134
*/
135

    
136
void
137
ep_crypto_cipher_free(EP_CRYPTO_CIPHER_CTX *ctx)
138
{
139
#if OPENSSL_VERSION_NUMBER >= 0x10100000        // version 1.1.0
140
        EVP_CIPHER_CTX_free(ctx->ctx);
141
#else
142
        if (EVP_CIPHER_CTX_cleanup(ctx->ctx) <= 0)
143
                (void) _ep_crypto_error(EP_STAT_CRYPTO_FAIL,
144
                                "cannot cleanup cipher context");
145
        ep_mem_free(ctx->ctx);
146
#endif
147
        ep_mem_free(ctx);
148
}
149

    
150

    
151
/*
152
**  Do symmetric encryption
153
**
154
**        This can be done using ep_crypto_cipher_crypt, which
155
**        encrypts or decrypts a block of memory and does the final
156
**        padding in one operation, or by calling ep_crypto_cipher_update
157
**        on multiple blocks followed by ep_crypto_cipher_final to
158
**        do the padding.
159
**
160
**        In all cases, the value of a successful status code contains
161
**        the number of bytes actually written to the output.
162
*/
163

    
164
EP_STAT
165
ep_crypto_cipher_crypt(
166
                EP_CRYPTO_CIPHER_CTX *ctx,
167
                void *_in,
168
                size_t inlen,
169
                void *_out,
170
                size_t outlen)
171
{
172
        uint8_t *in = (uint8_t *) _in;
173
        uint8_t *out = (uint8_t *) _out;
174
        int olen;
175
        int rval;
176

    
177
        // must allow room for final padding in output buffer
178
        if (outlen < inlen + EVP_CIPHER_CTX_key_length(ctx->ctx))
179
        {
180
                // potential buffer overflow
181
                return _ep_crypto_error(EP_STAT_BUF_OVERFLOW,
182
                                "cp_crypto_cipher_crypt: "
183
                                "short output buffer (%d < %d + %d)",
184
                        outlen, inlen, EVP_CIPHER_CTX_key_length(ctx->ctx));
185
        }
186

    
187
        if (EVP_CipherUpdate(ctx->ctx, (uint8_t *) out, &olen, (uint8_t *) in, inlen) <= 0)
188
        {
189
                return _ep_crypto_error(EP_STAT_CRYPTO_CIPHER,
190
                                "ep_crypto_cipher_crypt: "
191
                                "cannot encrypt/decrypt");
192
        }
193
        rval = olen;
194
        out += olen;
195
        if (EVP_CipherFinal_ex(ctx->ctx, out, &olen) <= 0)
196
        {
197
                return _ep_crypto_error(EP_STAT_CRYPTO_CIPHER,
198
                                "ep_crypto_cipher_crypt: "
199
                                "cannot finalize encrypt/decrypt");
200
        }
201

    
202
        rval += olen;
203
        EP_ASSERT(rval >= 0);
204
        return EP_STAT_FROM_INT(rval);
205
}
206

    
207

    
208
EP_STAT
209
ep_crypto_cipher_update(
210
                EP_CRYPTO_CIPHER_CTX *ctx,
211
                void *_in,
212
                size_t inlen,
213
                void *_out,
214
                size_t outlen)
215
{
216
        uint8_t *in = (uint8_t *) _in;
217
        uint8_t *out = (uint8_t *) _out;
218
        int olen;
219

    
220
        if (EVP_CipherUpdate(ctx->ctx, out, &olen, in, inlen) <= 0)
221
        {
222
                return _ep_crypto_error(EP_STAT_CRYPTO_CIPHER,
223
                                "ep_crypto_cipher_update: "
224
                                "cannot encrypt/decrypt");
225
        }
226

    
227
        EP_ASSERT(olen >= 0 && (unsigned) olen <= outlen);
228
        return EP_STAT_FROM_INT(olen);
229
}
230

    
231

    
232
EP_STAT
233
ep_crypto_cipher_final(
234
                EP_CRYPTO_CIPHER_CTX *ctx,
235
                void *_out,
236
                size_t outlen)
237
{
238
        uint8_t *out = (uint8_t *) _out;
239
        int olen;
240

    
241
        // allow room for possible final padding
242
        if ((ssize_t) outlen < EVP_CIPHER_CTX_key_length(ctx->ctx))
243
        {
244
                // potential buffer overflow
245
                return _ep_crypto_error(EP_STAT_BUF_OVERFLOW,
246
                                "ep_crypto_cipher_final: "
247
                                "short output buffer (%d < %d)",
248
                                outlen, EVP_CIPHER_CTX_key_length(ctx->ctx));
249
        }
250

    
251
        if (EVP_CipherFinal_ex(ctx->ctx, out, &olen) <= 0)
252
        {
253
                return _ep_crypto_error(EP_STAT_CRYPTO_CIPHER,
254
                                "ep_crypto_cipher_final: "
255
                                "cannot finalize encrypt/decrypt");
256
        }
257

    
258
        EP_ASSERT(olen >= 0);
259
        return EP_STAT_FROM_INT(olen);
260
}