/src/openssl/providers/implementations/ciphers/cipher_tdes_wrap.c
Line | Count | Source (jump to first uncovered line) |
1 | | /* |
2 | | * Copyright 1995-2024 The OpenSSL Project Authors. All Rights Reserved. |
3 | | * |
4 | | * Licensed under the Apache License 2.0 (the "License"). You may not use |
5 | | * this file except in compliance with the License. You can obtain a copy |
6 | | * in the file LICENSE in the source distribution or at |
7 | | * https://www.openssl.org/source/license.html |
8 | | */ |
9 | | |
10 | | /* |
11 | | * DES and SHA-1 low level APIs are deprecated for public use, but still ok for |
12 | | * internal use. |
13 | | */ |
14 | | #include "internal/deprecated.h" |
15 | | |
16 | | #include <openssl/sha.h> |
17 | | #include <openssl/rand.h> |
18 | | #include <openssl/proverr.h> |
19 | | #include "cipher_tdes_default.h" |
20 | | #include "crypto/evp.h" |
21 | | #include "crypto/sha.h" |
22 | | #include "prov/implementations.h" |
23 | | #include "prov/providercommon.h" |
24 | | |
25 | | #define TDES_WRAP_FLAGS PROV_CIPHER_FLAG_CUSTOM_IV | PROV_CIPHER_FLAG_RAND_KEY |
26 | | |
27 | | static OSSL_FUNC_cipher_update_fn tdes_wrap_update; |
28 | | static OSSL_FUNC_cipher_cipher_fn tdes_wrap_cipher; |
29 | | |
30 | | static const unsigned char wrap_iv[8] = { |
31 | | 0x4a, 0xdd, 0xa2, 0x2c, 0x79, 0xe8, 0x21, 0x05 |
32 | | }; |
33 | | |
34 | | static int des_ede3_unwrap(PROV_CIPHER_CTX *ctx, unsigned char *out, |
35 | | const unsigned char *in, size_t inl) |
36 | 0 | { |
37 | 0 | unsigned char icv[8], iv[TDES_IVLEN], sha1tmp[SHA_DIGEST_LENGTH]; |
38 | 0 | int rv = -1; |
39 | |
|
40 | 0 | if (inl < 24) |
41 | 0 | return -1; |
42 | 0 | if (out == NULL) |
43 | 0 | return inl - 16; |
44 | | |
45 | 0 | memcpy(ctx->iv, wrap_iv, 8); |
46 | | /* Decrypt first block which will end up as icv */ |
47 | 0 | ctx->hw->cipher(ctx, icv, in, 8); |
48 | | /* Decrypt central blocks */ |
49 | | /* |
50 | | * If decrypting in place move whole output along a block so the next |
51 | | * des_ede_cbc_cipher is in place. |
52 | | */ |
53 | 0 | if (out == in) { |
54 | 0 | memmove(out, out + 8, inl - 8); |
55 | 0 | in -= 8; |
56 | 0 | } |
57 | 0 | ctx->hw->cipher(ctx, out, in + 8, inl - 16); |
58 | | /* Decrypt final block which will be IV */ |
59 | 0 | ctx->hw->cipher(ctx, iv, in + inl - 8, 8); |
60 | | /* Reverse order of everything */ |
61 | 0 | BUF_reverse(icv, NULL, 8); |
62 | 0 | BUF_reverse(out, NULL, inl - 16); |
63 | 0 | BUF_reverse(ctx->iv, iv, 8); |
64 | | /* Decrypt again using new IV */ |
65 | 0 | ctx->hw->cipher(ctx, out, out, inl - 16); |
66 | 0 | ctx->hw->cipher(ctx, icv, icv, 8); |
67 | 0 | if (ossl_sha1(out, inl - 16, sha1tmp) /* Work out hash of first portion */ |
68 | 0 | && CRYPTO_memcmp(sha1tmp, icv, 8) == 0) |
69 | 0 | rv = inl - 16; |
70 | 0 | OPENSSL_cleanse(icv, 8); |
71 | 0 | OPENSSL_cleanse(sha1tmp, SHA_DIGEST_LENGTH); |
72 | 0 | OPENSSL_cleanse(iv, 8); |
73 | 0 | OPENSSL_cleanse(ctx->iv, sizeof(ctx->iv)); |
74 | 0 | if (rv == -1) |
75 | 0 | OPENSSL_cleanse(out, inl - 16); |
76 | |
|
77 | 0 | return rv; |
78 | 0 | } |
79 | | |
80 | | static int des_ede3_wrap(PROV_CIPHER_CTX *ctx, unsigned char *out, |
81 | | const unsigned char *in, size_t inl) |
82 | 0 | { |
83 | 0 | unsigned char sha1tmp[SHA_DIGEST_LENGTH]; |
84 | 0 | size_t ivlen = TDES_IVLEN; |
85 | 0 | size_t icvlen = TDES_IVLEN; |
86 | 0 | size_t len = inl + ivlen + icvlen; |
87 | |
|
88 | 0 | if (out == NULL) |
89 | 0 | return len; |
90 | | |
91 | | /* Copy input to output buffer + 8 so we have space for IV */ |
92 | 0 | memmove(out + ivlen, in, inl); |
93 | | /* Work out ICV */ |
94 | 0 | if (!ossl_sha1(in, inl, sha1tmp)) |
95 | 0 | return 0; |
96 | 0 | memcpy(out + inl + ivlen, sha1tmp, icvlen); |
97 | 0 | OPENSSL_cleanse(sha1tmp, SHA_DIGEST_LENGTH); |
98 | | /* Generate random IV */ |
99 | 0 | if (RAND_bytes_ex(ctx->libctx, ctx->iv, ivlen, 0) <= 0) |
100 | 0 | return 0; |
101 | 0 | memcpy(out, ctx->iv, ivlen); |
102 | | /* Encrypt everything after IV in place */ |
103 | 0 | ctx->hw->cipher(ctx, out + ivlen, out + ivlen, inl + ivlen); |
104 | 0 | BUF_reverse(out, NULL, len); |
105 | 0 | memcpy(ctx->iv, wrap_iv, ivlen); |
106 | 0 | ctx->hw->cipher(ctx, out, out, len); |
107 | 0 | return len; |
108 | 0 | } |
109 | | |
110 | | static int tdes_wrap_cipher_internal(PROV_CIPHER_CTX *ctx, unsigned char *out, |
111 | | const unsigned char *in, size_t inl) |
112 | 0 | { |
113 | | /* |
114 | | * Sanity check input length: we typically only wrap keys so EVP_MAXCHUNK |
115 | | * is more than will ever be needed. Also input length must be a multiple |
116 | | * of 8 bits. |
117 | | */ |
118 | 0 | if (inl >= EVP_MAXCHUNK || inl % 8) |
119 | 0 | return -1; |
120 | 0 | if (ctx->enc) |
121 | 0 | return des_ede3_wrap(ctx, out, in, inl); |
122 | 0 | else |
123 | 0 | return des_ede3_unwrap(ctx, out, in, inl); |
124 | 0 | } |
125 | | |
126 | | static int tdes_wrap_cipher(void *vctx, |
127 | | unsigned char *out, size_t *outl, size_t outsize, |
128 | | const unsigned char *in, size_t inl) |
129 | 0 | { |
130 | 0 | PROV_CIPHER_CTX *ctx = (PROV_CIPHER_CTX *)vctx; |
131 | 0 | int ret; |
132 | |
|
133 | 0 | *outl = 0; |
134 | 0 | if (!ossl_prov_is_running()) |
135 | 0 | return 0; |
136 | | |
137 | 0 | if (outsize < inl) { |
138 | 0 | ERR_raise(ERR_LIB_PROV, PROV_R_OUTPUT_BUFFER_TOO_SMALL); |
139 | 0 | return 0; |
140 | 0 | } |
141 | | |
142 | 0 | ret = tdes_wrap_cipher_internal(ctx, out, in, inl); |
143 | 0 | if (ret <= 0) |
144 | 0 | return 0; |
145 | | |
146 | 0 | *outl = ret; |
147 | 0 | return 1; |
148 | 0 | } |
149 | | |
150 | | static int tdes_wrap_update(void *vctx, unsigned char *out, size_t *outl, |
151 | | size_t outsize, const unsigned char *in, |
152 | | size_t inl) |
153 | 0 | { |
154 | 0 | *outl = 0; |
155 | 0 | if (inl == 0) |
156 | 0 | return 1; |
157 | 0 | if (outsize < inl) { |
158 | 0 | ERR_raise(ERR_LIB_PROV, PROV_R_OUTPUT_BUFFER_TOO_SMALL); |
159 | 0 | return 0; |
160 | 0 | } |
161 | | |
162 | 0 | if (!tdes_wrap_cipher(vctx, out, outl, outsize, in, inl)) { |
163 | 0 | ERR_raise(ERR_LIB_PROV, PROV_R_CIPHER_OPERATION_FAILED); |
164 | 0 | return 0; |
165 | 0 | } |
166 | 0 | return 1; |
167 | 0 | } |
168 | | |
169 | | |
170 | | # define IMPLEMENT_WRAP_CIPHER(flags, kbits, blkbits, ivbits) \ |
171 | | static OSSL_FUNC_cipher_newctx_fn tdes_wrap_newctx; \ |
172 | 0 | static void *tdes_wrap_newctx(void *provctx) \ |
173 | 0 | { \ |
174 | 0 | return ossl_tdes_newctx(provctx, EVP_CIPH_WRAP_MODE, kbits, blkbits, \ |
175 | 0 | ivbits, flags, \ |
176 | 0 | ossl_prov_cipher_hw_tdes_wrap_cbc()); \ |
177 | 0 | } \ |
178 | | static OSSL_FUNC_cipher_get_params_fn tdes_wrap_get_params; \ |
179 | 2 | static int tdes_wrap_get_params(OSSL_PARAM params[]) \ |
180 | 2 | { \ |
181 | 2 | return ossl_cipher_generic_get_params(params, EVP_CIPH_WRAP_MODE, flags, \ |
182 | 2 | kbits, blkbits, ivbits); \ |
183 | 2 | } \ |
184 | | const OSSL_DISPATCH ossl_tdes_wrap_cbc_functions[] = \ |
185 | | { \ |
186 | | { OSSL_FUNC_CIPHER_ENCRYPT_INIT, (void (*)(void)) ossl_tdes_einit }, \ |
187 | | { OSSL_FUNC_CIPHER_DECRYPT_INIT, (void (*)(void)) ossl_tdes_dinit }, \ |
188 | | { OSSL_FUNC_CIPHER_CIPHER, (void (*)(void))tdes_wrap_cipher }, \ |
189 | | { OSSL_FUNC_CIPHER_NEWCTX, (void (*)(void))tdes_wrap_newctx }, \ |
190 | | { OSSL_FUNC_CIPHER_FREECTX, (void (*)(void))ossl_tdes_freectx }, \ |
191 | | { OSSL_FUNC_CIPHER_UPDATE, (void (*)(void))tdes_wrap_update }, \ |
192 | | { OSSL_FUNC_CIPHER_FINAL, \ |
193 | | (void (*)(void))ossl_cipher_generic_stream_final }, \ |
194 | | { OSSL_FUNC_CIPHER_GET_PARAMS, (void (*)(void))tdes_wrap_get_params }, \ |
195 | | { OSSL_FUNC_CIPHER_GETTABLE_PARAMS, \ |
196 | | (void (*)(void))ossl_cipher_generic_gettable_params }, \ |
197 | | { OSSL_FUNC_CIPHER_GET_CTX_PARAMS, \ |
198 | | (void (*)(void))ossl_tdes_get_ctx_params }, \ |
199 | | { OSSL_FUNC_CIPHER_GETTABLE_CTX_PARAMS, \ |
200 | | (void (*)(void))ossl_tdes_gettable_ctx_params }, \ |
201 | | { OSSL_FUNC_CIPHER_SET_CTX_PARAMS, \ |
202 | | (void (*)(void))ossl_cipher_generic_set_ctx_params }, \ |
203 | | { OSSL_FUNC_CIPHER_SETTABLE_CTX_PARAMS, \ |
204 | | (void (*)(void))ossl_cipher_generic_settable_ctx_params }, \ |
205 | | OSSL_DISPATCH_END \ |
206 | | } |
207 | | |
208 | | /* ossl_tdes_wrap_cbc_functions */ |
209 | | IMPLEMENT_WRAP_CIPHER(TDES_WRAP_FLAGS, 64*3, 64, 0); |