@@ -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; i<DECAF_255_SER_BYTES; i++) { | |||
uint16_t delta = my_privkey->pub[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; i<sizeof(ss_ser); i++) { | |||
ss_ser[i] = (my_privkey->pub[i] & less) | (your_pubkey[i] & ~less); | |||
} | |||
shake256_update(sponge, ss_ser, sizeof(ss_ser)); | |||
/* update the greater */ | |||
for (i=0; i<sizeof(ss_ser); i++) { | |||
ss_ser[i] = (my_privkey->pub[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; i<sizeof(ss_ser); i++) { | |||
ss_ser[i] &= good; | |||
if (i < sizeof(my_privkey->sym)) { | |||
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; | |||
} |
@@ -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 | |||
@@ -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; | |||
/** | |||
@@ -14,6 +14,7 @@ | |||
#include <stdint.h> | |||
#include <sys/types.h> | |||
#include <stdlib.h> /* for NULL */ | |||
#include <decaf/common.h> | |||
@@ -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__ */ |
@@ -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<class T> inline void key ( | |||
const Serializable<T> &data, bool more = false | |||
const Serializable<T> &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<class T> inline void send_plaintext(const Serializable<T> &data, bool more = false) throw(ProtocolException) { | |||
send_plaintext(data.serialize(), more); | |||
template<class T> inline void send_plaintext(const Serializable<T> &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<class T> inline void recv_plaintext(const Serializable<T> &data, bool more = false) throw(ProtocolException) { | |||
recv_plaintext(data.serialize(), more); | |||
template<class T> inline void recv_plaintext(const Serializable<T> &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<class T> inline void ad(const Serializable<T> &data, bool more = false) throw(ProtocolException) { | |||
ad(data.serialize(), more); | |||
template<class T> inline void ad(const Serializable<T> &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<class T> inline SecureBuffer encrypt_no_auth(const Serializable<T> &data, bool more = false | |||
) throw(ProtocolException) { | |||
return encrypt_no_auth(data.serialize(), more); | |||
template<class T> inline SecureBuffer encrypt_no_auth(const Serializable<T> &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<class T> inline SecureBuffer decrypt_no_auth(const Serializable<T> &data, bool more = false | |||
) throw(ProtocolException) { | |||
return decrypt_no_auth(data.serialize(),more); | |||
template<class T> inline SecureBuffer decrypt_no_auth(const Serializable<T> &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<class T> inline SecureBuffer encrypt ( | |||
const Serializable<T> &data, uint8_t auth = 8 | |||
const Serializable<T> &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<class T> inline SecureBuffer decrypt ( | |||
const Serializable<T> &data, uint8_t auth = 8 | |||
const Serializable<T> &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 */ | |||
@@ -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 && j<len; j++) state[j]^=in[j]; | |||
if (out) memcpy(out, state, len); | |||
sponge->params->position += len; | |||
return; | |||
} else { | |||
if (in) { | |||
for (j=0; j<cando; j++) state[j]^=in[j]; | |||
in += cando; | |||
} | |||
unsigned int j, r = sponge->params->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; j<cando; j++) state[p+j] ^= in[j]; | |||
if (out) { | |||
memcpy(out, state, cando); | |||
memcpy(out, in, cando); | |||
out += cando; | |||
} | |||
state[cando] ^= 0x1; | |||
dokeccak(sponge); | |||
len -= cando; | |||
} | |||
} | |||
} | |||
static void strobe_forget ( | |||
keccak_sponge_t sponge, | |||
size_t len | |||
) { | |||
assert(sponge->params->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 && j<len; j++) { | |||
in += cando; | |||
break; | |||
case STROBE_MODE_ABSORB: | |||
for (j=0; j<cando; j++) state[p+j] ^= in[j]; | |||
in += cando; | |||
break; | |||
case STROBE_MODE_ABSORB_R: | |||
memcpy(state+p, in, cando); | |||
in += cando; | |||
break; | |||
case STROBE_MODE_SQUEEZE: | |||
memcpy(out, state+p, cando); | |||
out += cando; | |||
break; | |||
case STROBE_MODE_SQUEEZE_R: | |||
memcpy(out, state+p, cando); | |||
out += cando; | |||
memset(state+p, 0, cando); | |||
break; | |||
case STROBE_MODE_FORGET: | |||
memset(state+p, 0, cando); | |||
break; | |||
case STROBE_MODE_DUPLEX: | |||
for (j=0; j<cando; j++) { | |||
state[p+j] ^= in[j]; | |||
out[j] = state[p+j]; | |||
} | |||
in += cando; | |||
out += cando; | |||
break; | |||
case STROBE_MODE_DUPLEX_R: | |||
for (j=0; j<cando; j++) { | |||
unsigned char c = in[j]; | |||
out[j] = in[j] ^ state[j]; | |||
state[j] = c; | |||
out[j] = c ^ state[p+j]; | |||
state[p+j] = c; | |||
} | |||
sponge->params->position += len; | |||
in += cando; | |||
out += cando; | |||
break; | |||
default: | |||
assert(0); | |||
}; | |||
if (last) { | |||
sponge->params->position = p+len; | |||
return; | |||
} else { | |||
for (j=0; in && j<cando; j++) { | |||
unsigned char c = in[j]; | |||
out[j] = in[j] ^ state[j]; | |||
state[j] = c; | |||
} | |||
state[j] ^= 0x1; | |||
dokeccak(sponge); | |||
state[r] ^= EXCEEDED_RATE_PAD; | |||
keccakf(sponge->state, 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; i<len; i++) { | |||
chain |= zero[i]; | |||
residue |= sponge->state->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 */ |
@@ -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<IsoEd25519>::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); | |||
} | |||
@@ -13,6 +13,13 @@ | |||
#include <string.h> | |||
#include <decaf/shake.h> | |||
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; | |||
} | |||
} | |||
@@ -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))) { | |||