| /* |
| * Copyright 1995-2021 The OpenSSL Project Authors. All Rights Reserved. |
| * |
| * Licensed under the Apache License 2.0 (the "License"). You may not use |
| * this file except in compliance with the License. You can obtain a copy |
| * in the file LICENSE in the source distribution or at |
| * https://www.openssl.org/source/license.html |
| */ |
| |
| /* |
| * DES low level APIs are deprecated for public use, but still ok for internal |
| * use. |
| */ |
| #include "internal/deprecated.h" |
| |
| #include "prov/ciphercommon.h" |
| #include "cipher_des.h" |
| |
| static int cipher_hw_des_initkey(PROV_CIPHER_CTX *ctx, |
| const unsigned char *key, size_t keylen) |
| { |
| PROV_DES_CTX *dctx = (PROV_DES_CTX *)ctx; |
| DES_cblock *deskey = (DES_cblock *)key; |
| DES_key_schedule *ks = &dctx->dks.ks; |
| |
| dctx->dstream.cbc = NULL; |
| #if defined(SPARC_DES_CAPABLE) |
| if (SPARC_DES_CAPABLE) { |
| if (ctx->mode == EVP_CIPH_CBC_MODE) { |
| des_t4_key_expand(&deskey[0], ks); |
| dctx->dstream.cbc = ctx->enc ? des_t4_cbc_encrypt : |
| des_t4_cbc_decrypt; |
| return 1; |
| } |
| } |
| #endif |
| DES_set_key_unchecked(deskey, ks); |
| return 1; |
| } |
| |
| static void cipher_hw_des_copyctx(PROV_CIPHER_CTX *dst, |
| const PROV_CIPHER_CTX *src) |
| { |
| PROV_DES_CTX *sctx = (PROV_DES_CTX *)src; |
| PROV_DES_CTX *dctx = (PROV_DES_CTX *)dst; |
| |
| *dctx = *sctx; |
| dst->ks = &dctx->dks.ks; |
| } |
| |
| static int cipher_hw_des_ecb_cipher(PROV_CIPHER_CTX *ctx, unsigned char *out, |
| const unsigned char *in, size_t len) |
| { |
| size_t i, bl = ctx->blocksize; |
| DES_key_schedule *key = &(((PROV_DES_CTX *)ctx)->dks.ks); |
| |
| if (len < bl) |
| return 1; |
| for (i = 0, len -= bl; i <= len; i += bl) |
| DES_ecb_encrypt((const_DES_cblock *)(in + i), |
| (const_DES_cblock *)(out + i), key, ctx->enc); |
| return 1; |
| } |
| |
| static int cipher_hw_des_cbc_cipher(PROV_CIPHER_CTX *ctx, unsigned char *out, |
| const unsigned char *in, size_t len) |
| { |
| PROV_DES_CTX *dctx = (PROV_DES_CTX *)ctx; |
| DES_key_schedule *key = &(dctx->dks.ks); |
| |
| if (dctx->dstream.cbc != NULL) { |
| (*dctx->dstream.cbc) (in, out, len, key, ctx->iv); |
| return 1; |
| } |
| |
| while (len >= MAXCHUNK) { |
| DES_ncbc_encrypt(in, out, MAXCHUNK, key, (DES_cblock *)ctx->iv, |
| ctx->enc); |
| len -= MAXCHUNK; |
| in += MAXCHUNK; |
| out += MAXCHUNK; |
| } |
| if (len > 0) |
| DES_ncbc_encrypt(in, out, (long)len, key, (DES_cblock *)ctx->iv, |
| ctx->enc); |
| return 1; |
| } |
| |
| static int cipher_hw_des_ofb64_cipher(PROV_CIPHER_CTX *ctx, unsigned char *out, |
| const unsigned char *in, size_t len) |
| { |
| int num = ctx->num; |
| DES_key_schedule *key = &(((PROV_DES_CTX *)ctx)->dks.ks); |
| |
| while (len >= MAXCHUNK) { |
| DES_ofb64_encrypt(in, out, MAXCHUNK, key, (DES_cblock *)ctx->iv, &num); |
| len -= MAXCHUNK; |
| in += MAXCHUNK; |
| out += MAXCHUNK; |
| } |
| if (len > 0) { |
| DES_ofb64_encrypt(in, out, (long)len, key, (DES_cblock *)ctx->iv, &num); |
| } |
| ctx->num = num; |
| return 1; |
| } |
| |
| static int cipher_hw_des_cfb64_cipher(PROV_CIPHER_CTX *ctx, unsigned char *out, |
| const unsigned char *in, size_t len) |
| { |
| size_t chunk = MAXCHUNK; |
| DES_key_schedule *key = &(((PROV_DES_CTX *)ctx)->dks.ks); |
| int num = ctx->num; |
| |
| if (len < chunk) |
| chunk = len; |
| while (len > 0 && len >= chunk) { |
| DES_cfb64_encrypt(in, out, (long)chunk, key, (DES_cblock *)ctx->iv, |
| &num, ctx->enc); |
| len -= chunk; |
| in += chunk; |
| out += chunk; |
| if (len < chunk) |
| chunk = len; |
| } |
| ctx->num = num; |
| return 1; |
| } |
| |
| /* |
| * Although we have a CFB-r implementation for DES, it doesn't pack the right |
| * way, so wrap it here |
| */ |
| static int cipher_hw_des_cfb1_cipher(PROV_CIPHER_CTX *ctx, unsigned char *out, |
| const unsigned char *in, size_t inl) |
| { |
| size_t n, chunk = MAXCHUNK / 8; |
| DES_key_schedule *key = &(((PROV_DES_CTX *)ctx)->dks.ks); |
| unsigned char c[1], d[1]; |
| |
| if (inl < chunk) |
| chunk = inl; |
| |
| while (inl && inl >= chunk) { |
| for (n = 0; n < chunk * 8; ++n) { |
| c[0] = (in[n / 8] & (1 << (7 - n % 8))) ? 0x80 : 0; |
| DES_cfb_encrypt(c, d, 1, 1, key, (DES_cblock *)ctx->iv, ctx->enc); |
| out[n / 8] = |
| (out[n / 8] & ~(0x80 >> (unsigned int)(n % 8))) | |
| ((d[0] & 0x80) >> (unsigned int)(n % 8)); |
| } |
| inl -= chunk; |
| in += chunk; |
| out += chunk; |
| if (inl < chunk) |
| chunk = inl; |
| } |
| |
| return 1; |
| } |
| |
| static int cipher_hw_des_cfb8_cipher(PROV_CIPHER_CTX *ctx, unsigned char *out, |
| const unsigned char *in, size_t inl) |
| { |
| DES_key_schedule *key = &(((PROV_DES_CTX *)ctx)->dks.ks); |
| |
| while (inl >= MAXCHUNK) { |
| DES_cfb_encrypt(in, out, 8, (long)MAXCHUNK, key, |
| (DES_cblock *)ctx->iv, ctx->enc); |
| inl -= MAXCHUNK; |
| in += MAXCHUNK; |
| out += MAXCHUNK; |
| } |
| if (inl > 0) |
| DES_cfb_encrypt(in, out, 8, (long)inl, key, |
| (DES_cblock *)ctx->iv, ctx->enc); |
| return 1; |
| } |
| |
| #define PROV_CIPHER_HW_des_mode(mode) \ |
| static const PROV_CIPHER_HW des_##mode = { \ |
| cipher_hw_des_initkey, \ |
| cipher_hw_des_##mode##_cipher, \ |
| cipher_hw_des_copyctx \ |
| }; \ |
| const PROV_CIPHER_HW *ossl_prov_cipher_hw_des_##mode(void) \ |
| { \ |
| return &des_##mode; \ |
| } |
| |
| PROV_CIPHER_HW_des_mode(ecb) |
| PROV_CIPHER_HW_des_mode(cbc) |
| PROV_CIPHER_HW_des_mode(ofb64) |
| PROV_CIPHER_HW_des_mode(cfb64) |
| PROV_CIPHER_HW_des_mode(cfb1) |
| PROV_CIPHER_HW_des_mode(cfb8) |