/* Copyright 2015 The Chromium OS Authors. All rights reserved. * Use of this source code is governed by a BSD-style license that can be * found in the LICENSE file. */ #ifndef __EC_CHIP_G_DCRYPTO_INTERNAL_H #define __EC_CHIP_G_DCRYPTO_INTERNAL_H #include #include #include "common.h" #include "dcrypto.h" #include "fips.h" #include "fips_rand.h" #include "util.h" #ifdef __cplusplus extern "C" { #endif /* * SHA. */ #define CTRL_CTR_BIG_ENDIAN (__BYTE_ORDER__ == __ORDER_BIG_ENDIAN__) #define CTRL_ENABLE 1 #define CTRL_ENCRYPT 1 #define CTRL_NO_SOFT_RESET 0 #ifndef CHAR_BIT #define CHAR_BIT 8 #endif #ifndef SECTION_IS_RO int dcrypto_grab_sha_hw(void); void dcrypto_release_sha_hw(void); #endif /* Load data into KEYMGR SHA FIFO. */ void dcrypto_sha_fifo_load(const void *data, size_t n); /* * SHA implementation. This abstraction is backed by either a * software or hardware implementation. * * There could be only a single hardware SHA context in progress. The init * functions will try using the HW context, if available, unless 'sw_required' * is TRUE, in which case there will be no attempt to use the hardware for * this particular hashing session. */ /** * Reset hash context with the same hash function as configured. * Will crash if previously not configured! Used for HMAC. */ __always_inline void HASH_reinit(union hash_ctx *const ctx) { ctx->f->init(ctx); } /* Software implementations of hash functions. */ void SHA1_sw_init(struct sha1_ctx *const ctx); void SHA1_sw_update(struct sha1_ctx *const ctx, const void *data, size_t len); const struct sha1_digest *SHA1_sw_final(struct sha1_ctx *const ctx); const struct sha1_digest *SHA1_sw_hash(const void *data, size_t len, struct sha1_digest *digest); void SHA256_sw_init(struct sha256_ctx *const ctx); void SHA256_sw_update(struct sha256_ctx *const ctx, const void *data, size_t len); const struct sha256_digest *SHA256_sw_final(struct sha256_ctx *const ctx); const struct sha256_digest *SHA256_sw_hash(const void *data, size_t len, struct sha256_digest *digest); void SHA224_sw_init(struct sha224_ctx *const ctx); void SHA224_sw_update(struct sha224_ctx *const ctx, const void *data, size_t len); const struct sha224_digest *SHA224_sw_final(struct sha224_ctx *const ctx); const struct sha224_digest *SHA224_sw_hash(const void *data, size_t len, struct sha224_digest *digest); /** * Initialize HMAC for pre-configured hash. * This is generic function which can initialize HMAC with any supported * hash function. */ void HMAC_sw_init(union hmac_ctx *const ctx, const void *key, size_t len); const union sha_digests *HMAC_sw_final(union hmac_ctx *const ctx); /** * HMAC SHA2-224 initialization. */ __always_inline void HMAC_SHA224_sw_init( struct hmac_sha224_ctx *const ctx, const void *key, size_t len) { SHA224_sw_init(&ctx->hash); HMAC_sw_init((union hmac_ctx *)ctx, key, len); } __always_inline void HMAC_SHA224_update( struct hmac_sha224_ctx *const ctx, const void *data, size_t len) { ctx->hash.f->update((union hash_ctx *)&ctx->hash, data, len); } __always_inline const struct sha224_digest *HMAC_SHA224_final( struct hmac_sha224_ctx *const ctx) { return &ctx->hash.f->hmac_final((union hmac_ctx *)ctx)->sha224; } /** * HMAC SHA2-256 initialization. */ __always_inline void HMAC_SHA256_sw_init( struct hmac_sha256_ctx *const ctx, const void *key, size_t len) { SHA256_sw_init(&ctx->hash); HMAC_sw_init((union hmac_ctx *)ctx, key, len); } /** * HMAC SHA1 initialization. */ __always_inline void HMAC_SHA1_sw_init(struct hmac_sha1_ctx *const ctx, const void *key, size_t len) { SHA1_sw_init(&ctx->hash); HMAC_sw_init((union hmac_ctx *)ctx, key, len); } void SHA1_hw_init(struct sha1_ctx *ctx); void SHA256_hw_init(struct sha256_ctx *ctx); const struct sha1_digest *SHA1_hw_hash(const void *data, size_t len, struct sha1_digest *digest); const struct sha256_digest *SHA256_hw_hash(const void *data, size_t len, struct sha256_digest *digest); #ifdef CONFIG_UPTO_SHA512 void SHA384_sw_init(struct sha384_ctx *const ctx); void SHA384_sw_update(struct sha384_ctx *const ctx, const void *data, size_t len); const struct sha384_digest *SHA384_sw_final(struct sha384_ctx *const ctx); const struct sha384_digest *SHA384_sw_hash(const void *data, size_t len, struct sha384_digest *digest); void SHA512_sw_init(struct sha512_ctx *const ctx); void SHA512_sw_update(struct sha512_ctx *const ctx, const void *data, size_t len); const struct sha512_digest *SHA512_sw_final(struct sha512_ctx *ctx); const struct sha512_digest *SHA512_sw_hash(const void *data, size_t len, struct sha512_digest *digest); void SHA384_hw_init(struct sha384_ctx *ctx); void SHA512_hw_init(struct sha512_ctx *ctx); const struct sha384_digest *SHA384_hw_hash(const void *data, size_t len, struct sha384_digest *digest); const struct sha512_digest *SHA512_hw_hash(const void *data, size_t len, struct sha512_digest *digest); /** * HMAC SHA2-384 initialization. */ __always_inline void HMAC_SHA384_sw_init(struct hmac_sha384_ctx *ctx, const void *key, size_t len) { SHA384_sw_init(&ctx->hash); HMAC_sw_init((union hmac_ctx *)ctx, key, len); } /** * HMAC SHA2-512 initialization. */ __always_inline void HMAC_SHA512_sw_init(struct hmac_sha512_ctx *ctx, const void *key, size_t len) { SHA512_sw_init(&ctx->hash); HMAC_sw_init((union hmac_ctx *)ctx, key, len); } #endif /* * HMAC. FIPS 198-1 */ void HMAC_SHA256_hw_init(struct hmac_sha256_ctx *ctx, const void *key, size_t len); /* DCRYPTO HMAC-SHA256 final */ const struct sha256_digest *HMAC_SHA256_hw_final(struct hmac_sha256_ctx *ctx); /* * Hardware AES. */ enum dcrypto_result dcrypto_aes_init(const uint8_t *key, size_t key_len, const uint8_t *iv, enum cipher_mode c_mode, enum encrypt_mode e_mode); /* * BIGNUM. */ #define LITE_BN_BITS2 32 #define LITE_BN_BYTES 4 #define BN_DIGIT(b, i) ((b)->d[(i)].udata) void bn_init(struct LITE_BIGNUM *bn, void *buf, size_t len); #define bn_words(b) ((b)->dmax) int bn_eq(const struct LITE_BIGNUM *a, const struct LITE_BIGNUM *b); int bn_check_topbit(const struct LITE_BIGNUM *N); enum dcrypto_result bn_modexp(struct LITE_BIGNUM *output, const struct LITE_BIGNUM *input, const struct LITE_BIGNUM *exp, const struct LITE_BIGNUM *N); enum dcrypto_result bn_modexp_word(struct LITE_BIGNUM *output, const struct LITE_BIGNUM *input, uint32_t pubexp, const struct LITE_BIGNUM *N); enum dcrypto_result bn_modexp_blinded(struct LITE_BIGNUM *output, const struct LITE_BIGNUM *input, const struct LITE_BIGNUM *exp, const struct LITE_BIGNUM *N, uint32_t pubexp); uint32_t bn_add(struct LITE_BIGNUM *c, const struct LITE_BIGNUM *a); int32_t bn_sub(struct LITE_BIGNUM *c, const struct LITE_BIGNUM *a); enum dcrypto_result bn_modinv_vartime(struct LITE_BIGNUM *r, const struct LITE_BIGNUM *e, const struct LITE_BIGNUM *MOD); int bn_is_bit_set(const struct LITE_BIGNUM *a, size_t n); /* * Accelerated bn. */ enum dcrypto_result dcrypto_modexp(struct LITE_BIGNUM *output, const struct LITE_BIGNUM *input, const struct LITE_BIGNUM *exp, const struct LITE_BIGNUM *N); enum dcrypto_result dcrypto_modexp_word(struct LITE_BIGNUM *output, const struct LITE_BIGNUM *input, uint32_t pubexp, const struct LITE_BIGNUM *N); enum dcrypto_result dcrypto_modexp_blinded(struct LITE_BIGNUM *output, const struct LITE_BIGNUM *input, const struct LITE_BIGNUM *exp, const struct LITE_BIGNUM *N, uint32_t pubexp); /** * NIST SP 800-90A HMAC_DRBG_SHA2-256. */ struct drbg_ctx { uint32_t k[SHA256_DIGEST_WORDS]; uint32_t v[SHA256_DIGEST_WORDS]; uint32_t reseed_counter; uint32_t reseed_threshold; enum dcrypto_result magic_cookie; }; /* According to NIST SP 800-90A rev 1 B.2 * Maximum number of bits per request = 7500 bit, ~937 bytes */ #define HMAC_DRBG_MAX_OUTPUT_SIZE 937U #define HMAC_DRBG_DO_NOT_AUTO_RESEED 0xFFFFFFFF /* Check that DRBG is properly initialized. */ __always_inline bool hmac_drbg_ctx_valid(const struct drbg_ctx *drbg) { return drbg->magic_cookie == DCRYPTO_OK; } /* Standard initialization. */ void hmac_drbg_init(struct drbg_ctx *ctx, const void *entropy, size_t entropy_len, const void *nonce, size_t nonce_len, const void *perso, size_t perso_len, uint32_t reseed_threshold); void hmac_drbg_reseed(struct drbg_ctx *ctx, const void *entropy, size_t entropy_len, const void *additional_input, size_t additional_input_len); enum dcrypto_result hmac_drbg_generate(struct drbg_ctx *ctx, void *out, size_t out_len, const void *input, size_t input_len) __warn_unused_result; void drbg_exit(struct drbg_ctx *ctx); /** * TRNG service functions */ /** * Returns random number with indication wherever reading is valid. This is * different from rand() which doesn't provide any indication. * High 32-bits set to zero in case of error; otherwise value >> 32 == 1 * Use of uint64_t vs. struct results in more efficient code. */ uint64_t read_rand(void); /** * FIPS-compliant TRNG startup. * The entropy source's startup tests shall run the continuous health tests * over at least 4096 consecutive samples. * Note: This function can throw FIPS_FATAL_TRNG error * * To hide latency of reading TRNG data, this test is executed in 2 stages * @param stage is 0 or 1, choosing the stage. On each stage 2048 * samples are processed. Assuming that some other tasks can be executed * between stages, when TRNG FIFO if filled with samples. * * Some number of samples will be available in entropy_fifo */ bool fips_trng_startup(int stage); /** * Returns random number from TRNG with indication wherever reading is valid. * This is different from rand() which doesn't provide any indication. * High 32-bits set to zero in case of error; otherwise value >> 32 == 1 * Use of uint64_t vs. struct results in more efficient code. * Random is passed continuous TRNG health tests. * * @return uint64_t, low 32 bits - random high 32 bits - validity status */ uint64_t fips_trng_rand32(void); /** * Check that Cr50-wide HMAC_DRBG seeded according NIST SP 800-90A * recomendation is properly initialized and can be used. * Includes fips_crypto_allowed() check. * Initialize DRBG if it was not yet initialized. */ bool fips_drbg_init(void); /* FIPS DRBG initialized at boot time/first use. */ extern struct drbg_ctx fips_drbg; /* Initialize for use as RFC6979 DRBG. */ void hmac_drbg_init_rfc6979(struct drbg_ctx *ctx, const p256_int *key, const p256_int *message); /* Generate a p256 number between 1 < k < |p256| using provided DRBG. */ enum dcrypto_result p256_hmac_drbg_generate(struct drbg_ctx *ctx, p256_int *k_out); /* Set seed for fast random number generator using LFSR. */ void set_fast_random_seed(uint32_t seed); /* Generate week pseudorandom using LFSR for blinding purposes. */ uint32_t fast_random(void); typedef int32_t p256_sdigit; typedef uint64_t p256_ddigit; typedef int64_t p256_sddigit; #define P256_DIGITS(x) ((x)->a) #define P256_DIGIT(x, y) ((x)->a[y]) extern const p256_int SECP256r1_nMin2; /* Check p256 is a zero. */ int p256_is_zero(const p256_int *a); /* c := a + (single digit)b, returns carry 1 on carry. */ int p256_add_d(const p256_int *a, p256_digit b, p256_int *c); /* Returns -1, 0 or 1. */ int p256_cmp(const p256_int *a, const p256_int *b); /* Return -1 if a < b. */ int p256_lt_blinded(const p256_int *a, const p256_int *b); /** * Raw sign with provided nonce (k). Used internally and for testing. * * @param k valid random per-message nonce for ECDSA sign * @param key valid private key for ECDSA sign * @param message message to sign encoded as p-256 int * @param r generated signature * @param s generated signature * * @return DCRYPTO_OK if successful */ enum dcrypto_result dcrypto_p256_ecdsa_sign_raw( const p256_int *k, const p256_int *key, const p256_int *message, p256_int *r, p256_int *s) __warn_unused_result; /** * ECDSA P-256 Sign using provide DRBG as source for per-message random * nonces. Used primarily for deterministic signatures per RFC 6979. * * @param drbg initialized DRBG * @param key valid private key for ECDSA sign * @param message message to sign encoded as p-256 int * @param r generated signature * @param s generated signature * * @return DCRYPTO_OK if successful */ enum dcrypto_result dcrypto_p256_ecdsa_sign(struct drbg_ctx *drbg, const p256_int *key, const p256_int *message, p256_int *r, p256_int *s) __warn_unused_result; /** * Compute k*G (base point multiplication). Used to compute public key * from private scalar. * * @param k private key * @param x output component x * @param y output component y * * @return DCRYPTO_OK if successful */ enum dcrypto_result dcrypto_p256_base_point_mul( const p256_int *k, p256_int *x, p256_int *y) __warn_unused_result; /** * Compute multiplication of input point (in_x, in_y) by scalar k. * Used to compute shared point in ECDH. * * @param k private key * @param in_x input public component x * @param in_y input public component y * @param x output shared component x * @param y output shared component y * * @return DCRYPTO_OK if successful */ enum dcrypto_result dcrypto_p256_point_mul(const p256_int *k, const p256_int *in_x, const p256_int *in_y, p256_int *x, p256_int *y) __warn_unused_result; /** * Verify ECDSA NIST P-256 signature. * * @param key_x public key component x * @param key_y public key component y * @param message message digest converted to p256_int * @param r signature component r * @param s signature component s * * @return DCRYPTO_OK if signature is valid */ enum dcrypto_result dcrypto_p256_ecdsa_verify( const p256_int *key_x, const p256_int *key_y, const p256_int *message, const p256_int *r, const p256_int *s) __warn_unused_result; /** * Verify that provided point is on NIST P-256 curve. * * @param x public key component x * @param y public key component y * * @return DCRYPTO_OK if point is on curve */ enum dcrypto_result dcrypto_p256_is_valid_point( const p256_int *x, const p256_int *y) __warn_unused_result; /** * Pair-wise consistency test for private and public key. * * @param drbg - DRBG to use for nonce generation * @param d - private key (scalar) * @param x - public key part * @param y - public key part * * @return DCRYPTO_OK on success */ enum dcrypto_result dcrypto_p256_key_pwct( struct drbg_ctx *drbg, const p256_int *d, const p256_int *x, const p256_int *y) __warn_unused_result; /* Wipe content of rnd with pseudo-random values. */ void p256_fast_random(p256_int *rnd); /** * Sign using provided DRBG. Reseed DRBG with entropy from verified TRNG if * needed. * * @param drbg DRBG to use * @param key P-256 private key * @param message - Message to sign as P-256 (in little-endian) * @param r - Generated signature * @param s - Generated signature * @return DCRYPTO_OK if success */ enum dcrypto_result dcrypto_p256_fips_sign_internal( struct drbg_ctx *drbg, const p256_int *key, const p256_int *message, p256_int *r, p256_int *s) __warn_unused_result; /* * Accelerator runtime. * * Note dcrypto_init_and_lock grabs a mutex and dcrypto_unlock releases it. * Do not use dcrypto_call, dcrypto_imem_load or dcrypto_dmem_load w/o holding * the mutex. */ void dcrypto_init_and_lock(void); void dcrypto_unlock(void); uint32_t dcrypto_call(uint32_t adr) __attribute__((warn_unused_result)); void dcrypto_imem_load(size_t offset, const uint32_t *opcodes, size_t n_opcodes); /* * Returns 0 iff no difference was observed between existing and new content. */ uint32_t dcrypto_dmem_load(size_t offset, const void *words, size_t n_words); /* P256 based integration encryption (DH+AES128+SHA256). * Not FIPS 140-2 compliant, not used other than for tests * Authenticated data may be provided, where the first auth_data_len * bytes of in will be authenticated but not encrypted. * * Supports in-place encryption / decryption. * * The output format is: * 0x04 || PUBKEY || AUTH_DATA || AES128_CTR(PLAINTEXT) || * HMAC_SHA256(AUTH_DATA || CIPHERTEXT) */ size_t DCRYPTO_ecies_encrypt(void *out, size_t out_len, const void *in, size_t in_len, size_t auth_data_len, const uint8_t *iv, const p256_int *pub_x, const p256_int *pub_y, const uint8_t *salt, size_t salt_len, const uint8_t *info, size_t info_len); size_t DCRYPTO_ecies_decrypt(void *out, size_t out_len, const void *in, size_t in_len, size_t auth_data_len, const uint8_t *iv, const p256_int *d, const uint8_t *salt, size_t salt_len, const uint8_t *info, size_t info_len); /* * HKDF as per RFC 5869. Mentioned as conforming NIST SP 800-56C Rev.1 * [RFC 5869] specifies a version of the above extraction-then-expansion * key-derivation procedure using HMAC for both the extraction and expansion * steps. */ int DCRYPTO_hkdf(uint8_t *OKM, size_t OKM_len, const uint8_t *salt, size_t salt_len, const uint8_t *IKM, size_t IKM_len, const uint8_t *info, size_t info_len); /* AES-GCM-128/192/256 * NIST Special Publication 800-38D, IV is provided externally * Caller should use IV length according to section 8.2 of SP 800-38D * And choose appropriate IV construction method, constrain number * of invocations according to section 8.3 of SP 800-38D */ struct GCM_CTX { union { uint32_t d[4]; uint8_t c[16]; } block, Ej0; uint64_t aad_len; uint64_t count; size_t remainder; }; /* Initialize the GCM context structure. */ void DCRYPTO_gcm_init(struct GCM_CTX *ctx, uint32_t key_bits, const uint8_t *key, const uint8_t *iv, size_t iv_len); /* Additional authentication data to include in the tag calculation. */ void DCRYPTO_gcm_aad(struct GCM_CTX *ctx, const uint8_t *aad_data, size_t len); /* Encrypt & decrypt return the number of bytes written to out * (always an integral multiple of 16), or -1 on error. These functions * may be called repeatedly with incremental data. * * NOTE: if in_len is not a integral multiple of 16, then out_len must * be at least in_len - (in_len % 16) + 16 bytes. */ int DCRYPTO_gcm_encrypt(struct GCM_CTX *ctx, uint8_t *out, size_t out_len, const uint8_t *in, size_t in_len); int DCRYPTO_gcm_decrypt(struct GCM_CTX *ctx, uint8_t *out, size_t out_len, const uint8_t *in, size_t in_len); /* Encrypt & decrypt a partial final block, if any. These functions * return the number of bytes written to out (<= 15), or -1 on error. */ int DCRYPTO_gcm_encrypt_final(struct GCM_CTX *ctx, uint8_t *out, size_t out_len); int DCRYPTO_gcm_decrypt_final(struct GCM_CTX *ctx, uint8_t *out, size_t out_len); /* Compute the tag over AAD + encrypt or decrypt data, and return the * number of bytes written to tag. Returns -1 on error. */ int DCRYPTO_gcm_tag(struct GCM_CTX *ctx, uint8_t *tag, size_t tag_len); /* Cleanup secrets. */ void DCRYPTO_gcm_finish(struct GCM_CTX *ctx); /* AES-CMAC-128 * NIST Special Publication 800-38B, RFC 4493 * K: 128-bit key, M: message, len: number of bytes in M * Writes 128-bit tag to T; returns 0 if an error is encountered and 1 * otherwise. */ enum dcrypto_result DCRYPTO_aes_cmac(const uint8_t *K, const uint8_t *M, size_t len, uint32_t T[4]); /* key: 128-bit key, M: message, len: number of bytes in M, * T: tag to be verified * Returns 1 if the tag is correct and 0 otherwise. */ enum dcrypto_result DCRYPTO_aes_cmac_verify(const uint8_t *key, const uint8_t *M, size_t len, const uint32_t T[4]); #ifndef __alias #define __alias(func) __attribute__((alias(#func))) #endif /** * Macro to control optimization at function level. Typically used in * very tight and critical loops to override -Os and get a better code. * Only supported by gcc, so ignore it for clang. */ #ifndef __optimize #ifndef __clang__ #define __optimize(a) __attribute__((optimize(a))) #else #define __optimize(a) #endif #endif /* rotate 32-bit value right */ __always_inline uint32_t ror(uint32_t value, int bits) { /* return __builtin_rotateright32(value, bits); */ return (value >> bits) | (value << (32 - bits)); } /* rotate 64-bit value right */ __always_inline uint64_t ror64(uint64_t value, int bits) { /* return __builtin_rotateright64(value, bits); */ return (value >> bits) | (value << (64 - bits)); } /* rotate 32-bit value left */ __always_inline uint32_t rol(uint32_t value, int bits) { /* return __builtin_rotateleft32(value, bits); */ return (value << bits) | (value >> (32 - bits)); } /* rotate 64-bit value left */ __always_inline uint64_t rol64(uint64_t value, int bits) { /* return __builtin_rotateleft64(value, bits); */ return (value << bits) | (value >> (64 - bits)); } /* Functions to convert between uint32_t and uint64_t */ __always_inline uint32_t lo32(uint64_t v) { return (uint32_t)v; } __always_inline uint32_t hi32(uint64_t v) { return (uint32_t)(v >> 32); } __always_inline uint64_t make64(uint32_t hi, uint32_t lo) { return (((uint64_t)hi) << 32) | lo; } __always_inline uint32_t lo16(uint32_t v) { return (uint32_t)(v)&0xffff; } __always_inline uint32_t hi16(uint32_t v) { return (uint32_t)(v >> 16); } __always_inline int count_leading_zeros(uint32_t x) { /* __builtin_clz(0) is undefined, so explicitly return bit size. */ return (x) ? __builtin_clz(x) : 32; } __always_inline int count_trailing_zeros(uint32_t x) { /* __builtin_ctz(0) is undefined, so explicitly return bit size. */ return (x) ? __builtin_ctz(x) : 32; } /* stack based allocation */ #ifndef alloca #define alloca __builtin_alloca #endif /* Define machine word alignment mask. */ #define WORD_MASK (sizeof(uintptr_t) - 1) /* return true if pointer is not word aligned. */ __always_inline bool is_not_aligned(const void *ptr) { return (uintptr_t)ptr & WORD_MASK; } /** * @brief Launders the machine register sized value `val`. * * It returns a value identical to the input, while introducing an optimization * barrier that prevents the compiler from learning new information about the * original value, based on operations on the laundered value. For example * with code: * temp = b - a; * c = (cond)? temp + a : a; * compiler will reduce code to: * c = (cond)? b : a; * Which may not be desirable. * making temp = value_barrier(b-a) prevents compiler from such optimization. * * Another case is for double checks against fault injection: * if (cond == 0) { if (value_barrier(cond) != 0 ) panic(); } * Without value_barrier the nested check will be removed. * * @param val A machine register size integer to launder. * @return An integer which will happen to have the same value as `val` at * runtime. */ __always_inline uintptr_t value_barrier(uintptr_t val) { /** * The +r constraint tells the compiler that this is an "inout" * parameter: it means that not only does the black box depend on `val`, * but it also mutates it in an unspecified way. This ensures that the * laundering operation occurs in the right place in the dependency * ordering. */ asm("" : "+r"(val)); return val; } __always_inline void *value_barrier_ptr(void *val) { /** * The +r constraint tells the compiler that this is an "inout" * parameter: it means that not only does the black box depend on `val`, * but it also mutates it in an unspecified way. This ensures that the * laundering operation occurs in the right place in the dependency * ordering. */ asm("" : "+r"(val)); return val; } /** * Hardened select of word without branches. * * @param test the value to test * @param a the value returned if 'test' is not 0 * @param b the value returned if 'test' is zero * * @return b if test==0 and a otherwise; * * This function is mostly useful when test == 0 is a good result and * hardening is required to prevent easy generation of 'b'. * * Example: * hardened_select_if_zero(test, CRYPTO_FAIL, CRYPTO_OK) */ __always_inline uintptr_t hardened_select_if_zero(uintptr_t test, uintptr_t a, uintptr_t b) { uintptr_t bma = value_barrier(b - a); /* For test == 0, does nothing, otherwise damage bma. */ bma &= value_barrier(~test); return (test == 0) ? bma + a : a; } /* Convenience wrapper to return DCRYPTO_OK iff val == 0. */ __always_inline enum dcrypto_result dcrypto_ok_if_zero(uintptr_t val) { return (enum dcrypto_result)hardened_select_if_zero(val, DCRYPTO_FAIL, DCRYPTO_OK); } /* Process blocks using configured AES engine. */ size_t dcrypto_aes_process(uint32_t **out, const uint32_t **in, size_t len); /* * Key ladder. */ #ifndef __cplusplus enum dcrypto_appid; /* Forward declaration. */ int dcrypto_ladder_compute_usr(enum dcrypto_appid id, const uint32_t usr_salt[8]); int dcrypto_ladder_derive(enum dcrypto_appid appid, const uint32_t salt[8], const uint32_t input[8], uint32_t output[8]); #endif #ifdef __cplusplus } #endif #endif /* ! __EC_CHIP_G_DCRYPTO_INTERNAL_H */