Latest update.
This commit is contained in:
@@ -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 }
|
||||
};
|
||||
@@ -1 +1,2 @@
|
||||
SUBDIRS=digests ciphers macs kdfs exchange keymgmt signature
|
||||
SUBDIRS=digests ciphers macs kdfs exchange keymgmt signature asymciphers \
|
||||
serializers
|
||||
@@ -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);
|
||||
@@ -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.
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
Reference in New Issue
Block a user