2016-05-12 17:51:24 +03:00
|
|
|
/*
|
|
|
|
* CDDL HEADER START
|
|
|
|
*
|
|
|
|
* The contents of this file are subject to the terms of the
|
|
|
|
* Common Development and Distribution License (the "License").
|
|
|
|
* You may not use this file except in compliance with the License.
|
|
|
|
*
|
|
|
|
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
|
2022-07-12 00:16:13 +03:00
|
|
|
* or https://opensource.org/licenses/CDDL-1.0.
|
2016-05-12 17:51:24 +03:00
|
|
|
* See the License for the specific language governing permissions
|
|
|
|
* and limitations under the License.
|
|
|
|
*
|
|
|
|
* When distributing Covered Code, include this CDDL HEADER in each
|
|
|
|
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
|
|
|
|
* If applicable, add the following below this CDDL HEADER, with the
|
|
|
|
* fields enclosed by brackets "[]" replaced with your own identifying
|
|
|
|
* information: Portions Copyright [yyyy] [name of copyright owner]
|
|
|
|
*
|
|
|
|
* CDDL HEADER END
|
|
|
|
*/
|
|
|
|
/*
|
|
|
|
* Copyright 2009 Sun Microsystems, Inc. All rights reserved.
|
|
|
|
* Use is subject to license terms.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#ifndef _COMMON_CRYPTO_MODES_H
|
|
|
|
#define _COMMON_CRYPTO_MODES_H
|
|
|
|
|
|
|
|
#ifdef __cplusplus
|
|
|
|
extern "C" {
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#include <sys/zfs_context.h>
|
|
|
|
#include <sys/crypto/common.h>
|
|
|
|
#include <sys/crypto/impl.h>
|
|
|
|
|
2020-02-10 23:59:50 +03:00
|
|
|
/*
|
|
|
|
* Does the build chain support all instructions needed for the GCM assembler
|
|
|
|
* routines. AVX support should imply AES-NI and PCLMULQDQ, but make sure
|
|
|
|
* anyhow.
|
|
|
|
*/
|
|
|
|
#if defined(__x86_64__) && defined(HAVE_AVX) && \
|
2020-03-17 20:24:38 +03:00
|
|
|
defined(HAVE_AES) && defined(HAVE_PCLMULQDQ)
|
2020-02-10 23:59:50 +03:00
|
|
|
#define CAN_USE_GCM_ASM
|
2020-03-17 20:24:38 +03:00
|
|
|
extern boolean_t gcm_avx_can_use_movbe;
|
2020-02-10 23:59:50 +03:00
|
|
|
#endif
|
|
|
|
|
2016-05-12 17:51:24 +03:00
|
|
|
#define CCM_MODE 0x00000010
|
|
|
|
#define GCM_MODE 0x00000020
|
|
|
|
|
|
|
|
/*
|
|
|
|
* cc_keysched: Pointer to key schedule.
|
|
|
|
*
|
|
|
|
* cc_keysched_len: Length of the key schedule.
|
|
|
|
*
|
|
|
|
* cc_remainder: This is for residual data, i.e. data that can't
|
|
|
|
* be processed because there are too few bytes.
|
|
|
|
* Must wait until more data arrives.
|
|
|
|
*
|
|
|
|
* cc_remainder_len: Number of bytes in cc_remainder.
|
|
|
|
*
|
|
|
|
* cc_iv: Scratch buffer that sometimes contains the IV.
|
|
|
|
*
|
|
|
|
* cc_lastp: Pointer to previous block of ciphertext.
|
|
|
|
*
|
|
|
|
* cc_copy_to: Pointer to where encrypted residual data needs
|
|
|
|
* to be copied.
|
|
|
|
*
|
|
|
|
* cc_flags: PROVIDER_OWNS_KEY_SCHEDULE
|
|
|
|
* When a context is freed, it is necessary
|
|
|
|
* to know whether the key schedule was allocated
|
|
|
|
* by the caller, or internally, e.g. an init routine.
|
|
|
|
* If allocated by the latter, then it needs to be freed.
|
|
|
|
*
|
2024-05-18 14:57:36 +03:00
|
|
|
* CCM_MODE
|
2016-05-12 17:51:24 +03:00
|
|
|
*/
|
|
|
|
struct common_ctx {
|
|
|
|
void *cc_keysched;
|
|
|
|
size_t cc_keysched_len;
|
|
|
|
uint64_t cc_iv[2];
|
|
|
|
uint64_t cc_remainder[2];
|
|
|
|
size_t cc_remainder_len;
|
|
|
|
uint8_t *cc_lastp;
|
|
|
|
uint8_t *cc_copy_to;
|
|
|
|
uint32_t cc_flags;
|
|
|
|
};
|
|
|
|
|
|
|
|
typedef struct common_ctx common_ctx_t;
|
|
|
|
|
|
|
|
/*
|
|
|
|
*
|
|
|
|
* ccm_mac_len: Stores length of the MAC in CCM mode.
|
|
|
|
* ccm_mac_buf: Stores the intermediate value for MAC in CCM encrypt.
|
|
|
|
* In CCM decrypt, stores the input MAC value.
|
|
|
|
* ccm_data_len: Length of the plaintext for CCM mode encrypt, or
|
|
|
|
* length of the ciphertext for CCM mode decrypt.
|
|
|
|
* ccm_processed_data_len:
|
|
|
|
* Length of processed plaintext in CCM mode encrypt,
|
|
|
|
* or length of processed ciphertext for CCM mode decrypt.
|
|
|
|
* ccm_processed_mac_len:
|
|
|
|
* Length of MAC data accumulated in CCM mode decrypt.
|
|
|
|
*
|
|
|
|
* ccm_pt_buf: Only used in CCM mode decrypt. It stores the
|
|
|
|
* decrypted plaintext to be returned when
|
|
|
|
* MAC verification succeeds in decrypt_final.
|
|
|
|
* Memory for this should be allocated in the AES module.
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
typedef struct ccm_ctx {
|
|
|
|
struct common_ctx ccm_common;
|
|
|
|
uint32_t ccm_tmp[4];
|
|
|
|
size_t ccm_mac_len;
|
|
|
|
uint64_t ccm_mac_buf[2];
|
|
|
|
size_t ccm_data_len;
|
|
|
|
size_t ccm_processed_data_len;
|
|
|
|
size_t ccm_processed_mac_len;
|
|
|
|
uint8_t *ccm_pt_buf;
|
|
|
|
uint64_t ccm_mac_input_buf[2];
|
|
|
|
uint64_t ccm_counter_mask;
|
|
|
|
} ccm_ctx_t;
|
|
|
|
|
|
|
|
#define ccm_keysched ccm_common.cc_keysched
|
|
|
|
#define ccm_keysched_len ccm_common.cc_keysched_len
|
|
|
|
#define ccm_cb ccm_common.cc_iv
|
|
|
|
#define ccm_remainder ccm_common.cc_remainder
|
|
|
|
#define ccm_remainder_len ccm_common.cc_remainder_len
|
|
|
|
#define ccm_lastp ccm_common.cc_lastp
|
|
|
|
#define ccm_copy_to ccm_common.cc_copy_to
|
|
|
|
#define ccm_flags ccm_common.cc_flags
|
|
|
|
|
|
|
|
/*
|
|
|
|
* gcm_tag_len: Length of authentication tag.
|
|
|
|
*
|
|
|
|
* gcm_ghash: Stores output from the GHASH function.
|
|
|
|
*
|
|
|
|
* gcm_processed_data_len:
|
|
|
|
* Length of processed plaintext (encrypt) or
|
|
|
|
* length of processed ciphertext (decrypt).
|
|
|
|
*
|
|
|
|
* gcm_pt_buf: Stores the decrypted plaintext returned by
|
|
|
|
* decrypt_final when the computed authentication
|
|
|
|
* tag matches the user supplied tag.
|
|
|
|
*
|
|
|
|
* gcm_pt_buf_len: Length of the plaintext buffer.
|
|
|
|
*
|
|
|
|
* gcm_H: Subkey.
|
|
|
|
*
|
2020-02-10 23:59:50 +03:00
|
|
|
* gcm_Htable: Pre-computed and pre-shifted H, H^2, ... H^6 for the
|
|
|
|
* Karatsuba Algorithm in host byte order.
|
|
|
|
*
|
2016-05-12 17:51:24 +03:00
|
|
|
* gcm_J0: Pre-counter block generated from the IV.
|
|
|
|
*
|
|
|
|
* gcm_len_a_len_c: 64-bit representations of the bit lengths of
|
|
|
|
* AAD and ciphertext.
|
|
|
|
*/
|
|
|
|
typedef struct gcm_ctx {
|
|
|
|
struct common_ctx gcm_common;
|
|
|
|
size_t gcm_tag_len;
|
|
|
|
size_t gcm_processed_data_len;
|
|
|
|
size_t gcm_pt_buf_len;
|
|
|
|
uint32_t gcm_tmp[4];
|
2020-02-10 23:59:50 +03:00
|
|
|
/*
|
2020-10-31 01:24:21 +03:00
|
|
|
* The offset of gcm_Htable relative to gcm_ghash, (32), is hard coded
|
|
|
|
* in aesni-gcm-x86_64.S, so please don't change (or adjust there).
|
2020-02-10 23:59:50 +03:00
|
|
|
*/
|
2016-05-12 17:51:24 +03:00
|
|
|
uint64_t gcm_ghash[2];
|
|
|
|
uint64_t gcm_H[2];
|
2020-02-10 23:59:50 +03:00
|
|
|
#ifdef CAN_USE_GCM_ASM
|
2020-10-31 01:24:21 +03:00
|
|
|
uint64_t *gcm_Htable;
|
|
|
|
size_t gcm_htab_len;
|
2020-02-10 23:59:50 +03:00
|
|
|
#endif
|
2016-05-12 17:51:24 +03:00
|
|
|
uint64_t gcm_J0[2];
|
|
|
|
uint64_t gcm_len_a_len_c[2];
|
|
|
|
uint8_t *gcm_pt_buf;
|
2020-02-10 23:59:50 +03:00
|
|
|
#ifdef CAN_USE_GCM_ASM
|
|
|
|
boolean_t gcm_use_avx;
|
|
|
|
#endif
|
2016-05-12 17:51:24 +03:00
|
|
|
} gcm_ctx_t;
|
|
|
|
|
|
|
|
#define gcm_keysched gcm_common.cc_keysched
|
|
|
|
#define gcm_keysched_len gcm_common.cc_keysched_len
|
|
|
|
#define gcm_cb gcm_common.cc_iv
|
|
|
|
#define gcm_remainder gcm_common.cc_remainder
|
|
|
|
#define gcm_remainder_len gcm_common.cc_remainder_len
|
|
|
|
#define gcm_lastp gcm_common.cc_lastp
|
|
|
|
#define gcm_copy_to gcm_common.cc_copy_to
|
|
|
|
#define gcm_flags gcm_common.cc_flags
|
|
|
|
|
icp: Prevent compilers from optimizing away memset() in gcm_clear_ctx()
The recently merged f58e513f7408f353bf0151fdaf235d4e062e8950 was
intended to zero sensitive data before exit from encryption
functions to harden the code against theoretical information
leaks. Unfortunately, the method by which it did that is
optimized away by the compiler, so some information still leaks. This
was confirmed by counting function calls in disassembly.
After studying how the OpenBSD, FreeBSD and Linux kernels handle this,
and looking at our disassembly, I decided on a two-factor approach to
protect us from compiler dead store elimination passes.
The first factor is to stop trying to inline gcm_clear_ctx(). GCC does
not actually inline it in the first place, and testing suggests that
dead store elimination passes appear to become more powerful in a bad
way when inlining is forced, so we recognize that and move
gcm_clear_ctx() to a C file.
The second factor is to implement an explicit_memset() function based on
the technique used by `secure_zero_memory()` in FreeBSD's blake2
implementation, which coincidentally is functionally identical to the
one used by Linux. The source for this appears to be a LLVM bug:
https://llvm.org/bugs/show_bug.cgi?id=15495
Unlike both FreeBSD and Linux, we explicitly avoid the inline keyword,
based on my observations that GCC's dead store elimination pass becomes
more powerful when inlining is forced, under the assumption that it will
be equally powerful when the compiler does decide to inline function
calls.
Disassembly of GCC's output confirms that all 6 memset() calls are
executed with this patch applied.
Reviewed-by: Attila Fülöp <attila@fueloep.org>
Reviewed-by: Brian Behlendorf <behlendorf1@llnl.gov>
Signed-off-by: Richard Yao <richard.yao@alumni.stonybrook.edu>
Closes #14544
2023-03-01 04:28:50 +03:00
|
|
|
void gcm_clear_ctx(gcm_ctx_t *ctx);
|
2023-02-28 01:38:12 +03:00
|
|
|
|
2016-05-12 17:51:24 +03:00
|
|
|
typedef struct aes_ctx {
|
|
|
|
union {
|
|
|
|
ccm_ctx_t acu_ccm;
|
|
|
|
gcm_ctx_t acu_gcm;
|
|
|
|
} acu;
|
|
|
|
} aes_ctx_t;
|
|
|
|
|
2024-05-18 14:57:36 +03:00
|
|
|
#define ac_flags acu.acu_ccm.ccm_common.cc_flags
|
|
|
|
#define ac_remainder_len acu.acu_ccm.ccm_common.cc_remainder_len
|
|
|
|
#define ac_keysched acu.acu_ccm.ccm_common.cc_keysched
|
|
|
|
#define ac_keysched_len acu.acu_ccm.ccm_common.cc_keysched_len
|
|
|
|
#define ac_iv acu.acu_ccm.ccm_common.cc_iv
|
|
|
|
#define ac_lastp acu.acu_ccm.ccm_common.cc_lastp
|
2016-05-12 17:51:24 +03:00
|
|
|
#define ac_pt_buf acu.acu_ccm.ccm_pt_buf
|
|
|
|
#define ac_mac_len acu.acu_ccm.ccm_mac_len
|
|
|
|
#define ac_data_len acu.acu_ccm.ccm_data_len
|
|
|
|
#define ac_processed_mac_len acu.acu_ccm.ccm_processed_mac_len
|
|
|
|
#define ac_processed_data_len acu.acu_ccm.ccm_processed_data_len
|
|
|
|
#define ac_tag_len acu.acu_gcm.gcm_tag_len
|
|
|
|
|
|
|
|
extern int ccm_mode_encrypt_contiguous_blocks(ccm_ctx_t *, char *, size_t,
|
|
|
|
crypto_data_t *, size_t,
|
|
|
|
int (*encrypt_block)(const void *, const uint8_t *, uint8_t *),
|
|
|
|
void (*copy_block)(uint8_t *, uint8_t *),
|
|
|
|
void (*xor_block)(uint8_t *, uint8_t *));
|
|
|
|
|
|
|
|
extern int ccm_mode_decrypt_contiguous_blocks(ccm_ctx_t *, char *, size_t,
|
|
|
|
crypto_data_t *, size_t,
|
|
|
|
int (*encrypt_block)(const void *, const uint8_t *, uint8_t *),
|
|
|
|
void (*copy_block)(uint8_t *, uint8_t *),
|
|
|
|
void (*xor_block)(uint8_t *, uint8_t *));
|
|
|
|
|
|
|
|
extern int gcm_mode_encrypt_contiguous_blocks(gcm_ctx_t *, char *, size_t,
|
|
|
|
crypto_data_t *, size_t,
|
|
|
|
int (*encrypt_block)(const void *, const uint8_t *, uint8_t *),
|
|
|
|
void (*copy_block)(uint8_t *, uint8_t *),
|
|
|
|
void (*xor_block)(uint8_t *, uint8_t *));
|
|
|
|
|
|
|
|
extern int gcm_mode_decrypt_contiguous_blocks(gcm_ctx_t *, char *, size_t,
|
|
|
|
crypto_data_t *, size_t,
|
|
|
|
int (*encrypt_block)(const void *, const uint8_t *, uint8_t *),
|
|
|
|
void (*copy_block)(uint8_t *, uint8_t *),
|
|
|
|
void (*xor_block)(uint8_t *, uint8_t *));
|
|
|
|
|
|
|
|
int ccm_encrypt_final(ccm_ctx_t *, crypto_data_t *, size_t,
|
|
|
|
int (*encrypt_block)(const void *, const uint8_t *, uint8_t *),
|
|
|
|
void (*xor_block)(uint8_t *, uint8_t *));
|
|
|
|
|
|
|
|
int gcm_encrypt_final(gcm_ctx_t *, crypto_data_t *, size_t,
|
|
|
|
int (*encrypt_block)(const void *, const uint8_t *, uint8_t *),
|
|
|
|
void (*copy_block)(uint8_t *, uint8_t *),
|
|
|
|
void (*xor_block)(uint8_t *, uint8_t *));
|
|
|
|
|
|
|
|
extern int ccm_decrypt_final(ccm_ctx_t *, crypto_data_t *, size_t,
|
|
|
|
int (*encrypt_block)(const void *, const uint8_t *, uint8_t *),
|
|
|
|
void (*copy_block)(uint8_t *, uint8_t *),
|
|
|
|
void (*xor_block)(uint8_t *, uint8_t *));
|
|
|
|
|
|
|
|
extern int gcm_decrypt_final(gcm_ctx_t *, crypto_data_t *, size_t,
|
|
|
|
int (*encrypt_block)(const void *, const uint8_t *, uint8_t *),
|
|
|
|
void (*xor_block)(uint8_t *, uint8_t *));
|
|
|
|
|
|
|
|
extern int ccm_init_ctx(ccm_ctx_t *, char *, int, boolean_t, size_t,
|
|
|
|
int (*encrypt_block)(const void *, const uint8_t *, uint8_t *),
|
|
|
|
void (*xor_block)(uint8_t *, uint8_t *));
|
|
|
|
|
|
|
|
extern int gcm_init_ctx(gcm_ctx_t *, char *, size_t,
|
|
|
|
int (*encrypt_block)(const void *, const uint8_t *, uint8_t *),
|
|
|
|
void (*copy_block)(uint8_t *, uint8_t *),
|
|
|
|
void (*xor_block)(uint8_t *, uint8_t *));
|
|
|
|
|
|
|
|
extern void calculate_ccm_mac(ccm_ctx_t *, uint8_t *,
|
|
|
|
int (*encrypt_block)(const void *, const uint8_t *, uint8_t *));
|
|
|
|
|
|
|
|
extern void gcm_mul(uint64_t *, uint64_t *, uint64_t *);
|
|
|
|
|
|
|
|
extern void crypto_init_ptrs(crypto_data_t *, void **, offset_t *);
|
|
|
|
extern void crypto_get_ptrs(crypto_data_t *, void **, offset_t *,
|
|
|
|
uint8_t **, size_t *, uint8_t **, size_t);
|
|
|
|
|
|
|
|
extern void *ccm_alloc_ctx(int);
|
|
|
|
extern void *gcm_alloc_ctx(int);
|
|
|
|
extern void crypto_free_mode_ctx(void *);
|
|
|
|
|
|
|
|
#ifdef __cplusplus
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#endif /* _COMMON_CRYPTO_MODES_H */
|