Latest update.

This commit is contained in:
2020-01-17 19:45:12 +09:00
parent 016df9f433
commit 0f7abb4eb6
1100 changed files with 47785 additions and 16292 deletions
@@ -0,0 +1,4 @@
LIBS=../../../libcrypto
SOURCE[../../../libcrypto]=rsa_enc.c
@@ -0,0 +1,459 @@
/*
* Copyright 2019 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
*/
#include <openssl/crypto.h>
#include <openssl/evp.h>
#include <openssl/core_numbers.h>
#include <openssl/core_names.h>
#include <openssl/rsa.h>
#include <openssl/params.h>
#include <openssl/err.h>
/* Just for SSL_MAX_MASTER_KEY_LENGTH */
#include <openssl/ssl.h>
#include "internal/constant_time.h"
#include "crypto/rsa.h"
#include "prov/providercommonerr.h"
#include "prov/provider_ctx.h"
#include "prov/implementations.h"
#include <stdlib.h>
static OSSL_OP_asym_cipher_newctx_fn rsa_newctx;
static OSSL_OP_asym_cipher_encrypt_init_fn rsa_init;
static OSSL_OP_asym_cipher_encrypt_fn rsa_encrypt;
static OSSL_OP_asym_cipher_decrypt_init_fn rsa_init;
static OSSL_OP_asym_cipher_decrypt_fn rsa_decrypt;
static OSSL_OP_asym_cipher_freectx_fn rsa_freectx;
static OSSL_OP_asym_cipher_dupctx_fn rsa_dupctx;
static OSSL_OP_asym_cipher_get_ctx_params_fn rsa_get_ctx_params;
static OSSL_OP_asym_cipher_gettable_ctx_params_fn rsa_gettable_ctx_params;
static OSSL_OP_asym_cipher_set_ctx_params_fn rsa_set_ctx_params;
static OSSL_OP_asym_cipher_settable_ctx_params_fn rsa_settable_ctx_params;
/*
* What's passed as an actual key is defined by the KEYMGMT interface.
* We happen to know that our KEYMGMT simply passes RSA structures, so
* we use that here too.
*/
typedef struct {
OPENSSL_CTX *libctx;
RSA *rsa;
int pad_mode;
/* OAEP message digest */
EVP_MD *oaep_md;
/* message digest for MGF1 */
EVP_MD *mgf1_md;
/* OAEP label */
unsigned char *oaep_label;
size_t oaep_labellen;
/* TLS padding */
unsigned int client_version;
unsigned int alt_version;
} PROV_RSA_CTX;
static void *rsa_newctx(void *provctx)
{
PROV_RSA_CTX *prsactx = OPENSSL_zalloc(sizeof(PROV_RSA_CTX));
if (prsactx == NULL)
return NULL;
prsactx->libctx = PROV_LIBRARY_CONTEXT_OF(provctx);
return prsactx;
}
static int rsa_init(void *vprsactx, void *vrsa)
{
PROV_RSA_CTX *prsactx = (PROV_RSA_CTX *)vprsactx;
if (prsactx == NULL || vrsa == NULL || !RSA_up_ref(vrsa))
return 0;
RSA_free(prsactx->rsa);
prsactx->rsa = vrsa;
prsactx->pad_mode = RSA_PKCS1_PADDING;
return 1;
}
static int rsa_encrypt(void *vprsactx, unsigned char *out, size_t *outlen,
size_t outsize, const unsigned char *in, size_t inlen)
{
PROV_RSA_CTX *prsactx = (PROV_RSA_CTX *)vprsactx;
int ret;
if (out == NULL) {
size_t len = RSA_size(prsactx->rsa);
if (len == 0) {
ERR_raise(ERR_LIB_PROV, PROV_R_INVALID_KEY);
return 0;
}
*outlen = len;
return 1;
}
if (prsactx->pad_mode == RSA_PKCS1_OAEP_PADDING) {
int rsasize = RSA_size(prsactx->rsa);
unsigned char *tbuf;
if ((tbuf = OPENSSL_malloc(rsasize)) == NULL) {
PROVerr(0, ERR_R_MALLOC_FAILURE);
return 0;
}
ret = RSA_padding_add_PKCS1_OAEP_mgf1(tbuf, rsasize, in, inlen,
prsactx->oaep_label,
prsactx->oaep_labellen,
prsactx->oaep_md,
prsactx->mgf1_md);
if (!ret) {
OPENSSL_free(tbuf);
return 0;
}
ret = RSA_public_encrypt(rsasize, tbuf, out, prsactx->rsa,
RSA_NO_PADDING);
OPENSSL_free(tbuf);
} else {
ret = RSA_public_encrypt(inlen, in, out, prsactx->rsa,
prsactx->pad_mode);
}
/* A ret value of 0 is not an error */
if (ret < 0)
return ret;
*outlen = ret;
return 1;
}
static int rsa_decrypt(void *vprsactx, unsigned char *out, size_t *outlen,
size_t outsize, const unsigned char *in, size_t inlen)
{
PROV_RSA_CTX *prsactx = (PROV_RSA_CTX *)vprsactx;
int ret;
size_t len = RSA_size(prsactx->rsa);
if (prsactx->pad_mode == RSA_PKCS1_WITH_TLS_PADDING) {
if (out == NULL) {
*outlen = SSL_MAX_MASTER_KEY_LENGTH;
return 1;
}
if (outsize < SSL_MAX_MASTER_KEY_LENGTH) {
ERR_raise(ERR_LIB_PROV, PROV_R_BAD_LENGTH);
return 0;
}
} else {
if (out == NULL) {
if (len == 0) {
ERR_raise(ERR_LIB_PROV, PROV_R_INVALID_KEY);
return 0;
}
*outlen = len;
return 1;
}
if (outsize < len) {
ERR_raise(ERR_LIB_PROV, PROV_R_BAD_LENGTH);
return 0;
}
}
if (prsactx->pad_mode == RSA_PKCS1_OAEP_PADDING
|| prsactx->pad_mode == RSA_PKCS1_WITH_TLS_PADDING) {
unsigned char *tbuf;
if ((tbuf = OPENSSL_malloc(len)) == NULL) {
PROVerr(0, ERR_R_MALLOC_FAILURE);
return 0;
}
ret = RSA_private_decrypt(inlen, in, tbuf, prsactx->rsa,
RSA_NO_PADDING);
/*
* With no padding then, on success ret should be len, otherwise an
* error occurred (non-constant time)
*/
if (ret != (int)len) {
OPENSSL_free(tbuf);
ERR_raise(ERR_LIB_PROV, PROV_R_FAILED_TO_DECRYPT);
return 0;
}
if (prsactx->pad_mode == RSA_PKCS1_OAEP_PADDING) {
ret = RSA_padding_check_PKCS1_OAEP_mgf1(out, outsize, tbuf,
len, len,
prsactx->oaep_label,
prsactx->oaep_labellen,
prsactx->oaep_md,
prsactx->mgf1_md);
} else {
/* RSA_PKCS1_WITH_TLS_PADDING */
if (prsactx->client_version <= 0) {
ERR_raise(ERR_LIB_PROV, PROV_R_BAD_TLS_CLIENT_VERSION);
return 0;
}
ret = rsa_padding_check_PKCS1_type_2_TLS(out, outsize,
tbuf, len,
prsactx->client_version,
prsactx->alt_version);
}
OPENSSL_free(tbuf);
} else {
ret = RSA_private_decrypt(inlen, in, out, prsactx->rsa,
prsactx->pad_mode);
}
*outlen = constant_time_select_s(constant_time_msb_s(ret), *outlen, ret);
ret = constant_time_select_int(constant_time_msb(ret), 0, 1);
return ret;
}
static void rsa_freectx(void *vprsactx)
{
PROV_RSA_CTX *prsactx = (PROV_RSA_CTX *)vprsactx;
RSA_free(prsactx->rsa);
EVP_MD_free(prsactx->oaep_md);
EVP_MD_free(prsactx->mgf1_md);
OPENSSL_free(prsactx);
}
static void *rsa_dupctx(void *vprsactx)
{
PROV_RSA_CTX *srcctx = (PROV_RSA_CTX *)vprsactx;
PROV_RSA_CTX *dstctx;
dstctx = OPENSSL_zalloc(sizeof(*srcctx));
if (dstctx == NULL)
return NULL;
*dstctx = *srcctx;
if (dstctx->rsa != NULL && !RSA_up_ref(dstctx->rsa)) {
OPENSSL_free(dstctx);
return NULL;
}
if (dstctx->oaep_md != NULL && !EVP_MD_up_ref(dstctx->oaep_md)) {
RSA_free(dstctx->rsa);
OPENSSL_free(dstctx);
return NULL;
}
if (dstctx->mgf1_md != NULL && !EVP_MD_up_ref(dstctx->mgf1_md)) {
RSA_free(dstctx->rsa);
EVP_MD_free(dstctx->oaep_md);
OPENSSL_free(dstctx);
return NULL;
}
return dstctx;
}
static int rsa_get_ctx_params(void *vprsactx, OSSL_PARAM *params)
{
PROV_RSA_CTX *prsactx = (PROV_RSA_CTX *)vprsactx;
OSSL_PARAM *p;
if (prsactx == NULL || params == NULL)
return 0;
p = OSSL_PARAM_locate(params, OSSL_ASYM_CIPHER_PARAM_PAD_MODE);
if (p != NULL && !OSSL_PARAM_set_int(p, prsactx->pad_mode))
return 0;
p = OSSL_PARAM_locate(params, OSSL_ASYM_CIPHER_PARAM_OAEP_DIGEST);
if (p != NULL && !OSSL_PARAM_set_utf8_string(p, prsactx->oaep_md == NULL
? ""
: EVP_MD_name(prsactx->oaep_md)))
return 0;
p = OSSL_PARAM_locate(params, OSSL_ASYM_CIPHER_PARAM_MGF1_DIGEST);
if (p != NULL) {
EVP_MD *mgf1_md = prsactx->mgf1_md == NULL ? prsactx->oaep_md
: prsactx->mgf1_md;
if (!OSSL_PARAM_set_utf8_string(p, mgf1_md == NULL
? ""
: EVP_MD_name(mgf1_md)))
return 0;
}
p = OSSL_PARAM_locate(params, OSSL_ASYM_CIPHER_PARAM_OAEP_LABEL);
if (p != NULL && !OSSL_PARAM_set_octet_ptr(p, prsactx->oaep_label, 0))
return 0;
p = OSSL_PARAM_locate(params, OSSL_ASYM_CIPHER_PARAM_OAEP_LABEL_LEN);
if (p != NULL && !OSSL_PARAM_set_size_t(p, prsactx->oaep_labellen))
return 0;
p = OSSL_PARAM_locate(params, OSSL_ASYM_CIPHER_PARAM_TLS_CLIENT_VERSION);
if (p != NULL && !OSSL_PARAM_set_uint(p, prsactx->client_version))
return 0;
p = OSSL_PARAM_locate(params, OSSL_ASYM_CIPHER_PARAM_TLS_NEGOTIATED_VERSION);
if (p != NULL && !OSSL_PARAM_set_uint(p, prsactx->alt_version))
return 0;
return 1;
}
static const OSSL_PARAM known_gettable_ctx_params[] = {
OSSL_PARAM_utf8_string(OSSL_ASYM_CIPHER_PARAM_OAEP_DIGEST, NULL, 0),
OSSL_PARAM_int(OSSL_ASYM_CIPHER_PARAM_PAD_MODE, NULL),
OSSL_PARAM_utf8_string(OSSL_ASYM_CIPHER_PARAM_MGF1_DIGEST, NULL, 0),
OSSL_PARAM_DEFN(OSSL_ASYM_CIPHER_PARAM_OAEP_LABEL, OSSL_PARAM_OCTET_PTR,
NULL, 0),
OSSL_PARAM_size_t(OSSL_ASYM_CIPHER_PARAM_OAEP_LABEL_LEN, NULL),
OSSL_PARAM_uint(OSSL_ASYM_CIPHER_PARAM_TLS_CLIENT_VERSION, NULL),
OSSL_PARAM_uint(OSSL_ASYM_CIPHER_PARAM_TLS_NEGOTIATED_VERSION, NULL),
OSSL_PARAM_END
};
static const OSSL_PARAM *rsa_gettable_ctx_params(void)
{
return known_gettable_ctx_params;
}
static int rsa_set_ctx_params(void *vprsactx, const OSSL_PARAM params[])
{
PROV_RSA_CTX *prsactx = (PROV_RSA_CTX *)vprsactx;
const OSSL_PARAM *p;
/* Should be big enough */
char mdname[80], mdprops[80] = { '\0' };
char *str = mdname;
int pad_mode;
if (prsactx == NULL || params == NULL)
return 0;
p = OSSL_PARAM_locate_const(params, OSSL_ASYM_CIPHER_PARAM_OAEP_DIGEST);
if (p != NULL) {
if (!OSSL_PARAM_get_utf8_string(p, &str, sizeof(mdname)))
return 0;
str = mdprops;
p = OSSL_PARAM_locate_const(params,
OSSL_ASYM_CIPHER_PARAM_OAEP_DIGEST_PROPS);
if (p != NULL) {
if (!OSSL_PARAM_get_utf8_string(p, &str, sizeof(mdprops)))
return 0;
}
EVP_MD_free(prsactx->oaep_md);
prsactx->oaep_md = EVP_MD_fetch(prsactx->libctx, mdname, mdprops);
if (prsactx->oaep_md == NULL)
return 0;
}
p = OSSL_PARAM_locate_const(params, OSSL_ASYM_CIPHER_PARAM_PAD_MODE);
if (p != NULL) {
if (!OSSL_PARAM_get_int(p, &pad_mode))
return 0;
/*
* PSS padding is for signatures only so is not compatible with
* asymmetric cipher use.
*/
if (pad_mode == RSA_PKCS1_PSS_PADDING)
return 0;
if (pad_mode == RSA_PKCS1_OAEP_PADDING && prsactx->oaep_md == NULL) {
prsactx->oaep_md = EVP_MD_fetch(prsactx->libctx, "SHA1", mdprops);
if (prsactx->oaep_md == NULL)
return 0;
}
prsactx->pad_mode = pad_mode;
}
p = OSSL_PARAM_locate_const(params, OSSL_ASYM_CIPHER_PARAM_MGF1_DIGEST);
if (p != NULL) {
if (!OSSL_PARAM_get_utf8_string(p, &str, sizeof(mdname)))
return 0;
str = mdprops;
p = OSSL_PARAM_locate_const(params,
OSSL_ASYM_CIPHER_PARAM_MGF1_DIGEST_PROPS);
if (p != NULL) {
if (!OSSL_PARAM_get_utf8_string(p, &str, sizeof(mdprops)))
return 0;
} else {
str = NULL;
}
EVP_MD_free(prsactx->mgf1_md);
prsactx->mgf1_md = EVP_MD_fetch(prsactx->libctx, mdname, str);
if (prsactx->mgf1_md == NULL)
return 0;
}
p = OSSL_PARAM_locate_const(params, OSSL_ASYM_CIPHER_PARAM_OAEP_LABEL);
if (p != NULL) {
void *tmp_label = NULL;
size_t tmp_labellen;
if (!OSSL_PARAM_get_octet_string(p, &tmp_label, 0, &tmp_labellen))
return 0;
OPENSSL_free(prsactx->oaep_label);
prsactx->oaep_label = (unsigned char *)tmp_label;
prsactx->oaep_labellen = tmp_labellen;
}
p = OSSL_PARAM_locate_const(params, OSSL_ASYM_CIPHER_PARAM_TLS_CLIENT_VERSION);
if (p != NULL) {
unsigned int client_version;
if (!OSSL_PARAM_get_uint(p, &client_version))
return 0;
prsactx->client_version = client_version;
}
p = OSSL_PARAM_locate_const(params, OSSL_ASYM_CIPHER_PARAM_TLS_NEGOTIATED_VERSION);
if (p != NULL) {
unsigned int alt_version;
if (!OSSL_PARAM_get_uint(p, &alt_version))
return 0;
prsactx->alt_version = alt_version;
}
return 1;
}
static const OSSL_PARAM known_settable_ctx_params[] = {
OSSL_PARAM_utf8_string(OSSL_ASYM_CIPHER_PARAM_OAEP_DIGEST, NULL, 0),
OSSL_PARAM_int(OSSL_ASYM_CIPHER_PARAM_PAD_MODE, NULL),
OSSL_PARAM_utf8_string(OSSL_ASYM_CIPHER_PARAM_MGF1_DIGEST, NULL, 0),
OSSL_PARAM_utf8_string(OSSL_ASYM_CIPHER_PARAM_MGF1_DIGEST_PROPS, NULL, 0),
OSSL_PARAM_octet_string(OSSL_ASYM_CIPHER_PARAM_OAEP_LABEL, NULL, 0),
OSSL_PARAM_uint(OSSL_ASYM_CIPHER_PARAM_TLS_CLIENT_VERSION, NULL),
OSSL_PARAM_uint(OSSL_ASYM_CIPHER_PARAM_TLS_NEGOTIATED_VERSION, NULL),
OSSL_PARAM_END
};
static const OSSL_PARAM *rsa_settable_ctx_params(void)
{
return known_settable_ctx_params;
}
const OSSL_DISPATCH rsa_asym_cipher_functions[] = {
{ OSSL_FUNC_ASYM_CIPHER_NEWCTX, (void (*)(void))rsa_newctx },
{ OSSL_FUNC_ASYM_CIPHER_ENCRYPT_INIT, (void (*)(void))rsa_init },
{ OSSL_FUNC_ASYM_CIPHER_ENCRYPT, (void (*)(void))rsa_encrypt },
{ OSSL_FUNC_ASYM_CIPHER_DECRYPT_INIT, (void (*)(void))rsa_init },
{ OSSL_FUNC_ASYM_CIPHER_DECRYPT, (void (*)(void))rsa_decrypt },
{ OSSL_FUNC_ASYM_CIPHER_FREECTX, (void (*)(void))rsa_freectx },
{ OSSL_FUNC_ASYM_CIPHER_DUPCTX, (void (*)(void))rsa_dupctx },
{ OSSL_FUNC_ASYM_CIPHER_GET_CTX_PARAMS,
(void (*)(void))rsa_get_ctx_params },
{ OSSL_FUNC_ASYM_CIPHER_GETTABLE_CTX_PARAMS,
(void (*)(void))rsa_gettable_ctx_params },
{ OSSL_FUNC_ASYM_CIPHER_SET_CTX_PARAMS,
(void (*)(void))rsa_set_ctx_params },
{ OSSL_FUNC_ASYM_CIPHER_SETTABLE_CTX_PARAMS,
(void (*)(void))rsa_settable_ctx_params },
{ 0, NULL }
};
+2 -1
View File
@@ -1 +1,2 @@
SUBDIRS=digests ciphers macs kdfs exchange keymgmt signature
SUBDIRS=digests ciphers macs kdfs exchange keymgmt signature asymciphers \
serializers
+22 -2
View File
@@ -5,6 +5,8 @@
# The latter may become legacy sooner, so it's comfortable to have two
# variables already now, to switch the non-FIPSable TDES to legacy if needed.
$COMMON_GOAL=../../libcommon.a
$AES_GOAL=../../libimplementations.a
$TDES_1_GOAL=../../libimplementations.a
$TDES_2_GOAL=../../libimplementations.a
@@ -21,6 +23,13 @@ $RC5_GOAL=../../libimplementations.a
$RC2_GOAL=../../libimplementations.a
$CHACHA_GOAL=../../libimplementations.a
$CHACHAPOLY_GOAL=../../libimplementations.a
$SIV_GOAL=../../libimplementations.a
# This source is common building blocks for all ciphers in all our providers.
SOURCE[$COMMON_GOAL]=\
ciphercommon.c ciphercommon_hw.c ciphercommon_block.c \
ciphercommon_gcm.c ciphercommon_gcm_hw.c \
ciphercommon_ccm.c ciphercommon_ccm_hw.c
IF[{- !$disabled{des} -}]
SOURCE[$TDES_1_GOAL]=cipher_tdes.c cipher_tdes_hw.c
@@ -31,12 +40,20 @@ SOURCE[$AES_GOAL]=\
cipher_aes_xts.c cipher_aes_xts_hw.c \
cipher_aes_gcm.c cipher_aes_gcm_hw.c \
cipher_aes_ccm.c cipher_aes_ccm_hw.c \
cipher_aes_wrp.c
cipher_aes_wrp.c \
cipher_aes_cbc_hmac_sha.c \
cipher_aes_cbc_hmac_sha256_hw.c cipher_aes_cbc_hmac_sha1_hw.c
# Extra code to satisfy the FIPS and non-FIPS separation.
# When the AES-xxx-XTS moves to legacy, this can be removed.
SOURCE[../../libfips.a]=cipher_aes_xts_fips.c
SOURCE[../../libnonfips.a]=cipher_aes_xts_fips.c
IF[{- !$disabled{siv} -}]
SOURCE[$SIV_GOAL]=\
cipher_aes_siv.c cipher_aes_siv_hw.c
ENDIF
IF[{- !$disabled{des} -}]
SOURCE[$TDES_2_GOAL]=\
cipher_tdes_default.c cipher_tdes_default_hw.c \
@@ -91,6 +108,10 @@ ENDIF
IF[{- !$disabled{rc4} -}]
SOURCE[$RC4_GOAL]=\
cipher_rc4.c cipher_rc4_hw.c
IF[{- !$disabled{md5} -}]
SOURCE[$RC4_GOAL]=\
cipher_rc4_hmac_md5.c cipher_rc4_hmac_md5_hw.c
ENDIF
ENDIF
IF[{- !$disabled{rc5} -}]
@@ -111,4 +132,3 @@ IF[{- !$disabled{chacha} -}]
cipher_chacha20_poly1305.c cipher_chacha20_poly1305_hw.c
ENDIF
ENDIF
@@ -7,6 +7,13 @@
* https://www.openssl.org/source/license.html
*/
/*
* AES low level APIs are deprecated for public use, but still ok for internal
* use where we're using them to implement the higher level EVP interface, as is
* the case here.
*/
#include "internal/deprecated.h"
/* Dispatch functions for AES cipher modes ecb, cbc, ofb, cfb, ctr */
#include "cipher_aes.h"
@@ -31,7 +38,7 @@ static void *aes_dupctx(void *ctx)
ERR_raise(ERR_LIB_PROV, ERR_R_MALLOC_FAILURE);
return NULL;
}
*ret = *in;
in->base.hw->copyctx(&ret->base, &in->base);
return ret;
}
@@ -9,6 +9,7 @@
#include <openssl/aes.h>
#include "prov/ciphercommon.h"
#include "crypto/aes_platform.h"
typedef struct prov_aes_ctx_st {
PROV_CIPHER_CTX base; /* Must be first */
@@ -59,4 +60,3 @@ const PROV_CIPHER_HW *PROV_CIPHER_HW_aes_cfb128(size_t keybits);
const PROV_CIPHER_HW *PROV_CIPHER_HW_aes_cfb1(size_t keybits);
const PROV_CIPHER_HW *PROV_CIPHER_HW_aes_cfb8(size_t keybits);
const PROV_CIPHER_HW *PROV_CIPHER_HW_aes_ctr(size_t keybits);
@@ -0,0 +1,351 @@
/*
* Copyright 2019 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
*/
/*
* AES low level APIs are deprecated for public use, but still ok for internal
* use where we're using them to implement the higher level EVP interface, as is
* the case here.
*/
#include "internal/deprecated.h"
/* Dispatch functions for AES_CBC_HMAC_SHA ciphers */
#include "cipher_aes_cbc_hmac_sha.h"
#include "prov/implementations.h"
#ifndef AES_CBC_HMAC_SHA_CAPABLE
# define IMPLEMENT_CIPHER(nm, sub, kbits, blkbits, ivbits, flags) \
const OSSL_DISPATCH nm##kbits##sub##_functions[] = { \
{ 0, NULL } \
};
#else
# include "prov/providercommonerr.h"
/* TODO(3.0) Figure out what flags are required */
# define AES_CBC_HMAC_SHA_FLAGS (EVP_CIPH_CBC_MODE \
| EVP_CIPH_FLAG_DEFAULT_ASN1 \
| EVP_CIPH_FLAG_AEAD_CIPHER \
| EVP_CIPH_FLAG_TLS1_1_MULTIBLOCK)
static OSSL_OP_cipher_freectx_fn aes_cbc_hmac_sha1_freectx;
static OSSL_OP_cipher_freectx_fn aes_cbc_hmac_sha256_freectx;
static OSSL_OP_cipher_get_ctx_params_fn aes_get_ctx_params;
static OSSL_OP_cipher_gettable_ctx_params_fn aes_gettable_ctx_params;
static OSSL_OP_cipher_set_ctx_params_fn aes_set_ctx_params;
static OSSL_OP_cipher_settable_ctx_params_fn aes_settable_ctx_params;
# define aes_gettable_params cipher_generic_gettable_params
# define aes_einit cipher_generic_einit
# define aes_dinit cipher_generic_dinit
# define aes_update cipher_generic_stream_update
# define aes_final cipher_generic_stream_final
# define aes_cipher cipher_generic_cipher
static const OSSL_PARAM cipher_aes_known_settable_ctx_params[] = {
OSSL_PARAM_octet_string(OSSL_CIPHER_PARAM_AEAD_MAC_KEY, NULL, 0),
OSSL_PARAM_octet_string(OSSL_CIPHER_PARAM_AEAD_TLS1_AAD, NULL, 0),
# if !defined(OPENSSL_NO_MULTIBLOCK)
OSSL_PARAM_size_t(OSSL_CIPHER_PARAM_TLS1_MULTIBLOCK_MAX_SEND_FRAGMENT, NULL),
OSSL_PARAM_size_t(OSSL_CIPHER_PARAM_TLS1_MULTIBLOCK_AAD, NULL),
OSSL_PARAM_uint(OSSL_CIPHER_PARAM_TLS1_MULTIBLOCK_INTERLEAVE, NULL),
OSSL_PARAM_octet_string(OSSL_CIPHER_PARAM_TLS1_MULTIBLOCK_ENC, NULL, 0),
OSSL_PARAM_octet_string(OSSL_CIPHER_PARAM_TLS1_MULTIBLOCK_ENC_IN, NULL, 0),
# endif /* !defined(OPENSSL_NO_MULTIBLOCK) */
OSSL_PARAM_size_t(OSSL_CIPHER_PARAM_KEYLEN, NULL),
OSSL_PARAM_END
};
const OSSL_PARAM *aes_settable_ctx_params(void)
{
return cipher_aes_known_settable_ctx_params;
}
static int aes_set_ctx_params(void *vctx, const OSSL_PARAM params[])
{
PROV_AES_HMAC_SHA_CTX *ctx = (PROV_AES_HMAC_SHA_CTX *)vctx;
PROV_CIPHER_HW_AES_HMAC_SHA *hw =
(PROV_CIPHER_HW_AES_HMAC_SHA *)ctx->hw;
EVP_CTRL_TLS1_1_MULTIBLOCK_PARAM mb_param;
const OSSL_PARAM *p, *p1, *pin;
int ret = 1;
p = OSSL_PARAM_locate_const(params, OSSL_CIPHER_PARAM_AEAD_MAC_KEY);
if (p != NULL) {
if (p->data_type != OSSL_PARAM_OCTET_STRING) {
ERR_raise(ERR_LIB_PROV, PROV_R_FAILED_TO_GET_PARAMETER);
return 0;
}
hw->init_mac_key(ctx, p->data, p->data_size);
}
# if !defined(OPENSSL_NO_MULTIBLOCK)
p = OSSL_PARAM_locate_const(params,
OSSL_CIPHER_PARAM_TLS1_MULTIBLOCK_MAX_SEND_FRAGMENT);
if (p != NULL
&& !OSSL_PARAM_get_size_t(p, &ctx->multiblock_max_send_fragment)) {
ERR_raise(ERR_LIB_PROV, PROV_R_FAILED_TO_GET_PARAMETER);
return 0;
}
/*
* The inputs to tls1_multiblock_aad are:
* mb_param->inp
* mb_param->len
* mb_param->interleave
* The outputs of tls1_multiblock_aad are written to:
* ctx->multiblock_interleave
* ctx->multiblock_aad_packlen
*/
p = OSSL_PARAM_locate_const(params, OSSL_CIPHER_PARAM_TLS1_MULTIBLOCK_AAD);
if (p != NULL) {
p1 = OSSL_PARAM_locate_const(params,
OSSL_CIPHER_PARAM_TLS1_MULTIBLOCK_INTERLEAVE);
if (p->data_type != OSSL_PARAM_OCTET_STRING
|| p1 == NULL
|| !OSSL_PARAM_get_uint(p1, &mb_param.interleave)) {
ERR_raise(ERR_LIB_PROV, PROV_R_FAILED_TO_GET_PARAMETER);
return 0;
}
mb_param.inp = p->data;
mb_param.len = p->data_size;
if (hw->tls1_multiblock_aad(vctx, &mb_param) <= 0)
return 0;
}
/*
* The inputs to tls1_multiblock_encrypt are:
* mb_param->inp
* mb_param->len
* mb_param->interleave
* mb_param->out
* The outputs of tls1_multiblock_encrypt are:
* ctx->multiblock_encrypt_len
*/
p = OSSL_PARAM_locate_const(params, OSSL_CIPHER_PARAM_TLS1_MULTIBLOCK_ENC);
if (p != NULL) {
p1 = OSSL_PARAM_locate_const(params,
OSSL_CIPHER_PARAM_TLS1_MULTIBLOCK_INTERLEAVE);
pin = OSSL_PARAM_locate_const(params,
OSSL_CIPHER_PARAM_TLS1_MULTIBLOCK_ENC_IN);
if (p->data_type != OSSL_PARAM_OCTET_STRING
|| pin == NULL
|| pin->data_type != OSSL_PARAM_OCTET_STRING
|| p1 == NULL
|| !OSSL_PARAM_get_uint(p1, &mb_param.interleave)) {
ERR_raise(ERR_LIB_PROV, PROV_R_FAILED_TO_GET_PARAMETER);
return 0;
}
mb_param.out = p->data;
mb_param.inp = pin->data;
mb_param.len = pin->data_size;
if (hw->tls1_multiblock_encrypt(vctx, &mb_param) <= 0)
return 0;
}
# endif /* !defined(OPENSSL_NO_MULTIBLOCK) */
p = OSSL_PARAM_locate_const(params, OSSL_CIPHER_PARAM_AEAD_TLS1_AAD);
if (p != NULL) {
if (p->data_type != OSSL_PARAM_OCTET_STRING) {
ERR_raise(ERR_LIB_PROV, PROV_R_FAILED_TO_GET_PARAMETER);
return 0;
}
if (hw->set_tls1_aad(ctx, p->data, p->data_size) <= 0)
return 0;
}
p = OSSL_PARAM_locate_const(params, OSSL_CIPHER_PARAM_KEYLEN);
if (p != NULL) {
size_t keylen;
if (!OSSL_PARAM_get_size_t(p, &keylen)) {
ERR_raise(ERR_LIB_PROV, PROV_R_FAILED_TO_GET_PARAMETER);
return 0;
}
if (ctx->base.keylen != keylen) {
ERR_raise(ERR_LIB_PROV, PROV_R_INVALID_KEY_LENGTH);
return 0;
}
}
return ret;
}
static int aes_get_ctx_params(void *vctx, OSSL_PARAM params[])
{
PROV_AES_HMAC_SHA_CTX *ctx = (PROV_AES_HMAC_SHA_CTX *)vctx;
PROV_CIPHER_HW_AES_HMAC_SHA *hw =
(PROV_CIPHER_HW_AES_HMAC_SHA *)ctx->hw;
OSSL_PARAM *p;
# if !defined(OPENSSL_NO_MULTIBLOCK)
p = OSSL_PARAM_locate(params, OSSL_CIPHER_PARAM_TLS1_MULTIBLOCK_MAX_BUFSIZE);
if (p != NULL) {
size_t len = hw->tls1_multiblock_max_bufsize(ctx);
if (!OSSL_PARAM_set_size_t(p, len)) {
ERR_raise(ERR_LIB_PROV, PROV_R_FAILED_TO_SET_PARAMETER);
return 0;
}
}
p = OSSL_PARAM_locate(params, OSSL_CIPHER_PARAM_TLS1_MULTIBLOCK_INTERLEAVE);
if (p != NULL && !OSSL_PARAM_set_uint(p, ctx->multiblock_interleave)) {
ERR_raise(ERR_LIB_PROV, PROV_R_FAILED_TO_SET_PARAMETER);
return 0;
}
p = OSSL_PARAM_locate(params, OSSL_CIPHER_PARAM_TLS1_MULTIBLOCK_AAD_PACKLEN);
if (p != NULL && !OSSL_PARAM_set_uint(p, ctx->multiblock_aad_packlen)) {
ERR_raise(ERR_LIB_PROV, PROV_R_FAILED_TO_SET_PARAMETER);
return 0;
}
p = OSSL_PARAM_locate(params, OSSL_CIPHER_PARAM_TLS1_MULTIBLOCK_ENC_LEN);
if (p != NULL && !OSSL_PARAM_set_size_t(p, ctx->multiblock_encrypt_len)) {
ERR_raise(ERR_LIB_PROV, PROV_R_FAILED_TO_SET_PARAMETER);
return 0;
}
# endif /* !defined(OPENSSL_NO_MULTIBLOCK) */
p = OSSL_PARAM_locate(params, OSSL_CIPHER_PARAM_AEAD_TLS1_AAD_PAD);
if (p != NULL && !OSSL_PARAM_set_size_t(p, ctx->tls_aad_pad)) {
ERR_raise(ERR_LIB_PROV, PROV_R_FAILED_TO_SET_PARAMETER);
return 0;
}
p = OSSL_PARAM_locate(params, OSSL_CIPHER_PARAM_KEYLEN);
if (p != NULL && !OSSL_PARAM_set_size_t(p, ctx->base.keylen)) {
ERR_raise(ERR_LIB_PROV, PROV_R_FAILED_TO_SET_PARAMETER);
return 0;
}
p = OSSL_PARAM_locate(params, OSSL_CIPHER_PARAM_IVLEN);
if (p != NULL && !OSSL_PARAM_set_size_t(p, ctx->base.ivlen)) {
ERR_raise(ERR_LIB_PROV, PROV_R_FAILED_TO_SET_PARAMETER);
return 0;
}
p = OSSL_PARAM_locate(params, OSSL_CIPHER_PARAM_IV);
if (p != NULL
&& !OSSL_PARAM_set_octet_string(p, ctx->base.oiv, ctx->base.ivlen)) {
ERR_raise(ERR_LIB_PROV, PROV_R_FAILED_TO_SET_PARAMETER);
return 0;
}
return 1;
}
static const OSSL_PARAM cipher_aes_known_gettable_ctx_params[] = {
# if !defined(OPENSSL_NO_MULTIBLOCK)
OSSL_PARAM_size_t(OSSL_CIPHER_PARAM_TLS1_MULTIBLOCK_MAX_BUFSIZE, NULL),
OSSL_PARAM_uint(OSSL_CIPHER_PARAM_TLS1_MULTIBLOCK_INTERLEAVE, NULL),
OSSL_PARAM_uint(OSSL_CIPHER_PARAM_TLS1_MULTIBLOCK_AAD_PACKLEN, NULL),
OSSL_PARAM_size_t(OSSL_CIPHER_PARAM_TLS1_MULTIBLOCK_ENC_LEN, NULL),
# endif /* !defined(OPENSSL_NO_MULTIBLOCK) */
OSSL_PARAM_size_t(OSSL_CIPHER_PARAM_AEAD_TLS1_AAD_PAD, NULL),
OSSL_PARAM_size_t(OSSL_CIPHER_PARAM_KEYLEN, NULL),
OSSL_PARAM_size_t(OSSL_CIPHER_PARAM_IVLEN, NULL),
OSSL_PARAM_octet_string(OSSL_CIPHER_PARAM_IV, NULL, 0),
OSSL_PARAM_END
};
const OSSL_PARAM *aes_gettable_ctx_params(void)
{
return cipher_aes_known_gettable_ctx_params;
}
static void base_init(void *provctx, PROV_AES_HMAC_SHA_CTX *ctx,
const PROV_CIPHER_HW_AES_HMAC_SHA *meths,
size_t kbits, size_t blkbits, size_t ivbits,
uint64_t flags)
{
cipher_generic_initkey(&ctx->base, kbits, blkbits, ivbits,
EVP_CIPH_CBC_MODE, flags,
&meths->base, provctx);
ctx->hw = (PROV_CIPHER_HW_AES_HMAC_SHA *)ctx->base.hw;
}
static void *aes_cbc_hmac_sha1_newctx(void *provctx, size_t kbits,
size_t blkbits, size_t ivbits,
uint64_t flags)
{
PROV_AES_HMAC_SHA1_CTX *ctx = OPENSSL_zalloc(sizeof(*ctx));
if (ctx != NULL)
base_init(provctx, &ctx->base_ctx,
PROV_CIPHER_HW_aes_cbc_hmac_sha1(), kbits, blkbits,
ivbits, flags);
return ctx;
}
static void aes_cbc_hmac_sha1_freectx(void *vctx)
{
PROV_AES_HMAC_SHA1_CTX *ctx = (PROV_AES_HMAC_SHA1_CTX *)vctx;
if (ctx != NULL)
OPENSSL_clear_free(ctx, sizeof(ctx));
}
static void *aes_cbc_hmac_sha256_newctx(void *provctx, size_t kbits,
size_t blkbits, size_t ivbits,
uint64_t flags)
{
PROV_AES_HMAC_SHA256_CTX *ctx = OPENSSL_zalloc(sizeof(*ctx));
if (ctx != NULL)
base_init(provctx, &ctx->base_ctx,
PROV_CIPHER_HW_aes_cbc_hmac_sha256(), kbits, blkbits,
ivbits, flags);
return ctx;
}
static void aes_cbc_hmac_sha256_freectx(void *vctx)
{
PROV_AES_HMAC_SHA256_CTX *ctx = (PROV_AES_HMAC_SHA256_CTX *)vctx;
if (ctx != NULL)
OPENSSL_clear_free(ctx, sizeof(ctx));
}
# define IMPLEMENT_CIPHER(nm, sub, kbits, blkbits, ivbits, flags) \
static OSSL_OP_cipher_newctx_fn nm##_##kbits##_##sub##_newctx; \
static void *nm##_##kbits##_##sub##_newctx(void *provctx) \
{ \
return nm##_##sub##_newctx(provctx, kbits, blkbits, ivbits, flags); \
} \
static OSSL_OP_cipher_get_params_fn nm##_##kbits##_##sub##_get_params; \
static int nm##_##kbits##_##sub##_get_params(OSSL_PARAM params[]) \
{ \
return cipher_generic_get_params(params, EVP_CIPH_CBC_MODE, \
flags, kbits, blkbits, ivbits); \
} \
const OSSL_DISPATCH nm##kbits##sub##_functions[] = { \
{ OSSL_FUNC_CIPHER_NEWCTX, (void (*)(void))nm##_##kbits##_##sub##_newctx },\
{ OSSL_FUNC_CIPHER_FREECTX, (void (*)(void))nm##_##sub##_freectx }, \
{ OSSL_FUNC_CIPHER_ENCRYPT_INIT, (void (*)(void))nm##_einit }, \
{ OSSL_FUNC_CIPHER_DECRYPT_INIT, (void (*)(void))nm##_dinit }, \
{ OSSL_FUNC_CIPHER_UPDATE, (void (*)(void))nm##_update }, \
{ OSSL_FUNC_CIPHER_FINAL, (void (*)(void))nm##_final }, \
{ OSSL_FUNC_CIPHER_CIPHER, (void (*)(void))nm##_cipher }, \
{ OSSL_FUNC_CIPHER_GET_PARAMS, \
(void (*)(void))nm##_##kbits##_##sub##_get_params }, \
{ OSSL_FUNC_CIPHER_GETTABLE_PARAMS, \
(void (*)(void))nm##_gettable_params }, \
{ OSSL_FUNC_CIPHER_GET_CTX_PARAMS, \
(void (*)(void))nm##_get_ctx_params }, \
{ OSSL_FUNC_CIPHER_GETTABLE_CTX_PARAMS, \
(void (*)(void))nm##_gettable_ctx_params }, \
{ OSSL_FUNC_CIPHER_SET_CTX_PARAMS, \
(void (*)(void))nm##_set_ctx_params }, \
{ OSSL_FUNC_CIPHER_SETTABLE_CTX_PARAMS, \
(void (*)(void))nm##_settable_ctx_params }, \
{ 0, NULL } \
};
#endif /* AES_CBC_HMAC_SHA_CAPABLE */
/* aes128cbc_hmac_sha1_functions */
IMPLEMENT_CIPHER(aes, cbc_hmac_sha1, 128, 128, 128, AES_CBC_HMAC_SHA_FLAGS)
/* aes256cbc_hmac_sha1_functions */
IMPLEMENT_CIPHER(aes, cbc_hmac_sha1, 256, 128, 128, AES_CBC_HMAC_SHA_FLAGS)
/* aes128cbc_hmac_sha256_functions */
IMPLEMENT_CIPHER(aes, cbc_hmac_sha256, 128, 128, 128, AES_CBC_HMAC_SHA_FLAGS)
/* aes256cbc_hmac_sha256_functions */
IMPLEMENT_CIPHER(aes, cbc_hmac_sha256, 256, 128, 128, AES_CBC_HMAC_SHA_FLAGS)
@@ -0,0 +1,65 @@
/*
* Copyright 2019 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
*/
#include "prov/ciphercommon.h"
#include "crypto/aes_platform.h"
int cipher_capable_aes_cbc_hmac_sha1(void);
int cipher_capable_aes_cbc_hmac_sha256(void);
#ifdef AES_CBC_HMAC_SHA_CAPABLE
# include <openssl/aes.h>
# include <openssl/sha.h>
typedef struct prov_cipher_hw_aes_hmac_sha_ctx_st {
PROV_CIPHER_HW base; /* must be first */
void (*init_mac_key)(void *ctx, const unsigned char *inkey, size_t inlen);
int (*set_tls1_aad)(void *ctx, unsigned char *aad_rec, int aad_len);
# if !defined(OPENSSL_NO_MULTIBLOCK)
int (*tls1_multiblock_max_bufsize)(void *ctx);
int (*tls1_multiblock_aad)(
void *vctx, EVP_CTRL_TLS1_1_MULTIBLOCK_PARAM *param);
int (*tls1_multiblock_encrypt)(
void *ctx, EVP_CTRL_TLS1_1_MULTIBLOCK_PARAM *param);
# endif /* OPENSSL_NO_MULTIBLOCK) */
} PROV_CIPHER_HW_AES_HMAC_SHA;
typedef struct prov_aes_hmac_sha_ctx_st {
PROV_CIPHER_CTX base;
AES_KEY ks;
size_t payload_length; /* AAD length in decrypt case */
union {
unsigned int tls_ver;
unsigned char tls_aad[16]; /* 13 used */
} aux;
const PROV_CIPHER_HW_AES_HMAC_SHA *hw;
/* some value that are setup by set methods - that can be retrieved */
unsigned int multiblock_interleave;
unsigned int multiblock_aad_packlen;
size_t multiblock_max_send_fragment;
size_t multiblock_encrypt_len;
size_t tls_aad_pad;
} PROV_AES_HMAC_SHA_CTX;
typedef struct prov_aes_hmac_sha1_ctx_st {
PROV_AES_HMAC_SHA_CTX base_ctx;
SHA_CTX head, tail, md;
} PROV_AES_HMAC_SHA1_CTX;
typedef struct prov_aes_hmac_sha256_ctx_st {
PROV_AES_HMAC_SHA_CTX base_ctx;
SHA256_CTX head, tail, md;
} PROV_AES_HMAC_SHA256_CTX;
# define NO_PAYLOAD_LENGTH ((size_t)-1)
const PROV_CIPHER_HW_AES_HMAC_SHA *PROV_CIPHER_HW_aes_cbc_hmac_sha1(void);
const PROV_CIPHER_HW_AES_HMAC_SHA *PROV_CIPHER_HW_aes_cbc_hmac_sha256(void);
#endif /* AES_CBC_HMAC_SHA_CAPABLE */
@@ -0,0 +1,789 @@
/*
* Copyright 2011-2019 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
*/
/*
* AES low level APIs are deprecated for public use, but still ok for internal
* use where we're using them to implement the higher level EVP interface, as is
* the case here.
*/
#include "internal/deprecated.h"
#include "cipher_aes_cbc_hmac_sha.h"
#ifndef AES_CBC_HMAC_SHA_CAPABLE
int cipher_capable_aes_cbc_hmac_sha1(void)
{
return 0;
}
#else
# include "crypto/rand.h"
# include "crypto/evp.h"
# include "internal/constant_time.h"
void sha1_block_data_order(void *c, const void *p, size_t len);
void aesni_cbc_sha1_enc(const void *inp, void *out, size_t blocks,
const AES_KEY *key, unsigned char iv[16],
SHA_CTX *ctx, const void *in0);
int cipher_capable_aes_cbc_hmac_sha1(void)
{
return AESNI_CBC_HMAC_SHA_CAPABLE;
}
static int aesni_cbc_hmac_sha1_init_key(PROV_CIPHER_CTX *vctx,
const unsigned char *key, size_t keylen)
{
int ret;
PROV_AES_HMAC_SHA_CTX *ctx = (PROV_AES_HMAC_SHA_CTX *)vctx;
PROV_AES_HMAC_SHA1_CTX *sctx = (PROV_AES_HMAC_SHA1_CTX *)vctx;
if (ctx->base.enc)
ret = aesni_set_encrypt_key(key, keylen * 8, &ctx->ks);
else
ret = aesni_set_decrypt_key(key, keylen * 8, &ctx->ks);
SHA1_Init(&sctx->head); /* handy when benchmarking */
sctx->tail = sctx->head;
sctx->md = sctx->head;
ctx->payload_length = NO_PAYLOAD_LENGTH;
return ret < 0 ? 0 : 1;
}
static void sha1_update(SHA_CTX *c, const void *data, size_t len)
{
const unsigned char *ptr = data;
size_t res;
if ((res = c->num)) {
res = SHA_CBLOCK - res;
if (len < res)
res = len;
SHA1_Update(c, ptr, res);
ptr += res;
len -= res;
}
res = len % SHA_CBLOCK;
len -= res;
if (len) {
sha1_block_data_order(c, ptr, len / SHA_CBLOCK);
ptr += len;
c->Nh += len >> 29;
c->Nl += len <<= 3;
if (c->Nl < (unsigned int)len)
c->Nh++;
}
if (res)
SHA1_Update(c, ptr, res);
}
# if !defined(OPENSSL_NO_MULTIBLOCK)
typedef struct {
unsigned int A[8], B[8], C[8], D[8], E[8];
} SHA1_MB_CTX;
typedef struct {
const unsigned char *ptr;
int blocks;
} HASH_DESC;
typedef struct {
const unsigned char *inp;
unsigned char *out;
int blocks;
u64 iv[2];
} CIPH_DESC;
void sha1_multi_block(SHA1_MB_CTX *, const HASH_DESC *, int);
void aesni_multi_cbc_encrypt(CIPH_DESC *, void *, int);
static size_t tls1_multi_block_encrypt(void *vctx,
unsigned char *out,
const unsigned char *inp,
size_t inp_len, int n4x)
{ /* n4x is 1 or 2 */
PROV_AES_HMAC_SHA_CTX *ctx = (PROV_AES_HMAC_SHA_CTX *)vctx;
PROV_AES_HMAC_SHA1_CTX *sctx = (PROV_AES_HMAC_SHA1_CTX *)vctx;
HASH_DESC hash_d[8], edges[8];
CIPH_DESC ciph_d[8];
unsigned char storage[sizeof(SHA1_MB_CTX) + 32];
union {
u64 q[16];
u32 d[32];
u8 c[128];
} blocks[8];
SHA1_MB_CTX *mctx;
unsigned int frag, last, packlen, i;
unsigned int x4 = 4 * n4x, minblocks, processed = 0;
size_t ret = 0;
u8 *IVs;
# if defined(BSWAP8)
u64 seqnum;
# endif
/* ask for IVs in bulk */
if (rand_bytes_ex(ctx->base.libctx, (IVs = blocks[0].c), 16 * x4) <= 0)
return 0;
mctx = (SHA1_MB_CTX *) (storage + 32 - ((size_t)storage % 32)); /* align */
frag = (unsigned int)inp_len >> (1 + n4x);
last = (unsigned int)inp_len + frag - (frag << (1 + n4x));
if (last > frag && ((last + 13 + 9) % 64) < (x4 - 1)) {
frag++;
last -= x4 - 1;
}
packlen = 5 + 16 + ((frag + 20 + 16) & -16);
/* populate descriptors with pointers and IVs */
hash_d[0].ptr = inp;
ciph_d[0].inp = inp;
/* 5+16 is place for header and explicit IV */
ciph_d[0].out = out + 5 + 16;
memcpy(ciph_d[0].out - 16, IVs, 16);
memcpy(ciph_d[0].iv, IVs, 16);
IVs += 16;
for (i = 1; i < x4; i++) {
ciph_d[i].inp = hash_d[i].ptr = hash_d[i - 1].ptr + frag;
ciph_d[i].out = ciph_d[i - 1].out + packlen;
memcpy(ciph_d[i].out - 16, IVs, 16);
memcpy(ciph_d[i].iv, IVs, 16);
IVs += 16;
}
# if defined(BSWAP8)
memcpy(blocks[0].c, sctx->md.data, 8);
seqnum = BSWAP8(blocks[0].q[0]);
# endif
for (i = 0; i < x4; i++) {
unsigned int len = (i == (x4 - 1) ? last : frag);
# if !defined(BSWAP8)
unsigned int carry, j;
# endif
mctx->A[i] = sctx->md.h0;
mctx->B[i] = sctx->md.h1;
mctx->C[i] = sctx->md.h2;
mctx->D[i] = sctx->md.h3;
mctx->E[i] = sctx->md.h4;
/* fix seqnum */
# if defined(BSWAP8)
blocks[i].q[0] = BSWAP8(seqnum + i);
# else
for (carry = i, j = 8; j--;) {
blocks[i].c[j] = ((u8 *)sctx->md.data)[j] + carry;
carry = (blocks[i].c[j] - carry) >> (sizeof(carry) * 8 - 1);
}
# endif
blocks[i].c[8] = ((u8 *)sctx->md.data)[8];
blocks[i].c[9] = ((u8 *)sctx->md.data)[9];
blocks[i].c[10] = ((u8 *)sctx->md.data)[10];
/* fix length */
blocks[i].c[11] = (u8)(len >> 8);
blocks[i].c[12] = (u8)(len);
memcpy(blocks[i].c + 13, hash_d[i].ptr, 64 - 13);
hash_d[i].ptr += 64 - 13;
hash_d[i].blocks = (len - (64 - 13)) / 64;
edges[i].ptr = blocks[i].c;
edges[i].blocks = 1;
}
/* hash 13-byte headers and first 64-13 bytes of inputs */
sha1_multi_block(mctx, edges, n4x);
/* hash bulk inputs */
# define MAXCHUNKSIZE 2048
# if MAXCHUNKSIZE%64
# error "MAXCHUNKSIZE is not divisible by 64"
# elif MAXCHUNKSIZE
/*
* goal is to minimize pressure on L1 cache by moving in shorter steps,
* so that hashed data is still in the cache by the time we encrypt it
*/
minblocks = ((frag <= last ? frag : last) - (64 - 13)) / 64;
if (minblocks > MAXCHUNKSIZE / 64) {
for (i = 0; i < x4; i++) {
edges[i].ptr = hash_d[i].ptr;
edges[i].blocks = MAXCHUNKSIZE / 64;
ciph_d[i].blocks = MAXCHUNKSIZE / 16;
}
do {
sha1_multi_block(mctx, edges, n4x);
aesni_multi_cbc_encrypt(ciph_d, &ctx->ks, n4x);
for (i = 0; i < x4; i++) {
edges[i].ptr = hash_d[i].ptr += MAXCHUNKSIZE;
hash_d[i].blocks -= MAXCHUNKSIZE / 64;
edges[i].blocks = MAXCHUNKSIZE / 64;
ciph_d[i].inp += MAXCHUNKSIZE;
ciph_d[i].out += MAXCHUNKSIZE;
ciph_d[i].blocks = MAXCHUNKSIZE / 16;
memcpy(ciph_d[i].iv, ciph_d[i].out - 16, 16);
}
processed += MAXCHUNKSIZE;
minblocks -= MAXCHUNKSIZE / 64;
} while (minblocks > MAXCHUNKSIZE / 64);
}
# endif
# undef MAXCHUNKSIZE
sha1_multi_block(mctx, hash_d, n4x);
memset(blocks, 0, sizeof(blocks));
for (i = 0; i < x4; i++) {
unsigned int len = (i == (x4 - 1) ? last : frag),
off = hash_d[i].blocks * 64;
const unsigned char *ptr = hash_d[i].ptr + off;
off = (len - processed) - (64 - 13) - off; /* remainder actually */
memcpy(blocks[i].c, ptr, off);
blocks[i].c[off] = 0x80;
len += 64 + 13; /* 64 is HMAC header */
len *= 8; /* convert to bits */
if (off < (64 - 8)) {
# ifdef BSWAP4
blocks[i].d[15] = BSWAP4(len);
# else
PUTU32(blocks[i].c + 60, len);
# endif
edges[i].blocks = 1;
} else {
# ifdef BSWAP4
blocks[i].d[31] = BSWAP4(len);
# else
PUTU32(blocks[i].c + 124, len);
# endif
edges[i].blocks = 2;
}
edges[i].ptr = blocks[i].c;
}
/* hash input tails and finalize */
sha1_multi_block(mctx, edges, n4x);
memset(blocks, 0, sizeof(blocks));
for (i = 0; i < x4; i++) {
# ifdef BSWAP4
blocks[i].d[0] = BSWAP4(mctx->A[i]);
mctx->A[i] = sctx->tail.h0;
blocks[i].d[1] = BSWAP4(mctx->B[i]);
mctx->B[i] = sctx->tail.h1;
blocks[i].d[2] = BSWAP4(mctx->C[i]);
mctx->C[i] = sctx->tail.h2;
blocks[i].d[3] = BSWAP4(mctx->D[i]);
mctx->D[i] = sctx->tail.h3;
blocks[i].d[4] = BSWAP4(mctx->E[i]);
mctx->E[i] = sctx->tail.h4;
blocks[i].c[20] = 0x80;
blocks[i].d[15] = BSWAP4((64 + 20) * 8);
# else
PUTU32(blocks[i].c + 0, mctx->A[i]);
mctx->A[i] = sctx->tail.h0;
PUTU32(blocks[i].c + 4, mctx->B[i]);
mctx->B[i] = sctx->tail.h1;
PUTU32(blocks[i].c + 8, mctx->C[i]);
mctx->C[i] = sctx->tail.h2;
PUTU32(blocks[i].c + 12, mctx->D[i]);
mctx->D[i] = sctx->tail.h3;
PUTU32(blocks[i].c + 16, mctx->E[i]);
mctx->E[i] = sctx->tail.h4;
blocks[i].c[20] = 0x80;
PUTU32(blocks[i].c + 60, (64 + 20) * 8);
# endif /* BSWAP */
edges[i].ptr = blocks[i].c;
edges[i].blocks = 1;
}
/* finalize MACs */
sha1_multi_block(mctx, edges, n4x);
for (i = 0; i < x4; i++) {
unsigned int len = (i == (x4 - 1) ? last : frag), pad, j;
unsigned char *out0 = out;
memcpy(ciph_d[i].out, ciph_d[i].inp, len - processed);
ciph_d[i].inp = ciph_d[i].out;
out += 5 + 16 + len;
/* write MAC */
PUTU32(out + 0, mctx->A[i]);
PUTU32(out + 4, mctx->B[i]);
PUTU32(out + 8, mctx->C[i]);
PUTU32(out + 12, mctx->D[i]);
PUTU32(out + 16, mctx->E[i]);
out += 20;
len += 20;
/* pad */
pad = 15 - len % 16;
for (j = 0; j <= pad; j++)
*(out++) = pad;
len += pad + 1;
ciph_d[i].blocks = (len - processed) / 16;
len += 16; /* account for explicit iv */
/* arrange header */
out0[0] = ((u8 *)sctx->md.data)[8];
out0[1] = ((u8 *)sctx->md.data)[9];
out0[2] = ((u8 *)sctx->md.data)[10];
out0[3] = (u8)(len >> 8);
out0[4] = (u8)(len);
ret += len + 5;
inp += frag;
}
aesni_multi_cbc_encrypt(ciph_d, &ctx->ks, n4x);
OPENSSL_cleanse(blocks, sizeof(blocks));
OPENSSL_cleanse(mctx, sizeof(*mctx));
ctx->multiblock_encrypt_len = ret;
return ret;
}
# endif /* OPENSSL_NO_MULTIBLOCK */
static int aesni_cbc_hmac_sha1_cipher(PROV_CIPHER_CTX *vctx,
unsigned char *out,
const unsigned char *in, size_t len)
{
PROV_AES_HMAC_SHA_CTX *ctx = (PROV_AES_HMAC_SHA_CTX *)vctx;
PROV_AES_HMAC_SHA1_CTX *sctx = (PROV_AES_HMAC_SHA1_CTX *)vctx;
unsigned int l;
size_t plen = ctx->payload_length;
size_t iv = 0; /* explicit IV in TLS 1.1 and later */
size_t aes_off = 0, blocks;
size_t sha_off = SHA_CBLOCK - sctx->md.num;
ctx->payload_length = NO_PAYLOAD_LENGTH;
if (len % AES_BLOCK_SIZE)
return 0;
if (ctx->base.enc) {
if (plen == NO_PAYLOAD_LENGTH)
plen = len;
else if (len !=
((plen + SHA_DIGEST_LENGTH +
AES_BLOCK_SIZE) & -AES_BLOCK_SIZE))
return 0;
else if (ctx->aux.tls_ver >= TLS1_1_VERSION)
iv = AES_BLOCK_SIZE;
if (plen > (sha_off + iv)
&& (blocks = (plen - (sha_off + iv)) / SHA_CBLOCK)) {
sha1_update(&sctx->md, in + iv, sha_off);
aesni_cbc_sha1_enc(in, out, blocks, &ctx->ks, ctx->base.iv,
&sctx->md, in + iv + sha_off);
blocks *= SHA_CBLOCK;
aes_off += blocks;
sha_off += blocks;
sctx->md.Nh += blocks >> 29;
sctx->md.Nl += blocks <<= 3;
if (sctx->md.Nl < (unsigned int)blocks)
sctx->md.Nh++;
} else {
sha_off = 0;
}
sha_off += iv;
sha1_update(&sctx->md, in + sha_off, plen - sha_off);
if (plen != len) { /* "TLS" mode of operation */
if (in != out)
memcpy(out + aes_off, in + aes_off, plen - aes_off);
/* calculate HMAC and append it to payload */
SHA1_Final(out + plen, &sctx->md);
sctx->md = sctx->tail;
sha1_update(&sctx->md, out + plen, SHA_DIGEST_LENGTH);
SHA1_Final(out + plen, &sctx->md);
/* pad the payload|hmac */
plen += SHA_DIGEST_LENGTH;
for (l = len - plen - 1; plen < len; plen++)
out[plen] = l;
/* encrypt HMAC|padding at once */
aesni_cbc_encrypt(out + aes_off, out + aes_off, len - aes_off,
&ctx->ks, ctx->base.iv, 1);
} else {
aesni_cbc_encrypt(in + aes_off, out + aes_off, len - aes_off,
&ctx->ks, ctx->base.iv, 1);
}
} else {
union {
unsigned int u[SHA_DIGEST_LENGTH / sizeof(unsigned int)];
unsigned char c[32 + SHA_DIGEST_LENGTH];
} mac, *pmac;
/* arrange cache line alignment */
pmac = (void *)(((size_t)mac.c + 31) & ((size_t)0 - 32));
if (plen != NO_PAYLOAD_LENGTH) { /* "TLS" mode of operation */
size_t inp_len, mask, j, i;
unsigned int res, maxpad, pad, bitlen;
int ret = 1;
union {
unsigned int u[SHA_LBLOCK];
unsigned char c[SHA_CBLOCK];
} *data = (void *)sctx->md.data;
if ((ctx->aux.tls_aad[plen - 4] << 8 | ctx->aux.tls_aad[plen - 3])
>= TLS1_1_VERSION) {
if (len < (AES_BLOCK_SIZE + SHA_DIGEST_LENGTH + 1))
return 0;
/* omit explicit iv */
memcpy(ctx->base.iv, in, AES_BLOCK_SIZE);
in += AES_BLOCK_SIZE;
out += AES_BLOCK_SIZE;
len -= AES_BLOCK_SIZE;
} else if (len < (SHA_DIGEST_LENGTH + 1))
return 0;
/* decrypt HMAC|padding at once */
aesni_cbc_encrypt(in, out, len, &ctx->ks, ctx->base.iv, 0);
/* figure out payload length */
pad = out[len - 1];
maxpad = len - (SHA_DIGEST_LENGTH + 1);
maxpad |= (255 - maxpad) >> (sizeof(maxpad) * 8 - 8);
maxpad &= 255;
mask = constant_time_ge(maxpad, pad);
ret &= mask;
/*
* If pad is invalid then we will fail the above test but we must
* continue anyway because we are in constant time code. However,
* we'll use the maxpad value instead of the supplied pad to make
* sure we perform well defined pointer arithmetic.
*/
pad = constant_time_select(mask, pad, maxpad);
inp_len = len - (SHA_DIGEST_LENGTH + pad + 1);
ctx->aux.tls_aad[plen - 2] = inp_len >> 8;
ctx->aux.tls_aad[plen - 1] = inp_len;
/* calculate HMAC */
sctx->md = sctx->head;
sha1_update(&sctx->md, ctx->aux.tls_aad, plen);
/* code containing lucky-13 fix */
len -= SHA_DIGEST_LENGTH; /* amend mac */
if (len >= (256 + SHA_CBLOCK)) {
j = (len - (256 + SHA_CBLOCK)) & (0 - SHA_CBLOCK);
j += SHA_CBLOCK - sctx->md.num;
sha1_update(&sctx->md, out, j);
out += j;
len -= j;
inp_len -= j;
}
/* but pretend as if we hashed padded payload */
bitlen = sctx->md.Nl + (inp_len << 3); /* at most 18 bits */
# ifdef BSWAP4
bitlen = BSWAP4(bitlen);
# else
mac.c[0] = 0;
mac.c[1] = (unsigned char)(bitlen >> 16);
mac.c[2] = (unsigned char)(bitlen >> 8);
mac.c[3] = (unsigned char)bitlen;
bitlen = mac.u[0];
# endif /* BSWAP */
pmac->u[0] = 0;
pmac->u[1] = 0;
pmac->u[2] = 0;
pmac->u[3] = 0;
pmac->u[4] = 0;
for (res = sctx->md.num, j = 0; j < len; j++) {
size_t c = out[j];
mask = (j - inp_len) >> (sizeof(j) * 8 - 8);
c &= mask;
c |= 0x80 & ~mask & ~((inp_len - j) >> (sizeof(j) * 8 - 8));
data->c[res++] = (unsigned char)c;
if (res != SHA_CBLOCK)
continue;
/* j is not incremented yet */
mask = 0 - ((inp_len + 7 - j) >> (sizeof(j) * 8 - 1));
data->u[SHA_LBLOCK - 1] |= bitlen & mask;
sha1_block_data_order(&sctx->md, data, 1);
mask &= 0 - ((j - inp_len - 72) >> (sizeof(j) * 8 - 1));
pmac->u[0] |= sctx->md.h0 & mask;
pmac->u[1] |= sctx->md.h1 & mask;
pmac->u[2] |= sctx->md.h2 & mask;
pmac->u[3] |= sctx->md.h3 & mask;
pmac->u[4] |= sctx->md.h4 & mask;
res = 0;
}
for (i = res; i < SHA_CBLOCK; i++, j++)
data->c[i] = 0;
if (res > SHA_CBLOCK - 8) {
mask = 0 - ((inp_len + 8 - j) >> (sizeof(j) * 8 - 1));
data->u[SHA_LBLOCK - 1] |= bitlen & mask;
sha1_block_data_order(&sctx->md, data, 1);
mask &= 0 - ((j - inp_len - 73) >> (sizeof(j) * 8 - 1));
pmac->u[0] |= sctx->md.h0 & mask;
pmac->u[1] |= sctx->md.h1 & mask;
pmac->u[2] |= sctx->md.h2 & mask;
pmac->u[3] |= sctx->md.h3 & mask;
pmac->u[4] |= sctx->md.h4 & mask;
memset(data, 0, SHA_CBLOCK);
j += 64;
}
data->u[SHA_LBLOCK - 1] = bitlen;
sha1_block_data_order(&sctx->md, data, 1);
mask = 0 - ((j - inp_len - 73) >> (sizeof(j) * 8 - 1));
pmac->u[0] |= sctx->md.h0 & mask;
pmac->u[1] |= sctx->md.h1 & mask;
pmac->u[2] |= sctx->md.h2 & mask;
pmac->u[3] |= sctx->md.h3 & mask;
pmac->u[4] |= sctx->md.h4 & mask;
# ifdef BSWAP4
pmac->u[0] = BSWAP4(pmac->u[0]);
pmac->u[1] = BSWAP4(pmac->u[1]);
pmac->u[2] = BSWAP4(pmac->u[2]);
pmac->u[3] = BSWAP4(pmac->u[3]);
pmac->u[4] = BSWAP4(pmac->u[4]);
# else
for (i = 0; i < 5; i++) {
res = pmac->u[i];
pmac->c[4 * i + 0] = (unsigned char)(res >> 24);
pmac->c[4 * i + 1] = (unsigned char)(res >> 16);
pmac->c[4 * i + 2] = (unsigned char)(res >> 8);
pmac->c[4 * i + 3] = (unsigned char)res;
}
# endif /* BSWAP4 */
len += SHA_DIGEST_LENGTH;
sctx->md = sctx->tail;
sha1_update(&sctx->md, pmac->c, SHA_DIGEST_LENGTH);
SHA1_Final(pmac->c, &sctx->md);
/* verify HMAC */
out += inp_len;
len -= inp_len;
/* version of code with lucky-13 fix */
{
unsigned char *p = out + len - 1 - maxpad - SHA_DIGEST_LENGTH;
size_t off = out - p;
unsigned int c, cmask;
maxpad += SHA_DIGEST_LENGTH;
for (res = 0, i = 0, j = 0; j < maxpad; j++) {
c = p[j];
cmask =
((int)(j - off - SHA_DIGEST_LENGTH)) >> (sizeof(int) *
8 - 1);
res |= (c ^ pad) & ~cmask; /* ... and padding */
cmask &= ((int)(off - 1 - j)) >> (sizeof(int) * 8 - 1);
res |= (c ^ pmac->c[i]) & cmask;
i += 1 & cmask;
}
maxpad -= SHA_DIGEST_LENGTH;
res = 0 - ((0 - res) >> (sizeof(res) * 8 - 1));
ret &= (int)~res;
}
return ret;
} else {
/* decrypt HMAC|padding at once */
aesni_cbc_encrypt(in, out, len, &ctx->ks, ctx->base.iv, 0);
sha1_update(&sctx->md, out, len);
}
}
return 1;
}
/* EVP_CTRL_AEAD_SET_MAC_KEY */
static void aesni_cbc_hmac_sha1_set_mac_key(void *vctx,
const unsigned char *mac, size_t len)
{
PROV_AES_HMAC_SHA1_CTX *ctx = (PROV_AES_HMAC_SHA1_CTX *)vctx;
unsigned int i;
unsigned char hmac_key[64];
memset(hmac_key, 0, sizeof(hmac_key));
if (len > (int)sizeof(hmac_key)) {
SHA1_Init(&ctx->head);
sha1_update(&ctx->head, mac, len);
SHA1_Final(hmac_key, &ctx->head);
} else {
memcpy(hmac_key, mac, len);
}
for (i = 0; i < sizeof(hmac_key); i++)
hmac_key[i] ^= 0x36; /* ipad */
SHA1_Init(&ctx->head);
sha1_update(&ctx->head, hmac_key, sizeof(hmac_key));
for (i = 0; i < sizeof(hmac_key); i++)
hmac_key[i] ^= 0x36 ^ 0x5c; /* opad */
SHA1_Init(&ctx->tail);
sha1_update(&ctx->tail, hmac_key, sizeof(hmac_key));
OPENSSL_cleanse(hmac_key, sizeof(hmac_key));
}
/* EVP_CTRL_AEAD_TLS1_AAD */
static int aesni_cbc_hmac_sha1_set_tls1_aad(void *vctx,
unsigned char *aad_rec, int aad_len)
{
PROV_AES_HMAC_SHA_CTX *ctx = (PROV_AES_HMAC_SHA_CTX *)vctx;
PROV_AES_HMAC_SHA1_CTX *sctx = (PROV_AES_HMAC_SHA1_CTX *)vctx;
unsigned char *p = aad_rec;
unsigned int len;
if (aad_len != EVP_AEAD_TLS1_AAD_LEN)
return -1;
len = p[aad_len - 2] << 8 | p[aad_len - 1];
if (ctx->base.enc) {
ctx->payload_length = len;
if ((ctx->aux.tls_ver =
p[aad_len - 4] << 8 | p[aad_len - 3]) >= TLS1_1_VERSION) {
if (len < AES_BLOCK_SIZE)
return 0;
len -= AES_BLOCK_SIZE;
p[aad_len - 2] = len >> 8;
p[aad_len - 1] = len;
}
sctx->md = sctx->head;
sha1_update(&sctx->md, p, aad_len);
ctx->tls_aad_pad = (int)(((len + SHA_DIGEST_LENGTH +
AES_BLOCK_SIZE) & -AES_BLOCK_SIZE)
- len);
return 1;
} else {
memcpy(ctx->aux.tls_aad, aad_rec, aad_len);
ctx->payload_length = aad_len;
ctx->tls_aad_pad = SHA_DIGEST_LENGTH;
return 1;
}
}
# if !defined(OPENSSL_NO_MULTIBLOCK)
/* EVP_CTRL_TLS1_1_MULTIBLOCK_MAX_BUFSIZE */
static int aesni_cbc_hmac_sha1_tls1_multiblock_max_bufsize(void *vctx)
{
PROV_AES_HMAC_SHA_CTX *ctx = (PROV_AES_HMAC_SHA_CTX *)vctx;
OPENSSL_assert(ctx->multiblock_max_send_fragment != 0);
return (int)(5 + 16
+ (((int)ctx->multiblock_max_send_fragment + 20 + 16) & -16));
}
/* EVP_CTRL_TLS1_1_MULTIBLOCK_AAD */
static int aesni_cbc_hmac_sha1_tls1_multiblock_aad(
void *vctx, EVP_CTRL_TLS1_1_MULTIBLOCK_PARAM *param)
{
PROV_AES_HMAC_SHA_CTX *ctx = (PROV_AES_HMAC_SHA_CTX *)vctx;
PROV_AES_HMAC_SHA1_CTX *sctx = (PROV_AES_HMAC_SHA1_CTX *)vctx;
unsigned int n4x = 1, x4;
unsigned int frag, last, packlen, inp_len;
inp_len = param->inp[11] << 8 | param->inp[12];
ctx->multiblock_interleave = param->interleave;
if (ctx->base.enc) {
if ((param->inp[9] << 8 | param->inp[10]) < TLS1_1_VERSION)
return -1;
if (inp_len) {
if (inp_len < 4096)
return 0; /* too short */
if (inp_len >= 8192 && OPENSSL_ia32cap_P[2] & (1 << 5))
n4x = 2; /* AVX2 */
} else if ((n4x = param->interleave / 4) && n4x <= 2)
inp_len = param->len;
else
return -1;
sctx->md = sctx->head;
sha1_update(&sctx->md, param->inp, 13);
x4 = 4 * n4x;
n4x += 1;
frag = inp_len >> n4x;
last = inp_len + frag - (frag << n4x);
if (last > frag && ((last + 13 + 9) % 64 < (x4 - 1))) {
frag++;
last -= x4 - 1;
}
packlen = 5 + 16 + ((frag + 20 + 16) & -16);
packlen = (packlen << n4x) - packlen;
packlen += 5 + 16 + ((last + 20 + 16) & -16);
param->interleave = x4;
/* The returned values used by get need to be stored */
ctx->multiblock_interleave = x4;
ctx->multiblock_aad_packlen = packlen;
return 1;
}
return -1; /* not yet */
}
/* EVP_CTRL_TLS1_1_MULTIBLOCK_ENCRYPT */
static int aesni_cbc_hmac_sha1_tls1_multiblock_encrypt(
void *ctx, EVP_CTRL_TLS1_1_MULTIBLOCK_PARAM *param)
{
return (int)tls1_multi_block_encrypt(ctx, param->out,
param->inp, param->len,
param->interleave / 4);
}
#endif /* OPENSSL_NO_MULTIBLOCK */
static const PROV_CIPHER_HW_AES_HMAC_SHA cipher_hw_aes_hmac_sha1 = {
{
aesni_cbc_hmac_sha1_init_key,
aesni_cbc_hmac_sha1_cipher
},
aesni_cbc_hmac_sha1_set_mac_key,
aesni_cbc_hmac_sha1_set_tls1_aad,
# if !defined(OPENSSL_NO_MULTIBLOCK)
aesni_cbc_hmac_sha1_tls1_multiblock_max_bufsize,
aesni_cbc_hmac_sha1_tls1_multiblock_aad,
aesni_cbc_hmac_sha1_tls1_multiblock_encrypt
# endif
};
const PROV_CIPHER_HW_AES_HMAC_SHA *PROV_CIPHER_HW_aes_cbc_hmac_sha1(void)
{
return &cipher_hw_aes_hmac_sha1;
}
#endif /* AES_CBC_HMAC_SHA_CAPABLE */
@@ -0,0 +1,838 @@
/*
* Copyright 2011-2019 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
*/
/*
* AES low level APIs are deprecated for public use, but still ok for internal
* use where we're using them to implement the higher level EVP interface, as is
* the case here.
*/
#include "internal/deprecated.h"
#include "cipher_aes_cbc_hmac_sha.h"
#ifndef AES_CBC_HMAC_SHA_CAPABLE
int cipher_capable_aes_cbc_hmac_sha256(void)
{
return 0;
}
#else
# include "crypto/rand.h"
# include "crypto/evp.h"
# include "internal/constant_time.h"
void sha256_block_data_order(void *c, const void *p, size_t len);
int aesni_cbc_sha256_enc(const void *inp, void *out, size_t blocks,
const AES_KEY *key, unsigned char iv[16],
SHA256_CTX *ctx, const void *in0);
int cipher_capable_aes_cbc_hmac_sha256(void)
{
return AESNI_CBC_HMAC_SHA_CAPABLE
&& aesni_cbc_sha256_enc(NULL, NULL, 0, NULL, NULL, NULL, NULL);
}
static int aesni_cbc_hmac_sha256_init_key(PROV_CIPHER_CTX *vctx,
const unsigned char *key,
size_t keylen)
{
int ret;
PROV_AES_HMAC_SHA_CTX *ctx = (PROV_AES_HMAC_SHA_CTX *)vctx;
PROV_AES_HMAC_SHA256_CTX *sctx = (PROV_AES_HMAC_SHA256_CTX *)vctx;
if (ctx->base.enc)
ret = aesni_set_encrypt_key(key, ctx->base.keylen * 8, &ctx->ks);
else
ret = aesni_set_decrypt_key(key, ctx->base.keylen * 8, &ctx->ks);
SHA256_Init(&sctx->head); /* handy when benchmarking */
sctx->tail = sctx->head;
sctx->md = sctx->head;
ctx->payload_length = NO_PAYLOAD_LENGTH;
return ret < 0 ? 0 : 1;
}
void sha256_block_data_order(void *c, const void *p, size_t len);
static void sha256_update(SHA256_CTX *c, const void *data, size_t len)
{
const unsigned char *ptr = data;
size_t res;
if ((res = c->num)) {
res = SHA256_CBLOCK - res;
if (len < res)
res = len;
SHA256_Update(c, ptr, res);
ptr += res;
len -= res;
}
res = len % SHA256_CBLOCK;
len -= res;
if (len) {
sha256_block_data_order(c, ptr, len / SHA256_CBLOCK);
ptr += len;
c->Nh += len >> 29;
c->Nl += len <<= 3;
if (c->Nl < (unsigned int)len)
c->Nh++;
}
if (res)
SHA256_Update(c, ptr, res);
}
# if !defined(OPENSSL_NO_MULTIBLOCK)
typedef struct {
unsigned int A[8], B[8], C[8], D[8], E[8], F[8], G[8], H[8];
} SHA256_MB_CTX;
typedef struct {
const unsigned char *ptr;
int blocks;
} HASH_DESC;
typedef struct {
const unsigned char *inp;
unsigned char *out;
int blocks;
u64 iv[2];
} CIPH_DESC;
void sha256_multi_block(SHA256_MB_CTX *, const HASH_DESC *, int);
void aesni_multi_cbc_encrypt(CIPH_DESC *, void *, int);
static size_t tls1_multi_block_encrypt(void *vctx,
unsigned char *out,
const unsigned char *inp,
size_t inp_len, int n4x)
{ /* n4x is 1 or 2 */
PROV_AES_HMAC_SHA_CTX *ctx = (PROV_AES_HMAC_SHA_CTX *)vctx;
PROV_AES_HMAC_SHA256_CTX *sctx = (PROV_AES_HMAC_SHA256_CTX *)vctx;
HASH_DESC hash_d[8], edges[8];
CIPH_DESC ciph_d[8];
unsigned char storage[sizeof(SHA256_MB_CTX) + 32];
union {
u64 q[16];
u32 d[32];
u8 c[128];
} blocks[8];
SHA256_MB_CTX *mctx;
unsigned int frag, last, packlen, i;
unsigned int x4 = 4 * n4x, minblocks, processed = 0;
size_t ret = 0;
u8 *IVs;
# if defined(BSWAP8)
u64 seqnum;
# endif
/* ask for IVs in bulk */
if (rand_bytes_ex(ctx->base.libctx, (IVs = blocks[0].c), 16 * x4) <= 0)
return 0;
mctx = (SHA256_MB_CTX *) (storage + 32 - ((size_t)storage % 32)); /* align */
frag = (unsigned int)inp_len >> (1 + n4x);
last = (unsigned int)inp_len + frag - (frag << (1 + n4x));
if (last > frag && ((last + 13 + 9) % 64) < (x4 - 1)) {
frag++;
last -= x4 - 1;
}
packlen = 5 + 16 + ((frag + 32 + 16) & -16);
/* populate descriptors with pointers and IVs */
hash_d[0].ptr = inp;
ciph_d[0].inp = inp;
/* 5+16 is place for header and explicit IV */
ciph_d[0].out = out + 5 + 16;
memcpy(ciph_d[0].out - 16, IVs, 16);
memcpy(ciph_d[0].iv, IVs, 16);
IVs += 16;
for (i = 1; i < x4; i++) {
ciph_d[i].inp = hash_d[i].ptr = hash_d[i - 1].ptr + frag;
ciph_d[i].out = ciph_d[i - 1].out + packlen;
memcpy(ciph_d[i].out - 16, IVs, 16);
memcpy(ciph_d[i].iv, IVs, 16);
IVs += 16;
}
# if defined(BSWAP8)
memcpy(blocks[0].c, sctx->md.data, 8);
seqnum = BSWAP8(blocks[0].q[0]);
# endif
for (i = 0; i < x4; i++) {
unsigned int len = (i == (x4 - 1) ? last : frag);
# if !defined(BSWAP8)
unsigned int carry, j;
# endif
mctx->A[i] = sctx->md.h[0];
mctx->B[i] = sctx->md.h[1];
mctx->C[i] = sctx->md.h[2];
mctx->D[i] = sctx->md.h[3];
mctx->E[i] = sctx->md.h[4];
mctx->F[i] = sctx->md.h[5];
mctx->G[i] = sctx->md.h[6];
mctx->H[i] = sctx->md.h[7];
/* fix seqnum */
# if defined(BSWAP8)
blocks[i].q[0] = BSWAP8(seqnum + i);
# else
for (carry = i, j = 8; j--;) {
blocks[i].c[j] = ((u8 *)sctx->md.data)[j] + carry;
carry = (blocks[i].c[j] - carry) >> (sizeof(carry) * 8 - 1);
}
# endif
blocks[i].c[8] = ((u8 *)sctx->md.data)[8];
blocks[i].c[9] = ((u8 *)sctx->md.data)[9];
blocks[i].c[10] = ((u8 *)sctx->md.data)[10];
/* fix length */
blocks[i].c[11] = (u8)(len >> 8);
blocks[i].c[12] = (u8)(len);
memcpy(blocks[i].c + 13, hash_d[i].ptr, 64 - 13);
hash_d[i].ptr += 64 - 13;
hash_d[i].blocks = (len - (64 - 13)) / 64;
edges[i].ptr = blocks[i].c;
edges[i].blocks = 1;
}
/* hash 13-byte headers and first 64-13 bytes of inputs */
sha256_multi_block(mctx, edges, n4x);
/* hash bulk inputs */
# define MAXCHUNKSIZE 2048
# if MAXCHUNKSIZE%64
# error "MAXCHUNKSIZE is not divisible by 64"
# elif MAXCHUNKSIZE
/*
* goal is to minimize pressure on L1 cache by moving in shorter steps,
* so that hashed data is still in the cache by the time we encrypt it
*/
minblocks = ((frag <= last ? frag : last) - (64 - 13)) / 64;
if (minblocks > MAXCHUNKSIZE / 64) {
for (i = 0; i < x4; i++) {
edges[i].ptr = hash_d[i].ptr;
edges[i].blocks = MAXCHUNKSIZE / 64;
ciph_d[i].blocks = MAXCHUNKSIZE / 16;
}
do {
sha256_multi_block(mctx, edges, n4x);
aesni_multi_cbc_encrypt(ciph_d, &ctx->ks, n4x);
for (i = 0; i < x4; i++) {
edges[i].ptr = hash_d[i].ptr += MAXCHUNKSIZE;
hash_d[i].blocks -= MAXCHUNKSIZE / 64;
edges[i].blocks = MAXCHUNKSIZE / 64;
ciph_d[i].inp += MAXCHUNKSIZE;
ciph_d[i].out += MAXCHUNKSIZE;
ciph_d[i].blocks = MAXCHUNKSIZE / 16;
memcpy(ciph_d[i].iv, ciph_d[i].out - 16, 16);
}
processed += MAXCHUNKSIZE;
minblocks -= MAXCHUNKSIZE / 64;
} while (minblocks > MAXCHUNKSIZE / 64);
}
# endif
# undef MAXCHUNKSIZE
sha256_multi_block(mctx, hash_d, n4x);
memset(blocks, 0, sizeof(blocks));
for (i = 0; i < x4; i++) {
unsigned int len = (i == (x4 - 1) ? last : frag),
off = hash_d[i].blocks * 64;
const unsigned char *ptr = hash_d[i].ptr + off;
off = (len - processed) - (64 - 13) - off; /* remainder actually */
memcpy(blocks[i].c, ptr, off);
blocks[i].c[off] = 0x80;
len += 64 + 13; /* 64 is HMAC header */
len *= 8; /* convert to bits */
if (off < (64 - 8)) {
# ifdef BSWAP4
blocks[i].d[15] = BSWAP4(len);
# else
PUTU32(blocks[i].c + 60, len);
# endif
edges[i].blocks = 1;
} else {
# ifdef BSWAP4
blocks[i].d[31] = BSWAP4(len);
# else
PUTU32(blocks[i].c + 124, len);
# endif
edges[i].blocks = 2;
}
edges[i].ptr = blocks[i].c;
}
/* hash input tails and finalize */
sha256_multi_block(mctx, edges, n4x);
memset(blocks, 0, sizeof(blocks));
for (i = 0; i < x4; i++) {
# ifdef BSWAP4
blocks[i].d[0] = BSWAP4(mctx->A[i]);
mctx->A[i] = sctx->tail.h[0];
blocks[i].d[1] = BSWAP4(mctx->B[i]);
mctx->B[i] = sctx->tail.h[1];
blocks[i].d[2] = BSWAP4(mctx->C[i]);
mctx->C[i] = sctx->tail.h[2];
blocks[i].d[3] = BSWAP4(mctx->D[i]);
mctx->D[i] = sctx->tail.h[3];
blocks[i].d[4] = BSWAP4(mctx->E[i]);
mctx->E[i] = sctx->tail.h[4];
blocks[i].d[5] = BSWAP4(mctx->F[i]);
mctx->F[i] = sctx->tail.h[5];
blocks[i].d[6] = BSWAP4(mctx->G[i]);
mctx->G[i] = sctx->tail.h[6];
blocks[i].d[7] = BSWAP4(mctx->H[i]);
mctx->H[i] = sctx->tail.h[7];
blocks[i].c[32] = 0x80;
blocks[i].d[15] = BSWAP4((64 + 32) * 8);
# else
PUTU32(blocks[i].c + 0, mctx->A[i]);
mctx->A[i] = sctx->tail.h[0];
PUTU32(blocks[i].c + 4, mctx->B[i]);
mctx->B[i] = sctx->tail.h[1];
PUTU32(blocks[i].c + 8, mctx->C[i]);
mctx->C[i] = sctx->tail.h[2];
PUTU32(blocks[i].c + 12, mctx->D[i]);
mctx->D[i] = sctx->tail.h[3];
PUTU32(blocks[i].c + 16, mctx->E[i]);
mctx->E[i] = sctx->tail.h[4];
PUTU32(blocks[i].c + 20, mctx->F[i]);
mctx->F[i] = sctx->tail.h[5];
PUTU32(blocks[i].c + 24, mctx->G[i]);
mctx->G[i] = sctx->tail.h[6];
PUTU32(blocks[i].c + 28, mctx->H[i]);
mctx->H[i] = sctx->tail.h[7];
blocks[i].c[32] = 0x80;
PUTU32(blocks[i].c + 60, (64 + 32) * 8);
# endif /* BSWAP */
edges[i].ptr = blocks[i].c;
edges[i].blocks = 1;
}
/* finalize MACs */
sha256_multi_block(mctx, edges, n4x);
for (i = 0; i < x4; i++) {
unsigned int len = (i == (x4 - 1) ? last : frag), pad, j;
unsigned char *out0 = out;
memcpy(ciph_d[i].out, ciph_d[i].inp, len - processed);
ciph_d[i].inp = ciph_d[i].out;
out += 5 + 16 + len;
/* write MAC */
PUTU32(out + 0, mctx->A[i]);
PUTU32(out + 4, mctx->B[i]);
PUTU32(out + 8, mctx->C[i]);
PUTU32(out + 12, mctx->D[i]);
PUTU32(out + 16, mctx->E[i]);
PUTU32(out + 20, mctx->F[i]);
PUTU32(out + 24, mctx->G[i]);
PUTU32(out + 28, mctx->H[i]);
out += 32;
len += 32;
/* pad */
pad = 15 - len % 16;
for (j = 0; j <= pad; j++)
*(out++) = pad;
len += pad + 1;
ciph_d[i].blocks = (len - processed) / 16;
len += 16; /* account for explicit iv */
/* arrange header */
out0[0] = ((u8 *)sctx->md.data)[8];
out0[1] = ((u8 *)sctx->md.data)[9];
out0[2] = ((u8 *)sctx->md.data)[10];
out0[3] = (u8)(len >> 8);
out0[4] = (u8)(len);
ret += len + 5;
inp += frag;
}
aesni_multi_cbc_encrypt(ciph_d, &ctx->ks, n4x);
OPENSSL_cleanse(blocks, sizeof(blocks));
OPENSSL_cleanse(mctx, sizeof(*mctx));
ctx->multiblock_encrypt_len = ret;
return ret;
}
# endif /* !OPENSSL_NO_MULTIBLOCK */
static int aesni_cbc_hmac_sha256_cipher(PROV_CIPHER_CTX *vctx,
unsigned char *out,
const unsigned char *in, size_t len)
{
PROV_AES_HMAC_SHA_CTX *ctx = (PROV_AES_HMAC_SHA_CTX *)vctx;
PROV_AES_HMAC_SHA256_CTX *sctx = (PROV_AES_HMAC_SHA256_CTX *)vctx;
unsigned int l;
size_t plen = ctx->payload_length;
size_t iv = 0; /* explicit IV in TLS 1.1 and * later */
size_t aes_off = 0, blocks;
size_t sha_off = SHA256_CBLOCK - sctx->md.num;
ctx->payload_length = NO_PAYLOAD_LENGTH;
if (len % AES_BLOCK_SIZE)
return 0;
if (ctx->base.enc) {
if (plen == NO_PAYLOAD_LENGTH)
plen = len;
else if (len !=
((plen + SHA256_DIGEST_LENGTH +
AES_BLOCK_SIZE) & -AES_BLOCK_SIZE))
return 0;
else if (ctx->aux.tls_ver >= TLS1_1_VERSION)
iv = AES_BLOCK_SIZE;
/*
* Assembly stitch handles AVX-capable processors, but its
* performance is not optimal on AMD Jaguar, ~40% worse, for
* unknown reasons. Incidentally processor in question supports
* AVX, but not AMD-specific XOP extension, which can be used
* to identify it and avoid stitch invocation. So that after we
* establish that current CPU supports AVX, we even see if it's
* either even XOP-capable Bulldozer-based or GenuineIntel one.
* But SHAEXT-capable go ahead...
*/
if (((OPENSSL_ia32cap_P[2] & (1 << 29)) || /* SHAEXT? */
((OPENSSL_ia32cap_P[1] & (1 << (60 - 32))) && /* AVX? */
((OPENSSL_ia32cap_P[1] & (1 << (43 - 32))) /* XOP? */
| (OPENSSL_ia32cap_P[0] & (1 << 30))))) && /* "Intel CPU"? */
plen > (sha_off + iv) &&
(blocks = (plen - (sha_off + iv)) / SHA256_CBLOCK)) {
sha256_update(&sctx->md, in + iv, sha_off);
(void)aesni_cbc_sha256_enc(in, out, blocks, &ctx->ks,
ctx->base.iv,
&sctx->md, in + iv + sha_off);
blocks *= SHA256_CBLOCK;
aes_off += blocks;
sha_off += blocks;
sctx->md.Nh += blocks >> 29;
sctx->md.Nl += blocks <<= 3;
if (sctx->md.Nl < (unsigned int)blocks)
sctx->md.Nh++;
} else {
sha_off = 0;
}
sha_off += iv;
sha256_update(&sctx->md, in + sha_off, plen - sha_off);
if (plen != len) { /* "TLS" mode of operation */
if (in != out)
memcpy(out + aes_off, in + aes_off, plen - aes_off);
/* calculate HMAC and append it to payload */
SHA256_Final(out + plen, &sctx->md);
sctx->md = sctx->tail;
sha256_update(&sctx->md, out + plen, SHA256_DIGEST_LENGTH);
SHA256_Final(out + plen, &sctx->md);
/* pad the payload|hmac */
plen += SHA256_DIGEST_LENGTH;
for (l = len - plen - 1; plen < len; plen++)
out[plen] = l;
/* encrypt HMAC|padding at once */
aesni_cbc_encrypt(out + aes_off, out + aes_off, len - aes_off,
&ctx->ks, ctx->base.iv, 1);
} else {
aesni_cbc_encrypt(in + aes_off, out + aes_off, len - aes_off,
&ctx->ks, ctx->base.iv, 1);
}
} else {
union {
unsigned int u[SHA256_DIGEST_LENGTH / sizeof(unsigned int)];
unsigned char c[64 + SHA256_DIGEST_LENGTH];
} mac, *pmac;
/* arrange cache line alignment */
pmac = (void *)(((size_t)mac.c + 63) & ((size_t)0 - 64));
/* decrypt HMAC|padding at once */
aesni_cbc_encrypt(in, out, len, &ctx->ks,
ctx->base.iv, 0);
if (plen != NO_PAYLOAD_LENGTH) { /* "TLS" mode of operation */
size_t inp_len, mask, j, i;
unsigned int res, maxpad, pad, bitlen;
int ret = 1;
union {
unsigned int u[SHA_LBLOCK];
unsigned char c[SHA256_CBLOCK];
} *data = (void *)sctx->md.data;
if ((ctx->aux.tls_aad[plen - 4] << 8 | ctx->aux.tls_aad[plen - 3])
>= TLS1_1_VERSION)
iv = AES_BLOCK_SIZE;
if (len < (iv + SHA256_DIGEST_LENGTH + 1))
return 0;
/* omit explicit iv */
out += iv;
len -= iv;
/* figure out payload length */
pad = out[len - 1];
maxpad = len - (SHA256_DIGEST_LENGTH + 1);
maxpad |= (255 - maxpad) >> (sizeof(maxpad) * 8 - 8);
maxpad &= 255;
mask = constant_time_ge(maxpad, pad);
ret &= mask;
/*
* If pad is invalid then we will fail the above test but we must
* continue anyway because we are in constant time code. However,
* we'll use the maxpad value instead of the supplied pad to make
* sure we perform well defined pointer arithmetic.
*/
pad = constant_time_select(mask, pad, maxpad);
inp_len = len - (SHA256_DIGEST_LENGTH + pad + 1);
ctx->aux.tls_aad[plen - 2] = inp_len >> 8;
ctx->aux.tls_aad[plen - 1] = inp_len;
/* calculate HMAC */
sctx->md = sctx->head;
sha256_update(&sctx->md, ctx->aux.tls_aad, plen);
/* code with lucky-13 fix */
len -= SHA256_DIGEST_LENGTH; /* amend mac */
if (len >= (256 + SHA256_CBLOCK)) {
j = (len - (256 + SHA256_CBLOCK)) & (0 - SHA256_CBLOCK);
j += SHA256_CBLOCK - sctx->md.num;
sha256_update(&sctx->md, out, j);
out += j;
len -= j;
inp_len -= j;
}
/* but pretend as if we hashed padded payload */
bitlen = sctx->md.Nl + (inp_len << 3); /* at most 18 bits */
# ifdef BSWAP4
bitlen = BSWAP4(bitlen);
# else
mac.c[0] = 0;
mac.c[1] = (unsigned char)(bitlen >> 16);
mac.c[2] = (unsigned char)(bitlen >> 8);
mac.c[3] = (unsigned char)bitlen;
bitlen = mac.u[0];
# endif /* BSWAP */
pmac->u[0] = 0;
pmac->u[1] = 0;
pmac->u[2] = 0;
pmac->u[3] = 0;
pmac->u[4] = 0;
pmac->u[5] = 0;
pmac->u[6] = 0;
pmac->u[7] = 0;
for (res = sctx->md.num, j = 0; j < len; j++) {
size_t c = out[j];
mask = (j - inp_len) >> (sizeof(j) * 8 - 8);
c &= mask;
c |= 0x80 & ~mask & ~((inp_len - j) >> (sizeof(j) * 8 - 8));
data->c[res++] = (unsigned char)c;
if (res != SHA256_CBLOCK)
continue;
/* j is not incremented yet */
mask = 0 - ((inp_len + 7 - j) >> (sizeof(j) * 8 - 1));
data->u[SHA_LBLOCK - 1] |= bitlen & mask;
sha256_block_data_order(&sctx->md, data, 1);
mask &= 0 - ((j - inp_len - 72) >> (sizeof(j) * 8 - 1));
pmac->u[0] |= sctx->md.h[0] & mask;
pmac->u[1] |= sctx->md.h[1] & mask;
pmac->u[2] |= sctx->md.h[2] & mask;
pmac->u[3] |= sctx->md.h[3] & mask;
pmac->u[4] |= sctx->md.h[4] & mask;
pmac->u[5] |= sctx->md.h[5] & mask;
pmac->u[6] |= sctx->md.h[6] & mask;
pmac->u[7] |= sctx->md.h[7] & mask;
res = 0;
}
for (i = res; i < SHA256_CBLOCK; i++, j++)
data->c[i] = 0;
if (res > SHA256_CBLOCK - 8) {
mask = 0 - ((inp_len + 8 - j) >> (sizeof(j) * 8 - 1));
data->u[SHA_LBLOCK - 1] |= bitlen & mask;
sha256_block_data_order(&sctx->md, data, 1);
mask &= 0 - ((j - inp_len - 73) >> (sizeof(j) * 8 - 1));
pmac->u[0] |= sctx->md.h[0] & mask;
pmac->u[1] |= sctx->md.h[1] & mask;
pmac->u[2] |= sctx->md.h[2] & mask;
pmac->u[3] |= sctx->md.h[3] & mask;
pmac->u[4] |= sctx->md.h[4] & mask;
pmac->u[5] |= sctx->md.h[5] & mask;
pmac->u[6] |= sctx->md.h[6] & mask;
pmac->u[7] |= sctx->md.h[7] & mask;
memset(data, 0, SHA256_CBLOCK);
j += 64;
}
data->u[SHA_LBLOCK - 1] = bitlen;
sha256_block_data_order(&sctx->md, data, 1);
mask = 0 - ((j - inp_len - 73) >> (sizeof(j) * 8 - 1));
pmac->u[0] |= sctx->md.h[0] & mask;
pmac->u[1] |= sctx->md.h[1] & mask;
pmac->u[2] |= sctx->md.h[2] & mask;
pmac->u[3] |= sctx->md.h[3] & mask;
pmac->u[4] |= sctx->md.h[4] & mask;
pmac->u[5] |= sctx->md.h[5] & mask;
pmac->u[6] |= sctx->md.h[6] & mask;
pmac->u[7] |= sctx->md.h[7] & mask;
# ifdef BSWAP4
pmac->u[0] = BSWAP4(pmac->u[0]);
pmac->u[1] = BSWAP4(pmac->u[1]);
pmac->u[2] = BSWAP4(pmac->u[2]);
pmac->u[3] = BSWAP4(pmac->u[3]);
pmac->u[4] = BSWAP4(pmac->u[4]);
pmac->u[5] = BSWAP4(pmac->u[5]);
pmac->u[6] = BSWAP4(pmac->u[6]);
pmac->u[7] = BSWAP4(pmac->u[7]);
# else
for (i = 0; i < 8; i++) {
res = pmac->u[i];
pmac->c[4 * i + 0] = (unsigned char)(res >> 24);
pmac->c[4 * i + 1] = (unsigned char)(res >> 16);
pmac->c[4 * i + 2] = (unsigned char)(res >> 8);
pmac->c[4 * i + 3] = (unsigned char)res;
}
# endif /* BSWAP */
len += SHA256_DIGEST_LENGTH;
sctx->md = sctx->tail;
sha256_update(&sctx->md, pmac->c, SHA256_DIGEST_LENGTH);
SHA256_Final(pmac->c, &sctx->md);
/* verify HMAC */
out += inp_len;
len -= inp_len;
/* code containing lucky-13 fix */
{
unsigned char *p =
out + len - 1 - maxpad - SHA256_DIGEST_LENGTH;
size_t off = out - p;
unsigned int c, cmask;
maxpad += SHA256_DIGEST_LENGTH;
for (res = 0, i = 0, j = 0; j < maxpad; j++) {
c = p[j];
cmask =
((int)(j - off - SHA256_DIGEST_LENGTH)) >>
(sizeof(int) * 8 - 1);
res |= (c ^ pad) & ~cmask; /* ... and padding */
cmask &= ((int)(off - 1 - j)) >> (sizeof(int) * 8 - 1);
res |= (c ^ pmac->c[i]) & cmask;
i += 1 & cmask;
}
maxpad -= SHA256_DIGEST_LENGTH;
res = 0 - ((0 - res) >> (sizeof(res) * 8 - 1));
ret &= (int)~res;
}
return ret;
} else {
sha256_update(&sctx->md, out, len);
}
}
return 1;
}
/* EVP_CTRL_AEAD_SET_MAC_KEY */
static void aesni_cbc_hmac_sha256_set_mac_key(void *vctx,
const unsigned char *mackey,
size_t len)
{
PROV_AES_HMAC_SHA256_CTX *ctx = (PROV_AES_HMAC_SHA256_CTX *)vctx;
unsigned int i;
unsigned char hmac_key[64];
memset(hmac_key, 0, sizeof(hmac_key));
if (len > sizeof(hmac_key)) {
SHA256_Init(&ctx->head);
sha256_update(&ctx->head, mackey, len);
SHA256_Final(hmac_key, &ctx->head);
} else {
memcpy(hmac_key, mackey, len);
}
for (i = 0; i < sizeof(hmac_key); i++)
hmac_key[i] ^= 0x36; /* ipad */
SHA256_Init(&ctx->head);
sha256_update(&ctx->head, hmac_key, sizeof(hmac_key));
for (i = 0; i < sizeof(hmac_key); i++)
hmac_key[i] ^= 0x36 ^ 0x5c; /* opad */
SHA256_Init(&ctx->tail);
sha256_update(&ctx->tail, hmac_key, sizeof(hmac_key));
OPENSSL_cleanse(hmac_key, sizeof(hmac_key));
}
/* EVP_CTRL_AEAD_TLS1_AAD */
static int aesni_cbc_hmac_sha256_set_tls1_aad(void *vctx,
unsigned char *aad_rec, int aad_len)
{
PROV_AES_HMAC_SHA_CTX *ctx = (PROV_AES_HMAC_SHA_CTX *)vctx;
PROV_AES_HMAC_SHA256_CTX *sctx = (PROV_AES_HMAC_SHA256_CTX *)vctx;
unsigned char *p = aad_rec;
unsigned int len;
if (aad_len != EVP_AEAD_TLS1_AAD_LEN)
return -1;
len = p[aad_len - 2] << 8 | p[aad_len - 1];
if (ctx->base.enc) {
ctx->payload_length = len;
if ((ctx->aux.tls_ver =
p[aad_len - 4] << 8 | p[aad_len - 3]) >= TLS1_1_VERSION) {
if (len < AES_BLOCK_SIZE)
return 0;
len -= AES_BLOCK_SIZE;
p[aad_len] = len >> 8;
p[aad_len - 1] = len;
}
sctx->md = sctx->head;
sha256_update(&sctx->md, p, aad_len);
ctx->tls_aad_pad = (int)(((len + SHA256_DIGEST_LENGTH +
AES_BLOCK_SIZE) & -AES_BLOCK_SIZE)
- len);
return 1;
} else {
memcpy(ctx->aux.tls_aad, p, aad_len);
ctx->payload_length = aad_len;
ctx->tls_aad_pad = SHA256_DIGEST_LENGTH;
return 1;
}
}
# if !defined(OPENSSL_NO_MULTIBLOCK)
/* EVP_CTRL_TLS1_1_MULTIBLOCK_MAX_BUFSIZE */
static int aesni_cbc_hmac_sha256_tls1_multiblock_max_bufsize(
void *vctx)
{
PROV_AES_HMAC_SHA_CTX *ctx = (PROV_AES_HMAC_SHA_CTX *)vctx;
OPENSSL_assert(ctx->multiblock_max_send_fragment != 0);
return (int)(5 + 16
+ (((int)ctx->multiblock_max_send_fragment + 32 + 16) & -16));
}
/* EVP_CTRL_TLS1_1_MULTIBLOCK_AAD */
static int aesni_cbc_hmac_sha256_tls1_multiblock_aad(
void *vctx, EVP_CTRL_TLS1_1_MULTIBLOCK_PARAM *param)
{
PROV_AES_HMAC_SHA_CTX *ctx = (PROV_AES_HMAC_SHA_CTX *)vctx;
PROV_AES_HMAC_SHA256_CTX *sctx = (PROV_AES_HMAC_SHA256_CTX *)vctx;
unsigned int n4x = 1, x4;
unsigned int frag, last, packlen, inp_len;
inp_len = param->inp[11] << 8 | param->inp[12];
if (ctx->base.enc) {
if ((param->inp[9] << 8 | param->inp[10]) < TLS1_1_VERSION)
return -1;
if (inp_len) {
if (inp_len < 4096)
return 0; /* too short */
if (inp_len >= 8192 && OPENSSL_ia32cap_P[2] & (1 << 5))
n4x = 2; /* AVX2 */
} else if ((n4x = param->interleave / 4) && n4x <= 2)
inp_len = param->len;
else
return -1;
sctx->md = sctx->head;
sha256_update(&sctx->md, param->inp, 13);
x4 = 4 * n4x;
n4x += 1;
frag = inp_len >> n4x;
last = inp_len + frag - (frag << n4x);
if (last > frag && ((last + 13 + 9) % 64 < (x4 - 1))) {
frag++;
last -= x4 - 1;
}
packlen = 5 + 16 + ((frag + 32 + 16) & -16);
packlen = (packlen << n4x) - packlen;
packlen += 5 + 16 + ((last + 32 + 16) & -16);
param->interleave = x4;
/* The returned values used by get need to be stored */
ctx->multiblock_interleave = x4;
ctx->multiblock_aad_packlen = packlen;
return 1;
}
return -1; /* not yet */
}
/* EVP_CTRL_TLS1_1_MULTIBLOCK_ENCRYPT */
static int aesni_cbc_hmac_sha256_tls1_multiblock_encrypt(
void *ctx, EVP_CTRL_TLS1_1_MULTIBLOCK_PARAM *param)
{
return (int)tls1_multi_block_encrypt(ctx, param->out,
param->inp, param->len,
param->interleave / 4);
}
#endif
static const PROV_CIPHER_HW_AES_HMAC_SHA cipher_hw_aes_hmac_sha256 = {
{
aesni_cbc_hmac_sha256_init_key,
aesni_cbc_hmac_sha256_cipher
},
aesni_cbc_hmac_sha256_set_mac_key,
aesni_cbc_hmac_sha256_set_tls1_aad,
# if !defined(OPENSSL_NO_MULTIBLOCK)
aesni_cbc_hmac_sha256_tls1_multiblock_max_bufsize,
aesni_cbc_hmac_sha256_tls1_multiblock_aad,
aesni_cbc_hmac_sha256_tls1_multiblock_encrypt
# endif
};
const PROV_CIPHER_HW_AES_HMAC_SHA *PROV_CIPHER_HW_aes_cbc_hmac_sha256(void)
{
return &cipher_hw_aes_hmac_sha256;
}
#endif /* AES_CBC_HMAC_SHA_CAPABLE */
@@ -7,10 +7,16 @@
* https://www.openssl.org/source/license.html
*/
/*
* AES low level APIs are deprecated for public use, but still ok for internal
* use where we're using them to implement the higher level EVP interface, as is
* the case here.
*/
#include "internal/deprecated.h"
/* Dispatch functions for AES CCM mode */
#include "prov/ciphercommon.h"
#include "prov/cipher_ccm.h"
#include "cipher_aes_ccm.h"
#include "prov/implementations.h"
static void *aes_ccm_newctx(void *provctx, size_t keybits)
@@ -0,0 +1,48 @@
/*
* Copyright 2019 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
*/
#include <openssl/aes.h>
#include "prov/ciphercommon.h"
#include "prov/ciphercommon_ccm.h"
#include "crypto/aes_platform.h"
typedef struct prov_aes_ccm_ctx_st {
PROV_CCM_CTX base; /* Must be first */
union {
OSSL_UNION_ALIGN;
/*-
* Padding is chosen so that s390x.kmac.k overlaps with ks.ks and
* fc with ks.ks.rounds. Remember that on s390x, an AES_KEY's
* rounds field is used to store the function code and that the key
* schedule is not stored (if aes hardware support is detected).
*/
struct {
unsigned char pad[16];
AES_KEY ks;
} ks;
#if defined(OPENSSL_CPUID_OBJ) && defined(__s390__)
struct {
S390X_KMAC_PARAMS kmac;
unsigned long long blocks;
union {
unsigned long long g[2];
unsigned char b[AES_BLOCK_SIZE];
} nonce;
union {
unsigned long long g[2];
unsigned char b[AES_BLOCK_SIZE];
} buf;
unsigned char dummy_pad[168];
unsigned int fc; /* fc has same offset as ks.ks.rounds */
} s390x;
#endif /* defined(OPENSSL_CPUID_OBJ) && defined(__s390__) */
} ccm;
} PROV_AES_CCM_CTX;
const PROV_CCM_HW *PROV_AES_HW_ccm(size_t keylen);
@@ -9,8 +9,13 @@
/* AES CCM mode */
#include "prov/ciphercommon.h"
#include "prov/cipher_ccm.h"
/*
* This file uses the low level AES functions (which are deprecated for
* non-internal use) in order to implement provider AES ciphers.
*/
#include "internal/deprecated.h"
#include "cipher_aes_ccm.h"
#define AES_HW_CCM_SET_KEY_FN(fn_set_enc_key, fn_blk, fn_ccm_enc, fn_ccm_dec) \
fn_set_enc_key(key, keylen * 8, &actx->ccm.ks.ks); \
@@ -9,7 +9,7 @@
/*-
* AES-NI support for AES CCM.
* This file is included by cipher_ccm_hw.c
* This file is included by cipher_aes_ccm_hw.c
*/
static int ccm_aesni_initkey(PROV_CCM_CTX *ctx, const unsigned char *key,
@@ -9,7 +9,7 @@
/*-
* S390X support for AES CCM.
* This file is included by cipher_ccm_hw.c
* This file is included by cipher_aes_ccm_hw.c
*/
#define S390X_CCM_AAD_FLAG 0x40
@@ -9,7 +9,7 @@
/*-
* Fujitsu SPARC64 X support for AES CCM.
* This file is included by cipher_ccm_hw.c
* This file is included by cipher_aes_ccm_hw.c
*/
static int ccm_t4_aes_initkey(PROV_CCM_CTX *ctx, const unsigned char *key,
@@ -7,10 +7,16 @@
* https://www.openssl.org/source/license.html
*/
/*
* AES low level APIs are deprecated for public use, but still ok for internal
* use where we're using them to implement the higher level EVP interface, as is
* the case here.
*/
#include "internal/deprecated.h"
/* Dispatch functions for AES GCM mode */
#include "prov/ciphercommon.h"
#include "prov/cipher_gcm.h"
#include "cipher_aes_gcm.h"
#include "prov/implementations.h"
static void *aes_gcm_newctx(void *provctx, size_t keybits)
@@ -0,0 +1,44 @@
/*
* Copyright 2019 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
*/
#include <openssl/aes.h>
#include "prov/ciphercommon.h"
#include "prov/ciphercommon_gcm.h"
#include "crypto/aes_platform.h"
typedef struct prov_aes_gcm_ctx_st {
PROV_GCM_CTX base; /* must be first entry in struct */
union {
OSSL_UNION_ALIGN;
AES_KEY ks;
} ks; /* AES key schedule to use */
/* Platform specific data */
union {
int dummy;
#if defined(OPENSSL_CPUID_OBJ) && defined(__s390__)
struct {
union {
OSSL_UNION_ALIGN;
S390X_KMA_PARAMS kma;
} param;
unsigned int fc;
unsigned char ares[16];
unsigned char mres[16];
unsigned char kres[16];
int areslen;
int mreslen;
int kreslen;
int res;
} s390x;
#endif /* defined(OPENSSL_CPUID_OBJ) && defined(__s390__) */
} plat;
} PROV_AES_GCM_CTX;
const PROV_GCM_HW *PROV_AES_HW_gcm(size_t keybits);
@@ -9,10 +9,15 @@
/* Dispatch functions for AES GCM mode */
#include "prov/ciphercommon.h"
#include "prov/cipher_gcm.h"
/*
* This file uses the low level AES functions (which are deprecated for
* non-internal use) in order to implement provider AES ciphers.
*/
#include "internal/deprecated.h"
static int generic_aes_gcm_initkey(PROV_GCM_CTX *ctx, const unsigned char *key,
#include "cipher_aes_gcm.h"
static int aes_gcm_initkey(PROV_GCM_CTX *ctx, const unsigned char *key,
size_t keylen)
{
PROV_AES_GCM_CTX *actx = (PROV_AES_GCM_CTX *)ctx;
@@ -54,11 +59,76 @@ static int generic_aes_gcm_initkey(PROV_GCM_CTX *ctx, const unsigned char *key,
return 1;
}
static int generic_aes_gcm_cipher_update(PROV_GCM_CTX *ctx, const unsigned char *in,
size_t len, unsigned char *out)
{
if (ctx->enc) {
if (ctx->ctr != NULL) {
#if defined(AES_GCM_ASM)
size_t bulk = 0;
if (len >= AES_GCM_ENC_BYTES && AES_GCM_ASM(ctx)) {
size_t res = (16 - ctx->gcm.mres) % 16;
if (CRYPTO_gcm128_encrypt(&ctx->gcm, in, out, res))
return 0;
bulk = AES_gcm_encrypt(in + res, out + res, len - res,
ctx->gcm.key,
ctx->gcm.Yi.c, ctx->gcm.Xi.u);
ctx->gcm.len.u[1] += bulk;
bulk += res;
}
if (CRYPTO_gcm128_encrypt_ctr32(&ctx->gcm, in + bulk, out + bulk,
len - bulk, ctx->ctr))
return 0;
#else
if (CRYPTO_gcm128_encrypt_ctr32(&ctx->gcm, in, out, len, ctx->ctr))
return 0;
#endif /* AES_GCM_ASM */
} else {
if (CRYPTO_gcm128_encrypt(&ctx->gcm, in, out, len))
return 0;
}
} else {
if (ctx->ctr != NULL) {
#if defined(AES_GCM_ASM)
size_t bulk = 0;
if (len >= AES_GCM_DEC_BYTES && AES_GCM_ASM(ctx)) {
size_t res = (16 - ctx->gcm.mres) % 16;
if (CRYPTO_gcm128_decrypt(&ctx->gcm, in, out, res))
return -1;
bulk = AES_gcm_decrypt(in + res, out + res, len - res,
ctx->gcm.key,
ctx->gcm.Yi.c, ctx->gcm.Xi.u);
ctx->gcm.len.u[1] += bulk;
bulk += res;
}
if (CRYPTO_gcm128_decrypt_ctr32(&ctx->gcm, in + bulk, out + bulk,
len - bulk, ctx->ctr))
return 0;
#else
if (CRYPTO_gcm128_decrypt_ctr32(&ctx->gcm, in, out, len, ctx->ctr))
return 0;
#endif /* AES_GCM_ASM */
} else {
if (CRYPTO_gcm128_decrypt(&ctx->gcm, in, out, len))
return 0;
}
}
return 1;
}
static const PROV_GCM_HW aes_gcm = {
generic_aes_gcm_initkey,
aes_gcm_initkey,
gcm_setiv,
gcm_aad_update,
gcm_cipher_update,
generic_aes_gcm_cipher_update,
gcm_cipher_final,
gcm_one_shot
};
@@ -69,6 +139,8 @@ static const PROV_GCM_HW aes_gcm = {
# include "cipher_aes_gcm_hw_aesni.inc"
#elif defined(SPARC_AES_CAPABLE)
# include "cipher_aes_gcm_hw_t4.inc"
#elif defined(AES_PMULL_CAPABLE) && defined(AES_GCM_ASM)
# include "cipher_aes_gcm_hw_armv8.inc"
#else
const PROV_GCM_HW *PROV_AES_HW_gcm(size_t keybits)
{
@@ -9,7 +9,7 @@
/*-
* AES-NI support for AES GCM.
* This file is included by cipher_gcm_hw.c
* This file is included by cipher_aes_gcm_hw.c
*/
static int aesni_gcm_initkey(PROV_GCM_CTX *ctx, const unsigned char *key,
@@ -26,7 +26,7 @@ static const PROV_GCM_HW aesni_gcm = {
aesni_gcm_initkey,
gcm_setiv,
gcm_aad_update,
gcm_cipher_update,
generic_aes_gcm_cipher_update,
gcm_cipher_final,
gcm_one_shot
};
@@ -0,0 +1,83 @@
/*
* Copyright 2019 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
*/
/*
* Crypto extention support for AES GCM.
* This file is included by cipher_aes_gcm_hw.c
*/
size_t armv8_aes_gcm_encrypt(const unsigned char *in, unsigned char *out, size_t len,
const void *key, unsigned char ivec[16], u64 *Xi)
{
size_t align_bytes = 0;
align_bytes = len - len % 16;
AES_KEY *aes_key = (AES_KEY *)key;
switch(aes_key->rounds) {
case 10:
aes_gcm_enc_128_kernel(in, align_bytes * 8, out, (uint64_t *)Xi, ivec, key);
break;
case 12:
aes_gcm_enc_192_kernel(in, align_bytes * 8, out, (uint64_t *)Xi, ivec, key);
break;
case 14:
aes_gcm_enc_256_kernel(in, align_bytes * 8, out, (uint64_t *)Xi, ivec, key);
break;
}
return align_bytes;
}
size_t armv8_aes_gcm_decrypt(const unsigned char *in, unsigned char *out, size_t len,
const void *key, unsigned char ivec[16], u64 *Xi)
{
size_t align_bytes = 0;
align_bytes = len - len % 16;
AES_KEY *aes_key = (AES_KEY *)key;
switch(aes_key->rounds) {
case 10:
aes_gcm_dec_128_kernel(in, align_bytes * 8, out, (uint64_t *)Xi, ivec, key);
break;
case 12:
aes_gcm_dec_192_kernel(in, align_bytes * 8, out, (uint64_t *)Xi, ivec, key);
break;
case 14:
aes_gcm_dec_256_kernel(in, align_bytes * 8, out, (uint64_t *)Xi, ivec, key);
break;
}
return align_bytes;
}
static int armv8_aes_gcm_initkey(PROV_GCM_CTX *ctx, const unsigned char *key,
size_t keylen)
{
PROV_AES_GCM_CTX *actx = (PROV_AES_GCM_CTX *)ctx;
AES_KEY *ks = &actx->ks.ks;
GCM_HW_SET_KEY_CTR_FN(ks, aes_v8_set_encrypt_key, aes_v8_encrypt,
aes_v8_ctr32_encrypt_blocks);
return 1;
}
static const PROV_GCM_HW armv8_aes_gcm = {
armv8_aes_gcm_initkey,
gcm_setiv,
gcm_aad_update,
generic_aes_gcm_cipher_update,
gcm_cipher_final,
gcm_one_shot
};
const PROV_GCM_HW *PROV_AES_HW_gcm(size_t keybits)
{
return AES_PMULL_CAPABLE ? &armv8_aes_gcm : &aes_gcm;
}
@@ -9,7 +9,7 @@
/*-
* IBM S390X support for AES GCM.
* This file is included by cipher_gcm_hw.c
* This file is included by cipher_aes_gcm_hw.c
*/
/* iv + padding length for iv lengths != 12 */
@@ -9,7 +9,7 @@
/*-
* Fujitsu SPARC64 X support for AES GCM.
* This file is included by cipher_gcm_hw.c
* This file is included by cipher_aes_gcm_hw.c
*/
static int t4_aes_gcm_initkey(PROV_GCM_CTX *ctx, const unsigned char *key,
@@ -42,7 +42,7 @@ static const PROV_GCM_HW t4_aes_gcm = {
t4_aes_gcm_initkey,
gcm_setiv,
gcm_aad_update,
gcm_cipher_update,
generic_aes_gcm_cipher_update,
gcm_cipher_final,
gcm_one_shot
};
@@ -7,6 +7,12 @@
* https://www.openssl.org/source/license.html
*/
/*
* This file uses the low level AES functions (which are deprecated for
* non-internal use) in order to implement provider AES ciphers.
*/
#include "internal/deprecated.h"
#include "cipher_aes.h"
#include "prov/providercommonerr.h"
@@ -29,6 +35,10 @@ static int cipher_hw_aes_initkey(PROV_CIPHER_CTX *dat,
# ifdef HWAES_cbc_encrypt
if (dat->mode == EVP_CIPH_CBC_MODE)
dat->stream.cbc = (cbc128_f)HWAES_cbc_encrypt;
# endif
# ifdef HWAES_ecb_encrypt
if (dat->mode == EVP_CIPH_ECB_MODE)
dat->stream.ecb = (ecb128_f)HWAES_ecb_encrypt;
# endif
} else
#endif
@@ -64,6 +74,11 @@ static int cipher_hw_aes_initkey(PROV_CIPHER_CTX *dat,
dat->stream.cbc = (cbc128_f)HWAES_cbc_encrypt;
else
# endif
# ifdef HWAES_ecb_encrypt
if (dat->mode == EVP_CIPH_ECB_MODE)
dat->stream.ecb = (ecb128_f)HWAES_ecb_encrypt;
else
# endif
# ifdef HWAES_ctr32_encrypt_blocks
if (dat->mode == EVP_CIPH_CTR_MODE)
dat->stream.ctr = (ctr128_f)HWAES_ctr32_encrypt_blocks;
@@ -106,10 +121,13 @@ static int cipher_hw_aes_initkey(PROV_CIPHER_CTX *dat,
return 1;
}
IMPLEMENT_CIPHER_HW_COPYCTX(cipher_hw_aes_copyctx, PROV_AES_CTX)
#define PROV_CIPHER_HW_aes_mode(mode) \
static const PROV_CIPHER_HW aes_##mode = { \
cipher_hw_aes_initkey, \
cipher_hw_generic_##mode \
cipher_hw_generic_##mode, \
cipher_hw_aes_copyctx \
}; \
PROV_CIPHER_HW_declare(mode) \
const PROV_CIPHER_HW *PROV_CIPHER_HW_aes_##mode(size_t keybits) \
@@ -76,7 +76,8 @@ static int cipher_hw_aesni_ecb(PROV_CIPHER_CTX *ctx, unsigned char *out,
#define PROV_CIPHER_HW_declare(mode) \
static const PROV_CIPHER_HW aesni_##mode = { \
cipher_hw_aesni_initkey, \
cipher_hw_aesni_##mode \
cipher_hw_aesni_##mode, \
cipher_hw_aes_copyctx \
};
#define PROV_CIPHER_HW_select(mode) \
if (AESNI_CAPABLE) \
@@ -193,7 +193,8 @@ static int s390x_aes_cfb8_cipher_hw(PROV_CIPHER_CTX *dat, unsigned char *out,
#define PROV_CIPHER_HW_declare(mode) \
static const PROV_CIPHER_HW s390x_aes_##mode = { \
s390x_aes_##mode##_initkey, \
s390x_aes_##mode##_cipher_hw \
s390x_aes_##mode##_cipher_hw, \
cipher_hw_aes_copyctx \
};
#define PROV_CIPHER_HW_select(mode) \
if ((keybits == 128 && S390X_aes_128_##mode##_CAPABLE) \
@@ -88,7 +88,8 @@ static int cipher_hw_aes_t4_initkey(PROV_CIPHER_CTX *dat,
#define PROV_CIPHER_HW_declare(mode) \
static const PROV_CIPHER_HW aes_t4_##mode = { \
cipher_hw_aes_t4_initkey, \
cipher_hw_generic_##mode \
cipher_hw_generic_##mode, \
cipher_hw_aes_copyctx \
};
#define PROV_CIPHER_HW_select(mode) \
if (SPARC_AES_CAPABLE) \
@@ -7,9 +7,16 @@
* https://www.openssl.org/source/license.html
*/
/*
* AES low level APIs are deprecated for public use, but still ok for internal
* use where we're using them to implement the higher level EVP interface, as is
* the case here.
*/
#include "internal/deprecated.h"
#include "cipher_aes_ocb.h"
#include "prov/providercommonerr.h"
#include "prov/cipher_aead.h"
#include "prov/ciphercommon_aead.h"
#include "prov/implementations.h"
#define AES_OCB_FLAGS AEAD_FLAGS
@@ -84,8 +91,8 @@ static ossl_inline int aes_generic_ocb_cipher(PROV_AES_OCB_CTX *ctx,
static ossl_inline int aes_generic_ocb_copy_ctx(PROV_AES_OCB_CTX *dst,
PROV_AES_OCB_CTX *src)
{
return (!CRYPTO_ocb128_copy_ctx(&dst->ocb, &src->ocb,
&src->ksenc.ks, &src->ksdec.ks));
return CRYPTO_ocb128_copy_ctx(&dst->ocb, &src->ocb,
&dst->ksenc.ks, &dst->ksdec.ks);
}
/*-
@@ -214,6 +221,11 @@ static int aes_ocb_block_update(void *vctx, unsigned char *out, size_t *outl,
if (!ctx->key_set || !update_iv(ctx))
return 0;
if (inl == 0) {
*outl = 0;
return 1;
}
/* Are we dealing with AAD or normal data here? */
if (out == NULL) {
buf = ctx->aad_buf;
@@ -9,6 +9,7 @@
#include <openssl/aes.h>
#include "prov/ciphercommon.h"
#include "crypto/aes_platform.h"
#define OCB_MAX_TAG_LEN AES_BLOCK_SIZE
#define OCB_MAX_DATA_LEN AES_BLOCK_SIZE
@@ -7,6 +7,12 @@
* https://www.openssl.org/source/license.html
*/
/*
* This file uses the low level AES functions (which are deprecated for
* non-internal use) in order to implement provider AES ciphers.
*/
#include "internal/deprecated.h"
#include "cipher_aes_ocb.h"
#define OCB_SET_KEY_FN(fn_set_enc_key, fn_set_dec_key, \
@@ -0,0 +1,244 @@
/*
* Copyright 2019 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
*/
/* Dispatch functions for AES SIV mode */
/*
* This file uses the low level AES functions (which are deprecated for
* non-internal use) in order to implement provider AES ciphers.
*/
#include "internal/deprecated.h"
#include "cipher_aes_siv.h"
#include "prov/implementations.h"
#include "prov/providercommonerr.h"
#include "prov/ciphercommon_aead.h"
#define siv_stream_update siv_cipher
#define SIV_FLAGS AEAD_FLAGS
static void *aes_siv_newctx(void *provctx, size_t keybits, unsigned int mode,
uint64_t flags)
{
PROV_AES_SIV_CTX *ctx = OPENSSL_zalloc(sizeof(*ctx));
if (ctx != NULL) {
ctx->taglen = SIV_LEN;
ctx->mode = mode;
ctx->flags = flags;
ctx->keylen = keybits / 8;
ctx->hw = PROV_CIPHER_HW_aes_siv(keybits);
}
return ctx;
}
static void aes_siv_freectx(void *vctx)
{
PROV_AES_SIV_CTX *ctx = (PROV_AES_SIV_CTX *)vctx;
if (ctx != NULL) {
ctx->hw->cleanup(ctx);
OPENSSL_clear_free(ctx, sizeof(*ctx));
}
}
static int siv_init(void *vctx, const unsigned char *key, size_t keylen,
const unsigned char *iv, size_t ivlen, int enc)
{
PROV_AES_SIV_CTX *ctx = (PROV_AES_SIV_CTX *)vctx;
ctx->enc = enc;
if (key != NULL) {
if (keylen != ctx->keylen) {
ERR_raise(ERR_LIB_PROV, PROV_R_INVALID_KEY_LENGTH);
return 0;
}
return ctx->hw->initkey(ctx, key, ctx->keylen);
}
return 1;
}
static int siv_einit(void *vctx, const unsigned char *key, size_t keylen,
const unsigned char *iv, size_t ivlen)
{
return siv_init(vctx, key, keylen, iv, ivlen, 1);
}
static int siv_dinit(void *vctx, const unsigned char *key, size_t keylen,
const unsigned char *iv, size_t ivlen)
{
return siv_init(vctx, key, keylen, iv, ivlen, 0);
}
static int siv_cipher(void *vctx, unsigned char *out, size_t *outl,
size_t outsize, const unsigned char *in, size_t inl)
{
PROV_AES_SIV_CTX *ctx = (PROV_AES_SIV_CTX *)vctx;
if (inl == 0) {
*outl = 0;
return 1;
}
if (outsize < inl) {
ERR_raise(ERR_LIB_PROV, PROV_R_OUTPUT_BUFFER_TOO_SMALL);
return 0;
}
if (ctx->hw->cipher(ctx, out, in, inl) <= 0)
return 0;
if (outl != NULL)
*outl = inl;
return 1;
}
static int siv_stream_final(void *vctx, unsigned char *out, size_t *outl,
size_t outsize)
{
PROV_AES_SIV_CTX *ctx = (PROV_AES_SIV_CTX *)vctx;
if (!ctx->hw->cipher(vctx, out, NULL, 0))
return 0;
if (outl != NULL)
*outl = 0;
return 1;
}
static int aes_siv_get_ctx_params(void *vctx, OSSL_PARAM params[])
{
PROV_AES_SIV_CTX *ctx = (PROV_AES_SIV_CTX *)vctx;
SIV128_CONTEXT *sctx = &ctx->siv;
OSSL_PARAM *p;
p = OSSL_PARAM_locate(params, OSSL_CIPHER_PARAM_AEAD_TAG);
if (p != NULL && p->data_type == OSSL_PARAM_OCTET_STRING) {
if (!ctx->enc
|| p->data_size != ctx->taglen
|| !OSSL_PARAM_set_octet_string(p, &sctx->tag.byte, ctx->taglen)) {
ERR_raise(ERR_LIB_PROV, PROV_R_FAILED_TO_SET_PARAMETER);
return 0;
}
}
p = OSSL_PARAM_locate(params, OSSL_CIPHER_PARAM_AEAD_TAGLEN);
if (p != NULL && !OSSL_PARAM_set_size_t(p, ctx->taglen)) {
ERR_raise(ERR_LIB_PROV, PROV_R_FAILED_TO_SET_PARAMETER);
return 0;
}
p = OSSL_PARAM_locate(params, OSSL_CIPHER_PARAM_KEYLEN);
if (p != NULL && !OSSL_PARAM_set_size_t(p, ctx->keylen)) {
ERR_raise(ERR_LIB_PROV, PROV_R_FAILED_TO_SET_PARAMETER);
return 0;
}
return 1;
}
static const OSSL_PARAM aes_siv_known_gettable_ctx_params[] = {
OSSL_PARAM_size_t(OSSL_CIPHER_PARAM_KEYLEN, NULL),
OSSL_PARAM_size_t(OSSL_CIPHER_PARAM_AEAD_TAGLEN, NULL),
OSSL_PARAM_uint(OSSL_CIPHER_PARAM_SPEED, NULL),
OSSL_PARAM_octet_string(OSSL_CIPHER_PARAM_AEAD_TAG, NULL, 0),
OSSL_PARAM_END
};
static const OSSL_PARAM *aes_siv_gettable_ctx_params(void)
{
return aes_siv_known_gettable_ctx_params;
}
static int aes_siv_set_ctx_params(void *vctx, const OSSL_PARAM params[])
{
PROV_AES_SIV_CTX *ctx = (PROV_AES_SIV_CTX *)vctx;
const OSSL_PARAM *p;
unsigned int speed = 0;
p = OSSL_PARAM_locate_const(params, OSSL_CIPHER_PARAM_AEAD_TAG);
if (p != NULL) {
if (ctx->enc)
return 1;
if (p->data_type != OSSL_PARAM_OCTET_STRING
|| !ctx->hw->settag(ctx, p->data, p->data_size)) {
ERR_raise(ERR_LIB_PROV, PROV_R_FAILED_TO_GET_PARAMETER);
return 0;
}
}
p = OSSL_PARAM_locate_const(params, OSSL_CIPHER_PARAM_SPEED);
if (p != NULL) {
if (!OSSL_PARAM_get_uint(p, &speed)) {
ERR_raise(ERR_LIB_PROV, PROV_R_FAILED_TO_GET_PARAMETER);
return 0;
}
ctx->hw->setspeed(ctx, (int)speed);
}
p = OSSL_PARAM_locate_const(params, OSSL_CIPHER_PARAM_KEYLEN);
if (p != NULL) {
size_t keylen;
if (!OSSL_PARAM_get_size_t(p, &keylen)) {
ERR_raise(ERR_LIB_PROV, PROV_R_FAILED_TO_GET_PARAMETER);
return 0;
}
/* The key length can not be modified */
if (keylen != ctx->keylen)
return 0;
}
return 1;
}
static const OSSL_PARAM aes_siv_known_settable_ctx_params[] = {
OSSL_PARAM_size_t(OSSL_CIPHER_PARAM_KEYLEN, NULL),
OSSL_PARAM_uint(OSSL_CIPHER_PARAM_SPEED, NULL),
OSSL_PARAM_octet_string(OSSL_CIPHER_PARAM_AEAD_TAG, NULL, 0),
OSSL_PARAM_END
};
static const OSSL_PARAM *aes_siv_settable_ctx_params(void)
{
return aes_siv_known_settable_ctx_params;
}
#define IMPLEMENT_cipher(alg, lc, UCMODE, flags, kbits, blkbits, ivbits) \
static OSSL_OP_cipher_get_params_fn alg##_##kbits##_##lc##_get_params; \
static int alg##_##kbits##_##lc##_get_params(OSSL_PARAM params[]) \
{ \
return cipher_generic_get_params(params, EVP_CIPH_##UCMODE##_MODE, \
flags, 2*kbits, blkbits, ivbits); \
} \
static OSSL_OP_cipher_newctx_fn alg##kbits##lc##_newctx; \
static void * alg##kbits##lc##_newctx(void *provctx) \
{ \
return alg##_##lc##_newctx(provctx, 2*kbits, EVP_CIPH_##UCMODE##_MODE, \
flags); \
} \
const OSSL_DISPATCH alg##kbits##lc##_functions[] = { \
{ OSSL_FUNC_CIPHER_NEWCTX, (void (*)(void))alg##kbits##lc##_newctx }, \
{ OSSL_FUNC_CIPHER_FREECTX, (void (*)(void))alg##_##lc##_freectx }, \
{ OSSL_FUNC_CIPHER_ENCRYPT_INIT, (void (*)(void)) lc##_einit }, \
{ OSSL_FUNC_CIPHER_DECRYPT_INIT, (void (*)(void)) lc##_dinit }, \
{ OSSL_FUNC_CIPHER_UPDATE, (void (*)(void)) lc##_stream_update }, \
{ OSSL_FUNC_CIPHER_FINAL, (void (*)(void)) lc##_stream_final }, \
{ OSSL_FUNC_CIPHER_CIPHER, (void (*)(void)) lc##_cipher }, \
{ OSSL_FUNC_CIPHER_GET_PARAMS, \
(void (*)(void)) alg##_##kbits##_##lc##_get_params }, \
{ OSSL_FUNC_CIPHER_GETTABLE_PARAMS, \
(void (*)(void))cipher_generic_gettable_params }, \
{ OSSL_FUNC_CIPHER_GET_CTX_PARAMS, \
(void (*)(void)) alg##_##lc##_get_ctx_params }, \
{ OSSL_FUNC_CIPHER_GETTABLE_CTX_PARAMS, \
(void (*)(void)) alg##_##lc##_gettable_ctx_params }, \
{ OSSL_FUNC_CIPHER_SET_CTX_PARAMS, \
(void (*)(void)) alg##_##lc##_set_ctx_params }, \
{ OSSL_FUNC_CIPHER_SETTABLE_CTX_PARAMS, \
(void (*)(void)) alg##_##lc##_settable_ctx_params }, \
{ 0, NULL } \
};
IMPLEMENT_cipher(aes, siv, SIV, SIV_FLAGS, 128, 8, 0)
IMPLEMENT_cipher(aes, siv, SIV, SIV_FLAGS, 192, 8, 0)
IMPLEMENT_cipher(aes, siv, SIV, SIV_FLAGS, 256, 8, 0)
@@ -0,0 +1,35 @@
/*
* Copyright 2019 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
*/
#include "prov/ciphercommon.h"
#include "crypto/aes_platform.h"
#include "crypto/siv.h"
typedef struct prov_cipher_hw_aes_siv_st {
int (*initkey)(void *ctx, const uint8_t *key, size_t keylen);
int (*cipher)(void *ctx, unsigned char *out, const unsigned char *in,
size_t len);
void (*setspeed)(void *ctx, int speed);
int (*settag)(void *ctx, const unsigned char *tag, size_t tagl);
void (*cleanup)(void *ctx);
} PROV_CIPHER_HW_AES_SIV;
typedef struct prov_siv_ctx_st {
unsigned int mode; /* The mode that we are using */
unsigned int enc : 1; /* Set to 1 if we are encrypting or 0 otherwise */
uint64_t flags;
size_t keylen; /* The input keylength (twice the alg key length) */
size_t taglen; /* the taglen is the same as the sivlen */
SIV128_CONTEXT siv;
EVP_CIPHER *ctr; /* These are fetched - so we need to free them */
EVP_CIPHER *cbc;
const PROV_CIPHER_HW_AES_SIV *hw;
} PROV_AES_SIV_CTX;
const PROV_CIPHER_HW_AES_SIV *PROV_CIPHER_HW_aes_siv(size_t keybits);
@@ -0,0 +1,105 @@
/*
* Copyright 2019 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
*/
/*
* This file uses the low level AES functions (which are deprecated for
* non-internal use) in order to implement provider AES ciphers.
*/
#include "internal/deprecated.h"
#include "cipher_aes_siv.h"
static int aes_siv_initkey(void *vctx, const unsigned char *key, size_t keylen)
{
PROV_AES_SIV_CTX *ctx = (PROV_AES_SIV_CTX *)vctx;
SIV128_CONTEXT *sctx = &ctx->siv;
size_t klen = keylen / 2;
switch (klen) {
case 16:
ctx->cbc = EVP_CIPHER_fetch(NULL, "AES-128-CBC", "");
ctx->ctr = EVP_CIPHER_fetch(NULL, "AES-128-CTR", "");
break;
case 24:
ctx->cbc = EVP_CIPHER_fetch(NULL, "AES-192-CBC", "");
ctx->ctr = EVP_CIPHER_fetch(NULL, "AES-192-CTR", "");
break;
case 32:
ctx->cbc = EVP_CIPHER_fetch(NULL, "AES-256-CBC", "");
ctx->ctr = EVP_CIPHER_fetch(NULL, "AES-256-CTR", "");
break;
default:
return 0;
}
/*
* klen is the length of the underlying cipher, not the input key,
* which should be twice as long
*/
return CRYPTO_siv128_init(sctx, key, klen, ctx->cbc, ctx->ctr);
}
static int aes_siv_settag(void *vctx, const unsigned char *tag, size_t tagl)
{
PROV_AES_SIV_CTX *ctx = (PROV_AES_SIV_CTX *)vctx;
SIV128_CONTEXT *sctx = &ctx->siv;
return CRYPTO_siv128_set_tag(sctx, tag, tagl);
}
static void aes_siv_setspeed(void *vctx, int speed)
{
PROV_AES_SIV_CTX *ctx = (PROV_AES_SIV_CTX *)vctx;
SIV128_CONTEXT *sctx = &ctx->siv;
CRYPTO_siv128_speed(sctx, (int)speed);
}
static void aes_siv_cleanup(void *vctx)
{
PROV_AES_SIV_CTX *ctx = (PROV_AES_SIV_CTX *)vctx;
SIV128_CONTEXT *sctx = &ctx->siv;
CRYPTO_siv128_cleanup(sctx);
EVP_CIPHER_free(ctx->cbc);
EVP_CIPHER_free(ctx->ctr);
}
static int aes_siv_cipher(void *vctx, unsigned char *out,
const unsigned char *in, size_t len)
{
PROV_AES_SIV_CTX *ctx = (PROV_AES_SIV_CTX *)vctx;
SIV128_CONTEXT *sctx = &ctx->siv;
/* EncryptFinal or DecryptFinal */
if (in == NULL)
return CRYPTO_siv128_finish(sctx) == 0;
/* Deal with associated data */
if (out == NULL)
return (CRYPTO_siv128_aad(sctx, in, len) == 1);
if (ctx->enc)
return CRYPTO_siv128_encrypt(sctx, in, out, len) > 0;
return CRYPTO_siv128_decrypt(sctx, in, out, len) > 0;
}
static const PROV_CIPHER_HW_AES_SIV aes_siv_hw =
{
aes_siv_initkey,
aes_siv_cipher,
aes_siv_setspeed,
aes_siv_settag,
aes_siv_cleanup
};
const PROV_CIPHER_HW_AES_SIV *PROV_CIPHER_HW_aes_siv(size_t keybits)
{
return &aes_siv_hw;
}
@@ -7,6 +7,12 @@
* https://www.openssl.org/source/license.html
*/
/*
* This file uses the low level AES functions (which are deprecated for
* non-internal use) in order to implement provider AES ciphers.
*/
#include "internal/deprecated.h"
#include "cipher_aes.h"
#include "prov/providercommonerr.h"
#include "prov/implementations.h"
@@ -164,6 +170,11 @@ static int aes_wrap_cipher(void *vctx,
PROV_AES_WRAP_CTX *ctx = (PROV_AES_WRAP_CTX *)vctx;
size_t len;
if (inl == 0) {
*outl = 0;
return 1;
}
if (outsize < inl) {
ERR_raise(ERR_LIB_PROV, PROV_R_OUTPUT_BUFFER_TOO_SMALL);
return -1;
@@ -7,6 +7,13 @@
* https://www.openssl.org/source/license.html
*/
/*
* AES low level APIs are deprecated for public use, but still ok for internal
* use where we're using them to implement the higher level EVP interface, as is
* the case here.
*/
#include "internal/deprecated.h"
#include "cipher_aes_xts.h"
#include "prov/implementations.h"
#include "prov/providercommonerr.h"
@@ -134,7 +141,7 @@ static void *aes_xts_dupctx(void *vctx)
ERR_raise(ERR_LIB_PROV, ERR_R_MALLOC_FAILURE);
return NULL;
}
*ret = *in;
in->base.hw->copyctx(&ret->base, &in->base);
return ret;
}
@@ -152,7 +159,7 @@ static int aes_xts_cipher(void *vctx, unsigned char *out, size_t *outl,
return 0;
/*
* Impose a limit of 2^20 blocks per data unit as specifed by
* Impose a limit of 2^20 blocks per data unit as specified by
* IEEE Std 1619-2018. The earlier and obsolete IEEE Std 1619-2007
* indicated that this was a SHOULD NOT rather than a MUST NOT.
* NIST SP 800-38E mandates the same limit.
@@ -9,6 +9,7 @@
#include <openssl/aes.h>
#include "prov/ciphercommon.h"
#include "crypto/aes_platform.h"
/*
* Available in cipher_fips.c, and compiled with different values depending
@@ -7,6 +7,13 @@
* https://www.openssl.org/source/license.html
*/
/*
* AES low level APIs are deprecated for public use, but still ok for internal
* use where we're using them to implement the higher level EVP interface, as is
* the case here.
*/
#include "internal/deprecated.h"
#include "cipher_aes_xts.h"
#ifdef FIPS_MODE
@@ -7,6 +7,12 @@
* https://www.openssl.org/source/license.html
*/
/*
* This file uses the low level AES functions (which are deprecated for
* non-internal use) in order to implement provider AES ciphers.
*/
#include "internal/deprecated.h"
#include "cipher_aes_xts.h"
#define XTS_SET_KEY_FN(fn_set_enc_key, fn_set_dec_key, \
@@ -76,6 +82,17 @@ static int cipher_hw_aes_xts_generic_initkey(PROV_CIPHER_CTX *ctx,
return 1;
}
static void cipher_hw_aes_xts_copyctx(PROV_CIPHER_CTX *dst,
const PROV_CIPHER_CTX *src)
{
PROV_AES_XTS_CTX *sctx = (PROV_AES_XTS_CTX *)src;
PROV_AES_XTS_CTX *dctx = (PROV_AES_XTS_CTX *)dst;
*dctx = *sctx;
dctx->xts.key1 = &dctx->ks1.ks;
dctx->xts.key2 = &dctx->ks2.ks;
}
#if defined(AESNI_CAPABLE)
static int cipher_hw_aesni_xts_initkey(PROV_CIPHER_CTX *ctx,
@@ -92,7 +109,8 @@ static int cipher_hw_aesni_xts_initkey(PROV_CIPHER_CTX *ctx,
# define PROV_CIPHER_HW_declare_xts() \
static const PROV_CIPHER_HW aesni_xts = { \
cipher_hw_aesni_xts_initkey, \
NULL \
NULL, \
cipher_hw_aes_xts_copyctx \
};
# define PROV_CIPHER_HW_select_xts() \
if (AESNI_CAPABLE) \
@@ -130,7 +148,8 @@ static int cipher_hw_aes_xts_t4_initkey(PROV_CIPHER_CTX *ctx,
# define PROV_CIPHER_HW_declare_xts() \
static const PROV_CIPHER_HW aes_xts_t4 = { \
cipher_hw_aes_xts_t4_initkey, \
NULL \
NULL, \
cipher_hw_aes_xts_copyctx \
};
# define PROV_CIPHER_HW_select_xts() \
if (SPARC_AES_CAPABLE) \
@@ -143,7 +162,8 @@ if (SPARC_AES_CAPABLE) \
static const PROV_CIPHER_HW aes_generic_xts = {
cipher_hw_aes_xts_generic_initkey,
NULL
NULL,
cipher_hw_aes_xts_copyctx
};
PROV_CIPHER_HW_declare_xts()
const PROV_CIPHER_HW *PROV_CIPHER_HW_aes_xts(size_t keybits)
@@ -31,7 +31,7 @@ static void *aria_dupctx(void *ctx)
ERR_raise(ERR_LIB_PROV, ERR_R_MALLOC_FAILURE);
return NULL;
}
*ret = *in;
in->base.hw->copyctx(&ret->base, &in->base);
return ret;
}
@@ -9,7 +9,7 @@
#include "crypto/aria.h"
#include "prov/ciphercommon.h"
#include "prov/cipher_ccm.h"
#include "prov/ciphercommon_ccm.h"
typedef struct prov_aria_ccm_ctx_st {
PROV_CCM_CTX base; /* Must be first */
@@ -9,7 +9,7 @@
#include "crypto/aria.h"
#include "prov/ciphercommon.h"
#include "prov/cipher_gcm.h"
#include "prov/ciphercommon_gcm.h"
typedef struct prov_aria_gcm_ctx_st {
PROV_GCM_CTX base; /* must be first entry in struct */
@@ -23,24 +23,11 @@ static int aria_gcm_initkey(PROV_GCM_CTX *ctx, const unsigned char *key,
return 1;
}
static int aria_cipher_update(PROV_GCM_CTX *ctx, const unsigned char *in,
size_t len, unsigned char *out)
{
if (ctx->enc) {
if (CRYPTO_gcm128_encrypt(&ctx->gcm, in, out, len))
return 0;
} else {
if (CRYPTO_gcm128_decrypt(&ctx->gcm, in, out, len))
return 0;
}
return 1;
}
static const PROV_GCM_HW aria_gcm = {
aria_gcm_initkey,
gcm_setiv,
gcm_aad_update,
aria_cipher_update,
gcm_cipher_update,
gcm_cipher_final,
gcm_one_shot
};
@@ -29,10 +29,13 @@ static int cipher_hw_aria_initkey(PROV_CIPHER_CTX *dat,
return 1;
}
IMPLEMENT_CIPHER_HW_COPYCTX(cipher_hw_aria_copyctx, PROV_ARIA_CTX)
# define PROV_CIPHER_HW_aria_mode(mode) \
static const PROV_CIPHER_HW aria_##mode = { \
cipher_hw_aria_initkey, \
cipher_hw_chunked_##mode \
cipher_hw_chunked_##mode, \
cipher_hw_aria_copyctx \
}; \
const PROV_CIPHER_HW *PROV_CIPHER_HW_aria_##mode(size_t keybits) \
{ \
@@ -9,6 +9,12 @@
/* Dispatch functions for Blowfish cipher modes ecb, cbc, ofb, cfb */
/*
* BF low level APIs are deprecated for public use, but still ok for internal
* use.
*/
#include "internal/deprecated.h"
#include "cipher_blowfish.h"
#include "prov/implementations.h"
@@ -39,10 +45,10 @@ static void *blowfish_dupctx(void *ctx)
}
/* bf_ecb_functions */
IMPLEMENT_generic_cipher(blowfish, BLOWFISH, ecb, ECB, BF_FLAGS, 128, 64, 0, block)
IMPLEMENT_var_keylen_cipher(blowfish, BLOWFISH, ecb, ECB, BF_FLAGS, 128, 64, 0, block)
/* bf_cbc_functions */
IMPLEMENT_generic_cipher(blowfish, BLOWFISH, cbc, CBC, BF_FLAGS, 128, 64, 64, block)
IMPLEMENT_var_keylen_cipher(blowfish, BLOWFISH, cbc, CBC, BF_FLAGS, 128, 64, 64, block)
/* bf_ofb_functions */
IMPLEMENT_generic_cipher(blowfish, BLOWFISH, ofb64, OFB, BF_FLAGS, 64, 8, 64, stream)
IMPLEMENT_var_keylen_cipher(blowfish, BLOWFISH, ofb64, OFB, BF_FLAGS, 64, 8, 64, stream)
/* bf_cfb_functions */
IMPLEMENT_generic_cipher(blowfish, BLOWFISH, cfb64, CFB, BF_FLAGS, 64, 8, 64, stream)
IMPLEMENT_var_keylen_cipher(blowfish, BLOWFISH, cfb64, CFB, BF_FLAGS, 64, 8, 64, stream)
@@ -7,6 +7,12 @@
* https://www.openssl.org/source/license.html
*/
/*
* BF low level APIs are deprecated for public use, but still ok for internal
* use.
*/
#include "internal/deprecated.h"
#include "cipher_blowfish.h"
static int cipher_hw_blowfish_initkey(PROV_CIPHER_CTX *ctx,
@@ -7,6 +7,12 @@
* https://www.openssl.org/source/license.html
*/
/*
* Camellia low level APIs are deprecated for public use, but still ok for
* internal use.
*/
#include "internal/deprecated.h"
/* Dispatch functions for CAMELLIA cipher modes ecb, cbc, ofb, cfb, ctr */
#include "cipher_camellia.h"
@@ -31,7 +37,7 @@ static void *camellia_dupctx(void *ctx)
ERR_raise(ERR_LIB_PROV, ERR_R_MALLOC_FAILURE);
return NULL;
}
*ret = *in;
in->base.hw->copyctx(&ret->base, &in->base);
return ret;
}
@@ -9,6 +9,7 @@
#include "openssl/camellia.h"
#include "prov/ciphercommon.h"
#include "crypto/cmll_platform.h"
typedef struct prov_camellia_ctx_st {
PROV_CIPHER_CTX base; /* Must be first */
@@ -7,6 +7,12 @@
* https://www.openssl.org/source/license.html
*/
/*
* Camellia low level APIs are deprecated for public use, but still ok for
* internal use.
*/
#include "internal/deprecated.h"
#include "cipher_camellia.h"
#include <openssl/camellia.h>
@@ -35,6 +41,8 @@ static int cipher_hw_camellia_initkey(PROV_CIPHER_CTX *dat,
return 1;
}
IMPLEMENT_CIPHER_HW_COPYCTX(cipher_hw_camellia_copyctx, PROV_CAMELLIA_CTX)
# if defined(SPARC_CMLL_CAPABLE)
# include "cipher_camellia_hw_t4.inc"
# else
@@ -46,7 +54,8 @@ static int cipher_hw_camellia_initkey(PROV_CIPHER_CTX *dat,
#define PROV_CIPHER_HW_camellia_mode(mode) \
static const PROV_CIPHER_HW camellia_##mode = { \
cipher_hw_camellia_initkey, \
cipher_hw_generic_##mode \
cipher_hw_generic_##mode, \
cipher_hw_camellia_copyctx \
}; \
PROV_CIPHER_HW_declare(mode) \
const PROV_CIPHER_HW *PROV_CIPHER_HW_camellia_##mode(size_t keybits) \
@@ -76,7 +76,8 @@ static int cipher_hw_camellia_t4_initkey(PROV_CIPHER_CTX *dat,
#define PROV_CIPHER_HW_declare(mode) \
static const PROV_CIPHER_HW t4_camellia_##mode = { \
cipher_hw_camellia_t4_initkey, \
cipher_hw_generic_##mode \
cipher_hw_generic_##mode, \
cipher_hw_camellia_copyctx \
};
#define PROV_CIPHER_HW_select(mode) \
if (SPARC_CMLL_CAPABLE) \
@@ -7,10 +7,17 @@
* https://www.openssl.org/source/license.html
*/
/*
* CAST low level APIs are deprecated for public use, but still ok for
* internal use.
*/
#include "internal/deprecated.h"
/* Dispatch functions for cast cipher modes ecb, cbc, ofb, cfb */
#include "cipher_cast.h"
#include "prov/implementations.h"
#include "prov/providercommonerr.h"
#define CAST5_FLAGS (EVP_CIPH_VARIABLE_LENGTH)
@@ -39,10 +46,10 @@ static void *cast5_dupctx(void *ctx)
}
/* cast5128ecb_functions */
IMPLEMENT_generic_cipher(cast5, CAST, ecb, ECB, CAST5_FLAGS, 128, 64, 0, block)
IMPLEMENT_var_keylen_cipher(cast5, CAST, ecb, ECB, CAST5_FLAGS, 128, 64, 0, block)
/* cast5128cbc_functions */
IMPLEMENT_generic_cipher(cast5, CAST, cbc, CBC, CAST5_FLAGS, 128, 64, 64, block)
IMPLEMENT_var_keylen_cipher(cast5, CAST, cbc, CBC, CAST5_FLAGS, 128, 64, 64, block)
/* cast564ofb64_functions */
IMPLEMENT_generic_cipher(cast5, CAST, ofb64, OFB, CAST5_FLAGS, 64, 8, 64, stream)
IMPLEMENT_var_keylen_cipher(cast5, CAST, ofb64, OFB, CAST5_FLAGS, 64, 8, 64, stream)
/* cast564cfb64_functions */
IMPLEMENT_generic_cipher(cast5, CAST, cfb64, CFB, CAST5_FLAGS, 64, 8, 64, stream)
IMPLEMENT_var_keylen_cipher(cast5, CAST, cfb64, CFB, CAST5_FLAGS, 64, 8, 64, stream)
@@ -7,6 +7,12 @@
* https://www.openssl.org/source/license.html
*/
/*
* CAST low level APIs are deprecated for public use, but still ok for
* internal use.
*/
#include "internal/deprecated.h"
#include "cipher_cast.h"
static int cipher_hw_cast5_initkey(PROV_CIPHER_CTX *ctx,
@@ -55,7 +55,7 @@ static void chacha20_freectx(void *vctx)
PROV_CHACHA20_CTX *ctx = (PROV_CHACHA20_CTX *)vctx;
if (ctx != NULL) {
OPENSSL_clear_free(ctx, sizeof(ctx));
OPENSSL_clear_free(ctx, sizeof(*ctx));
}
}
@@ -66,7 +66,7 @@ static void chacha20_poly1305_freectx(void *vctx)
PROV_CHACHA20_POLY1305_CTX *ctx = (PROV_CHACHA20_POLY1305_CTX *)vctx;
if (ctx != NULL)
OPENSSL_clear_free(ctx, sizeof(ctx));
OPENSSL_clear_free(ctx, sizeof(*ctx));
}
static int chacha20_poly1305_get_params(OSSL_PARAM params[])
@@ -262,6 +262,11 @@ static int chacha20_poly1305_cipher(void *vctx, unsigned char *out,
PROV_CIPHER_HW_CHACHA20_POLY1305 *hw =
(PROV_CIPHER_HW_CHACHA20_POLY1305 *)ctx->hw;
if (inl == 0) {
*outl = 0;
return 1;
}
if (outsize < inl) {
ERR_raise(ERR_LIB_PROV, PROV_R_OUTPUT_BUFFER_TOO_SMALL);
return 0;
@@ -142,7 +142,7 @@ static int chacha20_poly1305_tls_cipher(PROV_CIPHER_CTX *bctx,
ctx->len.text = plen;
if (plen) {
if (ctx->enc)
if (bctx->enc)
ctr = xor128_encrypt_n_pad(out, in, ctr, plen);
else
ctr = xor128_decrypt_n_pad(out, in, ctr, plen);
@@ -8,6 +8,7 @@
*/
#include <openssl/des.h>
#include "crypto/des_platform.h"
/* TODO(3.0) Figure out what flags need to be here */
#define TDES_FLAGS (EVP_CIPH_RAND_KEY)
@@ -9,6 +9,12 @@
/* Dispatch functions for RC2 cipher modes ecb, cbc, ofb, cfb */
/*
* RC2 low level APIs are deprecated for public use, but still ok for internal
* use.
*/
#include "internal/deprecated.h"
#include "cipher_rc2.h"
#include "prov/implementations.h"
#include "prov/providercommonerr.h"
@@ -130,7 +136,7 @@ static int rc2_set_ctx_params(void *vctx, OSSL_PARAM params[])
PROV_RC2_CTX *ctx = (PROV_RC2_CTX *)vctx;
const OSSL_PARAM *p;
if (!cipher_generic_set_ctx_params(vctx, params))
if (!cipher_var_keylen_set_ctx_params(vctx, params))
return 0;
p = OSSL_PARAM_locate_const(params, OSSL_CIPHER_PARAM_RC2_KEYBITS);
if (p != NULL) {
@@ -176,6 +182,7 @@ OSSL_PARAM_size_t(OSSL_CIPHER_PARAM_RC2_KEYBITS, NULL),
CIPHER_DEFAULT_GETTABLE_CTX_PARAMS_END(rc2)
CIPHER_DEFAULT_SETTABLE_CTX_PARAMS_START(rc2)
OSSL_PARAM_size_t(OSSL_CIPHER_PARAM_KEYLEN, NULL),
OSSL_PARAM_size_t(OSSL_CIPHER_PARAM_RC2_KEYBITS, NULL),
CIPHER_DEFAULT_SETTABLE_CTX_PARAMS_END(rc2)
@@ -7,6 +7,12 @@
* https://www.openssl.org/source/license.html
*/
/*
* RC2 low level APIs are deprecated for public use, but still ok for internal
* use.
*/
#include "internal/deprecated.h"
#include "cipher_rc2.h"
static int cipher_hw_rc2_initkey(PROV_CIPHER_CTX *ctx,
@@ -9,6 +9,12 @@
/* Dispatch functions for RC4 ciphers */
/*
* RC4 low level APIs are deprecated for public use, but still ok for internal
* use.
*/
#include "internal/deprecated.h"
#include "cipher_rc4.h"
#include "prov/implementations.h"
@@ -71,13 +77,13 @@ const OSSL_DISPATCH alg##kbits##_functions[] = { \
{ OSSL_FUNC_CIPHER_GET_CTX_PARAMS, \
(void (*)(void))cipher_generic_get_ctx_params }, \
{ OSSL_FUNC_CIPHER_SET_CTX_PARAMS, \
(void (*)(void))cipher_generic_set_ctx_params }, \
(void (*)(void))cipher_var_keylen_set_ctx_params }, \
{ OSSL_FUNC_CIPHER_GETTABLE_PARAMS, \
(void (*)(void))cipher_generic_gettable_params }, \
{ OSSL_FUNC_CIPHER_GETTABLE_CTX_PARAMS, \
(void (*)(void))cipher_generic_gettable_ctx_params }, \
{ OSSL_FUNC_CIPHER_SETTABLE_CTX_PARAMS, \
(void (*)(void))cipher_generic_settable_ctx_params }, \
(void (*)(void))cipher_var_keylen_settable_ctx_params }, \
{ 0, NULL } \
};
@@ -0,0 +1,197 @@
/*
* Copyright 2019 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
*/
/* Dispatch functions for RC4_HMAC_MD5 cipher */
/*
* RC4 low level APIs are deprecated for public use, but still ok for internal
* use.
*/
#include "internal/deprecated.h"
#include "cipher_rc4_hmac_md5.h"
#include "prov/implementations.h"
#include "prov/providercommonerr.h"
/* TODO(3.0) Figure out what flags are required */
#define RC4_HMAC_MD5_FLAGS (EVP_CIPH_STREAM_CIPHER | EVP_CIPH_VARIABLE_LENGTH \
| EVP_CIPH_FLAG_AEAD_CIPHER)
#define RC4_HMAC_MD5_KEY_BITS (16 * 8)
#define RC4_HMAC_MD5_BLOCK_BITS (1 * 8)
#define RC4_HMAC_MD5_IV_BITS 0
#define RC4_HMAC_MD5_MODE 0
#define GET_HW(ctx) ((PROV_CIPHER_HW_RC4_HMAC_MD5 *)ctx->base.hw)
static OSSL_OP_cipher_newctx_fn rc4_hmac_md5_newctx;
static OSSL_OP_cipher_freectx_fn rc4_hmac_md5_freectx;
static OSSL_OP_cipher_get_ctx_params_fn rc4_hmac_md5_get_ctx_params;
static OSSL_OP_cipher_gettable_ctx_params_fn rc4_hmac_md5_gettable_ctx_params;
static OSSL_OP_cipher_set_ctx_params_fn rc4_hmac_md5_set_ctx_params;
static OSSL_OP_cipher_settable_ctx_params_fn rc4_hmac_md5_settable_ctx_params;
static OSSL_OP_cipher_get_params_fn rc4_hmac_md5_get_params;
#define rc4_hmac_md5_gettable_params cipher_generic_gettable_params
#define rc4_hmac_md5_einit cipher_generic_einit
#define rc4_hmac_md5_dinit cipher_generic_dinit
#define rc4_hmac_md5_update cipher_generic_stream_update
#define rc4_hmac_md5_final cipher_generic_stream_final
#define rc4_hmac_md5_cipher cipher_generic_cipher
static void *rc4_hmac_md5_newctx(void *provctx)
{
PROV_RC4_HMAC_MD5_CTX *ctx = OPENSSL_zalloc(sizeof(*ctx));
if (ctx != NULL)
cipher_generic_initkey(ctx, RC4_HMAC_MD5_KEY_BITS,
RC4_HMAC_MD5_BLOCK_BITS,
RC4_HMAC_MD5_IV_BITS,
RC4_HMAC_MD5_MODE, RC4_HMAC_MD5_FLAGS,
PROV_CIPHER_HW_rc4_hmac_md5(RC4_HMAC_MD5_KEY_BITS),
NULL);
return ctx;
}
static void rc4_hmac_md5_freectx(void *vctx)
{
PROV_RC4_HMAC_MD5_CTX *ctx = (PROV_RC4_HMAC_MD5_CTX *)vctx;
OPENSSL_clear_free(ctx, sizeof(*ctx));
}
static const OSSL_PARAM rc4_hmac_md5_known_gettable_ctx_params[] = {
OSSL_PARAM_size_t(OSSL_CIPHER_PARAM_KEYLEN, NULL),
OSSL_PARAM_size_t(OSSL_CIPHER_PARAM_IVLEN, NULL),
OSSL_PARAM_size_t(OSSL_CIPHER_PARAM_AEAD_TLS1_AAD_PAD, NULL),
OSSL_PARAM_END
};
const OSSL_PARAM *rc4_hmac_md5_gettable_ctx_params(void)
{
return rc4_hmac_md5_known_gettable_ctx_params;
}
static int rc4_hmac_md5_get_ctx_params(void *vctx, OSSL_PARAM params[])
{
PROV_RC4_HMAC_MD5_CTX *ctx = (PROV_RC4_HMAC_MD5_CTX *)vctx;
OSSL_PARAM *p;
p = OSSL_PARAM_locate(params, OSSL_CIPHER_PARAM_KEYLEN);
if (p != NULL && !OSSL_PARAM_set_size_t(p, ctx->base.keylen)) {
ERR_raise(ERR_LIB_PROV, PROV_R_FAILED_TO_SET_PARAMETER);
return 0;
}
p = OSSL_PARAM_locate(params, OSSL_CIPHER_PARAM_IVLEN);
if (p != NULL && !OSSL_PARAM_set_size_t(p, ctx->base.ivlen)) {
ERR_raise(ERR_LIB_PROV, PROV_R_FAILED_TO_SET_PARAMETER);
return 0;
}
p = OSSL_PARAM_locate(params, OSSL_CIPHER_PARAM_AEAD_TLS1_AAD_PAD);
if (p != NULL && !OSSL_PARAM_set_size_t(p, ctx->tls_aad_pad_sz)) {
ERR_raise(ERR_LIB_PROV, PROV_R_FAILED_TO_SET_PARAMETER);
return 0;
}
return 1;
}
static const OSSL_PARAM rc4_hmac_md5_known_settable_ctx_params[] = {
OSSL_PARAM_size_t(OSSL_CIPHER_PARAM_KEYLEN, NULL),
OSSL_PARAM_size_t(OSSL_CIPHER_PARAM_IVLEN, NULL),
OSSL_PARAM_octet_string(OSSL_CIPHER_PARAM_AEAD_TLS1_AAD, NULL, 0),
OSSL_PARAM_END
};
const OSSL_PARAM *rc4_hmac_md5_settable_ctx_params(void)
{
return rc4_hmac_md5_known_settable_ctx_params;
}
static int rc4_hmac_md5_set_ctx_params(void *vctx, const OSSL_PARAM params[])
{
PROV_RC4_HMAC_MD5_CTX *ctx = (PROV_RC4_HMAC_MD5_CTX *)vctx;
const OSSL_PARAM *p;
size_t sz;
p = OSSL_PARAM_locate_const(params, OSSL_CIPHER_PARAM_KEYLEN);
if (p != NULL) {
if (!OSSL_PARAM_get_size_t(p, &sz)) {
ERR_raise(ERR_LIB_PROV, PROV_R_FAILED_TO_GET_PARAMETER);
return 0;
}
if (ctx->base.keylen != sz) {
ERR_raise(ERR_LIB_PROV, PROV_R_INVALID_KEY_LENGTH);
return 0;
}
}
p = OSSL_PARAM_locate_const(params, OSSL_CIPHER_PARAM_IVLEN);
if (p != NULL) {
if (!OSSL_PARAM_get_size_t(p, &sz)) {
ERR_raise(ERR_LIB_PROV, PROV_R_FAILED_TO_GET_PARAMETER);
return 0;
}
if (ctx->base.ivlen != sz) {
ERR_raise(ERR_LIB_PROV, PROV_R_INVALID_IV_LENGTH);
return 0;
}
}
p = OSSL_PARAM_locate_const(params, OSSL_CIPHER_PARAM_AEAD_TLS1_AAD);
if (p != NULL) {
if (p->data_type != OSSL_PARAM_OCTET_STRING) {
ERR_raise(ERR_LIB_PROV, PROV_R_FAILED_TO_GET_PARAMETER);
return 0;
}
sz = GET_HW(ctx)->tls_init(&ctx->base, p->data, p->data_size);
if (sz == 0) {
ERR_raise(ERR_LIB_PROV, PROV_R_INVALID_DATA);
return 0;
}
ctx->tls_aad_pad_sz = sz;
}
p = OSSL_PARAM_locate_const(params, OSSL_CIPHER_PARAM_AEAD_TLS1_AAD);
if (p != NULL) {
if (p->data_type != OSSL_PARAM_OCTET_STRING) {
ERR_raise(ERR_LIB_PROV, PROV_R_FAILED_TO_GET_PARAMETER);
return 0;
}
GET_HW(ctx)->init_mackey(&ctx->base, p->data, p->data_size);
}
return 1;
}
static int rc4_hmac_md5_get_params(OSSL_PARAM params[])
{
return cipher_generic_get_params(params, RC4_HMAC_MD5_MODE,
RC4_HMAC_MD5_FLAGS,
RC4_HMAC_MD5_KEY_BITS,
RC4_HMAC_MD5_BLOCK_BITS,
RC4_HMAC_MD5_IV_BITS);
}
const OSSL_DISPATCH rc4_hmac_md5_functions[] = {
{ OSSL_FUNC_CIPHER_NEWCTX, (void (*)(void))rc4_hmac_md5_newctx },
{ OSSL_FUNC_CIPHER_FREECTX, (void (*)(void))rc4_hmac_md5_freectx },
{ OSSL_FUNC_CIPHER_ENCRYPT_INIT, (void (*)(void))rc4_hmac_md5_einit },
{ OSSL_FUNC_CIPHER_DECRYPT_INIT, (void (*)(void))rc4_hmac_md5_dinit },
{ OSSL_FUNC_CIPHER_UPDATE, (void (*)(void))rc4_hmac_md5_update },
{ OSSL_FUNC_CIPHER_FINAL, (void (*)(void))rc4_hmac_md5_final },
{ OSSL_FUNC_CIPHER_CIPHER, (void (*)(void))rc4_hmac_md5_cipher },
{ OSSL_FUNC_CIPHER_GET_PARAMS, (void (*)(void))rc4_hmac_md5_get_params },
{ OSSL_FUNC_CIPHER_GETTABLE_PARAMS,
(void (*)(void))rc4_hmac_md5_gettable_params },
{ OSSL_FUNC_CIPHER_GET_CTX_PARAMS,
(void (*)(void))rc4_hmac_md5_get_ctx_params },
{ OSSL_FUNC_CIPHER_GETTABLE_CTX_PARAMS,
(void (*)(void))rc4_hmac_md5_gettable_ctx_params },
{ OSSL_FUNC_CIPHER_SET_CTX_PARAMS,
(void (*)(void))rc4_hmac_md5_set_ctx_params },
{ OSSL_FUNC_CIPHER_SETTABLE_CTX_PARAMS,
(void (*)(void))rc4_hmac_md5_settable_ctx_params },
{ 0, NULL }
};
@@ -0,0 +1,33 @@
/*
* Copyright 2019 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
*/
#include <openssl/rc4.h>
#include <openssl/md5.h>
#include "prov/ciphercommon.h"
typedef struct prov_rc4_hmac_md5_ctx_st {
PROV_CIPHER_CTX base; /* Must be first */
union {
OSSL_UNION_ALIGN;
RC4_KEY ks;
} ks;
MD5_CTX head, tail, md;
size_t payload_length;
size_t tls_aad_pad_sz;
} PROV_RC4_HMAC_MD5_CTX;
typedef struct prov_cipher_hw_rc4_hmac_md5_st {
PROV_CIPHER_HW base; /* Must be first */
int (*tls_init)(PROV_CIPHER_CTX *ctx, unsigned char *aad, size_t aad_len);
void (*init_mackey)(PROV_CIPHER_CTX *ctx, const unsigned char *key,
size_t len);
} PROV_CIPHER_HW_RC4_HMAC_MD5;
const PROV_CIPHER_HW *PROV_CIPHER_HW_rc4_hmac_md5(size_t keybits);
@@ -0,0 +1,231 @@
/*
* Copyright 2019 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
*/
/* RC4_HMAC_MD5 cipher implementation */
/*
* RC4 low level APIs are deprecated for public use, but still ok for internal
* use.
*/
#include "internal/deprecated.h"
#include "cipher_rc4_hmac_md5.h"
#define NO_PAYLOAD_LENGTH ((size_t)-1)
#if defined(RC4_ASM) \
&& defined(MD5_ASM) \
&& (defined(__x86_64) \
|| defined(__x86_64__) \
|| defined(_M_AMD64) \
|| defined(_M_X64))
# define STITCHED_CALL
# define MOD 32 /* 32 is $MOD from rc4_md5-x86_64.pl */
#else
# define rc4_off 0
# define md5_off 0
#endif
static int cipher_hw_rc4_hmac_md5_initkey(PROV_CIPHER_CTX *bctx,
const uint8_t *key, size_t keylen)
{
PROV_RC4_HMAC_MD5_CTX *ctx = (PROV_RC4_HMAC_MD5_CTX *)bctx;
RC4_set_key(&ctx->ks.ks, keylen, key);
MD5_Init(&ctx->head); /* handy when benchmarking */
ctx->tail = ctx->head;
ctx->md = ctx->head;
ctx->payload_length = NO_PAYLOAD_LENGTH;
return 1;
}
static int cipher_hw_rc4_hmac_md5_cipher(PROV_CIPHER_CTX *bctx,
unsigned char *out,
const unsigned char *in, size_t len)
{
PROV_RC4_HMAC_MD5_CTX *ctx = (PROV_RC4_HMAC_MD5_CTX *)bctx;
RC4_KEY *ks = &ctx->ks.ks;
#if defined(STITCHED_CALL)
size_t rc4_off = MOD - 1 - (ks->x & (MOD - 1));
size_t md5_off = MD5_CBLOCK - ctx->md.num, blocks;
unsigned int l;
#endif
size_t plen = ctx->payload_length;
if (plen != NO_PAYLOAD_LENGTH && len != (plen + MD5_DIGEST_LENGTH))
return 0;
if (ctx->base.enc) {
if (plen == NO_PAYLOAD_LENGTH)
plen = len;
#if defined(STITCHED_CALL)
/* cipher has to "fall behind" */
if (rc4_off > md5_off)
md5_off += MD5_CBLOCK;
if (plen > md5_off
&& (blocks = (plen - md5_off) / MD5_CBLOCK)
&& (OPENSSL_ia32cap_P[0] & (1 << 20)) == 0) {
MD5_Update(&ctx->md, in, md5_off);
RC4(ks, rc4_off, in, out);
rc4_md5_enc(ks, in + rc4_off, out + rc4_off,
&ctx->md, in + md5_off, blocks);
blocks *= MD5_CBLOCK;
rc4_off += blocks;
md5_off += blocks;
ctx->md.Nh += blocks >> 29;
ctx->md.Nl += blocks <<= 3;
if (ctx->md.Nl < (unsigned int)blocks)
ctx->md.Nh++;
} else {
rc4_off = 0;
md5_off = 0;
}
#endif
MD5_Update(&ctx->md, in + md5_off, plen - md5_off);
if (plen != len) { /* "TLS" mode of operation */
if (in != out)
memcpy(out + rc4_off, in + rc4_off, plen - rc4_off);
/* calculate HMAC and append it to payload */
MD5_Final(out + plen, &ctx->md);
ctx->md = ctx->tail;
MD5_Update(&ctx->md, out + plen, MD5_DIGEST_LENGTH);
MD5_Final(out + plen, &ctx->md);
/* encrypt HMAC at once */
RC4(ks, len - rc4_off, out + rc4_off, out + rc4_off);
} else {
RC4(ks, len - rc4_off, in + rc4_off, out + rc4_off);
}
} else {
unsigned char mac[MD5_DIGEST_LENGTH];
#if defined(STITCHED_CALL)
/* digest has to "fall behind" */
if (md5_off > rc4_off)
rc4_off += 2 * MD5_CBLOCK;
else
rc4_off += MD5_CBLOCK;
if (len > rc4_off
&& (blocks = (len - rc4_off) / MD5_CBLOCK)
&& (OPENSSL_ia32cap_P[0] & (1 << 20)) == 0) {
RC4(ks, rc4_off, in, out);
MD5_Update(&ctx->md, out, md5_off);
rc4_md5_enc(ks, in + rc4_off, out + rc4_off,
&ctx->md, out + md5_off, blocks);
blocks *= MD5_CBLOCK;
rc4_off += blocks;
md5_off += blocks;
l = (ctx->md.Nl + (blocks << 3)) & 0xffffffffU;
if (l < ctx->md.Nl)
ctx->md.Nh++;
ctx->md.Nl = l;
ctx->md.Nh += blocks >> 29;
} else {
md5_off = 0;
rc4_off = 0;
}
#endif
/* decrypt HMAC at once */
RC4(ks, len - rc4_off, in + rc4_off, out + rc4_off);
if (plen != NO_PAYLOAD_LENGTH) {
/* "TLS" mode of operation */
MD5_Update(&ctx->md, out + md5_off, plen - md5_off);
/* calculate HMAC and verify it */
MD5_Final(mac, &ctx->md);
ctx->md = ctx->tail;
MD5_Update(&ctx->md, mac, MD5_DIGEST_LENGTH);
MD5_Final(mac, &ctx->md);
if (CRYPTO_memcmp(out + plen, mac, MD5_DIGEST_LENGTH))
return 0;
} else {
MD5_Update(&ctx->md, out + md5_off, len - md5_off);
}
}
ctx->payload_length = NO_PAYLOAD_LENGTH;
return 1;
}
static int cipher_hw_rc4_hmac_md5_tls_init(PROV_CIPHER_CTX *bctx,
unsigned char *aad, size_t aad_len)
{
PROV_RC4_HMAC_MD5_CTX *ctx = (PROV_RC4_HMAC_MD5_CTX *)bctx;
unsigned int len;
if (aad_len != EVP_AEAD_TLS1_AAD_LEN)
return 0;
len = aad[aad_len - 2] << 8 | aad[aad_len - 1];
if (!bctx->enc) {
if (len < MD5_DIGEST_LENGTH)
return 0;
len -= MD5_DIGEST_LENGTH;
aad[aad_len - 2] = len >> 8;
aad[aad_len - 1] = len;
}
ctx->payload_length = len;
ctx->md = ctx->head;
MD5_Update(&ctx->md, aad, aad_len);
return MD5_DIGEST_LENGTH;
}
static void cipher_hw_rc4_hmac_md5_init_mackey(PROV_CIPHER_CTX *bctx,
const unsigned char *key,
size_t len)
{
PROV_RC4_HMAC_MD5_CTX *ctx = (PROV_RC4_HMAC_MD5_CTX *)bctx;
unsigned int i;
unsigned char hmac_key[64];
memset(hmac_key, 0, sizeof(hmac_key));
if (len > (int)sizeof(hmac_key)) {
MD5_Init(&ctx->head);
MD5_Update(&ctx->head, key, len);
MD5_Final(hmac_key, &ctx->head);
} else {
memcpy(hmac_key, key, len);
}
for (i = 0; i < sizeof(hmac_key); i++)
hmac_key[i] ^= 0x36; /* ipad */
MD5_Init(&ctx->head);
MD5_Update(&ctx->head, hmac_key, sizeof(hmac_key));
for (i = 0; i < sizeof(hmac_key); i++)
hmac_key[i] ^= 0x36 ^ 0x5c; /* opad */
MD5_Init(&ctx->tail);
MD5_Update(&ctx->tail, hmac_key, sizeof(hmac_key));
OPENSSL_cleanse(hmac_key, sizeof(hmac_key));
}
static const PROV_CIPHER_HW_RC4_HMAC_MD5 rc4_hmac_md5_hw = {
{
cipher_hw_rc4_hmac_md5_initkey,
cipher_hw_rc4_hmac_md5_cipher
},
cipher_hw_rc4_hmac_md5_tls_init,
cipher_hw_rc4_hmac_md5_init_mackey
};
const PROV_CIPHER_HW *PROV_CIPHER_HW_rc4_hmac_md5(size_t keybits)
{
return (PROV_CIPHER_HW *)&rc4_hmac_md5_hw;
}
@@ -7,6 +7,12 @@
* https://www.openssl.org/source/license.html
*/
/*
* RC4 low level APIs are deprecated for public use, but still ok for internal
* use.
*/
#include "internal/deprecated.h"
#include "cipher_rc4.h"
static int cipher_hw_rc4_initkey(PROV_CIPHER_CTX *ctx,
@@ -9,6 +9,12 @@
/* Dispatch functions for RC5 cipher modes ecb, cbc, ofb, cfb */
/*
* RC5 low level APIs are deprecated for public use, but still ok for internal
* use.
*/
#include "internal/deprecated.h"
#include "cipher_rc5.h"
#include "prov/implementations.h"
#include "prov/providercommonerr.h"
@@ -44,7 +50,7 @@ static int rc5_set_ctx_params(void *vctx, const OSSL_PARAM params[])
PROV_RC5_CTX *ctx = (PROV_RC5_CTX *)vctx;
const OSSL_PARAM *p;
if (!cipher_generic_set_ctx_params(vctx, params))
if (!cipher_var_keylen_set_ctx_params(vctx, params))
return 0;
p = OSSL_PARAM_locate_const(params, OSSL_CIPHER_PARAM_ROUNDS);
@@ -71,6 +77,7 @@ CIPHER_DEFAULT_GETTABLE_CTX_PARAMS_START(rc5)
CIPHER_DEFAULT_GETTABLE_CTX_PARAMS_END(rc5)
CIPHER_DEFAULT_SETTABLE_CTX_PARAMS_START(rc5)
OSSL_PARAM_size_t(OSSL_CIPHER_PARAM_KEYLEN, NULL),
OSSL_PARAM_uint(OSSL_CIPHER_PARAM_ROUNDS, NULL),
CIPHER_DEFAULT_SETTABLE_CTX_PARAMS_END(rc5)
@@ -7,6 +7,12 @@
* https://www.openssl.org/source/license.html
*/
/*
* RC5 low level APIs are deprecated for public use, but still ok for internal
* use.
*/
#include "internal/deprecated.h"
#include "cipher_rc5.h"
static int cipher_hw_rc5_initkey(PROV_CIPHER_CTX *ctx,
@@ -9,6 +9,12 @@
/* Dispatch functions for Seed cipher modes ecb, cbc, ofb, cfb */
/*
* SEED low level APIs are deprecated for public use, but still ok for
* internal use.
*/
#include "internal/deprecated.h"
#include "cipher_seed.h"
#include "prov/implementations.h"
@@ -7,6 +7,12 @@
* https://www.openssl.org/source/license.html
*/
/*
* SEED low level APIs are deprecated for public use, but still ok for
* internal use.
*/
#include "internal/deprecated.h"
#include "cipher_seed.h"
static int cipher_hw_seed_initkey(PROV_CIPHER_CTX *ctx,
@@ -31,7 +31,7 @@ static void *sm4_dupctx(void *ctx)
ERR_raise(ERR_LIB_PROV, ERR_R_MALLOC_FAILURE);
return NULL;
}
*ret = *in;
in->base.hw->copyctx(&ret->base, &in->base);
return ret;
}
@@ -26,10 +26,13 @@ static int cipher_hw_sm4_initkey(PROV_CIPHER_CTX *ctx,
return 1;
}
IMPLEMENT_CIPHER_HW_COPYCTX(cipher_hw_sm4_copyctx, PROV_SM4_CTX)
# define PROV_CIPHER_HW_sm4_mode(mode) \
static const PROV_CIPHER_HW sm4_##mode = { \
cipher_hw_sm4_initkey, \
cipher_hw_chunked_##mode \
cipher_hw_chunked_##mode, \
cipher_hw_sm4_copyctx \
}; \
const PROV_CIPHER_HW *PROV_CIPHER_HW_sm4_##mode(size_t keybits) \
{ \
@@ -9,6 +9,7 @@
#include <openssl/des.h>
#include <openssl/core_numbers.h>
#include "crypto/des_platform.h"
#define DES_BLOCK_SIZE 8
#define TDES_IVLEN 8
@@ -14,7 +14,7 @@
#include "prov/implementations.h"
#include "prov/providercommonerr.h"
/* TODO (3.0) Figure out what flags are requred */
/* TODO (3.0) Figure out what flags are required */
#define TDES_WRAP_FLAGS (EVP_CIPH_WRAP_MODE | EVP_CIPH_CUSTOM_IV)
@@ -145,6 +145,8 @@ static int tdes_wrap_update(void *vctx, unsigned char *out, size_t *outl,
size_t inl)
{
*outl = 0;
if (inl == 0)
return 1;
if (outsize < inl) {
PROVerr(0, PROV_R_OUTPUT_BUFFER_TOO_SMALL);
return 0;
@@ -0,0 +1,433 @@
/*
* Copyright 2019 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
*/
/*
* Generic dispatch table functions for ciphers.
*/
#include "ciphercommon_local.h"
#include "prov/provider_ctx.h"
#include "prov/providercommonerr.h"
/*-
* Generic cipher functions for OSSL_PARAM gettables and settables
*/
static const OSSL_PARAM cipher_known_gettable_params[] = {
OSSL_PARAM_uint(OSSL_CIPHER_PARAM_MODE, NULL),
OSSL_PARAM_size_t(OSSL_CIPHER_PARAM_KEYLEN, NULL),
OSSL_PARAM_size_t(OSSL_CIPHER_PARAM_IVLEN, NULL),
OSSL_PARAM_size_t(OSSL_CIPHER_PARAM_BLOCK_SIZE, NULL),
OSSL_PARAM_ulong(OSSL_CIPHER_PARAM_FLAGS, NULL),
OSSL_PARAM_END
};
const OSSL_PARAM *cipher_generic_gettable_params(void)
{
return cipher_known_gettable_params;
}
int cipher_generic_get_params(OSSL_PARAM params[], unsigned int md,
unsigned long flags,
size_t kbits, size_t blkbits, size_t ivbits)
{
OSSL_PARAM *p;
p = OSSL_PARAM_locate(params, OSSL_CIPHER_PARAM_MODE);
if (p != NULL && !OSSL_PARAM_set_uint(p, md)) {
ERR_raise(ERR_LIB_PROV, PROV_R_FAILED_TO_SET_PARAMETER);
return 0;
}
p = OSSL_PARAM_locate(params, OSSL_CIPHER_PARAM_FLAGS);
if (p != NULL && !OSSL_PARAM_set_ulong(p, flags)) {
ERR_raise(ERR_LIB_PROV, PROV_R_FAILED_TO_SET_PARAMETER);
return 0;
}
p = OSSL_PARAM_locate(params, OSSL_CIPHER_PARAM_KEYLEN);
if (p != NULL && !OSSL_PARAM_set_size_t(p, kbits / 8)) {
ERR_raise(ERR_LIB_PROV, PROV_R_FAILED_TO_SET_PARAMETER);
return 0;
}
p = OSSL_PARAM_locate(params, OSSL_CIPHER_PARAM_BLOCK_SIZE);
if (p != NULL && !OSSL_PARAM_set_size_t(p, blkbits / 8)) {
ERR_raise(ERR_LIB_PROV, PROV_R_FAILED_TO_SET_PARAMETER);
return 0;
}
p = OSSL_PARAM_locate(params, OSSL_CIPHER_PARAM_IVLEN);
if (p != NULL && !OSSL_PARAM_set_size_t(p, ivbits / 8)) {
ERR_raise(ERR_LIB_PROV, PROV_R_FAILED_TO_SET_PARAMETER);
return 0;
}
return 1;
}
CIPHER_DEFAULT_GETTABLE_CTX_PARAMS_START(cipher_generic)
CIPHER_DEFAULT_GETTABLE_CTX_PARAMS_END(cipher_generic)
CIPHER_DEFAULT_SETTABLE_CTX_PARAMS_START(cipher_generic)
CIPHER_DEFAULT_SETTABLE_CTX_PARAMS_END(cipher_generic)
/*
* Variable key length cipher functions for OSSL_PARAM settables
*/
int cipher_var_keylen_set_ctx_params(void *vctx, const OSSL_PARAM params[])
{
PROV_CIPHER_CTX *ctx = (PROV_CIPHER_CTX *)vctx;
const OSSL_PARAM *p;
if (!cipher_generic_set_ctx_params(vctx, params))
return 0;
p = OSSL_PARAM_locate_const(params, OSSL_CIPHER_PARAM_KEYLEN);
if (p != NULL) {
size_t keylen;
if (!OSSL_PARAM_get_size_t(p, &keylen)) {
ERR_raise(ERR_LIB_PROV, PROV_R_FAILED_TO_GET_PARAMETER);
return 0;
}
ctx->keylen = keylen;
}
return 1;
}
CIPHER_DEFAULT_SETTABLE_CTX_PARAMS_START(cipher_var_keylen)
OSSL_PARAM_size_t(OSSL_CIPHER_PARAM_KEYLEN, NULL),
CIPHER_DEFAULT_SETTABLE_CTX_PARAMS_END(cipher_var_keylen)
/*-
* AEAD cipher functions for OSSL_PARAM gettables and settables
*/
static const OSSL_PARAM cipher_aead_known_gettable_ctx_params[] = {
OSSL_PARAM_size_t(OSSL_CIPHER_PARAM_KEYLEN, NULL),
OSSL_PARAM_size_t(OSSL_CIPHER_PARAM_IVLEN, NULL),
OSSL_PARAM_size_t(OSSL_CIPHER_PARAM_AEAD_TAGLEN, NULL),
OSSL_PARAM_octet_string(OSSL_CIPHER_PARAM_IV, NULL, 0),
OSSL_PARAM_octet_string(OSSL_CIPHER_PARAM_AEAD_TAG, NULL, 0),
OSSL_PARAM_size_t(OSSL_CIPHER_PARAM_AEAD_TLS1_AAD_PAD, NULL),
OSSL_PARAM_octet_string(OSSL_CIPHER_PARAM_AEAD_TLS1_GET_IV_GEN, NULL, 0),
OSSL_PARAM_END
};
const OSSL_PARAM *cipher_aead_gettable_ctx_params(void)
{
return cipher_aead_known_gettable_ctx_params;
}
static const OSSL_PARAM cipher_aead_known_settable_ctx_params[] = {
OSSL_PARAM_size_t(OSSL_CIPHER_PARAM_AEAD_IVLEN, NULL),
OSSL_PARAM_octet_string(OSSL_CIPHER_PARAM_AEAD_TAG, NULL, 0),
OSSL_PARAM_octet_string(OSSL_CIPHER_PARAM_AEAD_TLS1_AAD, NULL, 0),
OSSL_PARAM_octet_string(OSSL_CIPHER_PARAM_AEAD_TLS1_IV_FIXED, NULL, 0),
OSSL_PARAM_octet_string(OSSL_CIPHER_PARAM_AEAD_TLS1_SET_IV_INV, NULL, 0),
OSSL_PARAM_END
};
const OSSL_PARAM *cipher_aead_settable_ctx_params(void)
{
return cipher_aead_known_settable_ctx_params;
}
static int cipher_generic_init_internal(PROV_CIPHER_CTX *ctx,
const unsigned char *key, size_t keylen,
const unsigned char *iv, size_t ivlen,
int enc)
{
ctx->enc = enc ? 1 : 0;
if (iv != NULL && ctx->mode != EVP_CIPH_ECB_MODE) {
if (!cipher_generic_initiv(ctx, iv, ivlen))
return 0;
}
if (key != NULL) {
if ((ctx->flags & EVP_CIPH_VARIABLE_LENGTH) == 0) {
if (keylen != ctx->keylen) {
ERR_raise(ERR_LIB_PROV, PROV_R_INVALID_KEYLEN);
return 0;
}
} else {
ctx->keylen = keylen;
}
return ctx->hw->init(ctx, key, ctx->keylen);
}
return 1;
}
int cipher_generic_einit(void *vctx, const unsigned char *key, size_t keylen,
const unsigned char *iv, size_t ivlen)
{
return cipher_generic_init_internal((PROV_CIPHER_CTX *)vctx, key, keylen,
iv, ivlen, 1);
}
int cipher_generic_dinit(void *vctx, const unsigned char *key, size_t keylen,
const unsigned char *iv, size_t ivlen)
{
return cipher_generic_init_internal((PROV_CIPHER_CTX *)vctx, key, keylen,
iv, ivlen, 0);
}
int cipher_generic_block_update(void *vctx, unsigned char *out, size_t *outl,
size_t outsize, const unsigned char *in,
size_t inl)
{
size_t outlint = 0;
PROV_CIPHER_CTX *ctx = (PROV_CIPHER_CTX *)vctx;
size_t blksz = ctx->blocksize;
size_t nextblocks = fillblock(ctx->buf, &ctx->bufsz, blksz, &in, &inl);
/*
* If we're decrypting and we end an update on a block boundary we hold
* the last block back in case this is the last update call and the last
* block is padded.
*/
if (ctx->bufsz == blksz && (ctx->enc || inl > 0 || !ctx->pad)) {
if (outsize < blksz) {
ERR_raise(ERR_LIB_PROV, PROV_R_OUTPUT_BUFFER_TOO_SMALL);
return 0;
}
if (!ctx->hw->cipher(ctx, out, ctx->buf, blksz)) {
ERR_raise(ERR_LIB_PROV, PROV_R_CIPHER_OPERATION_FAILED);
return 0;
}
ctx->bufsz = 0;
outlint = blksz;
out += blksz;
}
if (nextblocks > 0) {
if (!ctx->enc && ctx->pad && nextblocks == inl) {
if (!ossl_assert(inl >= blksz)) {
ERR_raise(ERR_LIB_PROV, PROV_R_OUTPUT_BUFFER_TOO_SMALL);
return 0;
}
nextblocks -= blksz;
}
outlint += nextblocks;
if (outsize < outlint) {
ERR_raise(ERR_LIB_PROV, PROV_R_OUTPUT_BUFFER_TOO_SMALL);
return 0;
}
}
if (nextblocks > 0) {
if (!ctx->hw->cipher(ctx, out, in, nextblocks)) {
ERR_raise(ERR_LIB_PROV, PROV_R_CIPHER_OPERATION_FAILED);
return 0;
}
in += nextblocks;
inl -= nextblocks;
}
if (!trailingdata(ctx->buf, &ctx->bufsz, blksz, &in, &inl)) {
/* ERR_raise already called */
return 0;
}
*outl = outlint;
return inl == 0;
}
int cipher_generic_block_final(void *vctx, unsigned char *out, size_t *outl,
size_t outsize)
{
PROV_CIPHER_CTX *ctx = (PROV_CIPHER_CTX *)vctx;
size_t blksz = ctx->blocksize;
if (ctx->enc) {
if (ctx->pad) {
padblock(ctx->buf, &ctx->bufsz, blksz);
} else if (ctx->bufsz == 0) {
*outl = 0;
return 1;
} else if (ctx->bufsz != blksz) {
ERR_raise(ERR_LIB_PROV, PROV_R_WRONG_FINAL_BLOCK_LENGTH);
return 0;
}
if (outsize < blksz) {
ERR_raise(ERR_LIB_PROV, PROV_R_OUTPUT_BUFFER_TOO_SMALL);
return 0;
}
if (!ctx->hw->cipher(ctx, out, ctx->buf, blksz)) {
ERR_raise(ERR_LIB_PROV, PROV_R_CIPHER_OPERATION_FAILED);
return 0;
}
ctx->bufsz = 0;
*outl = blksz;
return 1;
}
/* Decrypting */
if (ctx->bufsz != blksz) {
if (ctx->bufsz == 0 && !ctx->pad) {
*outl = 0;
return 1;
}
ERR_raise(ERR_LIB_PROV, PROV_R_WRONG_FINAL_BLOCK_LENGTH);
return 0;
}
if (!ctx->hw->cipher(ctx, ctx->buf, ctx->buf, blksz)) {
ERR_raise(ERR_LIB_PROV, PROV_R_CIPHER_OPERATION_FAILED);
return 0;
}
if (ctx->pad && !unpadblock(ctx->buf, &ctx->bufsz, blksz)) {
/* ERR_raise already called */
return 0;
}
if (outsize < ctx->bufsz) {
ERR_raise(ERR_LIB_PROV, PROV_R_OUTPUT_BUFFER_TOO_SMALL);
return 0;
}
memcpy(out, ctx->buf, ctx->bufsz);
*outl = ctx->bufsz;
ctx->bufsz = 0;
return 1;
}
int cipher_generic_stream_update(void *vctx, unsigned char *out, size_t *outl,
size_t outsize, const unsigned char *in,
size_t inl)
{
PROV_CIPHER_CTX *ctx = (PROV_CIPHER_CTX *)vctx;
if (inl == 0) {
*outl = 0;
return 1;
}
if (outsize < inl) {
ERR_raise(ERR_LIB_PROV, PROV_R_OUTPUT_BUFFER_TOO_SMALL);
return 0;
}
if (!ctx->hw->cipher(ctx, out, in, inl)) {
ERR_raise(ERR_LIB_PROV, PROV_R_CIPHER_OPERATION_FAILED);
return 0;
}
*outl = inl;
return 1;
}
int cipher_generic_stream_final(void *vctx, unsigned char *out, size_t *outl,
size_t outsize)
{
*outl = 0;
return 1;
}
int cipher_generic_cipher(void *vctx,
unsigned char *out, size_t *outl, size_t outsize,
const unsigned char *in, size_t inl)
{
PROV_CIPHER_CTX *ctx = (PROV_CIPHER_CTX *)vctx;
if (outsize < inl) {
ERR_raise(ERR_LIB_PROV, PROV_R_OUTPUT_BUFFER_TOO_SMALL);
return 0;
}
if (!ctx->hw->cipher(ctx, out, in, inl)) {
ERR_raise(ERR_LIB_PROV, PROV_R_CIPHER_OPERATION_FAILED);
return 0;
}
*outl = inl;
return 1;
}
int cipher_generic_get_ctx_params(void *vctx, OSSL_PARAM params[])
{
PROV_CIPHER_CTX *ctx = (PROV_CIPHER_CTX *)vctx;
OSSL_PARAM *p;
p = OSSL_PARAM_locate(params, OSSL_CIPHER_PARAM_IVLEN);
if (p != NULL && !OSSL_PARAM_set_size_t(p, ctx->ivlen)) {
ERR_raise(ERR_LIB_PROV, PROV_R_FAILED_TO_SET_PARAMETER);
return 0;
}
p = OSSL_PARAM_locate(params, OSSL_CIPHER_PARAM_PADDING);
if (p != NULL && !OSSL_PARAM_set_uint(p, ctx->pad)) {
ERR_raise(ERR_LIB_PROV, PROV_R_FAILED_TO_SET_PARAMETER);
return 0;
}
p = OSSL_PARAM_locate(params, OSSL_CIPHER_PARAM_IV);
if (p != NULL
&& !OSSL_PARAM_set_octet_ptr(p, &ctx->oiv, ctx->ivlen)
&& !OSSL_PARAM_set_octet_string(p, &ctx->oiv, ctx->ivlen)) {
ERR_raise(ERR_LIB_PROV, PROV_R_FAILED_TO_SET_PARAMETER);
return 0;
}
p = OSSL_PARAM_locate(params, OSSL_CIPHER_PARAM_NUM);
if (p != NULL && !OSSL_PARAM_set_uint(p, ctx->num)) {
ERR_raise(ERR_LIB_PROV, PROV_R_FAILED_TO_SET_PARAMETER);
return 0;
}
p = OSSL_PARAM_locate(params, OSSL_CIPHER_PARAM_KEYLEN);
if (p != NULL && !OSSL_PARAM_set_size_t(p, ctx->keylen)) {
ERR_raise(ERR_LIB_PROV, PROV_R_FAILED_TO_SET_PARAMETER);
return 0;
}
return 1;
}
int cipher_generic_set_ctx_params(void *vctx, const OSSL_PARAM params[])
{
PROV_CIPHER_CTX *ctx = (PROV_CIPHER_CTX *)vctx;
const OSSL_PARAM *p;
p = OSSL_PARAM_locate_const(params, OSSL_CIPHER_PARAM_PADDING);
if (p != NULL) {
unsigned int pad;
if (!OSSL_PARAM_get_uint(p, &pad)) {
ERR_raise(ERR_LIB_PROV, PROV_R_FAILED_TO_GET_PARAMETER);
return 0;
}
ctx->pad = pad ? 1 : 0;
}
p = OSSL_PARAM_locate_const(params, OSSL_CIPHER_PARAM_NUM);
if (p != NULL) {
unsigned int num;
if (!OSSL_PARAM_get_uint(p, &num)) {
ERR_raise(ERR_LIB_PROV, PROV_R_FAILED_TO_GET_PARAMETER);
return 0;
}
ctx->num = num;
}
return 1;
}
int cipher_generic_initiv(PROV_CIPHER_CTX *ctx, const unsigned char *iv,
size_t ivlen)
{
if (ivlen != ctx->ivlen
|| ivlen > sizeof(ctx->iv)) {
ERR_raise(ERR_LIB_PROV, PROV_R_INVALID_IVLEN);
return 0;
}
ctx->iv_set = 1;
memcpy(ctx->iv, iv, ivlen);
memcpy(ctx->oiv, iv, ivlen);
return 1;
}
void cipher_generic_initkey(void *vctx, size_t kbits, size_t blkbits,
size_t ivbits, unsigned int mode, uint64_t flags,
const PROV_CIPHER_HW *hw, void *provctx)
{
PROV_CIPHER_CTX *ctx = (PROV_CIPHER_CTX *)vctx;
ctx->flags = flags;
ctx->pad = 1;
ctx->keylen = ((kbits) / 8);
ctx->ivlen = ((ivbits) / 8);
ctx->hw = hw;
ctx->mode = mode;
ctx->blocksize = blkbits / 8;
if (provctx != NULL)
ctx->libctx = PROV_LIBRARY_CONTEXT_OF(provctx); /* used for rand */
}
@@ -0,0 +1,115 @@
/*
* Copyright 2019 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
*/
#include <assert.h>
#include "ciphercommon_local.h"
#include "prov/providercommonerr.h"
/*
* Fills a single block of buffered data from the input, and returns the amount
* of data remaining in the input that is a multiple of the blocksize. The buffer
* is only filled if it already has some data in it, isn't full already or we
* don't have at least one block in the input.
*
* buf: a buffer of blocksize bytes
* buflen: contains the amount of data already in buf on entry. Updated with the
* amount of data in buf at the end. On entry *buflen must always be
* less than the blocksize
* blocksize: size of a block. Must be greater than 0 and a power of 2
* in: pointer to a pointer containing the input data
* inlen: amount of input data available
*
* On return buf is filled with as much data as possible up to a full block,
* *buflen is updated containing the amount of data in buf. *in is updated to
* the new location where input data should be read from, *inlen is updated with
* the remaining amount of data in *in. Returns the largest value <= *inlen
* which is a multiple of the blocksize.
*/
size_t fillblock(unsigned char *buf, size_t *buflen, size_t blocksize,
const unsigned char **in, size_t *inlen)
{
size_t blockmask = ~(blocksize - 1);
assert(*buflen <= blocksize);
assert(blocksize > 0 && (blocksize & (blocksize - 1)) == 0);
if (*buflen != blocksize && (*buflen != 0 || *inlen < blocksize)) {
size_t bufremain = blocksize - *buflen;
if (*inlen < bufremain)
bufremain = *inlen;
memcpy(buf + *buflen, *in, bufremain);
*in += bufremain;
*inlen -= bufremain;
*buflen += bufremain;
}
return *inlen & blockmask;
}
/*
* Fills the buffer with trailing data from an encryption/decryption that didn't
* fit into a full block.
*/
int trailingdata(unsigned char *buf, size_t *buflen, size_t blocksize,
const unsigned char **in, size_t *inlen)
{
if (*inlen == 0)
return 1;
if (*buflen + *inlen > blocksize) {
ERR_raise(ERR_LIB_PROV, ERR_R_INTERNAL_ERROR);
return 0;
}
memcpy(buf + *buflen, *in, *inlen);
*buflen += *inlen;
*inlen = 0;
return 1;
}
/* Pad the final block for encryption */
void padblock(unsigned char *buf, size_t *buflen, size_t blocksize)
{
size_t i;
unsigned char pad = (unsigned char)(blocksize - *buflen);
for (i = *buflen; i < blocksize; i++)
buf[i] = pad;
}
int unpadblock(unsigned char *buf, size_t *buflen, size_t blocksize)
{
size_t pad, i;
size_t len = *buflen;
if(len != blocksize) {
ERR_raise(ERR_LIB_PROV, ERR_R_INTERNAL_ERROR);
return 0;
}
/*
* The following assumes that the ciphertext has been authenticated.
* Otherwise it provides a padding oracle.
*/
pad = buf[blocksize - 1];
if (pad == 0 || pad > blocksize) {
ERR_raise(ERR_LIB_PROV, PROV_R_BAD_DECRYPT);
return 0;
}
for (i = 0; i < pad; i++) {
if (buf[--len] != pad) {
ERR_raise(ERR_LIB_PROV, PROV_R_BAD_DECRYPT);
return 0;
}
}
*buflen = len;
return 1;
}
@@ -0,0 +1,421 @@
/*
* Copyright 2019 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
*/
/* Dispatch functions for ccm mode */
#include "prov/ciphercommon.h"
#include "prov/ciphercommon_ccm.h"
#include "prov/providercommonerr.h"
static int ccm_cipher_internal(PROV_CCM_CTX *ctx, unsigned char *out,
size_t *padlen, const unsigned char *in,
size_t len);
static int ccm_tls_init(PROV_CCM_CTX *ctx, unsigned char *aad, size_t alen)
{
size_t len;
if (alen != EVP_AEAD_TLS1_AAD_LEN)
return 0;
/* Save the aad for later use. */
memcpy(ctx->buf, aad, alen);
ctx->tls_aad_len = alen;
len = ctx->buf[alen - 2] << 8 | ctx->buf[alen - 1];
if (len < EVP_CCM_TLS_EXPLICIT_IV_LEN)
return 0;
/* Correct length for explicit iv. */
len -= EVP_CCM_TLS_EXPLICIT_IV_LEN;
if (!ctx->enc) {
if (len < ctx->m)
return 0;
/* Correct length for tag. */
len -= ctx->m;
}
ctx->buf[alen - 2] = (unsigned char)(len >> 8);
ctx->buf[alen - 1] = (unsigned char)(len & 0xff);
/* Extra padding: tag appended to record. */
return ctx->m;
}
static int ccm_tls_iv_set_fixed(PROV_CCM_CTX *ctx, unsigned char *fixed,
size_t flen)
{
if (flen != EVP_CCM_TLS_FIXED_IV_LEN)
return 0;
/* Copy to first part of the iv. */
memcpy(ctx->iv, fixed, flen);
return 1;
}
static size_t ccm_get_ivlen(PROV_CCM_CTX *ctx)
{
return 15 - ctx->l;
}
int ccm_set_ctx_params(void *vctx, const OSSL_PARAM params[])
{
PROV_CCM_CTX *ctx = (PROV_CCM_CTX *)vctx;
const OSSL_PARAM *p;
size_t sz;
p = OSSL_PARAM_locate_const(params, OSSL_CIPHER_PARAM_AEAD_TAG);
if (p != NULL) {
if (p->data_type != OSSL_PARAM_OCTET_STRING) {
ERR_raise(ERR_LIB_PROV, PROV_R_FAILED_TO_GET_PARAMETER);
return 0;
}
if ((p->data_size & 1) || (p->data_size < 4) || p->data_size > 16) {
ERR_raise(ERR_LIB_PROV, PROV_R_INVALID_TAGLEN);
return 0;
}
if (p->data != NULL) {
if (ctx->enc) {
ERR_raise(ERR_LIB_PROV, PROV_R_TAG_NOT_NEEDED);
return 0;
}
memcpy(ctx->buf, p->data, p->data_size);
ctx->tag_set = 1;
}
ctx->m = p->data_size;
}
p = OSSL_PARAM_locate_const(params, OSSL_CIPHER_PARAM_AEAD_IVLEN);
if (p != NULL) {
size_t ivlen;
if (!OSSL_PARAM_get_size_t(p, &sz)) {
ERR_raise(ERR_LIB_PROV, PROV_R_FAILED_TO_GET_PARAMETER);
return 0;
}
ivlen = 15 - sz;
if (ivlen < 2 || ivlen > 8) {
ERR_raise(ERR_LIB_PROV, PROV_R_INVALID_IVLEN);
return 0;
}
ctx->l = ivlen;
}
p = OSSL_PARAM_locate_const(params, OSSL_CIPHER_PARAM_AEAD_TLS1_AAD);
if (p != NULL) {
if (p->data_type != OSSL_PARAM_OCTET_STRING) {
ERR_raise(ERR_LIB_PROV, PROV_R_FAILED_TO_GET_PARAMETER);
return 0;
}
sz = ccm_tls_init(ctx, p->data, p->data_size);
if (sz == 0) {
ERR_raise(ERR_LIB_PROV, PROV_R_INVALID_DATA);
return 0;
}
ctx->tls_aad_pad_sz = sz;
}
p = OSSL_PARAM_locate_const(params, OSSL_CIPHER_PARAM_AEAD_TLS1_IV_FIXED);
if (p != NULL) {
if (p->data_type != OSSL_PARAM_OCTET_STRING) {
ERR_raise(ERR_LIB_PROV, PROV_R_FAILED_TO_GET_PARAMETER);
return 0;
}
if (ccm_tls_iv_set_fixed(ctx, p->data, p->data_size) == 0) {
ERR_raise(ERR_LIB_PROV, PROV_R_INVALID_IVLEN);
return 0;
}
}
return 1;
}
int ccm_get_ctx_params(void *vctx, OSSL_PARAM params[])
{
PROV_CCM_CTX *ctx = (PROV_CCM_CTX *)vctx;
OSSL_PARAM *p;
p = OSSL_PARAM_locate(params, OSSL_CIPHER_PARAM_IVLEN);
if (p != NULL && !OSSL_PARAM_set_size_t(p, ccm_get_ivlen(ctx))) {
ERR_raise(ERR_LIB_PROV, PROV_R_FAILED_TO_SET_PARAMETER);
return 0;
}
p = OSSL_PARAM_locate(params, OSSL_CIPHER_PARAM_AEAD_TAGLEN);
if (p != NULL) {
size_t m = ctx->m;
if (!OSSL_PARAM_set_size_t(p, m)) {
ERR_raise(ERR_LIB_PROV, PROV_R_FAILED_TO_SET_PARAMETER);
return 0;
}
}
p = OSSL_PARAM_locate(params, OSSL_CIPHER_PARAM_IV);
if (p != NULL) {
if (ccm_get_ivlen(ctx) != p->data_size) {
ERR_raise(ERR_LIB_PROV, PROV_R_INVALID_IVLEN);
return 0;
}
if (!OSSL_PARAM_set_octet_string(p, ctx->iv, p->data_size)) {
ERR_raise(ERR_LIB_PROV, PROV_R_FAILED_TO_SET_PARAMETER);
return 0;
}
}
p = OSSL_PARAM_locate(params, OSSL_CIPHER_PARAM_KEYLEN);
if (p != NULL && !OSSL_PARAM_set_size_t(p, ctx->keylen)) {
ERR_raise(ERR_LIB_PROV, PROV_R_FAILED_TO_SET_PARAMETER);
return 0;
}
p = OSSL_PARAM_locate(params, OSSL_CIPHER_PARAM_AEAD_TLS1_AAD_PAD);
if (p != NULL && !OSSL_PARAM_set_size_t(p, ctx->tls_aad_pad_sz)) {
ERR_raise(ERR_LIB_PROV, PROV_R_FAILED_TO_SET_PARAMETER);
return 0;
}
p = OSSL_PARAM_locate(params, OSSL_CIPHER_PARAM_AEAD_TAG);
if (p != NULL) {
if (!ctx->enc || !ctx->tag_set) {
ERR_raise(ERR_LIB_PROV, PROV_R_TAG_NOTSET);
return 0;
}
if (p->data_type != OSSL_PARAM_OCTET_STRING) {
ERR_raise(ERR_LIB_PROV, PROV_R_FAILED_TO_SET_PARAMETER);
return 0;
}
if (!ctx->hw->gettag(ctx, p->data, p->data_size))
return 0;
ctx->tag_set = 0;
ctx->iv_set = 0;
ctx->len_set = 0;
}
return 1;
}
static int ccm_init(void *vctx, const unsigned char *key, size_t keylen,
const unsigned char *iv, size_t ivlen, int enc)
{
PROV_CCM_CTX *ctx = (PROV_CCM_CTX *)vctx;
ctx->enc = enc;
if (iv != NULL) {
if (ivlen != ccm_get_ivlen(ctx)) {
ERR_raise(ERR_LIB_PROV, PROV_R_INVALID_IVLEN);
return 0;
}
memcpy(ctx->iv, iv, ivlen);
ctx->iv_set = 1;
}
if (key != NULL) {
if (keylen != ctx->keylen) {
ERR_raise(ERR_LIB_PROV, PROV_R_INVALID_KEYLEN);
return 0;
}
return ctx->hw->setkey(ctx, key, keylen);
}
return 1;
}
int ccm_einit(void *vctx, const unsigned char *key, size_t keylen,
const unsigned char *iv, size_t ivlen)
{
return ccm_init(vctx, key, keylen, iv, ivlen, 1);
}
int ccm_dinit(void *vctx, const unsigned char *key, size_t keylen,
const unsigned char *iv, size_t ivlen)
{
return ccm_init(vctx, key, keylen, iv, ivlen, 0);
}
int ccm_stream_update(void *vctx, unsigned char *out, size_t *outl,
size_t outsize, const unsigned char *in,
size_t inl)
{
PROV_CCM_CTX *ctx = (PROV_CCM_CTX *)vctx;
if (outsize < inl) {
ERR_raise(ERR_LIB_PROV, PROV_R_OUTPUT_BUFFER_TOO_SMALL);
return 0;
}
if (!ccm_cipher_internal(ctx, out, outl, in, inl)) {
ERR_raise(ERR_LIB_PROV, PROV_R_CIPHER_OPERATION_FAILED);
return 0;
}
return 1;
}
int ccm_stream_final(void *vctx, unsigned char *out, size_t *outl,
size_t outsize)
{
PROV_CCM_CTX *ctx = (PROV_CCM_CTX *)vctx;
int i;
i = ccm_cipher_internal(ctx, out, outl, NULL, 0);
if (i <= 0)
return 0;
*outl = 0;
return 1;
}
int ccm_cipher(void *vctx,
unsigned char *out, size_t *outl, size_t outsize,
const unsigned char *in, size_t inl)
{
PROV_CCM_CTX *ctx = (PROV_CCM_CTX *)vctx;
if (outsize < inl) {
ERR_raise(ERR_LIB_PROV, PROV_R_OUTPUT_BUFFER_TOO_SMALL);
return 0;
}
if (ccm_cipher_internal(ctx, out, outl, in, inl) <= 0)
return 0;
*outl = inl;
return 1;
}
/* Copy the buffered iv */
static int ccm_set_iv(PROV_CCM_CTX *ctx, size_t mlen)
{
const PROV_CCM_HW *hw = ctx->hw;
if (!hw->setiv(ctx, ctx->iv, ccm_get_ivlen(ctx), mlen))
return 0;
ctx->len_set = 1;
return 1;
}
static int ccm_tls_cipher(PROV_CCM_CTX *ctx,
unsigned char *out, size_t *padlen,
const unsigned char *in, size_t len)
{
int rv = 0;
size_t olen = 0;
/* Encrypt/decrypt must be performed in place */
if (out != in || len < (EVP_CCM_TLS_EXPLICIT_IV_LEN + (size_t)ctx->m))
goto err;
/* If encrypting set explicit IV from sequence number (start of AAD) */
if (ctx->enc)
memcpy(out, ctx->buf, EVP_CCM_TLS_EXPLICIT_IV_LEN);
/* Get rest of IV from explicit IV */
memcpy(ctx->iv + EVP_CCM_TLS_FIXED_IV_LEN, in, EVP_CCM_TLS_EXPLICIT_IV_LEN);
/* Correct length value */
len -= EVP_CCM_TLS_EXPLICIT_IV_LEN + ctx->m;
if (!ccm_set_iv(ctx, len))
goto err;
/* Use saved AAD */
if (!ctx->hw->setaad(ctx, ctx->buf, ctx->tls_aad_len))
goto err;
/* Fix buffer to point to payload */
in += EVP_CCM_TLS_EXPLICIT_IV_LEN;
out += EVP_CCM_TLS_EXPLICIT_IV_LEN;
if (ctx->enc) {
if (!ctx->hw->auth_encrypt(ctx, in, out, len, out + len, ctx->m))
goto err;
olen = len + EVP_CCM_TLS_EXPLICIT_IV_LEN + ctx->m;
} else {
if (!ctx->hw->auth_decrypt(ctx, in, out, len,
(unsigned char *)in + len, ctx->m))
goto err;
olen = len;
}
rv = 1;
err:
*padlen = olen;
return rv;
}
static int ccm_cipher_internal(PROV_CCM_CTX *ctx, unsigned char *out,
size_t *padlen, const unsigned char *in,
size_t len)
{
int rv = 0;
size_t olen = 0;
const PROV_CCM_HW *hw = ctx->hw;
/* If no key set, return error */
if (!ctx->key_set)
return 0;
if (ctx->tls_aad_len != UNINITIALISED_SIZET)
return ccm_tls_cipher(ctx, out, padlen, in, len);
/* EVP_*Final() doesn't return any data */
if (in == NULL && out != NULL)
goto finish;
if (!ctx->iv_set)
goto err;
if (out == NULL) {
if (in == NULL) {
if (!ccm_set_iv(ctx, len))
goto err;
} else {
/* If we have AAD, we need a message length */
if (!ctx->len_set && len)
goto err;
if (!hw->setaad(ctx, in, len))
goto err;
}
} else {
/* If not set length yet do it */
if (!ctx->len_set && !ccm_set_iv(ctx, len))
goto err;
if (ctx->enc) {
if (!hw->auth_encrypt(ctx, in, out, len, NULL, 0))
goto err;
ctx->tag_set = 1;
} else {
/* The tag must be set before actually decrypting data */
if (!ctx->tag_set)
goto err;
if (!hw->auth_decrypt(ctx, in, out, len, ctx->buf, ctx->m))
goto err;
/* Finished - reset flags so calling this method again will fail */
ctx->iv_set = 0;
ctx->tag_set = 0;
ctx->len_set = 0;
}
}
olen = len;
finish:
rv = 1;
err:
*padlen = olen;
return rv;
}
void ccm_initctx(PROV_CCM_CTX *ctx, size_t keybits, const PROV_CCM_HW *hw)
{
ctx->keylen = keybits / 8;
ctx->key_set = 0;
ctx->iv_set = 0;
ctx->tag_set = 0;
ctx->len_set = 0;
ctx->l = 8;
ctx->m = 12;
ctx->tls_aad_len = UNINITIALISED_SIZET;
ctx->hw = hw;
}
@@ -0,0 +1,69 @@
/*
* Copyright 2019 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
*/
#include "prov/ciphercommon.h"
#include "prov/ciphercommon_ccm.h"
int ccm_generic_setiv(PROV_CCM_CTX *ctx, const unsigned char *nonce,
size_t nlen, size_t mlen)
{
return CRYPTO_ccm128_setiv(&ctx->ccm_ctx, nonce, nlen, mlen) == 0;
}
int ccm_generic_setaad(PROV_CCM_CTX *ctx, const unsigned char *aad, size_t alen)
{
CRYPTO_ccm128_aad(&ctx->ccm_ctx, aad, alen);
return 1;
}
int ccm_generic_gettag(PROV_CCM_CTX *ctx, unsigned char *tag, size_t tlen)
{
return CRYPTO_ccm128_tag(&ctx->ccm_ctx, tag, tlen) > 0;
}
int ccm_generic_auth_encrypt(PROV_CCM_CTX *ctx, const unsigned char *in,
unsigned char *out, size_t len,
unsigned char *tag, size_t taglen)
{
int rv;
if (ctx->str != NULL)
rv = CRYPTO_ccm128_encrypt_ccm64(&ctx->ccm_ctx, in,
out, len, ctx->str) == 0;
else
rv = CRYPTO_ccm128_encrypt(&ctx->ccm_ctx, in, out, len) == 0;
if (rv == 1 && tag != NULL)
rv = (CRYPTO_ccm128_tag(&ctx->ccm_ctx, tag, taglen) > 0);
return rv;
}
int ccm_generic_auth_decrypt(PROV_CCM_CTX *ctx, const unsigned char *in,
unsigned char *out, size_t len,
unsigned char *expected_tag, size_t taglen)
{
int rv = 0;
if (ctx->str != NULL)
rv = CRYPTO_ccm128_decrypt_ccm64(&ctx->ccm_ctx, in, out, len,
ctx->str) == 0;
else
rv = CRYPTO_ccm128_decrypt(&ctx->ccm_ctx, in, out, len) == 0;
if (rv) {
unsigned char tag[16];
if (!CRYPTO_ccm128_tag(&ctx->ccm_ctx, tag, taglen)
|| CRYPTO_memcmp(tag, expected_tag, taglen) != 0)
rv = 0;
}
if (rv == 0)
OPENSSL_cleanse(out, len);
return rv;
}
@@ -0,0 +1,530 @@
/*
* Copyright 2019 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
*/
/* Dispatch functions for gcm mode */
#include "prov/ciphercommon.h"
#include "prov/ciphercommon_gcm.h"
#include "prov/providercommonerr.h"
#include "crypto/rand.h"
#include "prov/provider_ctx.h"
static int gcm_tls_init(PROV_GCM_CTX *dat, unsigned char *aad, size_t aad_len);
static int gcm_tls_iv_set_fixed(PROV_GCM_CTX *ctx, unsigned char *iv,
size_t len);
static int gcm_tls_cipher(PROV_GCM_CTX *ctx, unsigned char *out, size_t *padlen,
const unsigned char *in, size_t len);
static int gcm_cipher_internal(PROV_GCM_CTX *ctx, unsigned char *out,
size_t *padlen, const unsigned char *in,
size_t len);
void gcm_initctx(void *provctx, PROV_GCM_CTX *ctx, size_t keybits,
const PROV_GCM_HW *hw, size_t ivlen_min)
{
ctx->pad = 1;
ctx->mode = EVP_CIPH_GCM_MODE;
ctx->taglen = UNINITIALISED_SIZET;
ctx->tls_aad_len = UNINITIALISED_SIZET;
ctx->ivlen_min = ivlen_min;
ctx->ivlen = (EVP_GCM_TLS_FIXED_IV_LEN + EVP_GCM_TLS_EXPLICIT_IV_LEN);
ctx->keylen = keybits / 8;
ctx->hw = hw;
ctx->libctx = PROV_LIBRARY_CONTEXT_OF(provctx);
}
static int gcm_init(void *vctx, const unsigned char *key, size_t keylen,
const unsigned char *iv, size_t ivlen, int enc)
{
PROV_GCM_CTX *ctx = (PROV_GCM_CTX *)vctx;
ctx->enc = enc;
if (iv != NULL) {
if (ivlen < ctx->ivlen_min || ivlen > sizeof(ctx->iv)) {
ERR_raise(ERR_LIB_PROV, PROV_R_INVALID_IV_LENGTH);
return 0;
}
ctx->ivlen = ivlen;
memcpy(ctx->iv, iv, ivlen);
ctx->iv_state = IV_STATE_BUFFERED;
}
if (key != NULL) {
if (keylen != ctx->keylen) {
ERR_raise(ERR_LIB_PROV, PROV_R_INVALID_KEY_LENGTH);
return 0;
}
return ctx->hw->setkey(ctx, key, ctx->keylen);
}
return 1;
}
int gcm_einit(void *vctx, const unsigned char *key, size_t keylen,
const unsigned char *iv, size_t ivlen)
{
return gcm_init(vctx, key, keylen, iv, ivlen, 1);
}
int gcm_dinit(void *vctx, const unsigned char *key, size_t keylen,
const unsigned char *iv, size_t ivlen)
{
return gcm_init(vctx, key, keylen, iv, ivlen, 0);
}
/* increment counter (64-bit int) by 1 */
static void ctr64_inc(unsigned char *counter)
{
int n = 8;
unsigned char c;
do {
--n;
c = counter[n];
++c;
counter[n] = c;
if (c > 0)
return;
} while (n > 0);
}
static int getivgen(PROV_GCM_CTX *ctx, unsigned char *out, size_t olen)
{
if (!ctx->iv_gen
|| !ctx->key_set
|| !ctx->hw->setiv(ctx, ctx->iv, ctx->ivlen))
return 0;
if (olen == 0 || olen > ctx->ivlen)
olen = ctx->ivlen;
memcpy(out, ctx->iv + ctx->ivlen - olen, olen);
/*
* Invocation field will be at least 8 bytes in size and so no need
* to check wrap around or increment more than last 8 bytes.
*/
ctr64_inc(ctx->iv + ctx->ivlen - 8);
ctx->iv_state = IV_STATE_COPIED;
return 1;
}
static int setivinv(PROV_GCM_CTX *ctx, unsigned char *in, size_t inl)
{
if (!ctx->iv_gen
|| !ctx->key_set
|| ctx->enc)
return 0;
memcpy(ctx->iv + ctx->ivlen - inl, in, inl);
if (!ctx->hw->setiv(ctx, ctx->iv, ctx->ivlen))
return 0;
ctx->iv_state = IV_STATE_COPIED;
return 1;
}
int gcm_get_ctx_params(void *vctx, OSSL_PARAM params[])
{
PROV_GCM_CTX *ctx = (PROV_GCM_CTX *)vctx;
OSSL_PARAM *p;
size_t sz;
p = OSSL_PARAM_locate(params, OSSL_CIPHER_PARAM_IVLEN);
if (p != NULL && !OSSL_PARAM_set_size_t(p, ctx->ivlen)) {
ERR_raise(ERR_LIB_PROV, PROV_R_FAILED_TO_SET_PARAMETER);
return 0;
}
p = OSSL_PARAM_locate(params, OSSL_CIPHER_PARAM_KEYLEN);
if (p != NULL && !OSSL_PARAM_set_size_t(p, ctx->keylen)) {
ERR_raise(ERR_LIB_PROV, PROV_R_FAILED_TO_SET_PARAMETER);
return 0;
}
p = OSSL_PARAM_locate(params, OSSL_CIPHER_PARAM_AEAD_TAGLEN);
if (p != NULL) {
size_t taglen = (ctx->taglen != UNINITIALISED_SIZET) ? ctx->taglen :
GCM_TAG_MAX_SIZE;
if (!OSSL_PARAM_set_size_t(p, taglen)) {
ERR_raise(ERR_LIB_PROV, PROV_R_FAILED_TO_SET_PARAMETER);
return 0;
}
}
p = OSSL_PARAM_locate(params, OSSL_CIPHER_PARAM_IV);
if (p != NULL) {
if (ctx->iv_gen != 1 && ctx->iv_gen_rand != 1)
return 0;
if (ctx->ivlen != p->data_size) {
ERR_raise(ERR_LIB_PROV, PROV_R_INVALID_IV_LENGTH);
return 0;
}
if (!OSSL_PARAM_set_octet_string(p, ctx->iv, ctx->ivlen)) {
ERR_raise(ERR_LIB_PROV, PROV_R_FAILED_TO_SET_PARAMETER);
return 0;
}
}
p = OSSL_PARAM_locate(params, OSSL_CIPHER_PARAM_AEAD_TLS1_AAD_PAD);
if (p != NULL && !OSSL_PARAM_set_size_t(p, ctx->tls_aad_pad_sz)) {
ERR_raise(ERR_LIB_PROV, PROV_R_FAILED_TO_SET_PARAMETER);
return 0;
}
p = OSSL_PARAM_locate(params, OSSL_CIPHER_PARAM_AEAD_TAG);
if (p != NULL) {
sz = p->data_size;
if (sz == 0
|| sz > EVP_GCM_TLS_TAG_LEN
|| !ctx->enc
|| ctx->taglen == UNINITIALISED_SIZET) {
ERR_raise(ERR_LIB_PROV, PROV_R_INVALID_TAG);
return 0;
}
if (!OSSL_PARAM_set_octet_string(p, ctx->buf, sz)) {
ERR_raise(ERR_LIB_PROV, PROV_R_FAILED_TO_SET_PARAMETER);
return 0;
}
}
p = OSSL_PARAM_locate(params, OSSL_CIPHER_PARAM_AEAD_TLS1_GET_IV_GEN);
if (p != NULL) {
if (p->data == NULL
|| p->data_type != OSSL_PARAM_OCTET_STRING
|| !getivgen(ctx, p->data, p->data_size))
return 0;
}
return 1;
}
int gcm_set_ctx_params(void *vctx, const OSSL_PARAM params[])
{
PROV_GCM_CTX *ctx = (PROV_GCM_CTX *)vctx;
const OSSL_PARAM *p;
size_t sz;
void *vp;
p = OSSL_PARAM_locate_const(params, OSSL_CIPHER_PARAM_AEAD_TAG);
if (p != NULL) {
vp = ctx->buf;
if (!OSSL_PARAM_get_octet_string(p, &vp, EVP_GCM_TLS_TAG_LEN, &sz)) {
ERR_raise(ERR_LIB_PROV, PROV_R_FAILED_TO_GET_PARAMETER);
return 0;
}
if (sz == 0 || ctx->enc) {
ERR_raise(ERR_LIB_PROV, PROV_R_INVALID_TAG);
return 0;
}
ctx->taglen = sz;
}
p = OSSL_PARAM_locate_const(params, OSSL_CIPHER_PARAM_AEAD_IVLEN);
if (p != NULL) {
if (!OSSL_PARAM_get_size_t(p, &sz)) {
ERR_raise(ERR_LIB_PROV, PROV_R_FAILED_TO_GET_PARAMETER);
return 0;
}
if (sz == 0 || sz > sizeof(ctx->iv)) {
ERR_raise(ERR_LIB_PROV, PROV_R_INVALID_IV_LENGTH);
return 0;
}
ctx->ivlen = sz;
}
p = OSSL_PARAM_locate_const(params, OSSL_CIPHER_PARAM_AEAD_TLS1_AAD);
if (p != NULL) {
if (p->data_type != OSSL_PARAM_OCTET_STRING) {
ERR_raise(ERR_LIB_PROV, PROV_R_FAILED_TO_GET_PARAMETER);
return 0;
}
sz = gcm_tls_init(ctx, p->data, p->data_size);
if (sz == 0) {
ERR_raise(ERR_LIB_PROV, PROV_R_INVALID_AAD);
return 0;
}
ctx->tls_aad_pad_sz = sz;
}
p = OSSL_PARAM_locate_const(params, OSSL_CIPHER_PARAM_AEAD_TLS1_IV_FIXED);
if (p != NULL) {
if (p->data_type != OSSL_PARAM_OCTET_STRING) {
ERR_raise(ERR_LIB_PROV, PROV_R_FAILED_TO_GET_PARAMETER);
return 0;
}
if (gcm_tls_iv_set_fixed(ctx, p->data, p->data_size) == 0) {
ERR_raise(ERR_LIB_PROV, PROV_R_FAILED_TO_GET_PARAMETER);
return 0;
}
}
p = OSSL_PARAM_locate_const(params, OSSL_CIPHER_PARAM_AEAD_TLS1_SET_IV_INV);
if (p != NULL) {
if (p->data == NULL
|| p->data_type != OSSL_PARAM_OCTET_STRING
|| !setivinv(ctx, p->data, p->data_size))
return 0;
}
return 1;
}
int gcm_stream_update(void *vctx, unsigned char *out, size_t *outl,
size_t outsize, const unsigned char *in, size_t inl)
{
PROV_GCM_CTX *ctx = (PROV_GCM_CTX *)vctx;
if (inl == 0) {
*outl = 0;
return 1;
}
if (outsize < inl) {
ERR_raise(ERR_LIB_PROV, PROV_R_OUTPUT_BUFFER_TOO_SMALL);
return -1;
}
if (gcm_cipher_internal(ctx, out, outl, in, inl) <= 0) {
ERR_raise(ERR_LIB_PROV, PROV_R_CIPHER_OPERATION_FAILED);
return -1;
}
return 1;
}
int gcm_stream_final(void *vctx, unsigned char *out, size_t *outl,
size_t outsize)
{
PROV_GCM_CTX *ctx = (PROV_GCM_CTX *)vctx;
int i;
i = gcm_cipher_internal(ctx, out, outl, NULL, 0);
if (i <= 0)
return 0;
*outl = 0;
return 1;
}
int gcm_cipher(void *vctx,
unsigned char *out, size_t *outl, size_t outsize,
const unsigned char *in, size_t inl)
{
PROV_GCM_CTX *ctx = (PROV_GCM_CTX *)vctx;
if (outsize < inl) {
ERR_raise(ERR_LIB_PROV, PROV_R_OUTPUT_BUFFER_TOO_SMALL);
return 0;
}
if (gcm_cipher_internal(ctx, out, outl, in, inl) <= 0)
return 0;
*outl = inl;
return 1;
}
/*
* See SP800-38D (GCM) Section 8 "Uniqueness requirement on IVS and keys"
*
* See also 8.2.2 RBG-based construction.
* Random construction consists of a free field (which can be NULL) and a
* random field which will use a DRBG that can return at least 96 bits of
* entropy strength. (The DRBG must be seeded by the FIPS module).
*/
static int gcm_iv_generate(PROV_GCM_CTX *ctx, int offset)
{
int sz = ctx->ivlen - offset;
/* Must be at least 96 bits */
if (sz <= 0 || ctx->ivlen < GCM_IV_DEFAULT_SIZE)
return 0;
/* Use DRBG to generate random iv */
if (rand_bytes_ex(ctx->libctx, ctx->iv + offset, sz) <= 0)
return 0;
ctx->iv_state = IV_STATE_BUFFERED;
ctx->iv_gen_rand = 1;
return 1;
}
static int gcm_cipher_internal(PROV_GCM_CTX *ctx, unsigned char *out,
size_t *padlen, const unsigned char *in,
size_t len)
{
size_t olen = 0;
int rv = 0;
const PROV_GCM_HW *hw = ctx->hw;
if (ctx->tls_aad_len != UNINITIALISED_SIZET)
return gcm_tls_cipher(ctx, out, padlen, in, len);
if (!ctx->key_set || ctx->iv_state == IV_STATE_FINISHED)
goto err;
/*
* FIPS requires generation of AES-GCM IV's inside the FIPS module.
* The IV can still be set externally (the security policy will state that
* this is not FIPS compliant). There are some applications
* where setting the IV externally is the only option available.
*/
if (ctx->iv_state == IV_STATE_UNINITIALISED) {
if (!ctx->enc || !gcm_iv_generate(ctx, 0))
goto err;
}
if (ctx->iv_state == IV_STATE_BUFFERED) {
if (!hw->setiv(ctx, ctx->iv, ctx->ivlen))
goto err;
ctx->iv_state = IV_STATE_COPIED;
}
if (in != NULL) {
/* The input is AAD if out is NULL */
if (out == NULL) {
if (!hw->aadupdate(ctx, in, len))
goto err;
} else {
/* The input is ciphertext OR plaintext */
if (!hw->cipherupdate(ctx, in, len, out))
goto err;
}
} else {
/* The tag must be set before actually decrypting data */
if (!ctx->enc && ctx->taglen == UNINITIALISED_SIZET)
goto err;
if (!hw->cipherfinal(ctx, ctx->buf))
goto err;
ctx->iv_state = IV_STATE_FINISHED; /* Don't reuse the IV */
goto finish;
}
olen = len;
finish:
rv = 1;
err:
*padlen = olen;
return rv;
}
static int gcm_tls_init(PROV_GCM_CTX *dat, unsigned char *aad, size_t aad_len)
{
unsigned char *buf;
size_t len;
if (aad_len != EVP_AEAD_TLS1_AAD_LEN)
return 0;
/* Save the aad for later use. */
buf = dat->buf;
memcpy(buf, aad, aad_len);
dat->tls_aad_len = aad_len;
dat->tls_enc_records = 0;
len = buf[aad_len - 2] << 8 | buf[aad_len - 1];
/* Correct length for explicit iv. */
if (len < EVP_GCM_TLS_EXPLICIT_IV_LEN)
return 0;
len -= EVP_GCM_TLS_EXPLICIT_IV_LEN;
/* If decrypting correct for tag too. */
if (!dat->enc) {
if (len < EVP_GCM_TLS_TAG_LEN)
return 0;
len -= EVP_GCM_TLS_TAG_LEN;
}
buf[aad_len - 2] = (unsigned char)(len >> 8);
buf[aad_len - 1] = (unsigned char)(len & 0xff);
/* Extra padding: tag appended to record. */
return EVP_GCM_TLS_TAG_LEN;
}
static int gcm_tls_iv_set_fixed(PROV_GCM_CTX *ctx, unsigned char *iv,
size_t len)
{
/* Special case: -1 length restores whole IV */
if (len == (size_t)-1) {
memcpy(ctx->iv, iv, ctx->ivlen);
ctx->iv_gen = 1;
ctx->iv_state = IV_STATE_BUFFERED;
return 1;
}
/* Fixed field must be at least 4 bytes and invocation field at least 8 */
if ((len < EVP_GCM_TLS_FIXED_IV_LEN)
|| (ctx->ivlen - (int)len) < EVP_GCM_TLS_EXPLICIT_IV_LEN)
return 0;
if (len > 0)
memcpy(ctx->iv, iv, len);
if (ctx->enc
&& rand_bytes_ex(ctx->libctx, ctx->iv + len, ctx->ivlen - len) <= 0)
return 0;
ctx->iv_gen = 1;
ctx->iv_state = IV_STATE_BUFFERED;
return 1;
}
/*
* Handle TLS GCM packet format. This consists of the last portion of the IV
* followed by the payload and finally the tag. On encrypt generate IV,
* encrypt payload and write the tag. On verify retrieve IV, decrypt payload
* and verify tag.
*/
static int gcm_tls_cipher(PROV_GCM_CTX *ctx, unsigned char *out, size_t *padlen,
const unsigned char *in, size_t len)
{
int rv = 0;
size_t arg = EVP_GCM_TLS_EXPLICIT_IV_LEN;
size_t plen = 0;
unsigned char *tag = NULL;
if (!ctx->key_set)
goto err;
/* Encrypt/decrypt must be performed in place */
if (out != in || len < (EVP_GCM_TLS_EXPLICIT_IV_LEN + EVP_GCM_TLS_TAG_LEN))
goto err;
/*
* Check for too many keys as per FIPS 140-2 IG A.5 "Key/IV Pair Uniqueness
* Requirements from SP 800-38D". The requirements is for one party to the
* communication to fail after 2^64 - 1 keys. We do this on the encrypting
* side only.
*/
if (ctx->enc && ++ctx->tls_enc_records == 0) {
ERR_raise(ERR_LIB_PROV, EVP_R_TOO_MANY_RECORDS);
goto err;
}
/*
* Set IV from start of buffer or generate IV and write to start of
* buffer.
*/
if (ctx->enc) {
if (!getivgen(ctx, out, arg))
goto err;
} else {
if (!setivinv(ctx, out, arg))
goto err;
}
/* Fix buffer and length to point to payload */
in += EVP_GCM_TLS_EXPLICIT_IV_LEN;
out += EVP_GCM_TLS_EXPLICIT_IV_LEN;
len -= EVP_GCM_TLS_EXPLICIT_IV_LEN + EVP_GCM_TLS_TAG_LEN;
tag = ctx->enc ? out + len : (unsigned char *)in + len;
if (!ctx->hw->oneshot(ctx, ctx->buf, ctx->tls_aad_len, in, len, out, tag,
EVP_GCM_TLS_TAG_LEN)) {
if (!ctx->enc)
OPENSSL_cleanse(out, len);
goto err;
}
if (ctx->enc)
plen = len + EVP_GCM_TLS_EXPLICIT_IV_LEN + EVP_GCM_TLS_TAG_LEN;
else
plen = len;
rv = 1;
err:
ctx->iv_state = IV_STATE_FINISHED;
ctx->tls_aad_len = UNINITIALISED_SIZET;
*padlen = plen;
return rv;
}
@@ -0,0 +1,68 @@
/*
* Copyright 2001-2019 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
*/
#include "prov/ciphercommon.h"
#include "prov/ciphercommon_gcm.h"
int gcm_setiv(PROV_GCM_CTX *ctx, const unsigned char *iv, size_t ivlen)
{
CRYPTO_gcm128_setiv(&ctx->gcm, iv, ivlen);
return 1;
}
int gcm_aad_update(PROV_GCM_CTX *ctx, const unsigned char *aad, size_t aad_len)
{
return CRYPTO_gcm128_aad(&ctx->gcm, aad, aad_len) == 0;
}
int gcm_cipher_update(PROV_GCM_CTX *ctx, const unsigned char *in,
size_t len, unsigned char *out)
{
if (ctx->enc) {
if (CRYPTO_gcm128_encrypt(&ctx->gcm, in, out, len))
return 0;
} else {
if (CRYPTO_gcm128_decrypt(&ctx->gcm, in, out, len))
return 0;
}
return 1;
}
int gcm_cipher_final(PROV_GCM_CTX *ctx, unsigned char *tag)
{
if (ctx->enc) {
CRYPTO_gcm128_tag(&ctx->gcm, tag, GCM_TAG_MAX_SIZE);
ctx->taglen = GCM_TAG_MAX_SIZE;
} else {
if (CRYPTO_gcm128_finish(&ctx->gcm, tag, ctx->taglen) != 0)
return 0;
}
return 1;
}
int gcm_one_shot(PROV_GCM_CTX *ctx, unsigned char *aad, size_t aad_len,
const unsigned char *in, size_t in_len,
unsigned char *out, unsigned char *tag, size_t tag_len)
{
int ret = 0;
/* Use saved AAD */
if (!ctx->hw->aadupdate(ctx, aad, aad_len))
goto err;
if (!ctx->hw->cipherupdate(ctx, in, in_len, out))
goto err;
ctx->taglen = GCM_TAG_MAX_SIZE;
if (!ctx->hw->cipherfinal(ctx, tag))
goto err;
ret = 1;
err:
return ret;
}
@@ -0,0 +1,194 @@
/*
* Copyright 2019 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
*/
#include "prov/ciphercommon.h"
/*-
* The generic cipher functions for cipher modes cbc, ecb, ofb, cfb and ctr.
* Used if there is no special hardware implementations.
*/
int cipher_hw_generic_cbc(PROV_CIPHER_CTX *dat, unsigned char *out,
const unsigned char *in, size_t len)
{
if (dat->stream.cbc)
(*dat->stream.cbc) (in, out, len, dat->ks, dat->iv, dat->enc);
else if (dat->enc)
CRYPTO_cbc128_encrypt(in, out, len, dat->ks, dat->iv, dat->block);
else
CRYPTO_cbc128_decrypt(in, out, len, dat->ks, dat->iv, dat->block);
return 1;
}
int cipher_hw_generic_ecb(PROV_CIPHER_CTX *dat, unsigned char *out,
const unsigned char *in, size_t len)
{
size_t i, bl = dat->blocksize;
if (len < bl)
return 1;
if (dat->stream.ecb) {
(*dat->stream.ecb) (in, out, len, dat->ks, dat->enc);
}
else {
for (i = 0, len -= bl; i <= len; i += bl)
(*dat->block) (in + i, out + i, dat->ks);
}
return 1;
}
int cipher_hw_generic_ofb128(PROV_CIPHER_CTX *dat, unsigned char *out,
const unsigned char *in, size_t len)
{
int num = dat->num;
CRYPTO_ofb128_encrypt(in, out, len, dat->ks, dat->iv, &num, dat->block);
dat->num = num;
return 1;
}
int cipher_hw_generic_cfb128(PROV_CIPHER_CTX *dat, unsigned char *out,
const unsigned char *in, size_t len)
{
int num = dat->num;
CRYPTO_cfb128_encrypt(in, out, len, dat->ks, dat->iv, &num, dat->enc,
dat->block);
dat->num = num;
return 1;
}
int cipher_hw_generic_cfb8(PROV_CIPHER_CTX *dat, unsigned char *out,
const unsigned char *in, size_t len)
{
int num = dat->num;
CRYPTO_cfb128_8_encrypt(in, out, len, dat->ks, dat->iv, &num, dat->enc,
dat->block);
dat->num = num;
return 1;
}
int cipher_hw_generic_cfb1(PROV_CIPHER_CTX *dat, unsigned char *out,
const unsigned char *in, size_t len)
{
int num = dat->num;
if ((dat->flags & EVP_CIPH_FLAG_LENGTH_BITS) != 0) {
CRYPTO_cfb128_1_encrypt(in, out, len, dat->ks, dat->iv, &num,
dat->enc, dat->block);
dat->num = num;
return 1;
}
while (len >= MAXBITCHUNK) {
CRYPTO_cfb128_1_encrypt(in, out, MAXBITCHUNK * 8, dat->ks,
dat->iv, &num, dat->enc, dat->block);
len -= MAXBITCHUNK;
out += MAXBITCHUNK;
in += MAXBITCHUNK;
}
if (len)
CRYPTO_cfb128_1_encrypt(in, out, len * 8, dat->ks, dat->iv, &num,
dat->enc, dat->block);
dat->num = num;
return 1;
}
int cipher_hw_generic_ctr(PROV_CIPHER_CTX *dat, unsigned char *out,
const unsigned char *in, size_t len)
{
unsigned int num = dat->num;
if (dat->stream.ctr)
CRYPTO_ctr128_encrypt_ctr32(in, out, len, dat->ks, dat->iv, dat->buf,
&num, dat->stream.ctr);
else
CRYPTO_ctr128_encrypt(in, out, len, dat->ks, dat->iv, dat->buf,
&num, dat->block);
dat->num = num;
return 1;
}
/*-
* The chunked cipher functions for cipher modes cbc, ecb, ofb, cfb and ctr.
* Used if there is no special hardware implementations.
*/
int cipher_hw_chunked_cbc(PROV_CIPHER_CTX *ctx, unsigned char *out,
const unsigned char *in, size_t inl)
{
while (inl >= MAXCHUNK) {
cipher_hw_generic_cbc(ctx, out, in, MAXCHUNK);
inl -= MAXCHUNK;
in += MAXCHUNK;
out += MAXCHUNK;
}
if (inl > 0)
cipher_hw_generic_cbc(ctx, out, in, inl);
return 1;
}
int cipher_hw_chunked_cfb8(PROV_CIPHER_CTX *ctx, unsigned char *out,
const unsigned char *in, size_t inl)
{
size_t chunk = MAXCHUNK;
if (inl < chunk)
chunk = inl;
while (inl > 0 && inl >= chunk) {
cipher_hw_generic_cfb8(ctx, out, in, inl);
inl -= chunk;
in += chunk;
out += chunk;
if (inl < chunk)
chunk = inl;
}
return 1;
}
int cipher_hw_chunked_cfb128(PROV_CIPHER_CTX *ctx, unsigned char *out,
const unsigned char *in, size_t inl)
{
size_t chunk = MAXCHUNK;
if (inl < chunk)
chunk = inl;
while (inl > 0 && inl >= chunk) {
cipher_hw_generic_cfb128(ctx, out, in, inl);
inl -= chunk;
in += chunk;
out += chunk;
if (inl < chunk)
chunk = inl;
}
return 1;
}
int cipher_hw_chunked_ofb128(PROV_CIPHER_CTX *ctx, unsigned char *out,
const unsigned char *in, size_t inl)
{
while (inl >= MAXCHUNK) {
cipher_hw_generic_ofb128(ctx, out, in, MAXCHUNK);
inl -= MAXCHUNK;
in += MAXCHUNK;
out += MAXCHUNK;
}
if (inl > 0)
cipher_hw_generic_ofb128(ctx, out, in, inl);
return 1;
}
@@ -0,0 +1,13 @@
/*
* Copyright 2019 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
*/
#include "prov/ciphercommon.h"
void padblock(unsigned char *buf, size_t *buflen, size_t blocksize);
int unpadblock(unsigned char *buf, size_t *buflen, size_t blocksize);
+5 -2
View File
@@ -1,6 +1,8 @@
# We make separate GOAL variables for each algorithm, to make it easy to
# switch each to the Legacy provider when needed.
$COMMON_GOAL=../../libcommon.a
$SHA1_GOAL=../../libimplementations.a
$SHA2_GOAL=../../libimplementations.a
$SHA3_GOAL=../../libimplementations.a
@@ -14,11 +16,12 @@ $MDC2_GOAL=../../liblegacy.a
$WHIRLPOOL_GOAL=../../liblegacy.a
$RIPEMD_GOAL=../../liblegacy.a
# This source is common for all digests in all our providers.
SOURCE[$COMMON_GOAL]=digestcommon.c
SOURCE[$SHA2_GOAL]=sha2_prov.c
SOURCE[$SHA3_GOAL]=sha3_prov.c
$GOAL=../../libimplementations.a
IF[{- !$disabled{blake2} -}]
SOURCE[$BLAKE2_GOAL]=blake2_prov.c blake2b_prov.c blake2s_prov.c
ENDIF
@@ -0,0 +1,46 @@
/*
* Copyright 2019 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
*/
#include "openssl/err.h"
#include "prov/digestcommon.h"
#include "prov/providercommonerr.h"
int digest_default_get_params(OSSL_PARAM params[], size_t blksz, size_t paramsz,
unsigned long flags)
{
OSSL_PARAM *p = NULL;
p = OSSL_PARAM_locate(params, OSSL_DIGEST_PARAM_BLOCK_SIZE);
if (p != NULL && !OSSL_PARAM_set_size_t(p, blksz)) {
ERR_raise(ERR_LIB_PROV, PROV_R_FAILED_TO_SET_PARAMETER);
return 0;
}
p = OSSL_PARAM_locate(params, OSSL_DIGEST_PARAM_SIZE);
if (p != NULL && !OSSL_PARAM_set_size_t(p, paramsz)) {
ERR_raise(ERR_LIB_PROV, PROV_R_FAILED_TO_SET_PARAMETER);
return 0;
}
p = OSSL_PARAM_locate(params, OSSL_DIGEST_PARAM_FLAGS);
if (p != NULL && !OSSL_PARAM_set_ulong(p, flags)) {
ERR_raise(ERR_LIB_PROV, PROV_R_FAILED_TO_SET_PARAMETER);
return 0;
}
return 1;
}
static const OSSL_PARAM digest_default_known_gettable_params[] = {
OSSL_PARAM_size_t(OSSL_DIGEST_PARAM_BLOCK_SIZE, NULL),
OSSL_PARAM_size_t(OSSL_DIGEST_PARAM_SIZE, NULL),
OSSL_PARAM_ulong(OSSL_DIGEST_PARAM_FLAGS, NULL),
OSSL_PARAM_END
};
const OSSL_PARAM *digest_default_gettable_params(void)
{
return digest_default_known_gettable_params;
}
@@ -7,6 +7,12 @@
* https://www.openssl.org/source/license.html
*/
/*
* MD2 low level APIs are deprecated for public use, but still ok for
* internal use.
*/
#include "internal/deprecated.h"
#include <openssl/crypto.h>
#include <openssl/md2.h>
#include "prov/digestcommon.h"
@@ -7,6 +7,12 @@
* https://www.openssl.org/source/license.html
*/
/*
* MD4 low level APIs are deprecated for public use, but still ok for
* internal use.
*/
#include "internal/deprecated.h"
#include <openssl/crypto.h>
#include <openssl/md4.h>
#include "prov/digestcommon.h"
@@ -7,6 +7,12 @@
* https://www.openssl.org/source/license.html
*/
/*
* MDC2 low level APIs are deprecated for public use, but still ok for
* internal use.
*/
#include "internal/deprecated.h"
#include <openssl/crypto.h>
#include <openssl/params.h>
#include <openssl/mdc2.h>
@@ -7,6 +7,12 @@
* https://www.openssl.org/source/license.html
*/
/*
* RIPEMD160 low level APIs are deprecated for public use, but still ok for
* internal use.
*/
#include "internal/deprecated.h"
#include <openssl/crypto.h>
#include <openssl/ripemd.h>
#include "prov/digestcommon.h"
@@ -241,7 +241,8 @@ static void *keccak_dupctx(void *ctx)
KECCAK1600_CTX *in = (KECCAK1600_CTX *)ctx;
KECCAK1600_CTX *ret = OPENSSL_malloc(sizeof(*ret));
*ret = *in;
if (ret != NULL)
*ret = *in;
return ret;
}
@@ -7,6 +7,12 @@
* https://www.openssl.org/source/license.html
*/
/*
* Whirlpool low level APIs are deprecated for public use, but still ok for
* internal use.
*/
#include "internal/deprecated.h"
#include <openssl/crypto.h>
#include <openssl/whrlpool.h>
#include "prov/digestcommon.h"
@@ -0,0 +1,324 @@
/*
* Copyright 2019 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
*/
#include <openssl/params.h>
#include <openssl/core_numbers.h>
#include <openssl/core_names.h>
#include <openssl/evp.h>
#include "internal/cryptlib.h"
#include "crypto/modes.h"
#define MAXCHUNK ((size_t)1 << (sizeof(long) * 8 - 2))
#define MAXBITCHUNK ((size_t)1 << (sizeof(size_t) * 8 - 4))
#define GENERIC_BLOCK_SIZE 16
#define IV_STATE_UNINITIALISED 0 /* initial state is not initialized */
#define IV_STATE_BUFFERED 1 /* iv has been copied to the iv buffer */
#define IV_STATE_COPIED 2 /* iv has been copied from the iv buffer */
#define IV_STATE_FINISHED 3 /* the iv has been used - so don't reuse it */
#define PROV_CIPHER_FUNC(type, name, args) typedef type (* OSSL_##name##_fn)args
typedef struct prov_cipher_hw_st PROV_CIPHER_HW;
typedef struct prov_cipher_ctx_st PROV_CIPHER_CTX;
typedef int (PROV_CIPHER_HW_FN)(PROV_CIPHER_CTX *dat, unsigned char *out,
const unsigned char *in, size_t len);
struct prov_cipher_ctx_st {
block128_f block;
union {
cbc128_f cbc;
ctr128_f ctr;
ecb128_f ecb;
} stream;
unsigned int mode;
size_t keylen; /* key size (in bytes) */
size_t ivlen;
size_t blocksize;
size_t bufsz; /* Number of bytes in buf */
unsigned int pad : 1; /* Whether padding should be used or not */
unsigned int enc : 1; /* Set to 1 for encrypt, or 0 otherwise */
unsigned int iv_set : 1; /* Set when the iv is copied to the iv/oiv buffers */
/*
* num contains the number of bytes of |iv| which are valid for modes that
* manage partial blocks themselves.
*/
unsigned int num;
uint64_t flags;
/* The original value of the iv */
unsigned char oiv[GENERIC_BLOCK_SIZE];
/* Buffer of partial blocks processed via update calls */
unsigned char buf[GENERIC_BLOCK_SIZE];
unsigned char iv[GENERIC_BLOCK_SIZE];
const PROV_CIPHER_HW *hw; /* hardware specific functions */
const void *ks; /* Pointer to algorithm specific key data */
OPENSSL_CTX *libctx;
};
struct prov_cipher_hw_st {
int (*init)(PROV_CIPHER_CTX *dat, const uint8_t *key, size_t keylen);
PROV_CIPHER_HW_FN *cipher;
void (*copyctx)(PROV_CIPHER_CTX *dst, const PROV_CIPHER_CTX *src);
};
OSSL_OP_cipher_encrypt_init_fn cipher_generic_einit;
OSSL_OP_cipher_decrypt_init_fn cipher_generic_dinit;
OSSL_OP_cipher_update_fn cipher_generic_block_update;
OSSL_OP_cipher_final_fn cipher_generic_block_final;
OSSL_OP_cipher_update_fn cipher_generic_stream_update;
OSSL_OP_cipher_final_fn cipher_generic_stream_final;
OSSL_OP_cipher_cipher_fn cipher_generic_cipher;
OSSL_OP_cipher_get_ctx_params_fn cipher_generic_get_ctx_params;
OSSL_OP_cipher_set_ctx_params_fn cipher_generic_set_ctx_params;
OSSL_OP_cipher_gettable_params_fn cipher_generic_gettable_params;
OSSL_OP_cipher_gettable_ctx_params_fn cipher_generic_gettable_ctx_params;
OSSL_OP_cipher_settable_ctx_params_fn cipher_generic_settable_ctx_params;
OSSL_OP_cipher_set_ctx_params_fn cipher_var_keylen_set_ctx_params;
OSSL_OP_cipher_settable_ctx_params_fn cipher_var_keylen_settable_ctx_params;
OSSL_OP_cipher_gettable_ctx_params_fn cipher_aead_gettable_ctx_params;
OSSL_OP_cipher_settable_ctx_params_fn cipher_aead_settable_ctx_params;
int cipher_generic_get_params(OSSL_PARAM params[], unsigned int md,
unsigned long flags,
size_t kbits, size_t blkbits, size_t ivbits);
void cipher_generic_initkey(void *vctx, size_t kbits, size_t blkbits,
size_t ivbits, unsigned int mode, uint64_t flags,
const PROV_CIPHER_HW *hw, void *provctx);
#define IMPLEMENT_generic_cipher_func(alg, UCALG, lcmode, UCMODE, flags, kbits,\
blkbits, ivbits, typ) \
const OSSL_DISPATCH alg##kbits##lcmode##_functions[] = { \
{ OSSL_FUNC_CIPHER_NEWCTX, \
(void (*)(void)) alg##_##kbits##_##lcmode##_newctx }, \
{ OSSL_FUNC_CIPHER_FREECTX, (void (*)(void)) alg##_freectx }, \
{ OSSL_FUNC_CIPHER_DUPCTX, (void (*)(void)) alg##_dupctx }, \
{ OSSL_FUNC_CIPHER_ENCRYPT_INIT, (void (*)(void))cipher_generic_einit }, \
{ OSSL_FUNC_CIPHER_DECRYPT_INIT, (void (*)(void))cipher_generic_dinit }, \
{ OSSL_FUNC_CIPHER_UPDATE, (void (*)(void))cipher_generic_##typ##_update },\
{ OSSL_FUNC_CIPHER_FINAL, (void (*)(void))cipher_generic_##typ##_final }, \
{ OSSL_FUNC_CIPHER_CIPHER, (void (*)(void))cipher_generic_cipher }, \
{ OSSL_FUNC_CIPHER_GET_PARAMS, \
(void (*)(void)) alg##_##kbits##_##lcmode##_get_params }, \
{ OSSL_FUNC_CIPHER_GET_CTX_PARAMS, \
(void (*)(void))cipher_generic_get_ctx_params }, \
{ OSSL_FUNC_CIPHER_SET_CTX_PARAMS, \
(void (*)(void))cipher_generic_set_ctx_params }, \
{ OSSL_FUNC_CIPHER_GETTABLE_PARAMS, \
(void (*)(void))cipher_generic_gettable_params }, \
{ OSSL_FUNC_CIPHER_GETTABLE_CTX_PARAMS, \
(void (*)(void))cipher_generic_gettable_ctx_params }, \
{ OSSL_FUNC_CIPHER_SETTABLE_CTX_PARAMS, \
(void (*)(void))cipher_generic_settable_ctx_params }, \
{ 0, NULL } \
};
#define IMPLEMENT_var_keylen_cipher_func(alg, UCALG, lcmode, UCMODE, flags, \
kbits, blkbits, ivbits, typ) \
const OSSL_DISPATCH alg##kbits##lcmode##_functions[] = { \
{ OSSL_FUNC_CIPHER_NEWCTX, \
(void (*)(void)) alg##_##kbits##_##lcmode##_newctx }, \
{ OSSL_FUNC_CIPHER_FREECTX, (void (*)(void)) alg##_freectx }, \
{ OSSL_FUNC_CIPHER_DUPCTX, (void (*)(void)) alg##_dupctx }, \
{ OSSL_FUNC_CIPHER_ENCRYPT_INIT, (void (*)(void))cipher_generic_einit }, \
{ OSSL_FUNC_CIPHER_DECRYPT_INIT, (void (*)(void))cipher_generic_dinit }, \
{ OSSL_FUNC_CIPHER_UPDATE, (void (*)(void))cipher_generic_##typ##_update },\
{ OSSL_FUNC_CIPHER_FINAL, (void (*)(void))cipher_generic_##typ##_final }, \
{ OSSL_FUNC_CIPHER_CIPHER, (void (*)(void))cipher_generic_cipher }, \
{ OSSL_FUNC_CIPHER_GET_PARAMS, \
(void (*)(void)) alg##_##kbits##_##lcmode##_get_params }, \
{ OSSL_FUNC_CIPHER_GET_CTX_PARAMS, \
(void (*)(void))cipher_generic_get_ctx_params }, \
{ OSSL_FUNC_CIPHER_SET_CTX_PARAMS, \
(void (*)(void))cipher_var_keylen_set_ctx_params }, \
{ OSSL_FUNC_CIPHER_GETTABLE_PARAMS, \
(void (*)(void))cipher_generic_gettable_params }, \
{ OSSL_FUNC_CIPHER_GETTABLE_CTX_PARAMS, \
(void (*)(void))cipher_generic_gettable_ctx_params }, \
{ OSSL_FUNC_CIPHER_SETTABLE_CTX_PARAMS, \
(void (*)(void))cipher_var_keylen_settable_ctx_params }, \
{ 0, NULL } \
};
#define IMPLEMENT_generic_cipher_genfn(alg, UCALG, lcmode, UCMODE, flags, \
kbits, blkbits, ivbits, typ) \
static OSSL_OP_cipher_get_params_fn alg##_##kbits##_##lcmode##_get_params; \
static int alg##_##kbits##_##lcmode##_get_params(OSSL_PARAM params[]) \
{ \
return cipher_generic_get_params(params, EVP_CIPH_##UCMODE##_MODE, flags, \
kbits, blkbits, ivbits); \
} \
static OSSL_OP_cipher_newctx_fn alg##_##kbits##_##lcmode##_newctx; \
static void * alg##_##kbits##_##lcmode##_newctx(void *provctx) \
{ \
PROV_##UCALG##_CTX *ctx = OPENSSL_zalloc(sizeof(*ctx)); \
if (ctx != NULL) { \
cipher_generic_initkey(ctx, kbits, blkbits, ivbits, \
EVP_CIPH_##UCMODE##_MODE, flags, \
PROV_CIPHER_HW_##alg##_##lcmode(kbits), NULL); \
} \
return ctx; \
} \
#define IMPLEMENT_generic_cipher(alg, UCALG, lcmode, UCMODE, flags, kbits, \
blkbits, ivbits, typ) \
IMPLEMENT_generic_cipher_genfn(alg, UCALG, lcmode, UCMODE, flags, kbits, \
blkbits, ivbits, typ) \
IMPLEMENT_generic_cipher_func(alg, UCALG, lcmode, UCMODE, flags, kbits, \
blkbits, ivbits, typ)
#define IMPLEMENT_var_keylen_cipher(alg, UCALG, lcmode, UCMODE, flags, kbits, \
blkbits, ivbits, typ) \
IMPLEMENT_generic_cipher_genfn(alg, UCALG, lcmode, UCMODE, flags, kbits, \
blkbits, ivbits, typ) \
IMPLEMENT_var_keylen_cipher_func(alg, UCALG, lcmode, UCMODE, flags, kbits, \
blkbits, ivbits, typ)
PROV_CIPHER_HW_FN cipher_hw_generic_cbc;
PROV_CIPHER_HW_FN cipher_hw_generic_ecb;
PROV_CIPHER_HW_FN cipher_hw_generic_ofb128;
PROV_CIPHER_HW_FN cipher_hw_generic_cfb128;
PROV_CIPHER_HW_FN cipher_hw_generic_cfb8;
PROV_CIPHER_HW_FN cipher_hw_generic_cfb1;
PROV_CIPHER_HW_FN cipher_hw_generic_ctr;
PROV_CIPHER_HW_FN cipher_hw_chunked_cbc;
PROV_CIPHER_HW_FN cipher_hw_chunked_cfb8;
PROV_CIPHER_HW_FN cipher_hw_chunked_cfb128;
PROV_CIPHER_HW_FN cipher_hw_chunked_ofb128;
#define cipher_hw_chunked_ecb cipher_hw_generic_ecb
#define cipher_hw_chunked_ctr cipher_hw_generic_ctr
#define cipher_hw_chunked_cfb1 cipher_hw_generic_cfb1
#define IMPLEMENT_CIPHER_HW_OFB(MODE, NAME, CTX_NAME, KEY_NAME, FUNC_PREFIX) \
static int cipher_hw_##NAME##_##MODE##_cipher(PROV_CIPHER_CTX *ctx, \
unsigned char *out, \
const unsigned char *in, size_t len) \
{ \
int num = ctx->num; \
KEY_NAME *key = &(((CTX_NAME *)ctx)->ks.ks); \
\
while (len >= MAXCHUNK) { \
FUNC_PREFIX##_encrypt(in, out, MAXCHUNK, key, ctx->iv, &num); \
len -= MAXCHUNK; \
in += MAXCHUNK; \
out += MAXCHUNK; \
} \
if (len > 0) { \
FUNC_PREFIX##_encrypt(in, out, (long)len, key, ctx->iv, &num); \
} \
ctx->num = num; \
return 1; \
}
#define IMPLEMENT_CIPHER_HW_ECB(MODE, NAME, CTX_NAME, KEY_NAME, FUNC_PREFIX) \
static int cipher_hw_##NAME##_##MODE##_cipher(PROV_CIPHER_CTX *ctx, \
unsigned char *out, \
const unsigned char *in, size_t len) \
{ \
size_t i, bl = ctx->blocksize; \
KEY_NAME *key = &(((CTX_NAME *)ctx)->ks.ks); \
\
if (len < bl) \
return 1; \
for (i = 0, len -= bl; i <= len; i += bl) \
FUNC_PREFIX##_encrypt(in + i, out + i, key, ctx->enc); \
return 1; \
}
#define IMPLEMENT_CIPHER_HW_CBC(MODE, NAME, CTX_NAME, KEY_NAME, FUNC_PREFIX) \
static int cipher_hw_##NAME##_##MODE##_cipher(PROV_CIPHER_CTX *ctx, \
unsigned char *out, \
const unsigned char *in, size_t len) \
{ \
KEY_NAME *key = &(((CTX_NAME *)ctx)->ks.ks); \
\
while (len >= MAXCHUNK) { \
FUNC_PREFIX##_encrypt(in, out, MAXCHUNK, key, ctx->iv, ctx->enc); \
len -= MAXCHUNK; \
in += MAXCHUNK; \
out += MAXCHUNK; \
} \
if (len > 0) \
FUNC_PREFIX##_encrypt(in, out, (long)len, key, ctx->iv, ctx->enc); \
return 1; \
}
#define IMPLEMENT_CIPHER_HW_CFB(MODE, NAME, CTX_NAME, KEY_NAME, FUNC_PREFIX) \
static int cipher_hw_##NAME##_##MODE##_cipher(PROV_CIPHER_CTX *ctx, \
unsigned char *out, \
const unsigned char *in, size_t len) \
{ \
size_t chunk = MAXCHUNK; \
KEY_NAME *key = &(((CTX_NAME *)ctx)->ks.ks); \
int num = ctx->num; \
\
if (len < chunk) \
chunk = len; \
while (len > 0 && len >= chunk) { \
FUNC_PREFIX##_encrypt(in, out, (long)chunk, key, ctx->iv, &num, \
ctx->enc); \
len -= chunk; \
in += chunk; \
out += chunk; \
if (len < chunk) \
chunk = len; \
} \
ctx->num = num; \
return 1; \
}
#define IMPLEMENT_CIPHER_HW_COPYCTX(name, CTX_TYPE) \
static void name(PROV_CIPHER_CTX *dst, const PROV_CIPHER_CTX *src) \
{ \
CTX_TYPE *sctx = (CTX_TYPE *)src; \
CTX_TYPE *dctx = (CTX_TYPE *)dst; \
\
*dctx = *sctx; \
dst->ks = &dctx->ks.ks; \
}
#define CIPHER_DEFAULT_GETTABLE_CTX_PARAMS_START(name) \
static const OSSL_PARAM name##_known_gettable_ctx_params[] = { \
OSSL_PARAM_size_t(OSSL_CIPHER_PARAM_KEYLEN, NULL), \
OSSL_PARAM_size_t(OSSL_CIPHER_PARAM_IVLEN, NULL), \
OSSL_PARAM_uint(OSSL_CIPHER_PARAM_PADDING, NULL), \
OSSL_PARAM_uint(OSSL_CIPHER_PARAM_NUM, NULL), \
OSSL_PARAM_octet_string(OSSL_CIPHER_PARAM_IV, NULL, 0),
#define CIPHER_DEFAULT_GETTABLE_CTX_PARAMS_END(name) \
OSSL_PARAM_END \
}; \
const OSSL_PARAM * name##_gettable_ctx_params(void) \
{ \
return name##_known_gettable_ctx_params; \
}
#define CIPHER_DEFAULT_SETTABLE_CTX_PARAMS_START(name) \
static const OSSL_PARAM name##_known_settable_ctx_params[] = { \
OSSL_PARAM_uint(OSSL_CIPHER_PARAM_PADDING, NULL), \
OSSL_PARAM_uint(OSSL_CIPHER_PARAM_NUM, NULL),
#define CIPHER_DEFAULT_SETTABLE_CTX_PARAMS_END(name) \
OSSL_PARAM_END \
}; \
const OSSL_PARAM * name##_settable_ctx_params(void) \
{ \
return name##_known_settable_ctx_params; \
}
int cipher_generic_initiv(PROV_CIPHER_CTX *ctx, const unsigned char *iv,
size_t ivlen);
size_t fillblock(unsigned char *buf, size_t *buflen, size_t blocksize,
const unsigned char **in, size_t *inlen);
int trailingdata(unsigned char *buf, size_t *buflen, size_t blocksize,
const unsigned char **in, size_t *inlen);
@@ -0,0 +1,52 @@
/*
* Copyright 2019 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
*/
#define UNINITIALISED_SIZET ((size_t)-1)
/* TODO(3.0) Figure out what flags are really needed */
#define AEAD_FLAGS (EVP_CIPH_FLAG_AEAD_CIPHER \
| EVP_CIPH_CUSTOM_IV \
| EVP_CIPH_ALWAYS_CALL_INIT \
| EVP_CIPH_CTRL_INIT \
| EVP_CIPH_CUSTOM_COPY)
#define IMPLEMENT_aead_cipher(alg, lc, UCMODE, flags, kbits, blkbits, ivbits) \
static OSSL_OP_cipher_get_params_fn alg##_##kbits##_##lc##_get_params; \
static int alg##_##kbits##_##lc##_get_params(OSSL_PARAM params[]) \
{ \
return cipher_generic_get_params(params, EVP_CIPH_##UCMODE##_MODE, \
flags, kbits, blkbits, ivbits); \
} \
static OSSL_OP_cipher_newctx_fn alg##kbits##lc##_newctx; \
static void * alg##kbits##lc##_newctx(void *provctx) \
{ \
return alg##_##lc##_newctx(provctx, kbits); \
} \
const OSSL_DISPATCH alg##kbits##lc##_functions[] = { \
{ OSSL_FUNC_CIPHER_NEWCTX, (void (*)(void))alg##kbits##lc##_newctx }, \
{ OSSL_FUNC_CIPHER_FREECTX, (void (*)(void))alg##_##lc##_freectx }, \
{ OSSL_FUNC_CIPHER_ENCRYPT_INIT, (void (*)(void)) lc##_einit }, \
{ OSSL_FUNC_CIPHER_DECRYPT_INIT, (void (*)(void)) lc##_dinit }, \
{ OSSL_FUNC_CIPHER_UPDATE, (void (*)(void)) lc##_stream_update }, \
{ OSSL_FUNC_CIPHER_FINAL, (void (*)(void)) lc##_stream_final }, \
{ OSSL_FUNC_CIPHER_CIPHER, (void (*)(void)) lc##_cipher }, \
{ OSSL_FUNC_CIPHER_GET_PARAMS, \
(void (*)(void)) alg##_##kbits##_##lc##_get_params }, \
{ OSSL_FUNC_CIPHER_GET_CTX_PARAMS, \
(void (*)(void)) lc##_get_ctx_params }, \
{ OSSL_FUNC_CIPHER_SET_CTX_PARAMS, \
(void (*)(void)) lc##_set_ctx_params }, \
{ OSSL_FUNC_CIPHER_GETTABLE_PARAMS, \
(void (*)(void))cipher_generic_gettable_params }, \
{ OSSL_FUNC_CIPHER_GETTABLE_CTX_PARAMS, \
(void (*)(void))cipher_aead_gettable_ctx_params }, \
{ OSSL_FUNC_CIPHER_SETTABLE_CTX_PARAMS, \
(void (*)(void))cipher_aead_settable_ctx_params }, \
{ 0, NULL } \
}
@@ -0,0 +1,99 @@
/*
* Copyright 2019 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
*/
#include "ciphercommon_aead.h"
typedef struct prov_ccm_hw_st PROV_CCM_HW;
#if defined(OPENSSL_CPUID_OBJ) && defined(__s390__)
/*-
* KMAC-AES parameter block - begin
* (see z/Architecture Principles of Operation >= SA22-7832-08)
*/
typedef struct S390X_kmac_params_st {
union {
unsigned long long g[2];
unsigned char b[16];
} icv;
unsigned char k[32];
} S390X_KMAC_PARAMS;
/* KMAC-AES parameter block - end */
#endif
/* Base structure that is shared by AES & ARIA for CCM MODE */
typedef struct prov_ccm_st {
unsigned int enc : 1;
unsigned int key_set : 1; /* Set if key initialised */
unsigned int iv_set : 1; /* Set if an iv is set */
unsigned int tag_set : 1; /* Set if tag is valid */
unsigned int len_set : 1; /* Set if message length set */
size_t l, m; /* L and M parameters from RFC3610 */
size_t keylen;
size_t tls_aad_len; /* TLS AAD length */
size_t tls_aad_pad_sz;
unsigned char iv[GENERIC_BLOCK_SIZE];
unsigned char buf[GENERIC_BLOCK_SIZE];
CCM128_CONTEXT ccm_ctx;
ccm128_f str;
const PROV_CCM_HW *hw; /* hardware specific methods */
} PROV_CCM_CTX;
PROV_CIPHER_FUNC(int, CCM_cipher, (PROV_CCM_CTX *ctx, unsigned char *out, \
size_t *padlen, const unsigned char *in, \
size_t len));
PROV_CIPHER_FUNC(int, CCM_setkey, (PROV_CCM_CTX *ctx, \
const unsigned char *key, size_t keylen));
PROV_CIPHER_FUNC(int, CCM_setiv, (PROV_CCM_CTX *dat, \
const unsigned char *iv, size_t ivlen, \
size_t mlen));
PROV_CIPHER_FUNC(int, CCM_setaad, (PROV_CCM_CTX *ctx, \
const unsigned char *aad, size_t aadlen));
PROV_CIPHER_FUNC(int, CCM_auth_encrypt, (PROV_CCM_CTX *ctx, \
const unsigned char *in, \
unsigned char *out, size_t len, \
unsigned char *tag, size_t taglen));
PROV_CIPHER_FUNC(int, CCM_auth_decrypt, (PROV_CCM_CTX *ctx, \
const unsigned char *in, \
unsigned char *out, size_t len, \
unsigned char *tag, size_t taglen));
PROV_CIPHER_FUNC(int, CCM_gettag, (PROV_CCM_CTX *ctx, \
unsigned char *tag, size_t taglen));
/*
* CCM Mode internal method table used to handle hardware specific differences,
* (and different algorithms).
*/
struct prov_ccm_hw_st {
OSSL_CCM_setkey_fn setkey;
OSSL_CCM_setiv_fn setiv;
OSSL_CCM_setaad_fn setaad;
OSSL_CCM_auth_encrypt_fn auth_encrypt;
OSSL_CCM_auth_decrypt_fn auth_decrypt;
OSSL_CCM_gettag_fn gettag;
};
OSSL_OP_cipher_encrypt_init_fn ccm_einit;
OSSL_OP_cipher_decrypt_init_fn ccm_dinit;
OSSL_OP_cipher_get_ctx_params_fn ccm_get_ctx_params;
OSSL_OP_cipher_set_ctx_params_fn ccm_set_ctx_params;
OSSL_OP_cipher_update_fn ccm_stream_update;
OSSL_OP_cipher_final_fn ccm_stream_final;
OSSL_OP_cipher_cipher_fn ccm_cipher;
void ccm_initctx(PROV_CCM_CTX *ctx, size_t keybits, const PROV_CCM_HW *hw);
int ccm_generic_setiv(PROV_CCM_CTX *ctx, const unsigned char *nonce,
size_t nlen, size_t mlen);
int ccm_generic_setaad(PROV_CCM_CTX *ctx, const unsigned char *aad, size_t alen);
int ccm_generic_gettag(PROV_CCM_CTX *ctx, unsigned char *tag, size_t tlen);
int ccm_generic_auth_encrypt(PROV_CCM_CTX *ctx, const unsigned char *in,
unsigned char *out, size_t len,
unsigned char *tag, size_t taglen);
int ccm_generic_auth_decrypt(PROV_CCM_CTX *ctx, const unsigned char *in,
unsigned char *out, size_t len,
unsigned char *expected_tag, size_t taglen);
@@ -0,0 +1,130 @@
/*
* Copyright 2019 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
*/
#include <openssl/aes.h>
#include "ciphercommon_aead.h"
typedef struct prov_gcm_hw_st PROV_GCM_HW;
#define GCM_IV_DEFAULT_SIZE 12 /* IV's for AES_GCM should normally be 12 bytes */
#define GCM_IV_MAX_SIZE 64
#define GCM_TAG_MAX_SIZE 16
#if defined(OPENSSL_CPUID_OBJ) && defined(__s390__)
/*-
* KMA-GCM-AES parameter block - begin
* (see z/Architecture Principles of Operation >= SA22-7832-11)
*/
typedef struct S390X_kma_params_st {
unsigned char reserved[12];
union {
unsigned int w;
unsigned char b[4];
} cv; /* 32 bit counter value */
union {
unsigned long long g[2];
unsigned char b[16];
} t; /* tag */
unsigned char h[16]; /* hash subkey */
unsigned long long taadl; /* total AAD length */
unsigned long long tpcl; /* total plaintxt/ciphertxt len */
union {
unsigned long long g[2];
unsigned int w[4];
} j0; /* initial counter value */
unsigned char k[32]; /* key */
} S390X_KMA_PARAMS;
#endif
typedef struct prov_gcm_ctx_st {
unsigned int mode; /* The mode that we are using */
size_t keylen;
size_t ivlen;
size_t ivlen_min;
size_t taglen;
size_t tls_aad_pad_sz;
size_t tls_aad_len; /* TLS AAD length */
uint64_t tls_enc_records; /* Number of TLS records encrypted */
/*
* num contains the number of bytes of |iv| which are valid for modes that
* manage partial blocks themselves.
*/
size_t num;
size_t bufsz; /* Number of bytes in buf */
uint64_t flags;
unsigned int iv_state; /* set to one of IV_STATE_XXX */
unsigned int enc:1; /* Set to 1 if we are encrypting or 0 otherwise */
unsigned int pad:1; /* Whether padding should be used or not */
unsigned int key_set:1; /* Set if key initialised */
unsigned int iv_gen_rand:1; /* No IV was specified, so generate a rand IV */
unsigned int iv_gen:1; /* It is OK to generate IVs */
unsigned char iv[GCM_IV_MAX_SIZE]; /* Buffer to use for IV's */
unsigned char buf[AES_BLOCK_SIZE]; /* Buffer of partial blocks processed via update calls */
OPENSSL_CTX *libctx; /* needed for rand calls */
const PROV_GCM_HW *hw; /* hardware specific methods */
GCM128_CONTEXT gcm;
ctr128_f ctr;
const void *ks;
} PROV_GCM_CTX;
PROV_CIPHER_FUNC(int, GCM_setkey, (PROV_GCM_CTX *ctx, const unsigned char *key,
size_t keylen));
PROV_CIPHER_FUNC(int, GCM_setiv, (PROV_GCM_CTX *dat, const unsigned char *iv,
size_t ivlen));
PROV_CIPHER_FUNC(int, GCM_aadupdate, (PROV_GCM_CTX *ctx,
const unsigned char *aad, size_t aadlen));
PROV_CIPHER_FUNC(int, GCM_cipherupdate, (PROV_GCM_CTX *ctx,
const unsigned char *in, size_t len,
unsigned char *out));
PROV_CIPHER_FUNC(int, GCM_cipherfinal, (PROV_GCM_CTX *ctx, unsigned char *tag));
PROV_CIPHER_FUNC(int, GCM_oneshot, (PROV_GCM_CTX *ctx, unsigned char *aad,
size_t aad_len, const unsigned char *in,
size_t in_len, unsigned char *out,
unsigned char *tag, size_t taglen));
struct prov_gcm_hw_st {
OSSL_GCM_setkey_fn setkey;
OSSL_GCM_setiv_fn setiv;
OSSL_GCM_aadupdate_fn aadupdate;
OSSL_GCM_cipherupdate_fn cipherupdate;
OSSL_GCM_cipherfinal_fn cipherfinal;
OSSL_GCM_oneshot_fn oneshot;
};
OSSL_OP_cipher_encrypt_init_fn gcm_einit;
OSSL_OP_cipher_decrypt_init_fn gcm_dinit;
OSSL_OP_cipher_get_ctx_params_fn gcm_get_ctx_params;
OSSL_OP_cipher_set_ctx_params_fn gcm_set_ctx_params;
OSSL_OP_cipher_cipher_fn gcm_cipher;
OSSL_OP_cipher_update_fn gcm_stream_update;
OSSL_OP_cipher_final_fn gcm_stream_final;
void gcm_initctx(void *provctx, PROV_GCM_CTX *ctx, size_t keybits,
const PROV_GCM_HW *hw, size_t ivlen_min);
int gcm_setiv(PROV_GCM_CTX *ctx, const unsigned char *iv, size_t ivlen);
int gcm_aad_update(PROV_GCM_CTX *ctx, const unsigned char *aad,
size_t aad_len);
int gcm_cipher_final(PROV_GCM_CTX *ctx, unsigned char *tag);
int gcm_one_shot(PROV_GCM_CTX *ctx, unsigned char *aad, size_t aad_len,
const unsigned char *in, size_t in_len,
unsigned char *out, unsigned char *tag, size_t tag_len);
int gcm_cipher_update(PROV_GCM_CTX *ctx, const unsigned char *in,
size_t len, unsigned char *out);
#define GCM_HW_SET_KEY_CTR_FN(ks, fn_set_enc_key, fn_block, fn_ctr) \
ctx->ks = ks; \
fn_set_enc_key(key, keylen * 8, ks); \
CRYPTO_gcm128_init(&ctx->gcm, ks, (block128_f)fn_block); \
ctx->ctr = (ctr128_f)fn_ctr; \
ctx->key_set = 1;
@@ -0,0 +1,104 @@
/*
* Copyright 2019 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
*/
#ifndef OSSL_PROVIDERS_DIGESTCOMMON_H
# define OSSL_PROVIDERS_DIGESTCOMMON_H
# include <openssl/core_numbers.h>
# include <openssl/core_names.h>
# include <openssl/params.h>
# ifdef __cplusplus
extern "C" {
# endif
#define PROV_FUNC_DIGEST_GET_PARAM(name, blksize, dgstsize, flags) \
static OSSL_OP_digest_get_params_fn name##_get_params; \
static int name##_get_params(OSSL_PARAM params[]) \
{ \
return digest_default_get_params(params, blksize, dgstsize, flags); \
}
#define PROV_DISPATCH_FUNC_DIGEST_GET_PARAMS(name) \
{ OSSL_FUNC_DIGEST_GET_PARAMS, (void (*)(void))name##_get_params }, \
{ OSSL_FUNC_DIGEST_GETTABLE_PARAMS, \
(void (*)(void))digest_default_gettable_params }
# define PROV_DISPATCH_FUNC_DIGEST_CONSTRUCT_START( \
name, CTX, blksize, dgstsize, flags, init, upd, fin) \
static OSSL_OP_digest_newctx_fn name##_newctx; \
static OSSL_OP_digest_freectx_fn name##_freectx; \
static OSSL_OP_digest_dupctx_fn name##_dupctx; \
static void *name##_newctx(void *prov_ctx) \
{ \
CTX *ctx = OPENSSL_zalloc(sizeof(*ctx)); \
return ctx; \
} \
static void name##_freectx(void *vctx) \
{ \
CTX *ctx = (CTX *)vctx; \
OPENSSL_clear_free(ctx, sizeof(*ctx)); \
} \
static void *name##_dupctx(void *ctx) \
{ \
CTX *in = (CTX *)ctx; \
CTX *ret = OPENSSL_malloc(sizeof(*ret)); \
if (ret != NULL) \
*ret = *in; \
return ret; \
} \
static OSSL_OP_digest_final_fn name##_internal_final; \
static int name##_internal_final(void *ctx, unsigned char *out, size_t *outl, \
size_t outsz) \
{ \
if (outsz >= dgstsize && fin(out, ctx)) { \
*outl = dgstsize; \
return 1; \
} \
return 0; \
} \
PROV_FUNC_DIGEST_GET_PARAM(name, blksize, dgstsize, flags) \
const OSSL_DISPATCH name##_functions[] = { \
{ OSSL_FUNC_DIGEST_NEWCTX, (void (*)(void))name##_newctx }, \
{ OSSL_FUNC_DIGEST_INIT, (void (*)(void))init }, \
{ OSSL_FUNC_DIGEST_UPDATE, (void (*)(void))upd }, \
{ OSSL_FUNC_DIGEST_FINAL, (void (*)(void))name##_internal_final }, \
{ OSSL_FUNC_DIGEST_FREECTX, (void (*)(void))name##_freectx }, \
{ OSSL_FUNC_DIGEST_DUPCTX, (void (*)(void))name##_dupctx }, \
PROV_DISPATCH_FUNC_DIGEST_GET_PARAMS(name)
# define PROV_DISPATCH_FUNC_DIGEST_CONSTRUCT_END \
{ 0, NULL } \
};
# define IMPLEMENT_digest_functions( \
name, CTX, blksize, dgstsize, flags, init, upd, fin) \
PROV_DISPATCH_FUNC_DIGEST_CONSTRUCT_START(name, CTX, blksize, dgstsize, flags, \
init, upd, fin), \
PROV_DISPATCH_FUNC_DIGEST_CONSTRUCT_END
# define IMPLEMENT_digest_functions_with_settable_ctx( \
name, CTX, blksize, dgstsize, flags, init, upd, fin, \
settable_ctx_params, set_ctx_params) \
PROV_DISPATCH_FUNC_DIGEST_CONSTRUCT_START(name, CTX, blksize, dgstsize, flags, \
init, upd, fin), \
{ OSSL_FUNC_DIGEST_SETTABLE_CTX_PARAMS, (void (*)(void))settable_ctx_params }, \
{ OSSL_FUNC_DIGEST_SET_CTX_PARAMS, (void (*)(void))set_ctx_params }, \
PROV_DISPATCH_FUNC_DIGEST_CONSTRUCT_END
const OSSL_PARAM *digest_default_gettable_params(void);
int digest_default_get_params(OSSL_PARAM params[], size_t blksz, size_t paramsz,
unsigned long flags);
# ifdef __cplusplus
}
# endif
#endif /* OSSL_PROVIDERS_DIGESTCOMMON_H */
@@ -75,6 +75,10 @@ extern const OSSL_DISPATCH aes128wrap_functions[];
extern const OSSL_DISPATCH aes256wrappad_functions[];
extern const OSSL_DISPATCH aes192wrappad_functions[];
extern const OSSL_DISPATCH aes128wrappad_functions[];
extern const OSSL_DISPATCH aes256cbc_hmac_sha1_functions[];
extern const OSSL_DISPATCH aes128cbc_hmac_sha1_functions[];
extern const OSSL_DISPATCH aes256cbc_hmac_sha256_functions[];
extern const OSSL_DISPATCH aes128cbc_hmac_sha256_functions[];
#ifndef OPENSSL_NO_ARIA
extern const OSSL_DISPATCH aria256gcm_functions[];
@@ -202,6 +206,9 @@ extern const OSSL_DISPATCH des_cfb8_functions[];
#ifndef OPENSSL_NO_RC4
extern const OSSL_DISPATCH rc440_functions[];
extern const OSSL_DISPATCH rc4128_functions[];
# ifndef OPENSSL_NO_MD5
extern const OSSL_DISPATCH rc4_hmac_md5_functions[];
# endif /* OPENSSL_NO_MD5 */
#endif /* OPENSSL_NO_RC4 */
#ifndef OPENSSL_NO_CHACHA
extern const OSSL_DISPATCH chacha20_functions[];
@@ -211,6 +218,12 @@ extern const OSSL_DISPATCH chacha20_poly1305_functions[];
#endif /* OPENSSL_NO_CHACHA */
#ifndef OPENSSL_NO_SIV
extern const OSSL_DISPATCH aes128siv_functions[];
extern const OSSL_DISPATCH aes192siv_functions[];
extern const OSSL_DISPATCH aes256siv_functions[];
#endif /* OPENSSL_NO_SIV */
/* MACs */
extern const OSSL_DISPATCH blake2bmac_functions[];
extern const OSSL_DISPATCH blake2smac_functions[];
@@ -236,14 +249,45 @@ extern const OSSL_DISPATCH kdf_kbkdf_functions[];
#ifndef OPENSSL_NO_CMS
extern const OSSL_DISPATCH kdf_x942_kdf_functions[];
#endif
extern const OSSL_DISPATCH kdf_krb5kdf_functions[];
/* Key management */
extern const OSSL_DISPATCH dh_keymgmt_functions[];
extern const OSSL_DISPATCH dsa_keymgmt_functions[];
extern const OSSL_DISPATCH rsa_keymgmt_functions[];
/* Key Exchange */
extern const OSSL_DISPATCH dh_keyexch_functions[];
/* Signature */
extern const OSSL_DISPATCH dsa_signature_functions[];
/* Asym Cipher */
extern const OSSL_DISPATCH rsa_asym_cipher_functions[];
/* Serializers */
extern const OSSL_DISPATCH rsa_priv_text_serializer_functions[];
extern const OSSL_DISPATCH rsa_pub_text_serializer_functions[];
extern const OSSL_DISPATCH rsa_priv_der_serializer_functions[];
extern const OSSL_DISPATCH rsa_pub_der_serializer_functions[];
extern const OSSL_DISPATCH rsa_priv_pem_serializer_functions[];
extern const OSSL_DISPATCH rsa_pub_pem_serializer_functions[];
extern const OSSL_DISPATCH dh_priv_text_serializer_functions[];
extern const OSSL_DISPATCH dh_pub_text_serializer_functions[];
extern const OSSL_DISPATCH dh_param_text_serializer_functions[];
extern const OSSL_DISPATCH dh_priv_der_serializer_functions[];
extern const OSSL_DISPATCH dh_pub_der_serializer_functions[];
extern const OSSL_DISPATCH dh_param_der_serializer_functions[];
extern const OSSL_DISPATCH dh_priv_pem_serializer_functions[];
extern const OSSL_DISPATCH dh_pub_pem_serializer_functions[];
extern const OSSL_DISPATCH dh_param_pem_serializer_functions[];
extern const OSSL_DISPATCH dsa_priv_text_serializer_functions[];
extern const OSSL_DISPATCH dsa_pub_text_serializer_functions[];
extern const OSSL_DISPATCH dsa_param_text_serializer_functions[];
extern const OSSL_DISPATCH dsa_priv_der_serializer_functions[];
extern const OSSL_DISPATCH dsa_pub_der_serializer_functions[];
extern const OSSL_DISPATCH dsa_param_der_serializer_functions[];
extern const OSSL_DISPATCH dsa_priv_pem_serializer_functions[];
extern const OSSL_DISPATCH dsa_pub_pem_serializer_functions[];
extern const OSSL_DISPATCH dsa_param_pem_serializer_functions[];
@@ -4,6 +4,7 @@
$TLS1_PRF_GOAL=../../libimplementations.a
$HKDF_GOAL=../../libimplementations.a
$KBKDF_GOAL=../../libimplementations.a
$KRB5KDF_GOAL=../../libimplementations.a
$PBKDF2_GOAL=../../libimplementations.a
$SSKDF_GOAL=../../libimplementations.a
$SCRYPT_GOAL=../../libimplementations.a
@@ -16,6 +17,8 @@ SOURCE[$HKDF_GOAL]=hkdf.c
SOURCE[$KBKDF_GOAL]=kbkdf.c
SOURCE[$KRB5KDF_GOAL]=krb5kdf.c
SOURCE[$PBKDF2_GOAL]=pbkdf2.c
# Extra code to satisfy the FIPS and non-FIPS separation.
# When the PBKDF2 moves to legacy, this can be removed.
+4 -2
View File
@@ -75,8 +75,10 @@ static void kdf_hkdf_free(void *vctx)
{
KDF_HKDF *ctx = (KDF_HKDF *)vctx;
kdf_hkdf_reset(ctx);
OPENSSL_free(ctx);
if (ctx != NULL) {
kdf_hkdf_reset(ctx);
OPENSSL_free(ctx);
}
}
static void kdf_hkdf_reset(void *vctx)
+4 -2
View File
@@ -113,8 +113,10 @@ static void kbkdf_free(void *vctx)
{
KBKDF *ctx = (KBKDF *)vctx;
kbkdf_reset(ctx);
OPENSSL_free(ctx);
if (ctx != NULL) {
kbkdf_reset(ctx);
OPENSSL_free(ctx);
}
}
static void kbkdf_reset(void *vctx)
+440
View File
@@ -0,0 +1,440 @@
/*
* Copyright 2018-2019 The OpenSSL Project Authors. All Rights Reserved.
*
* Licensed under the OpenSSL license (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
*/
#include <stdlib.h>
#include <stdarg.h>
#include <string.h>
#include <openssl/core_names.h>
#include <openssl/des.h>
#include <openssl/evp.h>
#include <openssl/kdf.h>
#include "internal/cryptlib.h"
#include "crypto/evp.h"
#include "internal/numbers.h"
#include "prov/implementations.h"
#include "prov/provider_ctx.h"
#include "prov/provider_util.h"
#include "prov/providercommonerr.h"
/* KRB5 KDF defined in RFC 3961, Section 5.1 */
static OSSL_OP_kdf_newctx_fn krb5kdf_new;
static OSSL_OP_kdf_freectx_fn krb5kdf_free;
static OSSL_OP_kdf_reset_fn krb5kdf_reset;
static OSSL_OP_kdf_derive_fn krb5kdf_derive;
static OSSL_OP_kdf_settable_ctx_params_fn krb5kdf_settable_ctx_params;
static OSSL_OP_kdf_set_ctx_params_fn krb5kdf_set_ctx_params;
static OSSL_OP_kdf_gettable_ctx_params_fn krb5kdf_gettable_ctx_params;
static OSSL_OP_kdf_get_ctx_params_fn krb5kdf_get_ctx_params;
static int KRB5KDF(const EVP_CIPHER *cipher, ENGINE *engine,
const unsigned char *key, size_t key_len,
const unsigned char *constant, size_t constant_len,
unsigned char *okey, size_t okey_len);
typedef struct {
void *provctx;
PROV_CIPHER cipher;
unsigned char *key;
size_t key_len;
unsigned char *constant;
size_t constant_len;
} KRB5KDF_CTX;
static void *krb5kdf_new(void *provctx)
{
KRB5KDF_CTX *ctx;
if ((ctx = OPENSSL_zalloc(sizeof(*ctx))) == NULL)
ERR_raise(ERR_LIB_PROV, ERR_R_MALLOC_FAILURE);
ctx->provctx = provctx;
return ctx;
}
static void krb5kdf_free(void *vctx)
{
KRB5KDF_CTX *ctx = (KRB5KDF_CTX *)vctx;
if (ctx != NULL) {
krb5kdf_reset(ctx);
OPENSSL_free(ctx);
}
}
static void krb5kdf_reset(void *vctx)
{
KRB5KDF_CTX *ctx = (KRB5KDF_CTX *)vctx;
ossl_prov_cipher_reset(&ctx->cipher);
OPENSSL_clear_free(ctx->key, ctx->key_len);
OPENSSL_clear_free(ctx->constant, ctx->constant_len);
memset(ctx, 0, sizeof(*ctx));
}
static int krb5kdf_set_membuf(unsigned char **dst, size_t *dst_len,
const OSSL_PARAM *p)
{
OPENSSL_clear_free(*dst, *dst_len);
*dst = NULL;
return OSSL_PARAM_get_octet_string(p, (void **)dst, 0, dst_len);
}
static int krb5kdf_derive(void *vctx, unsigned char *key,
size_t keylen)
{
KRB5KDF_CTX *ctx = (KRB5KDF_CTX *)vctx;
const EVP_CIPHER *cipher = ossl_prov_cipher_cipher(&ctx->cipher);
ENGINE *engine = ossl_prov_cipher_engine(&ctx->cipher);
if (cipher == NULL) {
ERR_raise(ERR_LIB_PROV, PROV_R_MISSING_CIPHER);
return 0;
}
if (ctx->key == NULL) {
ERR_raise(ERR_LIB_PROV, PROV_R_MISSING_KEY);
return 0;
}
if (ctx->constant == NULL) {
ERR_raise(ERR_LIB_PROV, PROV_R_MISSING_CONSTANT);
return 0;
}
return KRB5KDF(cipher, engine, ctx->key, ctx->key_len,
ctx->constant, ctx->constant_len,
key, keylen);
}
static int krb5kdf_set_ctx_params(void *vctx, const OSSL_PARAM params[])
{
const OSSL_PARAM *p;
KRB5KDF_CTX *ctx = vctx;
OPENSSL_CTX *provctx = PROV_LIBRARY_CONTEXT_OF(ctx->provctx);
if (!ossl_prov_cipher_load_from_params(&ctx->cipher, params, provctx))
return 0;
if ((p = OSSL_PARAM_locate_const(params, OSSL_KDF_PARAM_KEY)) != NULL)
if (!krb5kdf_set_membuf(&ctx->key, &ctx->key_len, p))
return 0;
if ((p = OSSL_PARAM_locate_const(params, OSSL_KDF_PARAM_CONSTANT))
!= NULL)
if (!krb5kdf_set_membuf(&ctx->constant, &ctx->constant_len, p))
return 0;
return 1;
}
static const OSSL_PARAM *krb5kdf_settable_ctx_params(void)
{
static const OSSL_PARAM known_settable_ctx_params[] = {
OSSL_PARAM_utf8_string(OSSL_KDF_PARAM_PROPERTIES, NULL, 0),
OSSL_PARAM_utf8_string(OSSL_KDF_PARAM_CIPHER, NULL, 0),
OSSL_PARAM_octet_string(OSSL_KDF_PARAM_KEY, NULL, 0),
OSSL_PARAM_octet_string(OSSL_KDF_PARAM_CONSTANT, NULL, 0),
OSSL_PARAM_END
};
return known_settable_ctx_params;
}
static int krb5kdf_get_ctx_params(void *vctx, OSSL_PARAM params[])
{
KRB5KDF_CTX *ctx = (KRB5KDF_CTX *)vctx;
const EVP_CIPHER *cipher;
size_t len;
OSSL_PARAM *p;
cipher = ossl_prov_cipher_cipher(&ctx->cipher);
if (cipher)
len = EVP_CIPHER_key_length(cipher);
else
len = EVP_MAX_KEY_LENGTH;
if ((p = OSSL_PARAM_locate(params, OSSL_KDF_PARAM_SIZE)) != NULL)
return OSSL_PARAM_set_size_t(p, len);
return -2;
}
static const OSSL_PARAM *krb5kdf_gettable_ctx_params(void)
{
static const OSSL_PARAM known_gettable_ctx_params[] = {
OSSL_PARAM_size_t(OSSL_KDF_PARAM_SIZE, NULL),
OSSL_PARAM_END
};
return known_gettable_ctx_params;
}
const OSSL_DISPATCH kdf_krb5kdf_functions[] = {
{ OSSL_FUNC_KDF_NEWCTX, (void(*)(void))krb5kdf_new },
{ OSSL_FUNC_KDF_FREECTX, (void(*)(void))krb5kdf_free },
{ OSSL_FUNC_KDF_RESET, (void(*)(void))krb5kdf_reset },
{ OSSL_FUNC_KDF_DERIVE, (void(*)(void))krb5kdf_derive },
{ OSSL_FUNC_KDF_SETTABLE_CTX_PARAMS,
(void(*)(void))krb5kdf_settable_ctx_params },
{ OSSL_FUNC_KDF_SET_CTX_PARAMS,
(void(*)(void))krb5kdf_set_ctx_params },
{ OSSL_FUNC_KDF_GETTABLE_CTX_PARAMS,
(void(*)(void))krb5kdf_gettable_ctx_params },
{ OSSL_FUNC_KDF_GET_CTX_PARAMS,
(void(*)(void))krb5kdf_get_ctx_params },
{ 0, NULL }
};
#ifndef OPENSSL_NO_DES
/*
* DES3 is a special case, it requires a random-to-key function and its
* input truncated to 21 bytes of the 24 produced by the cipher.
* See RFC3961 6.3.1
*/
static int fixup_des3_key(unsigned char *key)
{
unsigned char *cblock;
int i, j;
for (i = 2; i >= 0; i--) {
cblock = &key[i * 8];
memmove(cblock, &key[i * 7], 7);
cblock[7] = 0;
for (j = 0; j < 7; j++)
cblock[7] |= (cblock[j] & 1) << (j + 1);
DES_set_odd_parity((DES_cblock *)cblock);
}
/* fail if keys are such that triple des degrades to single des */
if (CRYPTO_memcmp(&key[0], &key[8], 8) == 0 ||
CRYPTO_memcmp(&key[8], &key[16], 8) == 0) {
return 0;
}
return 1;
}
#endif
/*
* N-fold(K) where blocksize is N, and constant_len is K
* Note: Here |= denotes concatenation
*
* L = lcm(N,K)
* R = L/K
*
* for r: 1 -> R
* s |= constant rot 13*(r-1))
*
* block = 0
* for k: 1 -> K
* block += s[N(k-1)..(N-1)k] (one's complement addition)
*
* Optimizing for space we compute:
* for each l in L-1 -> 0:
* s[l] = (constant rot 13*(l/K))[l%k]
* block[l % N] += s[l] (with carry)
* finally add carry if any
*/
static void n_fold(unsigned char *block, unsigned int blocksize,
const unsigned char *constant, size_t constant_len)
{
unsigned int tmp, gcd, remainder, lcm, carry;
int b, l;
if (constant_len == blocksize) {
memcpy(block, constant, constant_len);
return;
}
/* Least Common Multiple of lengths: LCM(a,b)*/
gcd = blocksize;
remainder = constant_len;
/* Calculate Great Common Divisor first GCD(a,b) */
while (remainder != 0) {
tmp = gcd % remainder;
gcd = remainder;
remainder = tmp;
}
/* resulting a is the GCD, LCM(a,b) = |a*b|/GCD(a,b) */
lcm = blocksize * constant_len / gcd;
/* now spread out the bits */
memset(block, 0, blocksize);
/* last to first to be able to bring carry forward */
carry = 0;
for (l = lcm - 1; l >= 0; l--) {
unsigned int rotbits, rshift, rbyte;
/* destination byte in block is l % N */
b = l % blocksize;
/* Our virtual s buffer is R = L/K long (K = constant_len) */
/* So we rotate backwards from R-1 to 0 (none) rotations */
rotbits = 13 * (l / constant_len);
/* find the byte on s where rotbits falls onto */
rbyte = l - (rotbits / 8);
/* calculate how much shift on that byte */
rshift = rotbits & 0x07;
/* rbyte % constant_len gives us the unrotated byte in the
* constant buffer, get also the previous byte then
* appropriately shift them to get the rotated byte we need */
tmp = (constant[(rbyte-1) % constant_len] << (8 - rshift)
| constant[rbyte % constant_len] >> rshift)
& 0xff;
/* add with carry to any value placed by previous passes */
tmp += carry + block[b];
block[b] = tmp & 0xff;
/* save any carry that may be left */
carry = tmp >> 8;
}
/* if any carry is left at the end, add it through the number */
for (b = blocksize - 1; b >= 0 && carry != 0; b--) {
carry += block[b];
block[b] = carry & 0xff;
carry >>= 8;
}
}
static int cipher_init(EVP_CIPHER_CTX *ctx,
const EVP_CIPHER *cipher, ENGINE *engine,
const unsigned char *key, size_t key_len)
{
int klen, ret;
ret = EVP_EncryptInit_ex(ctx, cipher, engine, key, NULL);
if (!ret)
goto out;
/* set the key len for the odd variable key len cipher */
klen = EVP_CIPHER_CTX_key_length(ctx);
if (key_len != (size_t)klen) {
ret = EVP_CIPHER_CTX_set_key_length(ctx, key_len);
if (!ret)
goto out;
}
/* we never want padding, either the length requested is a multiple of
* the cipher block size or we are passed a cipher that can cope with
* partial blocks via techniques like cipher text stealing */
ret = EVP_CIPHER_CTX_set_padding(ctx, 0);
if (!ret)
goto out;
out:
return ret;
}
static int KRB5KDF(const EVP_CIPHER *cipher, ENGINE *engine,
const unsigned char *key, size_t key_len,
const unsigned char *constant, size_t constant_len,
unsigned char *okey, size_t okey_len)
{
EVP_CIPHER_CTX *ctx = NULL;
unsigned char block[EVP_MAX_BLOCK_LENGTH * 2];
unsigned char *plainblock, *cipherblock;
size_t blocksize;
size_t cipherlen;
size_t osize;
#ifndef OPENSSL_NO_DES
int des3_no_fixup = 0;
#endif
int ret;
if (key_len != okey_len) {
#ifndef OPENSSL_NO_DES
/* special case for 3des, where the caller may be requesting
* the random raw key, instead of the fixed up key */
if (EVP_CIPHER_nid(cipher) == NID_des_ede3_cbc &&
key_len == 24 && okey_len == 21) {
des3_no_fixup = 1;
} else {
#endif
ERR_raise(ERR_LIB_PROV, PROV_R_WRONG_OUTPUT_BUFFER_SIZE);
return 0;
#ifndef OPENSSL_NO_DES
}
#endif
}
ctx = EVP_CIPHER_CTX_new();
if (ctx == NULL)
return 0;
ret = cipher_init(ctx, cipher, engine, key, key_len);
if (!ret)
goto out;
/* Initialize input block */
blocksize = EVP_CIPHER_CTX_block_size(ctx);
if (constant_len > blocksize) {
ERR_raise(ERR_LIB_PROV, PROV_R_INVALID_CONSTANT_LENGTH);
ret = 0;
goto out;
}
n_fold(block, blocksize, constant, constant_len);
plainblock = block;
cipherblock = block + EVP_MAX_BLOCK_LENGTH;
for (osize = 0; osize < okey_len; osize += cipherlen) {
int olen;
ret = EVP_EncryptUpdate(ctx, cipherblock, &olen,
plainblock, blocksize);
if (!ret)
goto out;
cipherlen = olen;
ret = EVP_EncryptFinal_ex(ctx, cipherblock, &olen);
if (!ret)
goto out;
if (olen != 0) {
ERR_raise(ERR_LIB_PROV, PROV_R_WRONG_FINAL_BLOCK_LENGTH);
ret = 0;
goto out;
}
/* write cipherblock out */
if (cipherlen > okey_len - osize)
cipherlen = okey_len - osize;
memcpy(okey + osize, cipherblock, cipherlen);
if (okey_len > osize + cipherlen) {
/* we need to reinitialize cipher context per spec */
ret = EVP_CIPHER_CTX_reset(ctx);
if (!ret)
goto out;
ret = cipher_init(ctx, cipher, engine, key, key_len);
if (!ret)
goto out;
/* also swap block offsets so last ciphertext becomes new
* plaintext */
plainblock = cipherblock;
if (cipherblock == block) {
cipherblock += EVP_MAX_BLOCK_LENGTH;
} else {
cipherblock = block;
}
}
}
#ifndef OPENSSL_NO_DES
if (EVP_CIPHER_nid(cipher) == NID_des_ede3_cbc && !des3_no_fixup) {
ret = fixup_des3_key(okey);
if (!ret) {
ERR_raise(ERR_LIB_PROV, PROV_R_FAILED_TO_GENERATE_KEY);
goto out;
}
}
#endif
ret = 1;
out:
EVP_CIPHER_CTX_free(ctx);
OPENSSL_cleanse(block, EVP_MAX_BLOCK_LENGTH * 2);
return ret;
}
+4 -2
View File
@@ -80,8 +80,10 @@ static void kdf_pbkdf2_free(void *vctx)
{
KDF_PBKDF2 *ctx = (KDF_PBKDF2 *)vctx;
kdf_pbkdf2_cleanup(ctx);
OPENSSL_free(ctx);
if (ctx != NULL) {
kdf_pbkdf2_cleanup(ctx);
OPENSSL_free(ctx);
}
}
static void kdf_pbkdf2_reset(void *vctx)
+5 -3
View File
@@ -74,9 +74,11 @@ static void kdf_scrypt_free(void *vctx)
{
KDF_SCRYPT *ctx = (KDF_SCRYPT *)vctx;
EVP_MD_meth_free(ctx->sha256);
kdf_scrypt_reset(ctx);
OPENSSL_free(ctx);
if (ctx != NULL) {
EVP_MD_meth_free(ctx->sha256);
kdf_scrypt_reset(ctx);
OPENSSL_free(ctx);
}
}
static void kdf_scrypt_reset(void *vctx)
+4 -2
View File
@@ -63,8 +63,10 @@ static void kdf_sshkdf_free(void *vctx)
{
KDF_SSHKDF *ctx = (KDF_SSHKDF *)vctx;
kdf_sshkdf_reset(ctx);
OPENSSL_free(ctx);
if (ctx != NULL) {
kdf_sshkdf_reset(ctx);
OPENSSL_free(ctx);
}
}
static void kdf_sshkdf_reset(void *vctx)
+4 -2
View File
@@ -315,8 +315,10 @@ static void sskdf_free(void *vctx)
{
KDF_SSKDF *ctx = (KDF_SSKDF *)vctx;
sskdf_reset(ctx);
OPENSSL_free(ctx);
if (ctx != NULL) {
sskdf_reset(ctx);
OPENSSL_free(ctx);
}
}
static int sskdf_set_buffer(unsigned char **out, size_t *out_len,

Some files were not shown because too many files have changed in this diff Show More