Browse Source

trying to update to the latest version of strobe. lots of stuff in flux though

master
Michael Hamburg 9 years ago
parent
commit
565522ffdf
9 changed files with 619 additions and 620 deletions
  1. +88
    -101
      src/decaf_crypto.c
  2. +7
    -2
      src/public_include/decaf/common.h
  3. +13
    -14
      src/public_include/decaf/crypto.h
  4. +215
    -118
      src/public_include/decaf/shake.h
  5. +59
    -59
      src/public_include/decaf/shake.hxx
  6. +216
    -315
      src/shake.c
  7. +9
    -9
      test/bench_decaf.cxx
  8. +10
    -0
      test/shakesum.c
  9. +2
    -2
      test/test_decaf.cxx

+ 88
- 101
src/decaf_crypto.c View File

@@ -17,16 +17,15 @@ void decaf_255_derive_private_key (
decaf_255_private_key_t priv, decaf_255_private_key_t priv,
const decaf_255_symmetric_key_t proto 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]; uint8_t encoded_scalar[DECAF_255_SCALAR_OVERKILL_BYTES];
decaf_255_point_t pub; 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)); memcpy(priv->sym, proto, sizeof(decaf_255_symmetric_key_t));
decaf_255_scalar_decode_long(priv->secret_scalar, encoded_scalar, sizeof(encoded_scalar)); 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)); 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_error_t
decaf_255_shared_secret ( decaf_255_shared_secret (
uint8_t *shared, uint8_t *shared,
size_t shared_bytes, size_t shared_bytes,
const decaf_255_private_key_t my_privkey, 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]; 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)); decaf_bzero(ss_ser, sizeof(ss_ser));
return ret; return ret;
} }


void void
decaf_255_sign_shake (
decaf_255_sign_strobe (
keccak_strobe_t strobe,
decaf_255_signature_t sig, 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_point_t point;
decaf_255_scalar_t nonce, challenge; 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 */ /* 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_scalar_decode_long(nonce, overkill, sizeof(overkill));
decaf_255_precomputed_scalarmul(point, decaf_255_precomputed_base, nonce); decaf_255_precomputed_scalarmul(point, decaf_255_precomputed_base, nonce);
decaf_255_point_encode(encoded, point);
decaf_255_point_encode(sig, point);


/* Derive challenge */ /* 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)); decaf_255_scalar_decode_long(challenge, overkill, sizeof(overkill));
/* Respond */ /* Respond */
@@ -150,41 +128,42 @@ decaf_255_sign_shake (
decaf_255_scalar_sub(nonce, nonce, challenge); decaf_255_scalar_sub(nonce, nonce, challenge);
/* Save results */ /* 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 */ /* Clean up */
decaf_255_scalar_destroy(nonce); decaf_255_scalar_destroy(nonce);
decaf_255_scalar_destroy(challenge); decaf_255_scalar_destroy(challenge);
decaf_bzero(overkill,sizeof(overkill)); decaf_bzero(overkill,sizeof(overkill));
decaf_bzero(encoded,sizeof(encoded));
} }


decaf_error_t decaf_error_t
decaf_255_verify_shake (
decaf_255_verify_strobe (
keccak_strobe_t strobe,
const decaf_255_signature_t sig, 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; decaf_bool_t ret;
uint8_t overkill[DECAF_255_SCALAR_OVERKILL_BYTES]; uint8_t overkill[DECAF_255_SCALAR_OVERKILL_BYTES];
decaf_255_point_t point, pubpoint; decaf_255_point_t point, pubpoint;
decaf_255_scalar_t challenge, response; 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 */ /* 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)); 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 ( decaf_255_base_double_scalarmul_non_secret (
pubpoint, response, pubpoint, challenge pubpoint, response, pubpoint, challenge
@@ -192,6 +171,14 @@ decaf_255_verify_shake (


ret &= decaf_255_point_eq(pubpoint, point); 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); return decaf_succeed_if(ret);
} }


@@ -202,11 +189,11 @@ decaf_255_sign (
const unsigned char *message, const unsigned char *message,
size_t message_len 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 decaf_error_t
@@ -216,10 +203,10 @@ decaf_255_verify (
const unsigned char *message, const unsigned char *message,
size_t message_len 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; return ret;
} }

+ 7
- 2
src/public_include/decaf/common.h View File

@@ -31,8 +31,13 @@
#define NONNULL5 __attribute__((nonnull(1,2,3,4,5))) #define NONNULL5 __attribute__((nonnull(1,2,3,4,5)))
/** @endcond */ /** @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)) \ #if (defined(__ILP64__) || defined(__amd64__) || defined(__x86_64__) || (((__UINT_FAST32_MAX__)>>30)>>30)) \
&& !defined(DECAF_FORCE_32_BIT) && !defined(DECAF_FORCE_32_BIT)
#define DECAF_WORD_BITS 64 #define DECAF_WORD_BITS 64


+ 13
- 14
src/public_include/decaf/crypto.h View File

@@ -96,33 +96,32 @@ void decaf_255_private_to_public (
* @param [in] shared_bytes The size of the buffer. * @param [in] shared_bytes The size of the buffer.
* @param [in] my_privkey My private key. * @param [in] my_privkey My private key.
* @param [in] your_pubkey Your public 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_SUCCESS Key exchange was successful.
* @retval DECAF_FAILURE Key exchange failed. * @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_error_t
decaf_255_shared_secret ( decaf_255_shared_secret (
uint8_t *shared, uint8_t *shared,
size_t shared_bytes, size_t shared_bytes,
const decaf_255_private_key_t my_privkey, 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; ) 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 [out] sig The signature.
* @param [in] priv Your private key. * @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 void
decaf_255_sign_shake (
decaf_255_sign_strobe (
keccak_strobe_t strobe,
decaf_255_signature_t sig, 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; ) NONNULL3 API_VIS;


/** /**
@@ -142,20 +141,20 @@ decaf_255_sign (
) NONNULL3 API_VIS; ) 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] sig The signature.
* @param [in] pub The public key. * @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_SUCCESS The signature verified successfully.
* @return DECAF_FAILURE The signature did not verify successfully. * @return DECAF_FAILURE The signature did not verify successfully.
*/ */
decaf_error_t decaf_error_t
decaf_255_verify_shake (
decaf_255_verify_strobe (
keccak_strobe_t strobe,
const decaf_255_signature_t sig, 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; ) NONNULL3 API_VIS WARN_UNUSED;


/** /**


+ 215
- 118
src/public_include/decaf/shake.h View File

@@ -14,6 +14,7 @@


#include <stdint.h> #include <stdint.h>
#include <sys/types.h> #include <sys/types.h>
#include <stdlib.h> /* for NULL */


#include <decaf/common.h> #include <decaf/common.h>


@@ -24,6 +25,8 @@
#define NONNULL2 __attribute__((nonnull(1,2))) #define NONNULL2 __attribute__((nonnull(1,2)))
#define NONNULL13 __attribute__((nonnull(1,3))) #define NONNULL13 __attribute__((nonnull(1,3)))
#define NONNULL3 __attribute__((nonnull(1,2,3))) #define NONNULL3 __attribute__((nonnull(1,2,3)))
#define INLINE __inline__ __attribute__((always_inline))
#define UNUSED __attribute__((unused))
/** @endcond */ /** @endcond */


#ifndef INTERNAL_SPONGE_STRUCT #ifndef INTERNAL_SPONGE_STRUCT
@@ -35,6 +38,7 @@
} keccak_sponge_t[1]; } keccak_sponge_t[1];
struct kparams_s; struct kparams_s;
#endif #endif
typedef struct keccak_sponge_s keccak_strobe_t[1], keccak_prng_t[1];


#ifdef __cplusplus #ifdef __cplusplus
extern "C" { extern "C" {
@@ -173,14 +177,14 @@ DECSHA3(512)
/** /**
* @brief Initialize a sponge-based CSPRNG from a buffer. * @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] in The initial data.
* @param [in] len The length of the initial data. * @param [in] len The length of the initial data.
* @param [in] deterministic If zero, allow RNG to stir in nondeterministic * @param [in] deterministic If zero, allow RNG to stir in nondeterministic
* data from RDRAND or RDTSC. * data from RDRAND or RDTSC.
*/ */
void spongerng_init_from_buffer ( void spongerng_init_from_buffer (
keccak_sponge_t sponge,
keccak_prng_t prng,
const uint8_t * __restrict__ in, const uint8_t * __restrict__ in,
size_t len, size_t len,
int deterministic int deterministic
@@ -193,7 +197,7 @@ void spongerng_init_from_buffer (
/** /**
* @brief Initialize a sponge-based CSPRNG from a file. * @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] file A name of a file containing initial data.
* @param [in] len The length of the initial data. Must be positive. * @param [in] len The length of the initial data. Must be positive.
* @param [in] deterministic If zero, allow RNG to stir in nondeterministic * @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. * @retval -2 len was 0.
*/ */
int spongerng_init_from_file ( int spongerng_init_from_file (
keccak_sponge_t sponge,
keccak_prng_t prng,
const char *file, const char *file,
size_t len, size_t len,
int deterministic int deterministic
@@ -226,7 +230,7 @@ int spongerng_init_from_file (
* @retval -1 An unknown error has occurred. * @retval -1 An unknown error has occurred.
*/ */
int spongerng_init_from_dev_urandom ( int spongerng_init_from_dev_urandom (
keccak_sponge_t sponge
keccak_prng_t prng
) API_VIS WARN_UNUSED; ) API_VIS WARN_UNUSED;


/** /**
@@ -237,7 +241,7 @@ int spongerng_init_from_dev_urandom (
* @param [in] len The output buffer's length. * @param [in] len The output buffer's length.
*/ */
void spongerng_next ( void spongerng_next (
keccak_sponge_t sponge,
keccak_prng_t prng,
uint8_t * __restrict__ out, uint8_t * __restrict__ out,
size_t len size_t len
) API_VIS; ) API_VIS;
@@ -250,7 +254,7 @@ void spongerng_next (
* @param [in] len The length of the initial data. * @param [in] len The length of the initial data.
*/ */
void spongerng_stir ( void spongerng_stir (
keccak_sponge_t sponge,
keccak_prng_t prng,
const uint8_t * __restrict__ in, const uint8_t * __restrict__ in,
size_t len size_t len
) NONNULL2 API_VIS; ) 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_128 API_VIS;
extern const struct kparams_s STROBE_KEYED_256 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. * @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] Strobe parameter descriptor
* @param [in] am_client Nonzero if this party * @param [in] am_client Nonzero if this party
* is the client. * is the client.
*/ */
void strobe_init ( void strobe_init (
keccak_sponge_t sponge,
keccak_strobe_t strobe,
const struct kparams_s *params, const struct kparams_s *params,
const char *proto,
uint8_t am_client uint8_t am_client
) NONNULL2 API_VIS; ) 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. * @brief Send plaintext in strobe context.
* @param [inout] The initialized strobe object. * @param [inout] The initialized strobe object.
* @param [in] Strobe parameter descriptor
* @param [in] in The plaintext. * @param [in] in The plaintext.
* @param [in] len The length of the plaintext. * @param [in] len The length of the plaintext.
* @param [in] iSent Nonzero if this side of exchange sent 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, 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. * @brief Report authenticated data in strobe context.
* @param [inout] The initialized strobe object. * @param [inout] The initialized strobe object.
* @param [in] Strobe parameter descriptor
* @param [in] in The plaintext. * @param [in] in The plaintext.
* @param [in] len The length of the ad. * @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, 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. * @brief Set nonce in strobe context.
* @param [inout] The initialized strobe object. * @param [inout] The initialized strobe object.
* @param [in] Strobe parameter descriptor
* @param [in] in The nonce. * @param [in] in The nonce.
* @param [in] len The length of 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, 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. * @brief Set key in strobe context.
* @param [inout] The initialized strobe object. * @param [inout] The initialized strobe object.
* @param [in] Strobe parameter descriptor
* @param [in] in The key. * @param [in] in The key.
* @param [in] len The length of 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, 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. * @brief Produce an authenticator.
* @param [inout] strobe The Strobe protocol context
* @param [inout] strobe The Strobe protocol context.
* @param [out] out The authenticator * @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. * @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 [inout] strobe The Strobe protocol context.
* @param [in] in The plaintext. * @param [in] in The plaintext.
* @param [out] out The ciphertext. * @param [out] out The ciphertext.
* @param [in] len The length of plaintext and 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, unsigned char *out,
const unsigned char *in, 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. * @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 [inout] strobe The Strobe protocol context.
* @param [in] in The ciphertext. * @param [in] in The ciphertext.
* @param [out] out The plaintext. * @param [out] out The plaintext.
* @param [in] len The length of plaintext and 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_decrypt (
keccak_sponge_t sponge,
static INLINE UNUSED void
strobe_decrypt (
keccak_strobe_t strobe,
unsigned char *out, unsigned char *out,
const unsigned char *in, 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. * @brief Produce a session-bound pseudorandom value.
@@ -423,24 +526,17 @@ decaf_bool_t strobe_decrypt (
* refreshing forward secrecy! It's to replace things * refreshing forward secrecy! It's to replace things
* like TCP session hash. * like TCP session hash.
* *
* @todo Figure out how to treat this wrt anti-rollback.
*
* @param [inout] strobe The Strobe protocol context * @param [inout] strobe The Strobe protocol context
* @param [out] out The authenticator
* @param [out] out The output random data.
* @param len The length. * @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. * @brief Verify an authenticator.
@@ -452,10 +548,10 @@ decaf_bool_t strobe_prng (
* @retval DECAF_FAILURE The operation failed because of a * @retval DECAF_FAILURE The operation failed because of a
* bad validator (or because you aren't keyed) * 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, const unsigned char *in,
size_t len
uint16_t len
) WARN_UNUSED NONNULL2 API_VIS; ) WARN_UNUSED NONNULL2 API_VIS;


/** /**
@@ -464,14 +560,13 @@ decaf_bool_t strobe_verify_auth (
* @param [in] Strobe parameter descriptor * @param [in] Strobe parameter descriptor
* @param [in] am_client Nonzero if this party * @param [in] am_client Nonzero if this party
* is the client. * 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 const struct kparams_s *params
) NONNULL2 API_VIS; ) NONNULL2 API_VIS;
#define strobe_destroy sponge_destroy


#ifdef __cplusplus #ifdef __cplusplus
} /* extern "C" */ } /* extern "C" */
@@ -483,5 +578,7 @@ decaf_bool_t strobe_respec (
#undef NONNULL13 #undef NONNULL13
#undef NONNULL2 #undef NONNULL2
#undef NONNULL3 #undef NONNULL3
#undef INLINE
#undef UNUSED
#endif /* __SHAKE_H__ */ #endif /* __SHAKE_H__ */

+ 59
- 59
src/public_include/decaf/shake.hxx View File

@@ -191,108 +191,104 @@ private:
class Strobe : private KeccakSponge { class Strobe : private KeccakSponge {
public: public:
/* TODO: pull out parameters */ /* TODO: pull out parameters */
static const uint16_t DEFAULT_AUTH_SIZE = 16;
/** Am I a server or a client? */ /** Am I a server or a client? */
enum client_or_server { SERVER, CLIENT }; enum client_or_server { SERVER, CLIENT };
inline Strobe ( inline Strobe (
const char *description,
client_or_server whoami, client_or_server whoami,
const kparams_s &params = STROBE_256 const kparams_s &params = STROBE_256
) NOEXCEPT : KeccakSponge(NOINIT()) { ) NOEXCEPT : KeccakSponge(NOINIT()) {
strobe_init(sp, &params, whoami == CLIENT);
strobe_init(sp, &params, description, whoami == CLIENT);
keyed = false;
} }


/* TODO: add a key type keyword */
/* TODO: add a "keyed" tracker */
inline void key ( inline void key (
const Block &data, bool more = false
const Block &data
) throw(ProtocolException) { ) 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 ( template<class T> inline void key (
const Serializable<T> &data, bool more = false
const Serializable<T> &data
) throw(ProtocolException) { ) 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 (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 (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) { 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 (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; SecureBuffer out(bytes); produce_auth(out); return out;
} }
inline void encrypt( 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) { ) throw(LengthException,ProtocolException) {
if (out.size() < data.size() || out.size() != data.size() + auth) throw LengthException(); if (out.size() < data.size() || out.size() != data.size() + auth) throw LengthException();
encrypt_no_auth(out.slice(0,data.size()), data); encrypt_no_auth(out.slice(0,data.size()), data);
@@ -300,19 +296,19 @@ public:
} }
inline SecureBuffer encrypt ( 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 ){ ) throw(LengthException,ProtocolException,std::bad_alloc ){
SecureBuffer out(data.size() + auth); encrypt(out, data, auth); return out; SecureBuffer out(data.size() + auth); encrypt(out, data, auth); return out;
} }
template<class T> inline SecureBuffer encrypt ( 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 ){ ) throw(LengthException,ProtocolException,std::bad_alloc ){
return encrypt(data.serialize(), auth); return encrypt(data.serialize(), auth);
} }
inline void decrypt ( 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) { ) throw(LengthException, CryptoException, ProtocolException) {
if (out.size() > data.size() || out.size() != data.size() - bytes) throw LengthException(); if (out.size() > data.size() || out.size() != data.size() - bytes) throw LengthException();
decrypt_no_auth(out, data.slice(0,out.size())); decrypt_no_auth(out, data.slice(0,out.size()));
@@ -320,13 +316,13 @@ public:
} }
template<class T> inline SecureBuffer decrypt ( 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 ){ ) throw(LengthException,ProtocolException,CryptoException, std::bad_alloc ){
return decrypt(data.serialize(), auth); return decrypt(data.serialize(), auth);
} }
inline SecureBuffer decrypt ( 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) { ) throw(LengthException,CryptoException,ProtocolException,std::bad_alloc) {
if (data.size() < bytes) throw LengthException(); if (data.size() < bytes) throw LengthException();
SecureBuffer out(data.size() - bytes); decrypt(out, data, bytes); return out; 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) { inline void verify_auth(const Block &auth) throw(LengthException,CryptoException) {
if (auth.size() == 0 || auth.size() > STROBE_MAX_AUTH_BYTES) throw LengthException(); 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 &params) throw(ProtocolException) { inline void respec(const kparams_s &params) throw(ProtocolException) {
if (!strobe_respec(sp, &params)) throw(ProtocolException());
if (!keyed) throw(ProtocolException());
strobe_respec(sp, &params);
} }
private:
bool keyed;
}; };
} /* namespace decaf */ } /* namespace decaf */


+ 216
- 315
src/shake.c View File

@@ -71,12 +71,6 @@ typedef struct keccak_sponge_s {


#define FLAG_ABSORBING 'A' #define FLAG_ABSORBING 'A'
#define FLAG_SQUEEZING 'Z' #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. **/ /** Constants. **/
static const uint8_t pi[24] = { 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=0; i<25; i++) a[i] = le64toh(a[i]);


for (i = startRound; i < 24; 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); a[y + x] ^= b[(x + 4) % 5] ^ rol(b[(x + 1) % 5], 1);
)) ))
// Rho and pi // Rho and pi
@@ -285,7 +280,7 @@ static void get_cpu_entropy(uint8_t *entropy, size_t len) {
} }
*eo ^= out; *eo ^= out;
} }
} else if (len>8) {
} else if (len>=8) {
uint64_t out; uint64_t out;
__asm__ __volatile__ ("rdtsc" : "=A"(out)); __asm__ __volatile__ ("rdtsc" : "=A"(out));
*(uint64_t*) entropy ^= out; *(uint64_t*) entropy ^= out;
@@ -297,51 +292,27 @@ static void get_cpu_entropy(uint8_t *entropy, size_t len) {
#endif #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 ( void spongerng_next (
keccak_sponge_t sponge, keccak_sponge_t sponge,
uint8_t * __restrict__ out, uint8_t * __restrict__ out,
size_t len 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, const uint8_t * __restrict__ in,
size_t len 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) { 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 = { 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 ( void spongerng_init_from_buffer (
@@ -393,8 +339,7 @@ void spongerng_init_from_buffer (
size_t len, size_t len,
int deterministic 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); spongerng_stir(sponge, in, len);
} }


@@ -404,14 +349,13 @@ int spongerng_init_from_file (
size_t len, size_t len,
int deterministic 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; if (!len) return -2;


int fd = open(file, O_RDONLY); int fd = open(file, O_RDONLY);
if (fd < 0) return errno ? errno : -1; if (fd < 0) return errno ? errno : -1;
uint8_t buffer[128];
uint8_t buffer[SPONGERNG_FILE_BLOCK_SIZE];
while (len) { while (len) {
ssize_t red = read(fd, buffer, (len > sizeof(buffer)) ? sizeof(buffer) : len); ssize_t red = read(fd, buffer, (len > sizeof(buffer)) ? sizeof(buffer) : len);
if (red <= 0) { if (red <= 0) {
@@ -422,8 +366,7 @@ int spongerng_init_from_file (
len -= red; len -= red;
}; };
close(fd); close(fd);

sponge->params->flags = deterministic ? FLAG_DET_ABS : FLAG_RNG_ABS;
return 0; 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( void strobe_init(
keccak_sponge_t sponge, keccak_sponge_t sponge,
const struct kparams_s *params, const struct kparams_s *params,
const char *proto,
uint8_t am_client uint8_t am_client
) { ) {
sponge_init(sponge,params); 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; 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 ( static void strobe_duplex (
keccak_sponge_t sponge, keccak_sponge_t sponge,
unsigned char *out, unsigned char *out,
const unsigned char *in, 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) { if (out) {
memcpy(out, state, cando);
memcpy(out, in, cando);
out += 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]; 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; return;
} else { } 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; 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, keccak_sponge_t sponge,
unsigned char *out, unsigned char *out,
const unsigned char *in,
size_t len, 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, keccak_sponge_t sponge,
const unsigned char *in, 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++) { 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, keccak_sponge_t sponge,
const struct kparams_s *params 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->rate = params->rate;
sponge->params->startRound = params->startRound; sponge->params->startRound = params->startRound;
return ret;
} }


/* FUTURE: Keyak instances, etc */ /* FUTURE: Keyak instances, etc */

+ 9
- 9
test/bench_decaf.cxx View File

@@ -157,7 +157,7 @@ static void tdh (
* hash gx and gy into the session secret (only into the MAC * hash gx and gy into the session secret (only into the MAC
* and AD) because of IPR concerns. * 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); Scalar xe(clientRng);
SecureBuffer gxe((Precomputed::base() * xe).serialize()); SecureBuffer gxe((Precomputed::base() * xe).serialize());
@@ -198,7 +198,7 @@ static void fhmqv (
Scalar y, const Block &gy Scalar y, const Block &gy
) { ) {
/* Don't use this, it's probably patented */ /* 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); Scalar xe(clientRng);
client.send_plaintext(gx); client.send_plaintext(gx);
@@ -238,7 +238,7 @@ static void spake2ee(
const Block &hashed_password, const Block &hashed_password,
bool aug bool aug
) { ) {
Strobe client(Strobe::CLIENT), server(Strobe::SERVER);
Strobe client("example::spake2ee",Strobe::CLIENT), server("example::spake2ee",Strobe::SERVER);
Scalar x(clientRng); Scalar x(clientRng);
@@ -394,7 +394,7 @@ int main(int argc, char **argv) {
SHAKE<128> shake1; SHAKE<128> shake1;
SHAKE<256> shake2; SHAKE<256> shake2;
SHA3<512> sha5; SHA3<512> sha5;
Strobe strobe(Strobe::CLIENT);
Strobe strobe("example::bench",Strobe::CLIENT);
unsigned char b1024[1024] = {1}; unsigned char b1024[1024] = {1};
for (Benchmark b("SHAKE128 1kiB", 30); b.iter(); ) { shake1 += Buffer(b1024,1024); } for (Benchmark b("SHAKE128 1kiB", 30); b.iter(); ) { shake1 += Buffer(b1024,1024); }
for (Benchmark b("SHAKE256 1kiB", 30); b.iter(); ) { shake2 += 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.key(Buffer(b1024,1024));
strobe.respec(STROBE_128); strobe.respec(STROBE_128);
for (Benchmark b("STROBE128 1kiB", 10); b.iter(); ) { 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); strobe.respec(STROBE_256);
for (Benchmark b("STROBE256 1kiB", 10); b.iter(); ) { 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); strobe.respec(STROBE_KEYED_128);
for (Benchmark b("STROBEk128 1kiB", 10); b.iter(); ) { 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); strobe.respec(STROBE_KEYED_256);
for (Benchmark b("STROBEk256 1kiB", 10); b.iter(); ) { 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(); Benches<IsoEd25519>::micro();
@@ -432,7 +432,7 @@ int main(int argc, char **argv) {
decaf_255_private_to_public(p2,s2); decaf_255_private_to_public(p2,s2);
for (Benchmark b("Shared secret"); b.iter(); ) { 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); ignore_result(ret);
assert(ret); assert(ret);
} }


+ 10
- 0
test/shakesum.c View File

@@ -13,6 +13,13 @@
#include <string.h> #include <string.h>
#include <decaf/shake.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) { int main(int argc, char **argv) {
(void)argc; (void)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")) { } else if (!strcmp(argv[1], "sha3-512") || !strcmp(argv[1], "SHA3-512")) {
outlen = 512/8; outlen = 512/8;
sha3_512_gen_init(sponge); sha3_512_gen_init(sponge);
} else {
usage();
return 2;
} }
} }




+ 2
- 2
test/test_decaf.cxx View File

@@ -360,10 +360,10 @@ static void test_decaf() {
decaf_255_private_to_public(p1,s1); decaf_255_private_to_public(p1,s1);
decaf_255_derive_private_key(s2,proto2); decaf_255_derive_private_key(s2,proto2);
decaf_255_private_to_public(p2,s2); 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"); 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"); test.fail(); printf("Fail ss21\n");
} }
if (memcmp(shared1,shared2,sizeof(shared1))) { if (memcmp(shared1,shared2,sizeof(shared1))) {


Loading…
Cancel
Save