#include #include #include "kyber512r3_indcpa.h" #include "kyber512r3_indcpa_avx2.h" #include "kyber512r3_params.h" #include "kyber512r3_symmetric.h" #include "pq-crypto/s2n_pq.h" #include "pq-crypto/s2n_pq_random.h" #include "tls/s2n_kem.h" #include "utils/s2n_safety.h" S2N_ENSURE_PORTABLE_OPTIMIZATIONS /************************************************* * Name: crypto_kem_keypair * * Description: Generates public and private key * for CCA-secure Kyber key encapsulation mechanism * * Arguments: - unsigned char *pk: pointer to output public key * (an already allocated array of S2N_KYBER_512_R3_PUBLIC_KEY_BYTES bytes) * - unsigned char *sk: pointer to output private key * (an already allocated array of S2N_KYBER_512_R3_SECRET_KEY_BYTES bytes) * * Returns 0 (success) **************************************************/ int s2n_kyber_512_r3_crypto_kem_keypair(const struct s2n_kem *kem, uint8_t *pk, uint8_t *sk) { POSIX_ENSURE(s2n_pq_is_enabled(), S2N_ERR_PQ_DISABLED); #if defined(S2N_KYBER512R3_AVX2_BMI2) if (s2n_kyber512r3_is_avx2_bmi2_enabled()) { POSIX_GUARD(indcpa_keypair_avx2(pk, sk)); } else #endif { POSIX_GUARD(indcpa_keypair(pk, sk)); } for (size_t i = 0; i < S2N_KYBER_512_R3_INDCPA_PUBLICKEYBYTES; i++) { sk[i + S2N_KYBER_512_R3_INDCPA_SECRETKEYBYTES] = pk[i]; } sha3_256(sk + S2N_KYBER_512_R3_SECRET_KEY_BYTES - 2 * S2N_KYBER_512_R3_SYMBYTES, pk, S2N_KYBER_512_R3_PUBLIC_KEY_BYTES); /* Value z for pseudo-random output on reject */ POSIX_GUARD_RESULT(s2n_get_random_bytes(sk + S2N_KYBER_512_R3_SECRET_KEY_BYTES - S2N_KYBER_512_R3_SYMBYTES, S2N_KYBER_512_R3_SYMBYTES)); return S2N_SUCCESS; } /************************************************* * Name: crypto_kem_enc * * Description: Generates cipher text and shared * secret for given public key * * Arguments: - unsigned char *ct: pointer to output cipher text * (an already allocated array of S2N_KYBER_512_R3_CIPHERTEXT_BYTES bytes) * - unsigned char *ss: pointer to output shared secret * (an already allocated array of S2N_KYBER_512_R3_SHARED_SECRET_BYTES bytes) * - const unsigned char *pk: pointer to input public key * (an already allocated array of S2N_KYBER_512_R3_PUBLIC_KEY_BYTES bytes) * * Returns 0 (success) **************************************************/ int s2n_kyber_512_r3_crypto_kem_enc(const struct s2n_kem *kem, uint8_t *ct, uint8_t *ss, const uint8_t *pk) { POSIX_ENSURE(s2n_pq_is_enabled(), S2N_ERR_PQ_DISABLED); uint8_t buf[2 * S2N_KYBER_512_R3_SYMBYTES]; /* Will contain key, coins */ uint8_t kr[2 * S2N_KYBER_512_R3_SYMBYTES]; POSIX_GUARD_RESULT(s2n_get_random_bytes(buf, S2N_KYBER_512_R3_SYMBYTES)); /* Don't release system RNG output */ sha3_256(buf, buf, S2N_KYBER_512_R3_SYMBYTES); /* Multitarget countermeasure for coins + contributory KEM */ sha3_256(buf + S2N_KYBER_512_R3_SYMBYTES, pk, S2N_KYBER_512_R3_PUBLIC_KEY_BYTES); sha3_512(kr, buf, 2 * S2N_KYBER_512_R3_SYMBYTES); /* coins are in kr+S2N_KYBER_512_R3_SYMBYTES */ #if defined(S2N_KYBER512R3_AVX2_BMI2) if (s2n_kyber512r3_is_avx2_bmi2_enabled()) { indcpa_enc_avx2(ct, buf, pk, kr + S2N_KYBER_512_R3_SYMBYTES); } else #endif { indcpa_enc(ct, buf, pk, kr + S2N_KYBER_512_R3_SYMBYTES); } /* overwrite coins in kr with H(c) */ sha3_256(kr + S2N_KYBER_512_R3_SYMBYTES, ct, S2N_KYBER_512_R3_CIPHERTEXT_BYTES); /* hash concatenation of pre-k and H(c) to k */ shake256(ss, S2N_KYBER_512_R3_SSBYTES, kr, 2 * S2N_KYBER_512_R3_SYMBYTES); return S2N_SUCCESS; } /************************************************* * Name: crypto_kem_dec * * Description: Generates shared secret for given * cipher text and private key * * Arguments: - unsigned char *ss: pointer to output shared secret * (an already allocated array of S2N_KYBER_512_R3_SHARED_SECRET_BYTES bytes) * - const unsigned char *ct: pointer to input cipher text * (an already allocated array of S2N_KYBER_512_R3_CIPHERTEXT_BYTES bytes) * - const unsigned char *sk: pointer to input private key * (an already allocated array of S2N_KYBER_512_R3_SECRET_KEY_BYTES bytes) * * Returns 0. * * On failure, ss will contain a pseudo-random value. **************************************************/ int s2n_kyber_512_r3_crypto_kem_dec(const struct s2n_kem *kem, uint8_t *ss, const uint8_t *ct, const uint8_t *sk) { POSIX_ENSURE(s2n_pq_is_enabled(), S2N_ERR_PQ_DISABLED); uint8_t buf[2 * S2N_KYBER_512_R3_SYMBYTES]; /* Will contain key, coins */ uint8_t kr[2 * S2N_KYBER_512_R3_SYMBYTES]; uint8_t cmp[S2N_KYBER_512_R3_CIPHERTEXT_BYTES]; const uint8_t *pk = sk + S2N_KYBER_512_R3_INDCPA_SECRETKEYBYTES; #if defined(S2N_KYBER512R3_AVX2_BMI2) if (s2n_kyber512r3_is_avx2_bmi2_enabled()) { indcpa_dec_avx2(buf, ct, sk); } else #endif { indcpa_dec(buf, ct, sk); } /* Multitarget countermeasure for coins + contributory KEM */ for (size_t i = 0; i < S2N_KYBER_512_R3_SYMBYTES; i++) { buf[S2N_KYBER_512_R3_SYMBYTES + i] = sk[S2N_KYBER_512_R3_SECRET_KEY_BYTES - 2 * S2N_KYBER_512_R3_SYMBYTES + i]; } sha3_512(kr, buf, 2 * S2N_KYBER_512_R3_SYMBYTES); /* coins are in kr+S2N_KYBER_512_R3_SYMBYTES */ #if defined(S2N_KYBER512R3_AVX2_BMI2) if (s2n_kyber512r3_is_avx2_bmi2_enabled()) { indcpa_enc_avx2(cmp, buf, pk, kr + S2N_KYBER_512_R3_SYMBYTES); } else #endif { indcpa_enc(cmp, buf, pk, kr + S2N_KYBER_512_R3_SYMBYTES); } /* If ct and cmp are equal (dont_copy = 1), decryption has succeeded and we do NOT overwrite pre-k below. * If ct and cmp are not equal (dont_copy = 0), decryption fails and we do overwrite pre-k. */ int dont_copy = s2n_constant_time_equals(ct, cmp, S2N_KYBER_512_R3_CIPHERTEXT_BYTES); /* overwrite coins in kr with H(c) */ sha3_256(kr + S2N_KYBER_512_R3_SYMBYTES, ct, S2N_KYBER_512_R3_CIPHERTEXT_BYTES); /* Overwrite pre-k with z on re-encryption failure */ POSIX_GUARD(s2n_constant_time_copy_or_dont(kr, sk + S2N_KYBER_512_R3_SECRET_KEY_BYTES - S2N_KYBER_512_R3_SYMBYTES, S2N_KYBER_512_R3_SYMBYTES, dont_copy)); /* hash concatenation of pre-k and H(c) to k */ shake256(ss, S2N_KYBER_512_R3_SSBYTES, kr, 2 * S2N_KYBER_512_R3_SYMBYTES); return S2N_SUCCESS; }