Home | History | Annotate | Line # | Download | only in ciphers
      1 /*
      2  * Copyright 1995-2021 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 {
     32     0x4a, 0xdd, 0xa2, 0x2c, 0x79, 0xe8, 0x21, 0x05
     33 };
     34 
     35 static int des_ede3_unwrap(PROV_CIPHER_CTX *ctx, unsigned char *out,
     36                            const unsigned char *in, size_t inl)
     37 {
     38     unsigned char icv[8], iv[TDES_IVLEN], sha1tmp[SHA_DIGEST_LENGTH];
     39     int rv = -1;
     40 
     41     if (inl < 24)
     42         return -1;
     43     if (out == NULL)
     44         return inl - 16;
     45 
     46     memcpy(ctx->iv, wrap_iv, 8);
     47     /* Decrypt first block which will end up as icv */
     48     ctx->hw->cipher(ctx, icv, in, 8);
     49     /* Decrypt central blocks */
     50     /*
     51      * If decrypting in place move whole output along a block so the next
     52      * des_ede_cbc_cipher is in place.
     53      */
     54     if (out == in) {
     55         memmove(out, out + 8, inl - 8);
     56         in -= 8;
     57     }
     58     ctx->hw->cipher(ctx, out, in + 8, inl - 16);
     59     /* Decrypt final block which will be IV */
     60     ctx->hw->cipher(ctx, iv, in + inl - 8, 8);
     61     /* Reverse order of everything */
     62     BUF_reverse(icv, NULL, 8);
     63     BUF_reverse(out, NULL, inl - 16);
     64     BUF_reverse(ctx->iv, iv, 8);
     65     /* Decrypt again using new IV */
     66     ctx->hw->cipher(ctx, out, out, inl - 16);
     67     ctx->hw->cipher(ctx, icv, icv, 8);
     68     if (ossl_sha1(out, inl - 16, sha1tmp) /* Work out hash of first portion */
     69             && CRYPTO_memcmp(sha1tmp, icv, 8) == 0)
     70         rv = inl - 16;
     71     OPENSSL_cleanse(icv, 8);
     72     OPENSSL_cleanse(sha1tmp, SHA_DIGEST_LENGTH);
     73     OPENSSL_cleanse(iv, 8);
     74     OPENSSL_cleanse(ctx->iv, sizeof(ctx->iv));
     75     if (rv == -1)
     76         OPENSSL_cleanse(out, inl - 16);
     77 
     78     return rv;
     79 }
     80 
     81 static int des_ede3_wrap(PROV_CIPHER_CTX *ctx, unsigned char *out,
     82                          const unsigned char *in, size_t inl)
     83 {
     84     unsigned char sha1tmp[SHA_DIGEST_LENGTH];
     85     size_t ivlen = TDES_IVLEN;
     86     size_t icvlen = TDES_IVLEN;
     87     size_t len = inl + ivlen + icvlen;
     88 
     89     if (out == NULL)
     90         return len;
     91 
     92     /* Copy input to output buffer + 8 so we have space for IV */
     93     memmove(out + ivlen, in, inl);
     94     /* Work out ICV */
     95     if (!ossl_sha1(in, inl, sha1tmp))
     96         return 0;
     97     memcpy(out + inl + ivlen, sha1tmp, icvlen);
     98     OPENSSL_cleanse(sha1tmp, SHA_DIGEST_LENGTH);
     99     /* Generate random IV */
    100     if (RAND_bytes_ex(ctx->libctx, ctx->iv, ivlen, 0) <= 0)
    101         return 0;
    102     memcpy(out, ctx->iv, ivlen);
    103     /* Encrypt everything after IV in place */
    104     ctx->hw->cipher(ctx, out + ivlen, out + ivlen, inl + ivlen);
    105     BUF_reverse(out, NULL, len);
    106     memcpy(ctx->iv, wrap_iv, ivlen);
    107     ctx->hw->cipher(ctx, out, out, len);
    108     return len;
    109 }
    110 
    111 static int tdes_wrap_cipher_internal(PROV_CIPHER_CTX *ctx, unsigned char *out,
    112                                      const unsigned char *in, size_t inl)
    113 {
    114     /*
    115      * Sanity check input length: we typically only wrap keys so EVP_MAXCHUNK
    116      * is more than will ever be needed. Also input length must be a multiple
    117      * of 8 bits.
    118      */
    119     if (inl >= EVP_MAXCHUNK || inl % 8)
    120         return -1;
    121     if (ctx->enc)
    122         return des_ede3_wrap(ctx, out, in, inl);
    123     else
    124         return des_ede3_unwrap(ctx, out, in, inl);
    125 }
    126 
    127 static int tdes_wrap_cipher(void *vctx,
    128                             unsigned char *out, size_t *outl, size_t outsize,
    129                             const unsigned char *in, size_t inl)
    130 {
    131     PROV_CIPHER_CTX *ctx = (PROV_CIPHER_CTX *)vctx;
    132     int ret;
    133 
    134     *outl = 0;
    135     if (!ossl_prov_is_running())
    136         return 0;
    137 
    138     if (outsize < inl) {
    139         ERR_raise(ERR_LIB_PROV, PROV_R_OUTPUT_BUFFER_TOO_SMALL);
    140         return 0;
    141     }
    142 
    143     ret = tdes_wrap_cipher_internal(ctx, out, in, inl);
    144     if (ret <= 0)
    145         return 0;
    146 
    147     *outl = ret;
    148     return 1;
    149 }
    150 
    151 static int tdes_wrap_update(void *vctx, unsigned char *out, size_t *outl,
    152                             size_t outsize, const unsigned char *in,
    153                             size_t inl)
    154 {
    155     *outl = 0;
    156     if (inl == 0)
    157         return 1;
    158     if (outsize < inl) {
    159         ERR_raise(ERR_LIB_PROV, PROV_R_OUTPUT_BUFFER_TOO_SMALL);
    160         return 0;
    161     }
    162 
    163     if (!tdes_wrap_cipher(vctx, out, outl, outsize, in, inl)) {
    164         ERR_raise(ERR_LIB_PROV, PROV_R_CIPHER_OPERATION_FAILED);
    165         return 0;
    166     }
    167     return 1;
    168 }
    169 
    170 
    171 # define IMPLEMENT_WRAP_CIPHER(flags, kbits, blkbits, ivbits)                  \
    172 static OSSL_FUNC_cipher_newctx_fn tdes_wrap_newctx;                            \
    173 static void *tdes_wrap_newctx(void *provctx)                                   \
    174 {                                                                              \
    175     return ossl_tdes_newctx(provctx, EVP_CIPH_WRAP_MODE, kbits, blkbits,       \
    176                             ivbits, flags,                                     \
    177                             ossl_prov_cipher_hw_tdes_wrap_cbc());              \
    178 }                                                                              \
    179 static OSSL_FUNC_cipher_get_params_fn tdes_wrap_get_params;                    \
    180 static int tdes_wrap_get_params(OSSL_PARAM params[])                           \
    181 {                                                                              \
    182     return ossl_cipher_generic_get_params(params, EVP_CIPH_WRAP_MODE, flags,   \
    183                                           kbits, blkbits, ivbits);             \
    184 }                                                                              \
    185 const OSSL_DISPATCH ossl_tdes_wrap_cbc_functions[] =                           \
    186 {                                                                              \
    187     { OSSL_FUNC_CIPHER_ENCRYPT_INIT, (void (*)(void)) ossl_tdes_einit },       \
    188     { OSSL_FUNC_CIPHER_DECRYPT_INIT, (void (*)(void)) ossl_tdes_dinit },       \
    189     { OSSL_FUNC_CIPHER_CIPHER, (void (*)(void))tdes_wrap_cipher },             \
    190     { OSSL_FUNC_CIPHER_NEWCTX, (void (*)(void))tdes_wrap_newctx },             \
    191     { OSSL_FUNC_CIPHER_FREECTX, (void (*)(void))ossl_tdes_freectx },           \
    192     { OSSL_FUNC_CIPHER_UPDATE, (void (*)(void))tdes_wrap_update },             \
    193     { OSSL_FUNC_CIPHER_FINAL,                                                  \
    194       (void (*)(void))ossl_cipher_generic_stream_final },                      \
    195     { OSSL_FUNC_CIPHER_GET_PARAMS, (void (*)(void))tdes_wrap_get_params },     \
    196     { OSSL_FUNC_CIPHER_GETTABLE_PARAMS,                                        \
    197       (void (*)(void))ossl_cipher_generic_gettable_params },                   \
    198     { OSSL_FUNC_CIPHER_GET_CTX_PARAMS,                                         \
    199       (void (*)(void))ossl_tdes_get_ctx_params },                              \
    200     { OSSL_FUNC_CIPHER_GETTABLE_CTX_PARAMS,                                    \
    201       (void (*)(void))ossl_tdes_gettable_ctx_params },                         \
    202     { OSSL_FUNC_CIPHER_SET_CTX_PARAMS,                                         \
    203       (void (*)(void))ossl_cipher_generic_set_ctx_params },                    \
    204     { OSSL_FUNC_CIPHER_SETTABLE_CTX_PARAMS,                                    \
    205       (void (*)(void))ossl_cipher_generic_settable_ctx_params },               \
    206     { 0, NULL }                                                                \
    207 }
    208 
    209 /* ossl_tdes_wrap_cbc_functions */
    210 IMPLEMENT_WRAP_CIPHER(TDES_WRAP_FLAGS, 64*3, 64, 0);
    211