| @@ -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; | |||
| @@ -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__ */ | |||
| @@ -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 */ | |||
| @@ -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<len; i++) { | |||
| chain |= zero[i]; | |||
| } | |||
| return ((decaf_dword_t)chain-1)>>(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 */ | |||
| @@ -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(); } | |||