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 { 37 unsigned char icv[8], iv[TDES_IVLEN], sha1tmp[SHA_DIGEST_LENGTH]; 38 int rv = -1; 39 40 if (inl < 24) 41 return -1; 42 if (out == NULL) 43 return inl - 16; 44 45 memcpy(ctx->iv, wrap_iv, 8); 46 /* Decrypt first block which will end up as icv */ 47 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 if (out == in) { 54 memmove(out, out + 8, inl - 8); 55 in -= 8; 56 } 57 ctx->hw->cipher(ctx, out, in + 8, inl - 16); 58 /* Decrypt final block which will be IV */ 59 ctx->hw->cipher(ctx, iv, in + inl - 8, 8); 60 /* Reverse order of everything */ 61 BUF_reverse(icv, NULL, 8); 62 BUF_reverse(out, NULL, inl - 16); 63 BUF_reverse(ctx->iv, iv, 8); 64 /* Decrypt again using new IV */ 65 ctx->hw->cipher(ctx, out, out, inl - 16); 66 ctx->hw->cipher(ctx, icv, icv, 8); 67 if (ossl_sha1(out, inl - 16, sha1tmp) /* Work out hash of first portion */ 68 && CRYPTO_memcmp(sha1tmp, icv, 8) == 0) 69 rv = inl - 16; 70 OPENSSL_cleanse(icv, 8); 71 OPENSSL_cleanse(sha1tmp, SHA_DIGEST_LENGTH); 72 OPENSSL_cleanse(iv, 8); 73 OPENSSL_cleanse(ctx->iv, sizeof(ctx->iv)); 74 if (rv == -1) 75 OPENSSL_cleanse(out, inl - 16); 76 77 return rv; 78 } 79 80 static int des_ede3_wrap(PROV_CIPHER_CTX *ctx, unsigned char *out, 81 const unsigned char *in, size_t inl) 82 { 83 unsigned char sha1tmp[SHA_DIGEST_LENGTH]; 84 size_t ivlen = TDES_IVLEN; 85 size_t icvlen = TDES_IVLEN; 86 size_t len = inl + ivlen + icvlen; 87 88 if (out == NULL) 89 return len; 90 91 /* Copy input to output buffer + 8 so we have space for IV */ 92 memmove(out + ivlen, in, inl); 93 /* Work out ICV */ 94 if (!ossl_sha1(in, inl, sha1tmp)) 95 return 0; 96 memcpy(out + inl + ivlen, sha1tmp, icvlen); 97 OPENSSL_cleanse(sha1tmp, SHA_DIGEST_LENGTH); 98 /* Generate random IV */ 99 if (RAND_bytes_ex(ctx->libctx, ctx->iv, ivlen, 0) <= 0) 100 return 0; 101 memcpy(out, ctx->iv, ivlen); 102 /* Encrypt everything after IV in place */ 103 ctx->hw->cipher(ctx, out + ivlen, out + ivlen, inl + ivlen); 104 BUF_reverse(out, NULL, len); 105 memcpy(ctx->iv, wrap_iv, ivlen); 106 ctx->hw->cipher(ctx, out, out, len); 107 return len; 108 } 109 110 static int tdes_wrap_cipher_internal(PROV_CIPHER_CTX *ctx, unsigned char *out, 111 const unsigned char *in, size_t inl) 112 { 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 if (inl >= EVP_MAXCHUNK || inl % 8) 119 return -1; 120 if (ctx->enc) 121 return des_ede3_wrap(ctx, out, in, inl); 122 else 123 return des_ede3_unwrap(ctx, out, in, inl); 124 } 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 { 130 PROV_CIPHER_CTX *ctx = (PROV_CIPHER_CTX *)vctx; 131 int ret; 132 133 *outl = 0; 134 if (!ossl_prov_is_running()) 135 return 0; 136 137 if (outsize < inl) { 138 ERR_raise(ERR_LIB_PROV, PROV_R_OUTPUT_BUFFER_TOO_SMALL); 139 return 0; 140 } 141 142 ret = tdes_wrap_cipher_internal(ctx, out, in, inl); 143 if (ret <= 0) 144 return 0; 145 146 *outl = ret; 147 return 1; 148 } 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 { 154 *outl = 0; 155 if (inl == 0) 156 return 1; 157 if (outsize < inl) { 158 ERR_raise(ERR_LIB_PROV, PROV_R_OUTPUT_BUFFER_TOO_SMALL); 159 return 0; 160 } 161 162 if (!tdes_wrap_cipher(vctx, out, outl, outsize, in, inl)) { 163 ERR_raise(ERR_LIB_PROV, PROV_R_CIPHER_OPERATION_FAILED); 164 return 0; 165 } 166 return 1; 167 } 168 169 170 # define IMPLEMENT_WRAP_CIPHER(flags, kbits, blkbits, ivbits) \ 171 static OSSL_FUNC_cipher_newctx_fn tdes_wrap_newctx; \ 172 static void *tdes_wrap_newctx(void *provctx) \ 173 { \ 174 return ossl_tdes_newctx(provctx, EVP_CIPH_WRAP_MODE, kbits, blkbits, \ 175 ivbits, flags, \ 176 ossl_prov_cipher_hw_tdes_wrap_cbc()); \ 177 } \ 178 static OSSL_FUNC_cipher_get_params_fn tdes_wrap_get_params; \ 179 static int tdes_wrap_get_params(OSSL_PARAM params[]) \ 180 { \ 181 return ossl_cipher_generic_get_params(params, EVP_CIPH_WRAP_MODE, flags, \ 182 kbits, blkbits, ivbits); \ 183 } \ 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); 210