diff --git a/include/decaf.hxx b/include/decaf.hxx index 0eaf3d6..f1056ef 100644 --- a/include/decaf.hxx +++ b/include/decaf.hxx @@ -211,7 +211,7 @@ public: /** Move non-constructor */ inline SecureBuffer(Block &&move) { *this = (Block &)move; } - /** Move-assign constructor */ + /** Move-assign constructor. TODO: check that this actually gets used.*/ inline SecureBuffer& operator=(SecureBuffer &&move) { clear(); data_ = move.data_; move.data_ = NULL; diff --git a/include/shake.h b/include/shake.h index c99197c..a6e92a4 100644 --- a/include/shake.h +++ b/include/shake.h @@ -21,6 +21,10 @@ /** @cond internal */ #define API_VIS __attribute__((visibility("default"))) #define WARN_UNUSED __attribute__((warn_unused_result)) +#define NONNULL1 __attribute__((nonnull(1))) +#define NONNULL2 __attribute__((nonnull(1,2))) +#define NONNULL13 __attribute__((nonnull(1,3))) +#define NONNULL3 __attribute__((nonnull(1,2,3))) /** @endcond */ /* TODO: different containing structs for each primitive? */ @@ -32,14 +36,8 @@ /** @endcond */ } keccak_sponge_t[1]; struct kparams_s; - typedef struct { uint64_t opaque; } strobe_params_t[1]; #endif -typedef struct strobe_s { - keccak_sponge_t sponge; - strobe_params_t params; -} strobe_s, strobe_t[1]; - #ifdef __cplusplus extern "C" { #endif @@ -122,39 +120,39 @@ void sponge_hash ( /** @cond internal */ #define DECSHAKE(n) \ extern const struct kparams_s SHAKE##n##_params_s API_VIS; \ - static inline void shake##n##_init(keccak_sponge_t sponge) { \ + static inline void NONNULL1 shake##n##_init(keccak_sponge_t sponge) { \ sponge_init(sponge, &SHAKE##n##_params_s); \ } \ - static inline void shake##n##_update(keccak_sponge_t sponge, const uint8_t *in, size_t inlen ) { \ + static inline void NONNULL2 shake##n##_update(keccak_sponge_t sponge, const uint8_t *in, size_t inlen ) { \ sha3_update(sponge, in, inlen); \ } \ - static inline void shake##n##_final(keccak_sponge_t sponge, uint8_t *out, size_t outlen ) { \ + static inline void NONNULL2 shake##n##_final(keccak_sponge_t sponge, uint8_t *out, size_t outlen ) { \ sha3_output(sponge, out, outlen); \ sponge_init(sponge, &SHAKE##n##_params_s); \ } \ - static inline void shake##n##_hash(uint8_t *out, size_t outlen, const uint8_t *in, size_t inlen) { \ + static inline void NONNULL13 shake##n##_hash(uint8_t *out, size_t outlen, const uint8_t *in, size_t inlen) { \ sponge_hash(in,inlen,out,outlen,&SHAKE##n##_params_s); \ } \ - static inline void shake##n##_destroy( keccak_sponge_t sponge ) { \ + static inline void NONNULL1 shake##n##_destroy( keccak_sponge_t sponge ) { \ sponge_destroy(sponge); \ } #define DECSHA3(n) \ extern const struct kparams_s SHA3_##n##_params_s API_VIS; \ - static inline void sha3_##n##_init(keccak_sponge_t sponge) { \ + static inline void NONNULL1 sha3_##n##_init(keccak_sponge_t sponge) { \ sponge_init(sponge, &SHA3_##n##_params_s); \ } \ - static inline void sha3_##n##_update(keccak_sponge_t sponge, const uint8_t *in, size_t inlen ) { \ + static inline void NONNULL2 sha3_##n##_update(keccak_sponge_t sponge, const uint8_t *in, size_t inlen ) { \ sha3_update(sponge, in, inlen); \ } \ - static inline void sha3_##n##_final(keccak_sponge_t sponge, uint8_t *out, size_t outlen ) { \ + static inline void NONNULL2 sha3_##n##_final(keccak_sponge_t sponge, uint8_t *out, size_t outlen ) { \ sha3_output(sponge, out, outlen); \ sponge_init(sponge, &SHA3_##n##_params_s); \ } \ - static inline void sha3_##n##_hash(uint8_t *out, size_t outlen, const uint8_t *in, size_t inlen) { \ + static inline void NONNULL13 sha3_##n##_hash(uint8_t *out, size_t outlen, const uint8_t *in, size_t inlen) { \ sponge_hash(in,inlen,out,outlen,&SHA3_##n##_params_s); \ } \ - static inline void sha3_##n##_destroy( keccak_sponge_t sponge ) { \ + static inline void NONNULL1 sha3_##n##_destroy( keccak_sponge_t sponge ) { \ sponge_destroy(sponge); \ } /** @endcond */ @@ -180,7 +178,7 @@ void spongerng_init_from_buffer ( const uint8_t * __restrict__ in, size_t len, int deterministic -) API_VIS; +) NONNULL2 API_VIS; /* FIXME!! This interface has the opposite retval convention from other functions * in the library. (0=success). Should they be harmonized? @@ -205,7 +203,7 @@ int spongerng_init_from_file ( const char *file, size_t len, int deterministic -) API_VIS WARN_UNUSED; +) NONNULL2 API_VIS WARN_UNUSED; /* FIXME!! This interface has the opposite retval convention from other functions @@ -249,7 +247,16 @@ void spongerng_stir ( keccak_sponge_t sponge, const uint8_t * __restrict__ in, size_t len -) API_VIS; +) NONNULL2 API_VIS; + +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; + +/** TODO: remove this restriction?? */ +#define STROBE_MAX_AUTH_BYTES 255 + +/** TODO: check "more" flags? */ /** * @brief Initialize Strobe protocol context. @@ -258,11 +265,88 @@ void spongerng_stir ( * @param [in] am_client Nonzero if this party * is the client. */ -void strobe_init( - strobe_t strobe, +void strobe_init ( + keccak_sponge_t sponge, const struct kparams_s *params, uint8_t am_client -); +) NONNULL2 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, + const unsigned char *in, + size_t len, + uint8_t iSent, + uint8_t more +) NONNULL2 API_VIS; + +/** + * @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, + const unsigned char *in, + size_t len, + uint8_t more +) NONNULL2 API_VIS; + +/** + * @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, + const unsigned char *in, + size_t len, + uint8_t more +) NONNULL2 API_VIS; + +/** + * @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, + const unsigned char *in, + size_t len, + uint8_t more +) NONNULL2 API_VIS; /** * @brief Produce an authenticator. @@ -270,12 +354,61 @@ void strobe_init( * @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). */ -void strobe_produce_auth ( - strobe_t strobe, +decaf_bool_t strobe_produce_auth ( + keccak_sponge_t sponge, unsigned char *out, size_t len -); +) NONNULL2 API_VIS; + +/** + * @brief Encrypt bytes from in to out. + * @warning Doesn't produce an auth tag (TODO?) + * @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, + unsigned char *out, + const unsigned char *in, + size_t len, + uint8_t more +) NONNULL3 API_VIS; + +/** + * @brief Decrypt bytes from in to out. + * @warning Doesn't check an auth tag (TODO?) + * @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, + unsigned char *out, + const unsigned char *in, + size_t len, + uint8_t more +) NONNULL3 API_VIS; /** * @brief Produce a session-bound pseudorandom value. @@ -289,12 +422,19 @@ void strobe_produce_auth ( * @param [inout] strobe The Strobe protocol context * @param [out] out The authenticator * @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). */ -void strobe_prng ( - strobe_t strobe, +decaf_bool_t strobe_prng ( + keccak_sponge_t sponge, unsigned char *out, - size_t len -); + size_t len, + uint8_t more +) NONNULL2 API_VIS; /** * @brief Verify an authenticator. @@ -302,12 +442,15 @@ void strobe_prng ( * @param [in] in 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 failed because of a + * bad validator (or because you aren't keyed) */ decaf_bool_t strobe_verify_auth ( - strobe_t strobe, + keccak_sponge_t sponge, const unsigned char *in, size_t len -); +) WARN_UNUSED NONNULL2 API_VIS; /** * @brief Respecify Strobe protocol object's crypto. @@ -315,19 +458,14 @@ 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) */ -void strobe_respec ( - strobe_t strobe, +decaf_bool_t strobe_respec ( + keccak_sponge_t sponge, const struct kparams_s *params -); - -/** - * @brief Destroy a Strobe context. - * @param [out] strobe The object to destroy. - */ -void strobe_destroy ( - strobe_t strobe -); +) NONNULL2 API_VIS; #ifdef __cplusplus } /* extern "C" */ @@ -335,5 +473,9 @@ void strobe_destroy ( #undef API_VIS #undef WARN_UNUSED +#undef NONNULL1 +#undef NONNULL13 +#undef NONNULL2 +#undef NONNULL3 #endif /* __SHAKE_H__ */ diff --git a/include/shake.hxx b/include/shake.hxx index 34390c7..87fe307 100644 --- a/include/shake.hxx +++ b/include/shake.hxx @@ -130,6 +130,13 @@ template<> const struct kparams_s *SHA3<256>::get_params() { return &SHA3_256_pa template<> const struct kparams_s *SHA3<384>::get_params() { return &SHA3_384_params_s; } template<> const struct kparams_s *SHA3<512>::get_params() { return &SHA3_512_params_s; } /** @endcond */ + +/** @brief An exception for misused protocol, eg encrypt with no key. */ +class ProtocolException : public std::exception { +public: + /** @return "ProtocolException" */ + virtual const char * what() const NOEXCEPT { return "ProtocolException"; } +}; /** Sponge-based random-number generator */ class SpongeRng : private KeccakSponge { @@ -194,6 +201,157 @@ decaf<448>::Point::Point(SpongeRng &rng, bool uniform) { } } /**@endcond*/ + +class Strobe : private KeccakSponge { +public: + /* TODO: pull out parameters */ + + /** Am I a server or a client? */ + enum client_or_server { SERVER, CLIENT }; + + inline Strobe ( + client_or_server whoami, + const kparams_s ¶ms = STROBE_256 + ) NOEXCEPT : KeccakSponge(NOINIT()) { + strobe_init(sp, ¶ms, whoami == CLIENT); + } + + inline void key ( + const Block &data, bool more = false + ) throw(ProtocolException) { + if (!strobe_key(sp, data, data.size(), more)) throw ProtocolException(); + } + + inline void nonce(const Block &data, bool more = false + ) throw(ProtocolException) { + if (!strobe_nonce(sp, data, data.size(), more)) throw ProtocolException(); + } + + inline void plaintext(const Block &data, bool iSent, bool more = false + ) throw(ProtocolException) { + if (!strobe_plaintext(sp, data, data.size(), iSent, more)) + throw(ProtocolException()); + } + + inline void ad(const Block &data, bool more = false + ) throw(ProtocolException) { + if (!strobe_ad(sp, data, data.size(), more)) + throw(ProtocolException()); + } + + inline void encrypt_no_auth( + Buffer &out, const Block &data, bool more = false + ) throw(LengthException,ProtocolException) { + if (out.size() != data.size()) throw LengthException(); + if (!strobe_encrypt(sp, out, data, data.size(), more)) throw(ProtocolException()); + } + + inline void encrypt_no_auth( + TmpBuffer out, const Block &data, bool more = false + ) throw(LengthException,ProtocolException) { + encrypt_no_auth((Buffer &)out, data, more); + } + + 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 void decrypt_no_auth( + Buffer &out, const Block &data, bool more = false + ) throw(LengthException,ProtocolException) { + if (out.size() != data.size()) throw LengthException(); + if (!strobe_decrypt(sp, out, data, data.size(), more)) throw ProtocolException(); + } + + inline void decrypt_no_auth( + TmpBuffer out, const Block &data, bool more = false + ) throw(LengthException,ProtocolException) { + decrypt_no_auth((Buffer &)out, data, more); + } + + 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 void produce_auth(Buffer &out) throw(LengthException,ProtocolException) { + if (out.size() > STROBE_MAX_AUTH_BYTES) throw LengthException(); + if (!strobe_produce_auth(sp, out, out.size())) throw ProtocolException(); + } + + inline void produce_auth(TmpBuffer out) throw(LengthException,ProtocolException) { + produce_auth((Buffer &)out); + } + + inline SecureBuffer produce_auth( + uint8_t bytes = 8 + ) throw(ProtocolException) { + SecureBuffer out(bytes); produce_auth(out); return out; + } + + inline void encrypt( + Buffer &out, const Block &data, uint8_t auth = 8 + ) throw(LengthException,ProtocolException) { + if (out.size() < data.size() || out.size() != data.size() + auth) throw LengthException(); + encrypt(out.slice(0,data.size()), data); + produce_auth(out.slice(data.size(),auth)); + } + + inline void encrypt ( + TmpBuffer out, const Block &data, uint8_t auth = 8 + ) throw(LengthException,ProtocolException) { + encrypt((Buffer &)out, data, auth); + } + + inline SecureBuffer encrypt ( + const Block &data, uint8_t auth = 8 + ) throw(LengthException,ProtocolException,std::bad_alloc ){ + SecureBuffer out(data.size() + auth); encrypt(out, data, auth); return out; + } + + inline void decrypt ( + Buffer &out, const Block &data, uint8_t bytes = 8 + ) throw(LengthException, CryptoException, ProtocolException) { + if (out.size() > data.size() || out.size() != data.size() - bytes) throw LengthException(); + decrypt(out, data.slice(0,out.size())); + verify_auth(data.slice(out.size(),bytes)); + } + + inline void decrypt ( + TmpBuffer out, const Block &data, uint8_t bytes = 8 + ) throw(LengthException,CryptoException,ProtocolException) { + decrypt((Buffer &)out, data, bytes); + } + + inline SecureBuffer decrypt ( + const Block &data, uint8_t bytes = 8 + ) throw(LengthException,CryptoException,ProtocolException,std::bad_alloc) { + if (data.size() < bytes) throw LengthException(); + SecureBuffer out(data.size() - bytes); decrypt(out, data, bytes); return out; + } + + 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, auth.size())) throw CryptoException(); + } + + inline void prng(Buffer &out, bool more = false) NOEXCEPT { + (void)strobe_prng(sp, out, out.size(), more); + } + + inline void prng(TmpBuffer out, bool more = false) NOEXCEPT { + prng((Buffer &)out, more); + } + + inline SecureBuffer prng(size_t bytes, bool more = false) { + SecureBuffer out(bytes); prng(out, more); return out; + } + + inline void respec(const kparams_s ¶ms) throw(ProtocolException) { + if (!strobe_respec(sp, ¶ms)) throw(ProtocolException()); + } +}; } /* namespace decaf */ diff --git a/src/shake.c b/src/shake.c index 14d1660..b29a46c 100644 --- a/src/shake.c +++ b/src/shake.c @@ -58,13 +58,9 @@ typedef union { } kdomain_t[1]; typedef struct kparams_s { - uint8_t position, flags, rate, startRound, pad, ratePad, maxOut, _; + uint8_t position, flags, rate, startRound, pad, ratePad, maxOut, client; } kparams_t[1]; -typedef struct strobe_params_s { - uint8_t client, _[7]; -} strobe_params_t[1]; - typedef struct keccak_sponge_s { kdomain_t state; kparams_t params; @@ -451,14 +447,18 @@ int spongerng_init_from_dev_urandom ( return spongerng_init_from_file(sponge, "/dev/urandom", 64, 0); } +const struct kparams_s STROBE_256 = { 0, 0, 200-256/4, 0, 0, 0, 0, 0 }; +const struct kparams_s STROBE_KEYED_256 = { 0, 0, 200-256/4, 12, 0, 0, 0, 0 }; +const struct kparams_s STROBE_KEYED_128 = { 0, 0, 200-128/4, 12, 0, 0, 0, 0 }; + /* Strobe is different in that its rate is padded by one byte. */ void strobe_init( - strobe_t strobe, + keccak_sponge_t sponge, const struct kparams_s *params, uint8_t am_client ) { - sponge_init(strobe->sponge,params); - strobe->params->client = !!am_client; + sponge_init(sponge,params); + sponge->params->client = !!am_client; } static void strobe_duplex ( @@ -493,6 +493,28 @@ static void strobe_duplex ( } } +static void strobe_forget ( + keccak_sponge_t sponge, + size_t len +) { + assert(sponge->params->rate < sizeof(sponge->state)); + assert(sponge->params->position <= sizeof(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, 0, len); + sponge->params->position = len; + } +} + static void strobe_unduplex ( keccak_sponge_t sponge, unsigned char *out, @@ -525,138 +547,190 @@ static void strobe_unduplex ( } } -enum { KEY, NONCE, AD, PLAINTEXT, CIPHERTEXT, TAGFORGET, DIVERSIFIER, PRNG, FORK, JOIN, RESPEC }; +enum { KEY=1, NONCE, AD, PLAINTEXT, CIPHERTEXT, TAGFORGET, DIVERSIFIER, PRNG, FORK, JOIN, RESPEC }; #define CLIENT_TO_SERVER 0 -#define SERVER_TO_CLIENT 1 +#define SERVER_TO_CLIENT 0x80 -struct strobe_control { - uint8_t next; - uint8_t bytes; - uint8_t flags; -} __attribute__((packed)); - -static void strobe_control_word ( - strobe_t strobe, - const struct strobe_control *control +static decaf_bool_t strobe_control_word ( + keccak_sponge_t sponge, + const unsigned char *control, + size_t len, + uint8_t more ) { - assert(strobe->sponge->params->rate < sizeof(strobe->sponge->state)); - strobe_duplex(strobe->sponge,NULL,(const unsigned char *)control,sizeof(*control)); - strobe->sponge->state->b[strobe->sponge->params->position] ^= 0x1; - strobe->sponge->state->b[strobe->sponge->params->rate] ^= 0x2; - dokeccak(strobe->sponge); + 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; } -void strobe_encrypt ( - strobe_t strobe, +decaf_bool_t strobe_encrypt ( + keccak_sponge_t sponge, unsigned char *out, const unsigned char *in, - size_t len + size_t len, + uint8_t more ) { - struct strobe_control cont = { CIPHERTEXT, 0, - strobe->params->client ? CLIENT_TO_SERVER : SERVER_TO_CLIENT }; - strobe_control_word(strobe, &cont); - strobe_duplex(strobe->sponge, out, in, len); + 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; } -void strobe_decrypt ( - strobe_t strobe, +decaf_bool_t strobe_decrypt ( + keccak_sponge_t sponge, unsigned char *out, const unsigned char *in, - size_t len + 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_duplex(sponge, out, in, len); + if (!sponge->params->pad/*keyed*/) ret = DECAF_FAILURE; + return ret; +} + +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 ) { - struct strobe_control cont = { CIPHERTEXT, 0, - strobe->params->client ? SERVER_TO_CLIENT : CLIENT_TO_SERVER }; - strobe_control_word(strobe, &cont); - strobe_duplex(strobe->sponge, out, in, len); + unsigned char control[] = { NONCE }; + decaf_bool_t ret = strobe_control_word(sponge, control, sizeof(control), more); + strobe_duplex(sponge, NULL, in, len); + return ret; } -void strobe_plaintext ( - strobe_t strobe, +decaf_bool_t strobe_ad ( + keccak_sponge_t sponge, const unsigned char *in, size_t len, - uint8_t iSent + uint8_t more ) { - struct strobe_control cont = { CIPHERTEXT, 0, - (strobe->params->client == !!iSent) ? CLIENT_TO_SERVER : SERVER_TO_CLIENT }; - strobe_control_word(strobe, &cont); - strobe_duplex(strobe->sponge, NULL, in, len); + 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 -void strobe_produce_auth ( - strobe_t strobe, +decaf_bool_t strobe_produce_auth ( + keccak_sponge_t sponge, unsigned char *out, size_t len ) { - assert(len < strobe->sponge->params->rate - STROBE_FORGET_BYTES); - struct strobe_control cont = { TAGFORGET, len, - strobe->params->client ? CLIENT_TO_SERVER : SERVER_TO_CLIENT }; - strobe_control_word(strobe, &cont); - strobe_duplex(strobe->sponge, out, NULL, len); - strobe_duplex(strobe->sponge, NULL, - &strobe->sponge->state->b[strobe->sponge->params->position], - STROBE_FORGET_BYTES - ); + 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; } -void strobe_prng ( - strobe_t strobe, +decaf_bool_t strobe_prng ( + keccak_sponge_t sponge, unsigned char *out, - size_t len + size_t len, + uint8_t more ) { - struct strobe_control cont = { PRNG, 0, 0 }; - strobe_control_word(strobe, &cont); - strobe_duplex(strobe->sponge, out, NULL, len); - - /* Forget. TODO: ORLY? */ - cont.next = TAGFORGET; - strobe_control_word(strobe, &cont); - strobe_duplex(strobe->sponge, NULL, - &strobe->sponge->state->b[0], - STROBE_FORGET_BYTES - ); + /* FIXME: length?? */ + unsigned char control[] = { PRNG }; + decaf_bool_t ret = strobe_control_word(sponge, control, sizeof(control), more); + strobe_duplex(sponge, out, NULL, len); + // /** TODO: orly? */ + // 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; } /* TODO: remove reliance on decaf? */ decaf_bool_t strobe_verify_auth ( - strobe_t strobe, + keccak_sponge_t sponge, const unsigned char *in, size_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]; - decaf_bool_t chain=0; - assert(len < strobe->sponge->params->rate - STROBE_FORGET_BYTES); - struct strobe_control cont = { TAGFORGET, len, - strobe->params->client ? CLIENT_TO_SERVER : SERVER_TO_CLIENT }; - strobe_control_word(strobe, &cont); - strobe_unduplex(strobe->sponge, zero, in, len); - strobe_duplex(strobe->sponge, NULL, - &strobe->sponge->state->b[strobe->sponge->params->position], - STROBE_FORGET_BYTES); + strobe_unduplex(sponge, zero, in, len); + strobe_forget(sponge, STROBE_FORGET_BYTES); /* Check for 0 */ + decaf_bool_t chain=0; unsigned i; for (i=0; i>(8*sizeof(decaf_word_t)); + ret &= ((decaf_dword_t)chain-1)>>(8*sizeof(decaf_word_t)); + if (!sponge->params->pad/*keyed*/) ret = DECAF_FAILURE; + return ret; } -void strobe_destroy ( - strobe_t strobe -) { - decaf_bzero(strobe,sizeof(strobe_t)); -} - -void strobe_respec ( - strobe_t strobe, +decaf_bool_t strobe_respec ( + keccak_sponge_t sponge, const struct kparams_s *params ) { - struct strobe_control cont = { RESPEC, params->rate, params->startRound }; - strobe_control_word(strobe, &cont); - strobe->sponge->params[0] = params[0]; + 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; + sponge->params->rate = params->rate; + sponge->params->startRound = params->startRound; + return ret; } /* TODO: Keyak instances, etc */ diff --git a/test/bench_decaf.cxx b/test/bench_decaf.cxx index dd66621..6698817 100644 --- a/test/bench_decaf.cxx +++ b/test/bench_decaf.cxx @@ -66,6 +66,7 @@ static void printSI(double x, const char *unit, const char *spacer = " ") { class Benchmark { static const int NTESTS = 1000; static double totalCy, totalS; + /* FIXME Tcy if get descheduled */ public: int i, ntests; double begin; @@ -138,10 +139,19 @@ int main(int argc, char **argv) { decaf::SHAKE<128> shake1; decaf::SHAKE<256> shake2; decaf::SHA3<512> sha5; + decaf::Strobe strobe(decaf::Strobe::CLIENT); unsigned char b1024[1024] = {1}; for (Benchmark b("SHAKE128 1kiB", 30); b.iter(); ) { shake1 += decaf::TmpBuffer(b1024,1024); } for (Benchmark b("SHAKE256 1kiB", 30); b.iter(); ) { shake2 += decaf::TmpBuffer(b1024,1024); } for (Benchmark b("SHA3-512 1kiB", 30); b.iter(); ) { sha5 += decaf::TmpBuffer(b1024,1024); } + strobe.key(decaf::TmpBuffer(b1024,1024)); + for (Benchmark b("STROBE256 1kiB", 30); b.iter(); ) { + strobe.encrypt_no_auth(decaf::TmpBuffer(b1024,1024),decaf::TmpBuffer(b1024,1024),b.i>1); + } + strobe.respec(STROBE_KEYED_128); + for (Benchmark b("STROBEk128 1kiB", 30); b.iter(); ) { + strobe.encrypt_no_auth(decaf::TmpBuffer(b1024,1024),decaf::TmpBuffer(b1024,1024),b.i>1); + } for (Benchmark b("Scalar add", 1000); b.iter(); ) { s+=t; } for (Benchmark b("Scalar times", 100); b.iter(); ) { s*=t; } for (Benchmark b("Scalar inv", 1); b.iter(); ) { s.inverse(); }