From 565522ffdf4412461f0d3c41c59a7ae8a30243c0 Mon Sep 17 00:00:00 2001 From: Michael Hamburg Date: Tue, 24 Nov 2015 17:42:00 -0800 Subject: [PATCH] trying to update to the latest version of strobe. lots of stuff in flux though --- src/decaf_crypto.c | 189 +++++----- src/public_include/decaf/common.h | 9 +- src/public_include/decaf/crypto.h | 27 +- src/public_include/decaf/shake.h | 333 +++++++++++------- src/public_include/decaf/shake.hxx | 118 +++---- src/shake.c | 531 ++++++++++++----------------- test/bench_decaf.cxx | 18 +- test/shakesum.c | 10 + test/test_decaf.cxx | 4 +- 9 files changed, 619 insertions(+), 620 deletions(-) diff --git a/src/decaf_crypto.c b/src/decaf_crypto.c index c567727..dc4e523 100644 --- a/src/decaf_crypto.c +++ b/src/decaf_crypto.c @@ -17,16 +17,15 @@ void decaf_255_derive_private_key ( decaf_255_private_key_t priv, const decaf_255_symmetric_key_t proto ) { - const char *magic = "decaf_255_derive_private_key"; + const char *magic = "decaf::derive_255_private_key"; /* TODO: canonicalize and freeze */ uint8_t encoded_scalar[DECAF_255_SCALAR_OVERKILL_BYTES]; decaf_255_point_t pub; - - shake256_ctx_t sponge; - shake256_init(sponge); - shake256_update(sponge, proto, sizeof(decaf_255_symmetric_key_t)); - shake256_update(sponge, (const unsigned char *)magic, strlen(magic)); - shake256_final(sponge, encoded_scalar, sizeof(encoded_scalar)); - shake256_destroy(sponge); + + keccak_strobe_t strobe; + strobe_init(strobe, &STROBE_256, magic, 0); + strobe_key(strobe, proto, sizeof(decaf_255_symmetric_key_t)); + strobe_prng(strobe, encoded_scalar, sizeof(encoded_scalar)); + strobe_destroy(strobe); memcpy(priv->sym, proto, sizeof(decaf_255_symmetric_key_t)); decaf_255_scalar_decode_long(priv->secret_scalar, encoded_scalar, sizeof(encoded_scalar)); @@ -51,98 +50,77 @@ void decaf_255_private_to_public ( memcpy(pub, priv->pub, sizeof(decaf_255_public_key_t)); } +static const uint16_t SHARED_SECRET_MAX_BLOCK_SIZE = 1<<12; /* TODO: standardize and freeze */ + decaf_error_t decaf_255_shared_secret ( uint8_t *shared, size_t shared_bytes, const decaf_255_private_key_t my_privkey, - const decaf_255_public_key_t your_pubkey + const decaf_255_public_key_t your_pubkey, + int me_first ) { + const char *magic = "decaf::decaf_255_shared_secret"; /* TODO: canonicalize and freeze */ + keccak_strobe_t strobe; + strobe_init(strobe, &STROBE_256, magic, 0); + uint8_t ss_ser[DECAF_255_SER_BYTES]; - const char *nope = "decaf_255_ss_invalid"; - - unsigned i; - /* Lexsort keys. Less will be -1 if mine is less, and 0 otherwise. */ - uint16_t less = 0; - for (i=0; ipub[i]; - delta -= your_pubkey[i]; - /* Case: - * = -> delta = 0 -> hi delta-1 = -1, hi delta = 0 - * > -> delta > 0 -> hi delta-1 = 0, hi delta = 0 - * < -> delta < 0 -> hi delta-1 = (doesnt matter), hi delta = -1 - */ - less &= delta-1; - less |= delta; - } - less >>= 8; - - shake256_ctx_t sponge; - shake256_init(sponge); - - /* update the lesser */ - for (i=0; ipub[i] & less) | (your_pubkey[i] & ~less); - } - shake256_update(sponge, ss_ser, sizeof(ss_ser)); - - /* update the greater */ - for (i=0; ipub[i] & ~less) | (your_pubkey[i] & less); + + if (me_first) { + strobe_ad(strobe,my_privkey->pub,sizeof(decaf_255_public_key_t)); + strobe_ad(strobe,your_pubkey,sizeof(decaf_255_public_key_t)); + } else { + strobe_ad(strobe,your_pubkey,sizeof(decaf_255_public_key_t)); + strobe_ad(strobe,my_privkey->pub,sizeof(decaf_255_public_key_t)); } - shake256_update(sponge, ss_ser, sizeof(ss_ser)); - - decaf_error_t ret = decaf_255_direct_scalarmul(ss_ser, your_pubkey, my_privkey->secret_scalar, DECAF_FALSE, DECAF_TRUE); - decaf_bool_t good = decaf_successful(ret); - /* If invalid, then replace ... */ - for (i=0; isym)) { - ss_ser[i] |= my_privkey->sym[i] & ~good; - } else if (i - sizeof(my_privkey->sym) < strlen(nope)) { - ss_ser[i] |= nope[i-sizeof(my_privkey->sym)] & ~good; - } + decaf_error_t ret = decaf_255_direct_scalarmul( + ss_ser, your_pubkey, my_privkey->secret_scalar, DECAF_FALSE, DECAF_TRUE + ); + + strobe_transact(strobe,NULL,ss_ser,sizeof(ss_ser),STROBE_CW_DH_KEY); + + while (shared_bytes) { + uint16_t cando = (shared_bytes > SHARED_SECRET_MAX_BLOCK_SIZE) + ? SHARED_SECRET_MAX_BLOCK_SIZE : shared_bytes; + strobe_prng(strobe,shared,cando); + shared_bytes -= cando; + shared += cando; } - shake256_update(sponge, ss_ser, sizeof(ss_ser)); - shake256_final(sponge, shared, shared_bytes); - shake256_destroy(sponge); - + strobe_destroy(strobe); decaf_bzero(ss_ser, sizeof(ss_ser)); return ret; } void -decaf_255_sign_shake ( +decaf_255_sign_strobe ( + keccak_strobe_t strobe, decaf_255_signature_t sig, - const decaf_255_private_key_t priv, - const shake256_ctx_t shake + const decaf_255_private_key_t priv ) { - const char *magic = "decaf_255_sign_shake"; - - uint8_t overkill[DECAF_255_SCALAR_OVERKILL_BYTES], encoded[DECAF_255_SER_BYTES]; + uint8_t overkill[DECAF_255_SCALAR_OVERKILL_BYTES]; decaf_255_point_t point; decaf_255_scalar_t nonce, challenge; + /* Stir pubkey */ + strobe_transact(strobe,NULL,priv->pub,sizeof(decaf_255_public_key_t),STROBE_CW_SIG_PK); + /* Derive nonce */ - shake256_ctx_t ctx; - memcpy(ctx, shake, sizeof(ctx)); - shake256_update(ctx, priv->sym, sizeof(priv->sym)); - shake256_update(ctx, (const unsigned char *)magic, strlen(magic)); - shake256_final(ctx, overkill, sizeof(overkill)); + keccak_strobe_t strobe2; + memcpy(strobe2,strobe,sizeof(strobe2)); + strobe_key(strobe2,priv->sym,sizeof(decaf_255_symmetric_key_t)); + strobe_prng(strobe2,overkill,sizeof(overkill)); + strobe_destroy(strobe2); decaf_255_scalar_decode_long(nonce, overkill, sizeof(overkill)); decaf_255_precomputed_scalarmul(point, decaf_255_precomputed_base, nonce); - decaf_255_point_encode(encoded, point); + decaf_255_point_encode(sig, point); + /* Derive challenge */ - memcpy(ctx, shake, sizeof(ctx)); - shake256_update(ctx, priv->pub, sizeof(priv->pub)); - shake256_update(ctx, encoded, sizeof(encoded)); - shake256_final(ctx, overkill, sizeof(overkill)); - shake256_destroy(ctx); + strobe_transact(strobe,NULL,sig,DECAF_255_SER_BYTES,STROBE_CW_SIG_EPH); + strobe_transact(strobe,overkill,NULL,sizeof(overkill),STROBE_CW_SIG_CHAL); decaf_255_scalar_decode_long(challenge, overkill, sizeof(overkill)); /* Respond */ @@ -150,41 +128,42 @@ decaf_255_sign_shake ( decaf_255_scalar_sub(nonce, nonce, challenge); /* Save results */ - memcpy(sig, encoded, sizeof(encoded)); - decaf_255_scalar_encode(&sig[sizeof(encoded)], nonce); + decaf_255_scalar_encode(overkill, nonce); + strobe_transact(strobe,&sig[DECAF_255_SER_BYTES],overkill,DECAF_255_SCALAR_BYTES,STROBE_CW_SIG_RESP); /* Clean up */ decaf_255_scalar_destroy(nonce); decaf_255_scalar_destroy(challenge); decaf_bzero(overkill,sizeof(overkill)); - decaf_bzero(encoded,sizeof(encoded)); } decaf_error_t -decaf_255_verify_shake ( +decaf_255_verify_strobe ( + keccak_strobe_t strobe, const decaf_255_signature_t sig, - const decaf_255_public_key_t pub, - const shake256_ctx_t shake + const decaf_255_public_key_t pub ) { decaf_bool_t ret; - + uint8_t overkill[DECAF_255_SCALAR_OVERKILL_BYTES]; decaf_255_point_t point, pubpoint; decaf_255_scalar_t challenge, response; + /* Stir pubkey */ + strobe_transact(strobe,NULL,pub,sizeof(decaf_255_public_key_t),STROBE_CW_SIG_PK); + + /* Derive nonce */ + strobe_transact(strobe,NULL,sig,DECAF_255_SER_BYTES,STROBE_CW_SIG_EPH); + ret = decaf_successful( decaf_255_point_decode(point, sig, DECAF_TRUE) ); + /* Derive challenge */ - shake256_ctx_t ctx; - memcpy(ctx, shake, sizeof(ctx)); - shake256_update(ctx, pub, sizeof(decaf_255_public_key_t)); - shake256_update(ctx, sig, DECAF_255_SER_BYTES); - shake256_final(ctx, overkill, sizeof(overkill)); - shake256_destroy(ctx); + strobe_transact(strobe,overkill,NULL,sizeof(overkill),STROBE_CW_SIG_CHAL); decaf_255_scalar_decode_long(challenge, overkill, sizeof(overkill)); - - /* Decode points. */ - ret = decaf_successful(decaf_255_point_decode(point, sig, DECAF_TRUE)); - ret &= decaf_successful(decaf_255_point_decode(pubpoint, pub, DECAF_FALSE)); - ret &= decaf_successful(decaf_255_scalar_decode(response, &sig[DECAF_255_SER_BYTES])); + + /* Decode response */ + strobe_transact(strobe,overkill,&sig[DECAF_255_SER_BYTES],DECAF_255_SCALAR_BYTES,STROBE_CW_SIG_RESP); + ret &= decaf_successful( decaf_255_scalar_decode(response, overkill) ); + ret &= decaf_successful( decaf_255_point_decode(pubpoint, pub, DECAF_FALSE) ); decaf_255_base_double_scalarmul_non_secret ( pubpoint, response, pubpoint, challenge @@ -192,6 +171,14 @@ decaf_255_verify_shake ( ret &= decaf_255_point_eq(pubpoint, point); + /* Nothing here is secret, so don't do these things: + decaf_bzero(overkill,sizeof(overkill)); + decaf_255_point_destroy(point); + decaf_255_point_destroy(pubpoint); + decaf_255_scalar_destroy(challenge); + decaf_255_scalar_destroy(response); + */ + return decaf_succeed_if(ret); } @@ -202,11 +189,11 @@ decaf_255_sign ( const unsigned char *message, size_t message_len ) { - shake256_ctx_t ctx; - shake256_init(ctx); - shake256_update(ctx, message, message_len); - decaf_255_sign_shake(sig, priv, ctx); - shake256_destroy(ctx); + keccak_strobe_t ctx; + strobe_init(ctx,&STROBE_256,"decaf::decaf_255_sign",0); /* TODO: canonicalize and freeze */ + strobe_transact(ctx, NULL, message, message_len, STROBE_CW_STREAMING_PLAINTEXT); + decaf_255_sign_strobe(ctx, sig, priv); + strobe_destroy(ctx); } decaf_error_t @@ -216,10 +203,10 @@ decaf_255_verify ( const unsigned char *message, size_t message_len ) { - shake256_ctx_t ctx; - shake256_init(ctx); - shake256_update(ctx, message, message_len); - decaf_error_t ret = decaf_255_verify_shake(sig, pub, ctx); - shake256_destroy(ctx); + keccak_strobe_t ctx; + strobe_init(ctx,&STROBE_256,"decaf::decaf_255_sign",0); /* TODO: canonicalize and freeze */ + strobe_transact(ctx, NULL, message, message_len, STROBE_CW_STREAMING_PLAINTEXT); + decaf_error_t ret = decaf_255_verify_strobe(ctx, sig, pub); + strobe_destroy(ctx); return ret; } diff --git a/src/public_include/decaf/common.h b/src/public_include/decaf/common.h index 62732ef..db49a52 100644 --- a/src/public_include/decaf/common.h +++ b/src/public_include/decaf/common.h @@ -31,8 +31,13 @@ #define NONNULL5 __attribute__((nonnull(1,2,3,4,5))) /** @endcond */ -/* Internal word types */ -/* TODO: decide this internally, per curve, based on how it was built! */ +/* Internal word types. + * + * Somewhat tricky. This could be decided separately per platform. However, + * the structs do need to be all the same size and alignment on a given + * platform to support dynamic linking, since even if you header was built + * with eg arch_neon, you might end up linking a library built with arch_arm32. + */ #if (defined(__ILP64__) || defined(__amd64__) || defined(__x86_64__) || (((__UINT_FAST32_MAX__)>>30)>>30)) \ && !defined(DECAF_FORCE_32_BIT) #define DECAF_WORD_BITS 64 diff --git a/src/public_include/decaf/crypto.h b/src/public_include/decaf/crypto.h index 4ca19e4..8723cca 100644 --- a/src/public_include/decaf/crypto.h +++ b/src/public_include/decaf/crypto.h @@ -96,33 +96,32 @@ void decaf_255_private_to_public ( * @param [in] shared_bytes The size of the buffer. * @param [in] my_privkey My private key. * @param [in] your_pubkey Your public key. + * @param [in] me_first Direction flag to break symmetry. * * @retval DECAF_SUCCESS Key exchange was successful. * @retval DECAF_FAILURE Key exchange failed. - * - * @warning This is a pretty silly shared secret computation - * and will almost definitely change in the future. */ decaf_error_t decaf_255_shared_secret ( uint8_t *shared, size_t shared_bytes, const decaf_255_private_key_t my_privkey, - const decaf_255_public_key_t your_pubkey + const decaf_255_public_key_t your_pubkey, + int me_first ) NONNULL134 WARN_UNUSED API_VIS; /** - * @brief Sign a message from its SHAKE context. + * @brief Sign a message from a STROBE context. * * @param [out] sig The signature. * @param [in] priv Your private key. - * @param [in] shake A SHAKE256 context with the message. + * @param [in] strobe A STROBE context with the message. */ void -decaf_255_sign_shake ( +decaf_255_sign_strobe ( + keccak_strobe_t strobe, decaf_255_signature_t sig, - const decaf_255_private_key_t priv, - const shake256_ctx_t shake + const decaf_255_private_key_t priv ) NONNULL3 API_VIS; /** @@ -142,20 +141,20 @@ decaf_255_sign ( ) NONNULL3 API_VIS; /** - * @brief Verify a signed message from its SHAKE context. + * @brief Verify a signed message from its STROBE context. * * @param [in] sig The signature. * @param [in] pub The public key. - * @param [in] shake A SHAKE256 context with the message. + * @param [in] strobe A STROBE context with the message. * * @return DECAF_SUCCESS The signature verified successfully. * @return DECAF_FAILURE The signature did not verify successfully. */ decaf_error_t -decaf_255_verify_shake ( +decaf_255_verify_strobe ( + keccak_strobe_t strobe, const decaf_255_signature_t sig, - const decaf_255_public_key_t pub, - const shake256_ctx_t shake + const decaf_255_public_key_t pub ) NONNULL3 API_VIS WARN_UNUSED; /** diff --git a/src/public_include/decaf/shake.h b/src/public_include/decaf/shake.h index 871eb82..803bafd 100644 --- a/src/public_include/decaf/shake.h +++ b/src/public_include/decaf/shake.h @@ -14,6 +14,7 @@ #include #include +#include /* for NULL */ #include @@ -24,6 +25,8 @@ #define NONNULL2 __attribute__((nonnull(1,2))) #define NONNULL13 __attribute__((nonnull(1,3))) #define NONNULL3 __attribute__((nonnull(1,2,3))) +#define INLINE __inline__ __attribute__((always_inline)) +#define UNUSED __attribute__((unused)) /** @endcond */ #ifndef INTERNAL_SPONGE_STRUCT @@ -35,6 +38,7 @@ } keccak_sponge_t[1]; struct kparams_s; #endif +typedef struct keccak_sponge_s keccak_strobe_t[1], keccak_prng_t[1]; #ifdef __cplusplus extern "C" { @@ -173,14 +177,14 @@ DECSHA3(512) /** * @brief Initialize a sponge-based CSPRNG from a buffer. * - * @param [out] sponge The sponge object. + * @param [out] prng The prng object. * @param [in] in The initial data. * @param [in] len The length of the initial data. * @param [in] deterministic If zero, allow RNG to stir in nondeterministic * data from RDRAND or RDTSC. */ void spongerng_init_from_buffer ( - keccak_sponge_t sponge, + keccak_prng_t prng, const uint8_t * __restrict__ in, size_t len, int deterministic @@ -193,7 +197,7 @@ void spongerng_init_from_buffer ( /** * @brief Initialize a sponge-based CSPRNG from a file. * - * @param [out] sponge The sponge object. + * @param [out] prng The prng object. * @param [in] file A name of a file containing initial data. * @param [in] len The length of the initial data. Must be positive. * @param [in] deterministic If zero, allow RNG to stir in nondeterministic @@ -205,7 +209,7 @@ void spongerng_init_from_buffer ( * @retval -2 len was 0. */ int spongerng_init_from_file ( - keccak_sponge_t sponge, + keccak_prng_t prng, const char *file, size_t len, int deterministic @@ -226,7 +230,7 @@ int spongerng_init_from_file ( * @retval -1 An unknown error has occurred. */ int spongerng_init_from_dev_urandom ( - keccak_sponge_t sponge + keccak_prng_t prng ) API_VIS WARN_UNUSED; /** @@ -237,7 +241,7 @@ int spongerng_init_from_dev_urandom ( * @param [in] len The output buffer's length. */ void spongerng_next ( - keccak_sponge_t sponge, + keccak_prng_t prng, uint8_t * __restrict__ out, size_t len ) API_VIS; @@ -250,7 +254,7 @@ void spongerng_next ( * @param [in] len The length of the initial data. */ void spongerng_stir ( - keccak_sponge_t sponge, + keccak_prng_t prng, const uint8_t * __restrict__ in, size_t len ) NONNULL2 API_VIS; @@ -260,161 +264,260 @@ extern const struct kparams_s STROBE_256 API_VIS; extern const struct kparams_s STROBE_KEYED_128 API_VIS; extern const struct kparams_s STROBE_KEYED_256 API_VIS; -#define STROBE_MAX_AUTH_BYTES 255 +typedef enum { + STROBE_MODE_ABSORB = 0, + STROBE_MODE_DUPLEX = 1, + STROBE_MODE_ABSORB_R = 2, + STROBE_MODE_DUPLEX_R = 3, + /* FIXME: no bits allocated in .py version */ + STROBE_MODE_PLAINTEXT = 4, + STROBE_MODE_SQUEEZE = 5, + STROBE_MODE_FORGET = 6, + STROBE_MODE_SQUEEZE_R = 7 +} strobe_mode_t; + +static const uint32_t + STROBE_FLAG_CLIENT_SENT = 1<<8, + STROBE_FLAG_IMPLICIT = 1<<9, + STROBE_FLAG_FORGET = 1<<12, + STROBE_FLAG_NO_LENGTH = 1<<15, + + /* After 1<<16, flags don't go to the sponge anymore, they just affect the handling */ + STROBE_FLAG_RECV = 1<<16, + STROBE_FLAG_RUN_F = 1<<17, + STROBE_FLAG_MORE = 1<<18, + STROBE_FLAG_LENGTH_64 = 1<<19, + STROBE_FLAG_NONDIR = STROBE_FLAG_IMPLICIT; /* Currently same as implicit */ + +/** Automatic flags implied by the mode */ +/* HACK: SQUEEZE_R is treated as directional because its' MAC */ +#define STROBE_AUTO_FLAGS(_mode) \ + ( (((_mode)&1) ? STROBE_FLAG_RUN_F : 0) \ + | (( ((_mode) & ~2) == STROBE_MODE_ABSORB \ + || (_mode) == STROBE_MODE_SQUEEZE \ + || (_mode) == STROBE_MODE_FORGET \ + ) ? STROBE_FLAG_IMPLICIT|STROBE_FLAG_NONDIR : 0) \ + ) + +#define STROBE_CONTROL_WORD(_name,_id,_mode,_flags) \ + static const uint32_t _name = _id | (_mode<<10) | (_mode<<29) | _flags | STROBE_AUTO_FLAGS(_mode) + +STROBE_CONTROL_WORD(STROBE_CW_INIT, 0x00, STROBE_MODE_ABSORB, 0); + +/* Ciphers */ +STROBE_CONTROL_WORD(STROBE_CW_FIXED_KEY, 0x10, STROBE_MODE_ABSORB, 0); +STROBE_CONTROL_WORD(STROBE_CW_STATIC_PUB, 0x11, STROBE_MODE_PLAINTEXT, 0); +STROBE_CONTROL_WORD(STROBE_CW_DH_EPH, 0x12, STROBE_MODE_PLAINTEXT, 0); +STROBE_CONTROL_WORD(STROBE_CW_DH_KEY, 0x13, STROBE_MODE_ABSORB, 0); +STROBE_CONTROL_WORD(STROBE_CW_PRNG, 0x18, STROBE_MODE_SQUEEZE, STROBE_FLAG_FORGET); +STROBE_CONTROL_WORD(STROBE_CW_SESSION_HASH, 0x19, STROBE_MODE_SQUEEZE, 0); + +/* Reuse for PRNG */ +STROBE_CONTROL_WORD(STROBE_CW_PRNG_INITIAL_SEED, 0x10, STROBE_MODE_ABSORB, STROBE_FLAG_LENGTH_64); +STROBE_CONTROL_WORD(STROBE_CW_PRNG_RESEED, 0x11, STROBE_MODE_ABSORB, STROBE_FLAG_LENGTH_64); +STROBE_CONTROL_WORD(STROBE_CW_PRNG_CPU_SEED, 0x12, STROBE_MODE_ABSORB, 0); +STROBE_CONTROL_WORD(STROBE_CW_PRNG_USER_SEED, 0x13, STROBE_MODE_ABSORB, STROBE_FLAG_LENGTH_64); +STROBE_CONTROL_WORD(STROBE_CW_PRNG_PRNG, 0x14, STROBE_MODE_SQUEEZE, STROBE_FLAG_LENGTH_64 | STROBE_FLAG_FORGET); + +/* Signatures */ +STROBE_CONTROL_WORD(STROBE_CW_SIG_SCHEME, 0x20, STROBE_MODE_ABSORB, 0); +STROBE_CONTROL_WORD(STROBE_CW_SIG_PK, 0x21, STROBE_MODE_ABSORB, 0); +STROBE_CONTROL_WORD(STROBE_CW_SIG_EPH, 0x22, STROBE_MODE_PLAINTEXT, 0); +STROBE_CONTROL_WORD(STROBE_CW_SIG_CHAL, 0x23, STROBE_MODE_SQUEEZE, 0); +STROBE_CONTROL_WORD(STROBE_CW_SIG_RESP, 0x24, STROBE_MODE_DUPLEX, 0); + + +/* Payloads and encrypted data */ + +STROBE_CONTROL_WORD(STROBE_CW_PAYLOAD_PLAINTEXT, 0x30, STROBE_MODE_PLAINTEXT, 0); +STROBE_CONTROL_WORD(STROBE_CW_PAYLOAD_CIPHERTEXT, 0x31, STROBE_MODE_DUPLEX, 0); +STROBE_CONTROL_WORD(STROBE_CW_MAC, 0x32, STROBE_MODE_SQUEEZE_R, STROBE_FLAG_FORGET); +STROBE_CONTROL_WORD(STROBE_CW_AD_EXPLICIT, 0x34, STROBE_MODE_PLAINTEXT, 0); +STROBE_CONTROL_WORD(STROBE_CW_AD_IMPLICIT, 0x35, STROBE_MODE_ABSORB, 0); +STROBE_CONTROL_WORD(STROBE_CW_NONCE_EXPLICIT, 0x36, STROBE_MODE_PLAINTEXT, 0); +STROBE_CONTROL_WORD(STROBE_CW_NONCE_IMPLICIT, 0x37, STROBE_MODE_ABSORB, 0); + +STROBE_CONTROL_WORD(STROBE_CW_STREAMING_PLAINTEXT,0x30, STROBE_MODE_PLAINTEXT, STROBE_FLAG_NO_LENGTH); /* TODO: orly? */ + +/* Change spec, control flow, etc */ +STROBE_CONTROL_WORD(STROBE_CW_COMPRESS, 0x40, STROBE_MODE_ABSORB_R, 0); +/* FIXME: adjust this respec logic */ +STROBE_CONTROL_WORD(STROBE_CW_RESPEC_INFO, 0x41, STROBE_MODE_ABSORB, STROBE_FLAG_RUN_F | STROBE_FLAG_FORGET); +STROBE_CONTROL_WORD(STROBE_CW_RESPEC, 0x42, STROBE_MODE_ABSORB_R, STROBE_FLAG_RUN_F); +STROBE_CONTROL_WORD(STROBE_CW_FORK, 0x43, STROBE_MODE_ABSORB_R, STROBE_FLAG_RUN_F | STROBE_FLAG_FORGET); +/* FIXME: instance can be rolled back to recover other INSTANCEs */ +STROBE_CONTROL_WORD(STROBE_CW_INSTANCE, 0x44, STROBE_MODE_ABSORB_R, STROBE_FLAG_FORGET); +STROBE_CONTROL_WORD(STROBE_CW_ACKNOWLEDGE, 0x45, STROBE_MODE_PLAINTEXT, 0); + +static INLINE UNUSED WARN_UNUSED uint32_t +strobe_cw_recv(uint32_t cw) { + uint32_t recv_toggle = (cw & STROBE_FLAG_NONDIR) ? 0 : STROBE_FLAG_RECV; + if (cw & STROBE_FLAG_IMPLICIT) { + return cw ^ recv_toggle; + } else { + uint32_t modes_2[8] = { + /* Note: most of these really shouldn't happen... */ + STROBE_MODE_ABSORB, + STROBE_MODE_DUPLEX_R, + STROBE_MODE_ABSORB_R, + STROBE_MODE_DUPLEX, + STROBE_MODE_PLAINTEXT, + STROBE_MODE_SQUEEZE, + STROBE_MODE_FORGET, + STROBE_MODE_ABSORB + }; + + return ((cw & ((1<<29)-1)) | (modes_2[cw>>29]<<29)) ^ recv_toggle; + } +} + +#define STROBE_MAX_AUTH_BYTES 32 -/** TODO: check "more" flags? */ /** * @brief Initialize Strobe protocol context. - * @param [out] The initialized strobe object. + * @param [out] strobe The uninitialized strobe object. * @param [in] Strobe parameter descriptor * @param [in] am_client Nonzero if this party * is the client. */ void strobe_init ( - keccak_sponge_t sponge, + keccak_strobe_t strobe, const struct kparams_s *params, + const char *proto, uint8_t am_client ) NONNULL2 API_VIS; - + +/** + * @brief Run a transaction against a STROBE state. + * @param [inout] strobe The initialized STROBE object. + * @param [out] out The output. + * @param [in] in The input. + * @param [in] len The length of the input/output. + * @param [in] cw_flags The control word with flags. + */ +void strobe_transact ( + keccak_strobe_t strobe, + unsigned char *out, + const unsigned char *in, + size_t len, + uint32_t cw_flags +) NONNULL1 API_VIS; + /** * @brief Send plaintext in strobe context. * @param [inout] The initialized strobe object. - * @param [in] Strobe parameter descriptor * @param [in] in The plaintext. * @param [in] len The length of the plaintext. * @param [in] iSent Nonzero if this side of exchange sent the plaintext. - * @param [in] more Nonzero if this is a continuation. - * @retval DECAF_SUCCESS The operation applied successfully. - * @retval DECAF_FAILURE The operation applied, but is dangerous - * because it breaks the usual flow (by doing keyed operations - * before a key is specified, or by specifying more when the previous - * operation didn't match). */ -decaf_bool_t strobe_plaintext ( - keccak_sponge_t sponge, +static INLINE UNUSED void strobe_plaintext ( + keccak_strobe_t strobe, const unsigned char *in, - size_t len, - uint8_t iSent, - uint8_t more -) NONNULL2 API_VIS; + uint16_t len, + uint8_t iSent +) { + strobe_transact( + strobe, NULL, in, len, + iSent ? STROBE_CW_PAYLOAD_PLAINTEXT + : strobe_cw_recv(STROBE_CW_PAYLOAD_PLAINTEXT) + ); +} /** * @brief Report authenticated data in strobe context. * @param [inout] The initialized strobe object. - * @param [in] Strobe parameter descriptor * @param [in] in The plaintext. * @param [in] len The length of the ad. - * @param [in] more Nonzero if this is a continuation. - * @retval DECAF_SUCCESS The operation applied successfully. - * @retval DECAF_FAILURE The operation applied, but is dangerous - * because it breaks the usual flow (by doing keyed operations - * before a key is specified, or by specifying more when the previous - * operation didn't match). */ -decaf_bool_t strobe_ad ( - keccak_sponge_t sponge, +static INLINE UNUSED void strobe_ad ( + keccak_strobe_t strobe, const unsigned char *in, - size_t len, - uint8_t more -) NONNULL2 API_VIS; - + size_t len +) { + strobe_transact( strobe, NULL, in, len, STROBE_CW_AD_EXPLICIT ); +} + /** * @brief Set nonce in strobe context. * @param [inout] The initialized strobe object. - * @param [in] Strobe parameter descriptor * @param [in] in The nonce. * @param [in] len The length of the nonce. - * @param [in] more Nonzero if this is a continuation. - * @retval DECAF_SUCCESS The operation applied successfully. - * @retval DECAF_FAILURE The operation applied, but is dangerous - * because it breaks the usual flow (by doing keyed operations - * before a key is specified, or by specifying more when the previous - * operation didn't match). */ -decaf_bool_t strobe_nonce ( - keccak_sponge_t sponge, +static INLINE UNUSED void strobe_nonce ( + keccak_strobe_t strobe, const unsigned char *in, - size_t len, - uint8_t more -) NONNULL2 API_VIS; + uint16_t len +) { + strobe_transact( strobe, NULL, in, len, STROBE_CW_NONCE_EXPLICIT ); +} /** * @brief Set key in strobe context. * @param [inout] The initialized strobe object. - * @param [in] Strobe parameter descriptor * @param [in] in The key. * @param [in] len The length of the key. - * @param [in] more Nonzero if this is a continuation. */ -decaf_bool_t strobe_key ( - keccak_sponge_t sponge, +static INLINE UNUSED void +strobe_key ( + keccak_strobe_t strobe, const unsigned char *in, - size_t len, - uint8_t more -) NONNULL2 API_VIS; + uint16_t len +) { + strobe_transact( strobe, NULL, in, len, STROBE_CW_DH_KEY ); /* FIXME: what about other kinds of keys? */ +} + /** * @brief Produce an authenticator. - * @param [inout] strobe The Strobe protocol context + * @param [inout] strobe The Strobe protocol context. * @param [out] out The authenticator - * @param len The length, which must be no more than - * @todo 32? - * @retval DECAF_SUCCESS The operation applied successfully. - * @retval DECAF_FAILURE The operation applied, but is dangerous - * because it breaks the usual flow (by doing keyed operations - * before a key is specified, or by specifying more when the previous - * operation didn't match). + * @param len The length. */ -decaf_bool_t strobe_produce_auth ( - keccak_sponge_t sponge, - unsigned char *out, - size_t len -) NONNULL2 API_VIS; +static INLINE UNUSED void +strobe_produce_auth ( + keccak_strobe_t strobe, + unsigned char *out, + uint16_t len +) { + strobe_transact( strobe, out, NULL, len, STROBE_CW_MAC ); +} /** * @brief Encrypt bytes from in to out. - * @warning Doesn't produce an auth tag (TODO?) + * @warning Doesn't produce an auth tag. * @param [inout] strobe The Strobe protocol context. * @param [in] in The plaintext. * @param [out] out The ciphertext. * @param [in] len The length of plaintext and ciphertext. - * @param [in] more This is a continuation. - * @retval DECAF_SUCCESS The operation applied successfully. - * @retval DECAF_FAILURE The operation applied, but is dangerous - * because it breaks the usual flow (by doing keyed operations - * before a key is specified, or by specifying more when the previous - * operation didn't match). */ -decaf_bool_t strobe_encrypt ( - keccak_sponge_t sponge, +static INLINE UNUSED void +strobe_encrypt ( + keccak_strobe_t strobe, unsigned char *out, const unsigned char *in, - size_t len, - uint8_t more -) NONNULL3 API_VIS; + uint16_t len +) { + strobe_transact(strobe, out, in, len, STROBE_CW_PAYLOAD_CIPHERTEXT); +} /** * @brief Decrypt bytes from in to out. - * @warning Doesn't check an auth tag (TODO?) + * @warning Doesn't check an auth tag. * @param [inout] strobe The Strobe protocol context. * @param [in] in The ciphertext. * @param [out] out The plaintext. * @param [in] len The length of plaintext and ciphertext. - * @param [in] more This is a continuation. - * @retval DECAF_SUCCESS The operation applied successfully. - * @retval DECAF_FAILURE The operation applied, but is dangerous - * because it breaks the usual flow (by doing keyed operations - * before a key is specified, or by specifying more when the previous - * operation didn't match). */ -decaf_bool_t strobe_decrypt ( - keccak_sponge_t sponge, +static INLINE UNUSED void +strobe_decrypt ( + keccak_strobe_t strobe, unsigned char *out, const unsigned char *in, - size_t len, - uint8_t more -) NONNULL3 API_VIS; + uint16_t len +) { + strobe_transact(strobe, out, in, len, strobe_cw_recv(STROBE_CW_PAYLOAD_CIPHERTEXT)); +} /** * @brief Produce a session-bound pseudorandom value. @@ -423,24 +526,17 @@ decaf_bool_t strobe_decrypt ( * refreshing forward secrecy! It's to replace things * like TCP session hash. * - * @todo Figure out how to treat this wrt anti-rollback. - * * @param [inout] strobe The Strobe protocol context - * @param [out] out The authenticator + * @param [out] out The output random data. * @param len The length. - * - * @retval DECAF_SUCCESS The operation applied successfully. - * @retval DECAF_FAILURE The operation applied, but is dangerous - * because it breaks the usual flow (by doing keyed operations - * before a key is specified, or by specifying more when the previous - * operation didn't match). - */ -decaf_bool_t strobe_prng ( - keccak_sponge_t sponge, - unsigned char *out, - size_t len, - uint8_t more -) NONNULL2 API_VIS; + */ +static inline void strobe_prng ( + keccak_strobe_t strobe, + unsigned char *out, + uint16_t len +) { + strobe_transact( strobe, out, NULL, len, STROBE_CW_PRNG ); +} /** * @brief Verify an authenticator. @@ -452,10 +548,10 @@ decaf_bool_t strobe_prng ( * @retval DECAF_FAILURE The operation failed because of a * bad validator (or because you aren't keyed) */ -decaf_bool_t strobe_verify_auth ( - keccak_sponge_t sponge, +decaf_error_t strobe_verify_auth ( + keccak_strobe_t strobe, const unsigned char *in, - size_t len + uint16_t len ) WARN_UNUSED NONNULL2 API_VIS; /** @@ -464,14 +560,13 @@ decaf_bool_t strobe_verify_auth ( * @param [in] Strobe parameter descriptor * @param [in] am_client Nonzero if this party * is the client. - * @retval DECAF_SUCCESS The operation applied successfully. - * @retval DECAF_FAILURE The operation failed because of a - * bad validator (or because you aren't keyed) */ -decaf_bool_t strobe_respec ( - keccak_sponge_t sponge, +void strobe_respec ( + keccak_strobe_t strobe, const struct kparams_s *params ) NONNULL2 API_VIS; + +#define strobe_destroy sponge_destroy #ifdef __cplusplus } /* extern "C" */ @@ -483,5 +578,7 @@ decaf_bool_t strobe_respec ( #undef NONNULL13 #undef NONNULL2 #undef NONNULL3 +#undef INLINE +#undef UNUSED #endif /* __SHAKE_H__ */ diff --git a/src/public_include/decaf/shake.hxx b/src/public_include/decaf/shake.hxx index e03ec8e..77151aa 100644 --- a/src/public_include/decaf/shake.hxx +++ b/src/public_include/decaf/shake.hxx @@ -191,108 +191,104 @@ private: class Strobe : private KeccakSponge { public: /* TODO: pull out parameters */ + static const uint16_t DEFAULT_AUTH_SIZE = 16; /** Am I a server or a client? */ enum client_or_server { SERVER, CLIENT }; inline Strobe ( + const char *description, client_or_server whoami, const kparams_s ¶ms = STROBE_256 ) NOEXCEPT : KeccakSponge(NOINIT()) { - strobe_init(sp, ¶ms, whoami == CLIENT); + strobe_init(sp, ¶ms, description, whoami == CLIENT); + keyed = false; } + /* TODO: add a key type keyword */ + /* TODO: add a "keyed" tracker */ inline void key ( - const Block &data, bool more = false + const Block &data ) throw(ProtocolException) { - if (!strobe_key(sp, data.data(), data.size(), more)) throw ProtocolException(); + strobe_key(sp, data.data(), data.size()); + keyed = true; } template inline void key ( - const Serializable &data, bool more = false + const Serializable &data ) throw(ProtocolException) { - key(data.serialize(), more); + key(data.serialize()); } - inline void nonce(const Block &data, bool more = false) throw(ProtocolException) { - if (!strobe_nonce(sp, data.data(), data.size(), more)) throw ProtocolException(); + inline void nonce(const Block &data) NOEXCEPT { + strobe_nonce(sp, data.data(), data.size()); } - inline void send_plaintext(const Block &data, bool more = false) throw(ProtocolException) { - if (!strobe_plaintext(sp, data.data(), data.size(), true, more)) - throw(ProtocolException()); + /* TODO: this doesn't actually send ... maybe think about gluing to socket code? */ + inline void send_plaintext(const Block &data) NOEXCEPT { + strobe_plaintext(sp, data.data(), data.size(), true); } - template inline void send_plaintext(const Serializable &data, bool more = false) throw(ProtocolException) { - send_plaintext(data.serialize(), more); + template inline void send_plaintext(const Serializable &data) NOEXCEPT { + send_plaintext(data.serialize()); } - inline void recv_plaintext(const Block &data, bool more = false - ) throw(ProtocolException) { - if (!strobe_plaintext(sp, data.data(), data.size(), false, more)) - throw(ProtocolException()); + inline void recv_plaintext(const Block &data) NOEXCEPT { + strobe_plaintext(sp, data.data(), data.size(), false); } - template inline void recv_plaintext(const Serializable &data, bool more = false) throw(ProtocolException) { - recv_plaintext(data.serialize(), more); + template inline void recv_plaintext(const Serializable &data) NOEXCEPT { + recv_plaintext(data.serialize()); } - inline void ad(const Block &data, bool more = false) throw(ProtocolException) { - if (!strobe_ad(sp, data.data(), data.size(), more)) - throw(ProtocolException()); + inline void ad(const Block &data) { + strobe_ad(sp, data.data(), data.size()); } - template inline void ad(const Serializable &data, bool more = false) throw(ProtocolException) { - ad(data.serialize(), more); + template inline void ad(const Serializable &data) NOEXCEPT { + ad(data.serialize()); } - inline void encrypt_no_auth( - Buffer out, const Block &data, bool more = false - ) throw(LengthException,ProtocolException) { + inline void encrypt_no_auth(Buffer out, const Block &data) throw(LengthException,ProtocolException) { + if (!keyed) throw ProtocolException(); if (out.size() != data.size()) throw LengthException(); - if (!strobe_encrypt(sp, out.data(), data.data(), data.size(), more)) throw(ProtocolException()); + strobe_encrypt(sp, out.data(), data.data(), data.size()); } - inline SecureBuffer encrypt_no_auth(const Block &data, bool more = false - ) throw(ProtocolException) { - SecureBuffer out(data.size()); encrypt_no_auth(out, data, more); return out; + inline SecureBuffer encrypt_no_auth(const Block &data) throw(ProtocolException) { + SecureBuffer out(data.size()); encrypt_no_auth(out, data); return out; } - template inline SecureBuffer encrypt_no_auth(const Serializable &data, bool more = false - ) throw(ProtocolException) { - return encrypt_no_auth(data.serialize(), more); + template inline SecureBuffer encrypt_no_auth(const Serializable &data) throw(ProtocolException) { + return encrypt_no_auth(data.serialize()); } - inline void decrypt_no_auth( - Buffer out, const Block &data, bool more = false - ) throw(LengthException,ProtocolException) { + inline void decrypt_no_auth(Buffer out, const Block &data) throw(LengthException,ProtocolException) { + if (!keyed) throw ProtocolException(); if (out.size() != data.size()) throw LengthException(); - if (!strobe_decrypt(sp, out.data(), data.data(), data.size(), more)) throw ProtocolException(); + strobe_decrypt(sp, out.data(), data.data(), data.size()); } - inline SecureBuffer decrypt_no_auth(const Block &data, bool more = false - ) throw(ProtocolException) { - SecureBuffer out(data.size()); decrypt_no_auth(out, data, more); return out; + inline SecureBuffer decrypt_no_auth(const Block &data) throw(ProtocolException) { + SecureBuffer out(data.size()); decrypt_no_auth(out, data); return out; } - template inline SecureBuffer decrypt_no_auth(const Serializable &data, bool more = false - ) throw(ProtocolException) { - return decrypt_no_auth(data.serialize(),more); + template inline SecureBuffer decrypt_no_auth(const Serializable &data) throw(ProtocolException) { + return decrypt_no_auth(data.serialize()); } inline void produce_auth(Buffer out) throw(LengthException,ProtocolException) { + if (!keyed) throw ProtocolException(); /* TODO: maybe. Could use for eg sanity or dos protection */ if (out.size() > STROBE_MAX_AUTH_BYTES) throw LengthException(); - if (!strobe_produce_auth(sp, out.data(), out.size())) throw ProtocolException(); + strobe_produce_auth(sp, out.data(), out.size()); } - inline SecureBuffer produce_auth( - uint8_t bytes = 8 - ) throw(ProtocolException) { + inline SecureBuffer produce_auth(uint8_t bytes = DEFAULT_AUTH_SIZE) throw(ProtocolException) { SecureBuffer out(bytes); produce_auth(out); return out; } inline void encrypt( - Buffer out, const Block &data, uint8_t auth = 8 + Buffer out, const Block &data, uint8_t auth = DEFAULT_AUTH_SIZE ) throw(LengthException,ProtocolException) { if (out.size() < data.size() || out.size() != data.size() + auth) throw LengthException(); encrypt_no_auth(out.slice(0,data.size()), data); @@ -300,19 +296,19 @@ public: } inline SecureBuffer encrypt ( - const Block &data, uint8_t auth = 8 + const Block &data, uint8_t auth = DEFAULT_AUTH_SIZE ) throw(LengthException,ProtocolException,std::bad_alloc ){ SecureBuffer out(data.size() + auth); encrypt(out, data, auth); return out; } template inline SecureBuffer encrypt ( - const Serializable &data, uint8_t auth = 8 + const Serializable &data, uint8_t auth = DEFAULT_AUTH_SIZE ) throw(LengthException,ProtocolException,std::bad_alloc ){ return encrypt(data.serialize(), auth); } inline void decrypt ( - Buffer out, const Block &data, uint8_t bytes = 8 + Buffer out, const Block &data, uint8_t bytes = DEFAULT_AUTH_SIZE ) throw(LengthException, CryptoException, ProtocolException) { if (out.size() > data.size() || out.size() != data.size() - bytes) throw LengthException(); decrypt_no_auth(out, data.slice(0,out.size())); @@ -320,13 +316,13 @@ public: } template inline SecureBuffer decrypt ( - const Serializable &data, uint8_t auth = 8 + const Serializable &data, uint8_t auth = DEFAULT_AUTH_SIZE ) throw(LengthException,ProtocolException,CryptoException, std::bad_alloc ){ return decrypt(data.serialize(), auth); } inline SecureBuffer decrypt ( - const Block &data, uint8_t bytes = 8 + const Block &data, uint8_t bytes = DEFAULT_AUTH_SIZE ) throw(LengthException,CryptoException,ProtocolException,std::bad_alloc) { if (data.size() < bytes) throw LengthException(); SecureBuffer out(data.size() - bytes); decrypt(out, data, bytes); return out; @@ -334,20 +330,24 @@ public: inline void verify_auth(const Block &auth) throw(LengthException,CryptoException) { if (auth.size() == 0 || auth.size() > STROBE_MAX_AUTH_BYTES) throw LengthException(); - if (!strobe_verify_auth(sp, auth.data(), auth.size())) throw CryptoException(); + if (strobe_verify_auth(sp, auth.data(), auth.size()) != DECAF_SUCCESS) throw CryptoException(); } - inline void prng(Buffer out, bool more = false) NOEXCEPT { - (void)strobe_prng(sp, out.data(), out.size(), more); + inline void prng(Buffer out) NOEXCEPT { + (void)strobe_prng(sp, out.data(), out.size()); } - inline SecureBuffer prng(size_t bytes, bool more = false) { - SecureBuffer out(bytes); prng(out, more); return out; + inline SecureBuffer prng(size_t bytes) { + SecureBuffer out(bytes); prng(out); return out; } inline void respec(const kparams_s ¶ms) throw(ProtocolException) { - if (!strobe_respec(sp, ¶ms)) throw(ProtocolException()); + if (!keyed) throw(ProtocolException()); + strobe_respec(sp, ¶ms); } + +private: + bool keyed; }; } /* namespace decaf */ diff --git a/src/shake.c b/src/shake.c index bb2af87..73e2134 100644 --- a/src/shake.c +++ b/src/shake.c @@ -71,12 +71,6 @@ typedef struct keccak_sponge_s { #define FLAG_ABSORBING 'A' #define FLAG_SQUEEZING 'Z' -#define FLAG_RNG_SQU 'R' -#define FLAG_DET_SQU 'D' -#define FLAG_RNG_ABS 'r' -#define FLAG_DET_ABS 'd' -#define FLAG_RNG_UNI 'u' -#define FLAG_DET_UNI 'g' /** Constants. **/ static const uint8_t pi[24] = { @@ -119,8 +113,9 @@ keccakf(kdomain_t state, uint8_t startRound) { for (i=0; i<25; i++) a[i] = le64toh(a[i]); for (i = startRound; i < 24; i++) { - FOR51(x, b[x] = 0; FOR55(y, b[x] ^= a[x + y];)) - FOR51(x, FOR55(y, + FOR51(x, b[x] = 0; ) + FOR55(y, FOR51(x, b[x] ^= a[x + y]; )) + FOR55(y, FOR51(x, a[y + x] ^= b[(x + 4) % 5] ^ rol(b[(x + 1) % 5], 1); )) // Rho and pi @@ -285,7 +280,7 @@ static void get_cpu_entropy(uint8_t *entropy, size_t len) { } *eo ^= out; } - } else if (len>8) { + } else if (len>=8) { uint64_t out; __asm__ __volatile__ ("rdtsc" : "=A"(out)); *(uint64_t*) entropy ^= out; @@ -297,51 +292,27 @@ static void get_cpu_entropy(uint8_t *entropy, size_t len) { #endif } +static const uint16_t SPONGERNG_MAX_BLOCK_SIZE = 1<<12; /* TODO: standardize and freeze */ +static const uint16_t SPONGERNG_FILE_BLOCK_SIZE = 1<<12; /* TODO: standardize and freeze */ +static const char *SPONGERNG_NAME = "spongerng"; /* TODO: canonicalize name */ + void spongerng_next ( keccak_sponge_t sponge, uint8_t * __restrict__ out, size_t len ) { - assert(sponge->params->position < sponge->params->rate); - assert(sponge->params->rate < sizeof(sponge->state)); - - switch(sponge->params->flags) { - case FLAG_DET_SQU: case FLAG_RNG_SQU: break; - case FLAG_DET_ABS: case FLAG_RNG_ABS: - { - uint8_t* state = sponge->state->b; - state[sponge->params->position] ^= sponge->params->pad; - state[sponge->params->rate - 1] ^= sponge->params->ratePad; - dokeccak(sponge); - sponge->params->flags = (sponge->params->flags == FLAG_DET_ABS) ? FLAG_DET_SQU : FLAG_RNG_SQU; - break; - } - default: assert(0); - }; - - while (len) { - size_t cando = sponge->params->rate - sponge->params->position; - uint8_t* state = &sponge->state->b[sponge->params->position]; - if (cando > len) { - memcpy(out, state, len); - memset(state, 0, len); - sponge->params->position += len; - return; - } else { - memcpy(out, state, cando); - memset(state, 0, cando); - if (sponge->params->flags == FLAG_RNG_SQU) - get_cpu_entropy(sponge->state->b, 32); - dokeccak(sponge); - len -= cando; - out += cando; - } + if (sponge->params->client) { + /* nondet */ + uint8_t cpu_entropy[32]; + get_cpu_entropy(cpu_entropy, sizeof(cpu_entropy)); + strobe_transact(sponge,NULL,cpu_entropy,sizeof(cpu_entropy),STROBE_CW_PRNG_CPU_SEED); } - - /* Anti-rollback */ - if (sponge->params->position < 32) { - memset(&sponge->state->b, 0, 32); - sponge->params->position = 32; + + while (len) { + uint16_t cando = (len > SPONGERNG_MAX_BLOCK_SIZE) ? SPONGERNG_MAX_BLOCK_SIZE : len; + strobe_transact(sponge,out,NULL,cando,STROBE_CW_PRNG); + out += cando; + len -= cando; } } @@ -350,41 +321,16 @@ void spongerng_stir ( const uint8_t * __restrict__ in, size_t len ) { - assert(sponge->params->position < sponge->params->rate); - assert(sponge->params->rate < sizeof(sponge->state)); - - switch(sponge->params->flags) { - case FLAG_RNG_SQU: - get_cpu_entropy(sponge->state->b, 32); - /* fall through */ - case FLAG_DET_SQU: - sponge->params->flags = (sponge->params->flags == FLAG_DET_SQU) ? FLAG_DET_ABS : FLAG_RNG_ABS; - dokeccak(sponge); - break; - case FLAG_DET_ABS: case FLAG_RNG_ABS: break; - case FLAG_DET_UNI: case FLAG_RNG_UNI: break; - default: assert(0); - }; - while (len) { - size_t i; - size_t cando = sponge->params->rate - sponge->params->position; - uint8_t* state = &sponge->state->b[sponge->params->position]; - if (cando > len) { - for (i = 0; i < len; i += 1) state[i] ^= in[i]; - sponge->params->position += len; - return; - } else { - for (i = 0; i < cando; i += 1) state[i] ^= in[i]; - dokeccak(sponge); - len -= cando; - in += cando; - } + uint16_t cando = (len > SPONGERNG_MAX_BLOCK_SIZE) ? SPONGERNG_MAX_BLOCK_SIZE : len; + strobe_transact(sponge,NULL,in,cando,STROBE_CW_PRNG_USER_SEED); + in += cando; + len -= cando; } } static const struct kparams_s spongerng_params = { - 0, FLAG_RNG_UNI, 200-256/4, 0, 0x06, 0x80, 0xFF, 0 + 0, 0, 200-256/4, 0, 0x06, 0x80, 0xFF, 0 }; void spongerng_init_from_buffer ( @@ -393,8 +339,7 @@ void spongerng_init_from_buffer ( size_t len, int deterministic ) { - sponge_init(sponge, &spongerng_params); - sponge->params->flags = deterministic ? FLAG_DET_ABS : FLAG_RNG_ABS; + strobe_init(sponge, &spongerng_params, SPONGERNG_NAME, !deterministic); spongerng_stir(sponge, in, len); } @@ -404,14 +349,13 @@ int spongerng_init_from_file ( size_t len, int deterministic ) { - sponge_init(sponge, &spongerng_params); - sponge->params->flags = deterministic ? FLAG_DET_UNI : FLAG_RNG_UNI; + strobe_init(sponge, &spongerng_params, SPONGERNG_NAME, !deterministic); if (!len) return -2; int fd = open(file, O_RDONLY); if (fd < 0) return errno ? errno : -1; - uint8_t buffer[128]; + uint8_t buffer[SPONGERNG_FILE_BLOCK_SIZE]; while (len) { ssize_t red = read(fd, buffer, (len > sizeof(buffer)) ? sizeof(buffer) : len); if (red <= 0) { @@ -422,8 +366,7 @@ int spongerng_init_from_file ( len -= red; }; close(fd); - - sponge->params->flags = deterministic ? FLAG_DET_ABS : FLAG_RNG_ABS; + return 0; } @@ -442,283 +385,241 @@ const struct kparams_s STROBE_KEYED_128 = { 0, 0, 200-128/4, 12, 0, 0, 0, 0 }; void strobe_init( keccak_sponge_t sponge, const struct kparams_s *params, + const char *proto, uint8_t am_client ) { sponge_init(sponge,params); + + const char *a_string = "STROBE full v0.2"; + unsigned len = strlen(a_string); + memcpy ( + &sponge->state->b[sizeof(sponge->state)-len], + a_string, + len + ); + + strobe_transact(sponge, NULL, (const unsigned char *)proto, strlen(proto), STROBE_CW_INIT); + + sponge->state->b[sponge->params->rate+1] = 1; sponge->params->client = !!am_client; } +static const uint8_t EXCEEDED_RATE_PAD = 0x2; +static __inline__ uint8_t CONTROL_WORD_PAD(int cw_size) { + assert(cw_size >= 0 && cw_size <= 31); + return 0xC0 | cw_size; +} + static void strobe_duplex ( keccak_sponge_t sponge, unsigned char *out, const unsigned char *in, - size_t len + size_t len, + mode_t mode ) { - unsigned j; - while (len) { - assert(sponge->params->rate >= sponge->params->position); - size_t cando = sponge->params->rate - sponge->params->position; - uint8_t* state = &sponge->state->b[sponge->params->position]; - if (cando >= len) { - for (j=0; in && jparams->position += len; - return; - } else { - if (in) { - for (j=0; jparams->rate, p = sponge->params->position; + uint8_t* state = &sponge->state->b[0]; + + /* sanity */ + assert(r < sizeof(sponge->state) && r >= p); + switch (mode) { + case STROBE_MODE_PLAINTEXT: + assert(in || len==0); + break; + case STROBE_MODE_ABSORB: + case STROBE_MODE_ABSORB_R: + assert((in||len==0) && !out); + break; + case STROBE_MODE_DUPLEX: + case STROBE_MODE_DUPLEX_R: + assert((in && out) || len==0); + break; + case STROBE_MODE_SQUEEZE: + case STROBE_MODE_SQUEEZE_R: + assert((out || len==0) && !in); + break; + case STROBE_MODE_FORGET: + assert(!in && !out); + break; + default: + assert(0); + } + + while(1) { + unsigned int cando = r - p; + unsigned int last = (cando >= len); + if (last) { + cando = len; + } + + switch (mode) { + case STROBE_MODE_PLAINTEXT: + for (j=0; jparams->rate < sizeof(sponge->state)); - assert(sponge->params->position <= sponge->params->rate); - if (sizeof(sponge->state) - sponge->params->rate < len) { - /** Tiny case */ - unsigned char tmp[len]; - strobe_duplex(sponge,tmp,NULL,len); - if (sponge->params->position) dokeccak(sponge); - strobe_duplex(sponge,tmp,NULL,len); - decaf_bzero(tmp,len); - } else { - if (sponge->params->rate < len + sponge->params->position) { - dokeccak(sponge); - } - memset(&sponge->state->b[sponge->params->position], 0, len); - sponge->params->position += len; - } -} - -static void strobe_unduplex ( - keccak_sponge_t sponge, - unsigned char *out, - const unsigned char *in, - size_t len -) { - unsigned j; - while (len) { - assert(sponge->params->rate >= sponge->params->position); - size_t cando = sponge->params->rate - sponge->params->position; - uint8_t* state = &sponge->state->b[sponge->params->position]; - if (cando >= len) { - for (j=0; in && jparams->position += len; + in += cando; + out += cando; + break; + + default: + assert(0); + }; + + if (last) { + sponge->params->position = p+len; return; } else { - for (j=0; in && jstate, sponge->params->startRound); len -= cando; + p = 0; } } } -enum { KEY=1, NONCE, AD, PLAINTEXT, CIPHERTEXT, TAGFORGET, DIVERSIFIER, PRNG, FORK, JOIN, RESPEC }; - -#define CLIENT_TO_SERVER 0 -#define SERVER_TO_CLIENT 0x80 - -static decaf_bool_t strobe_control_word ( - keccak_sponge_t sponge, - const unsigned char *control, - size_t len, - uint8_t more -) { - assert(sponge->params->rate < sizeof(sponge->state)); - decaf_bool_t ret = DECAF_SUCCESS; - if (!more) { - strobe_duplex(sponge,NULL,control,len); - sponge->state->b[sponge->params->position] ^= 0x1; - sponge->state->b[sponge->params->rate] ^= 0x2; - dokeccak(sponge); - sponge->params->flags = control[len-1]; - } else if (sponge->params->flags && sponge->params->flags != control[len-1]) { - ret = DECAF_FAILURE; - } - sponge->params->flags = control[len-1]; - return ret; +static inline mode_t get_mode ( uint32_t cw_flags ) { + return (mode_t)((cw_flags >> 29) & 7); } -decaf_bool_t strobe_encrypt ( - keccak_sponge_t sponge, - unsigned char *out, - const unsigned char *in, - size_t len, - uint8_t more -) { - unsigned char control[] = { CIPHERTEXT | - (sponge->params->client ? CLIENT_TO_SERVER : SERVER_TO_CLIENT) - }; - decaf_bool_t ret = strobe_control_word(sponge, control, sizeof(control), more); - strobe_duplex(sponge, out, in, len); - if (!sponge->params->pad/*keyed*/) ret = DECAF_FAILURE; - return ret; -} +static const int STROBE_FORGET_BYTES = 32; -decaf_bool_t strobe_decrypt ( - keccak_sponge_t sponge, - unsigned char *out, - const unsigned char *in, - size_t len, - uint8_t more -) { - unsigned char control[] = { CIPHERTEXT | - (sponge->params->client ? SERVER_TO_CLIENT : CLIENT_TO_SERVER) - }; - decaf_bool_t ret = strobe_control_word(sponge, control, sizeof(control), more); - strobe_unduplex(sponge, out, in, len); - if (!sponge->params->pad/*keyed*/) ret = DECAF_FAILURE; - return ret; -} +static const uint8_t FLAG_NOPARSE = 1; -decaf_bool_t strobe_plaintext ( - keccak_sponge_t sponge, - const unsigned char *in, - size_t len, - uint8_t iSent, - uint8_t more -) { - unsigned char control[] = { PLAINTEXT | - ((sponge->params->client == !!iSent) ? CLIENT_TO_SERVER : SERVER_TO_CLIENT) - }; - decaf_bool_t ret = strobe_control_word(sponge, control, sizeof(control), more); - strobe_duplex(sponge, NULL, in, len); - return ret; -} - -decaf_bool_t strobe_key ( - keccak_sponge_t sponge, - const unsigned char *in, - size_t len, - uint8_t more -) { - unsigned char control[] = { KEY }; - decaf_bool_t ret = strobe_control_word(sponge, control, sizeof(control), more); - strobe_duplex(sponge, NULL, in, len); - sponge->params->pad/*=keyed*/ = 1; - return ret; -} - -decaf_bool_t strobe_nonce ( - keccak_sponge_t sponge, - const unsigned char *in, - size_t len, - uint8_t more -) { - unsigned char control[] = { NONCE }; - decaf_bool_t ret = strobe_control_word(sponge, control, sizeof(control), more); - strobe_duplex(sponge, NULL, in, len); - return ret; -} - -decaf_bool_t strobe_ad ( - keccak_sponge_t sponge, - const unsigned char *in, - size_t len, - uint8_t more -) { - unsigned char control[] = { AD }; - decaf_bool_t ret = strobe_control_word(sponge, control, sizeof(control), more); - strobe_duplex(sponge, NULL, in, len); - return ret; -} - -#define STROBE_FORGET_BYTES 32 - -decaf_bool_t strobe_produce_auth ( - keccak_sponge_t sponge, - unsigned char *out, - size_t len -) { - unsigned char control[] = { - (unsigned char)len, - (unsigned char)STROBE_FORGET_BYTES, - TAGFORGET | (sponge->params->client ? CLIENT_TO_SERVER : SERVER_TO_CLIENT) - }; - decaf_bool_t ret = strobe_control_word(sponge, control, sizeof(control), 0); - strobe_duplex(sponge, out, NULL, len); - strobe_forget(sponge, STROBE_FORGET_BYTES); - if (!sponge->params->pad/*keyed*/) ret = DECAF_FAILURE; - return ret; -} - -decaf_bool_t strobe_prng ( +void strobe_transact ( keccak_sponge_t sponge, unsigned char *out, + const unsigned char *in, size_t len, - uint8_t more + uint32_t cw_flags ) { - unsigned char control[9] = { PRNG }; - int i; - for (i=0; i<8; i++) control[i+1] = len>>(8*i); + if ( (cw_flags & STROBE_FLAG_NONDIR) == 0 + /* extraneous nots to change ints to bools :-/ */ + && !(cw_flags & STROBE_FLAG_RECV) != !(sponge->params->client) ) { + cw_flags ^= STROBE_FLAG_CLIENT_SENT; + } + + uint64_t my_len = len, len_cw = (cw_flags & STROBE_FLAG_LENGTH_64) ? 10 : 4; + if (cw_flags & STROBE_FLAG_NO_LENGTH) { + my_len = 0; + } else { + assert(my_len < 1<<16); + } - decaf_bool_t ret = strobe_control_word(sponge, control, sizeof(control), more); - strobe_duplex(sponge, out, NULL, len); - // TODO: forget as follows? this breaks "more" - // unsigned char control2[] = { 0, STROBE_FORGET_BYTES, TAGFORGET }; - // ret &= strobe_control_word(sponge, control2, sizeof(control2)); - // strobe_forget(sponge, STROBE_FORGET_BYTES); - if (!sponge->params->pad/*keyed*/) ret = DECAF_FAILURE; - return ret; + if (cw_flags & STROBE_FLAG_MORE) { + assert(cw_flags & STROBE_FLAG_NO_LENGTH); /* FUTURE */ + } else { + uint8_t cwb[10] = { + cw_flags, + cw_flags>>8, + my_len, + my_len>>8, + my_len>>16, + my_len>>24, + my_len>>32, + my_len>>40, + my_len>>48, + my_len>>56 + }; + strobe_duplex(sponge, NULL, cwb, len_cw, STROBE_MODE_ABSORB_R); + if ((cw_flags & STROBE_FLAG_RUN_F) || (sponge->params->flags & FLAG_NOPARSE)) { + sponge->state->b[sponge->params->position] ^= CONTROL_WORD_PAD(len_cw); + dokeccak(sponge); + } + + sponge->params->flags &= ~FLAG_NOPARSE; + if (cw_flags & STROBE_FLAG_NO_LENGTH) { + sponge->params->flags |= FLAG_NOPARSE; + } + } + + strobe_duplex(sponge, out, in, len, get_mode(cw_flags)); + if (cw_flags & STROBE_FLAG_FORGET) { + + uint32_t len = sponge->params->rate - sponge->params->position; + if (len < STROBE_FORGET_BYTES + len_cw) len += sponge->params->rate; + len -= len_cw; + + if (cw_flags & STROBE_FLAG_NO_LENGTH) len = 2*STROBE_FORGET_BYTES; + + strobe_duplex( + sponge, NULL, NULL, len, + STROBE_MODE_FORGET + ); + } } -decaf_bool_t strobe_verify_auth ( +decaf_error_t strobe_verify_auth ( keccak_sponge_t sponge, const unsigned char *in, - size_t len + uint16_t len ) { - unsigned char control[] = { - (unsigned char)len, - (unsigned char)STROBE_FORGET_BYTES, - TAGFORGET | (sponge->params->client ? SERVER_TO_CLIENT : CLIENT_TO_SERVER) - }; - decaf_bool_t ret = strobe_control_word(sponge, control, sizeof(control), 0); - unsigned char zero[len]; - strobe_unduplex(sponge, zero, in, len); - strobe_forget(sponge, STROBE_FORGET_BYTES); + if (len > sponge->params->rate) return DECAF_FAILURE; + strobe_transact(sponge, NULL, in, len, strobe_cw_recv(STROBE_CW_MAC)); - /* Check for 0 */ - decaf_bool_t chain=0; - unsigned i; + int32_t residue = 0; + int i; for (i=0; istate->b[i]; } - ret &= ((decaf_dword_t)chain-1)>>(8*sizeof(decaf_word_t)); - if (!sponge->params->pad/*keyed*/) ret = DECAF_FAILURE; - return ret; + + return decaf_succeed_if((residue-1)>>8); } -decaf_bool_t strobe_respec ( +void strobe_respec ( keccak_sponge_t sponge, const struct kparams_s *params ) { - unsigned char control[] = { params->rate, params->startRound, RESPEC }; - decaf_bool_t ret = strobe_control_word(sponge, control, sizeof(control), 0); - if (!sponge->params->pad/*keyed*/) ret = DECAF_FAILURE; + uint8_t in[] = { params->rate, params->startRound }; /* TODO: nail down */ + strobe_transact( sponge, NULL, in, sizeof(in), STROBE_CW_RESPEC_INFO ); + strobe_transact( sponge, NULL, NULL, 0, STROBE_CW_RESPEC ); + assert(sponge->params->position == 0); sponge->params->rate = params->rate; sponge->params->startRound = params->startRound; - return ret; } /* FUTURE: Keyak instances, etc */ diff --git a/test/bench_decaf.cxx b/test/bench_decaf.cxx index 43fb08e..e27cee2 100644 --- a/test/bench_decaf.cxx +++ b/test/bench_decaf.cxx @@ -157,7 +157,7 @@ static void tdh ( * hash gx and gy into the session secret (only into the MAC * and AD) because of IPR concerns. */ - Strobe client(Strobe::CLIENT), server(Strobe::SERVER); + Strobe client("example::tripleDH",Strobe::CLIENT), server("example::tripleDH",Strobe::SERVER); Scalar xe(clientRng); SecureBuffer gxe((Precomputed::base() * xe).serialize()); @@ -198,7 +198,7 @@ static void fhmqv ( Scalar y, const Block &gy ) { /* Don't use this, it's probably patented */ - Strobe client(Strobe::CLIENT), server(Strobe::SERVER); + Strobe client("example::fhmqv",Strobe::CLIENT), server("example::fhmqv",Strobe::SERVER); Scalar xe(clientRng); client.send_plaintext(gx); @@ -238,7 +238,7 @@ static void spake2ee( const Block &hashed_password, bool aug ) { - Strobe client(Strobe::CLIENT), server(Strobe::SERVER); + Strobe client("example::spake2ee",Strobe::CLIENT), server("example::spake2ee",Strobe::SERVER); Scalar x(clientRng); @@ -394,7 +394,7 @@ int main(int argc, char **argv) { SHAKE<128> shake1; SHAKE<256> shake2; SHA3<512> sha5; - Strobe strobe(Strobe::CLIENT); + Strobe strobe("example::bench",Strobe::CLIENT); unsigned char b1024[1024] = {1}; for (Benchmark b("SHAKE128 1kiB", 30); b.iter(); ) { shake1 += Buffer(b1024,1024); } for (Benchmark b("SHAKE256 1kiB", 30); b.iter(); ) { shake2 += Buffer(b1024,1024); } @@ -402,19 +402,19 @@ int main(int argc, char **argv) { strobe.key(Buffer(b1024,1024)); strobe.respec(STROBE_128); for (Benchmark b("STROBE128 1kiB", 10); b.iter(); ) { - strobe.encrypt_no_auth(Buffer(b1024,1024),Buffer(b1024,1024),b.i>1); + strobe.encrypt_no_auth(Buffer(b1024,1024),Buffer(b1024,1024)); } strobe.respec(STROBE_256); for (Benchmark b("STROBE256 1kiB", 10); b.iter(); ) { - strobe.encrypt_no_auth(Buffer(b1024,1024),Buffer(b1024,1024),b.i>1); + strobe.encrypt_no_auth(Buffer(b1024,1024),Buffer(b1024,1024)); } strobe.respec(STROBE_KEYED_128); for (Benchmark b("STROBEk128 1kiB", 10); b.iter(); ) { - strobe.encrypt_no_auth(Buffer(b1024,1024),Buffer(b1024,1024),b.i>1); + strobe.encrypt_no_auth(Buffer(b1024,1024),Buffer(b1024,1024)); } strobe.respec(STROBE_KEYED_256); for (Benchmark b("STROBEk256 1kiB", 10); b.iter(); ) { - strobe.encrypt_no_auth(Buffer(b1024,1024),Buffer(b1024,1024),b.i>1); + strobe.encrypt_no_auth(Buffer(b1024,1024),Buffer(b1024,1024)); } Benches::micro(); @@ -432,7 +432,7 @@ int main(int argc, char **argv) { decaf_255_private_to_public(p2,s2); for (Benchmark b("Shared secret"); b.iter(); ) { - decaf_bool_t ret = decaf_255_shared_secret(ss,sizeof(ss),s1,p2); + decaf_bool_t ret = decaf_255_shared_secret(ss,sizeof(ss),s1,p2,1); ignore_result(ret); assert(ret); } diff --git a/test/shakesum.c b/test/shakesum.c index 1c247bb..0348163 100644 --- a/test/shakesum.c +++ b/test/shakesum.c @@ -13,6 +13,13 @@ #include #include +void usage() { + fprintf( + stderr, + "shakesum [shake256|shake128|sha3-224|sha3-384|sha3-512] < infile > outfile\n" + ); +} + int main(int argc, char **argv) { (void)argc; (void)argv; @@ -42,6 +49,9 @@ int main(int argc, char **argv) { } else if (!strcmp(argv[1], "sha3-512") || !strcmp(argv[1], "SHA3-512")) { outlen = 512/8; sha3_512_gen_init(sponge); + } else { + usage(); + return 2; } } diff --git a/test/test_decaf.cxx b/test/test_decaf.cxx index 5c30794..1e7a1f5 100644 --- a/test/test_decaf.cxx +++ b/test/test_decaf.cxx @@ -360,10 +360,10 @@ static void test_decaf() { decaf_255_private_to_public(p1,s1); decaf_255_derive_private_key(s2,proto2); decaf_255_private_to_public(p2,s2); - if (DECAF_SUCCESS != decaf_255_shared_secret (shared1,sizeof(shared1),s1,p2)) { + if (DECAF_SUCCESS != decaf_255_shared_secret (shared1,sizeof(shared1),s1,p2,0)) { test.fail(); printf("Fail ss12\n"); } - if (DECAF_SUCCESS != decaf_255_shared_secret (shared2,sizeof(shared2),s2,p1)) { + if (DECAF_SUCCESS != decaf_255_shared_secret (shared2,sizeof(shared2),s2,p1,1)) { test.fail(); printf("Fail ss21\n"); } if (memcmp(shared1,shared2,sizeof(shared1))) {