| @@ -13,6 +13,7 @@ | |||||
| #include <stdlib.h> | #include <stdlib.h> | ||||
| #include "field.h" | #include "field.h" | ||||
| #include "f_field.h" | |||||
| #include "decaf.h" | #include "decaf.h" | ||||
| #include "decaf_config.h" | #include "decaf_config.h" | ||||
| @@ -59,16 +60,15 @@ static void scalar_print(const char *name, const API_NS(scalar_t) sc) { /* UNIFY | |||||
| } | } | ||||
| static void field_print(const gf f) { /* UNIFY */ | static void field_print(const gf f) { /* UNIFY */ | ||||
| const int GF_SER_BYTES = (GF_BITS + 7) / 8; | |||||
| unsigned char ser[GF_SER_BYTES]; | |||||
| unsigned char ser[SER_BYTES]; | |||||
| gf_serialize(ser,f); | gf_serialize(ser,f); | ||||
| int b=0, i, comma=0; | int b=0, i, comma=0; | ||||
| unsigned long long limb = 0; | unsigned long long limb = 0; | ||||
| printf("{FIELD_LITERAL("); | printf("{FIELD_LITERAL("); | ||||
| for (i=0; i<GF_SER_BYTES; i++) { | |||||
| for (i=0; i<SER_BYTES; i++) { | |||||
| limb |= ((uint64_t)ser[i])<<b; | limb |= ((uint64_t)ser[i])<<b; | ||||
| b += 8; | b += 8; | ||||
| if (b >= GF_LIT_LIMB_BITS || i == GF_SER_BYTES-1) { | |||||
| if (b >= GF_LIT_LIMB_BITS || i == SER_BYTES-1) { | |||||
| limb &= (1ull<<GF_LIT_LIMB_BITS) -1; | limb &= (1ull<<GF_LIT_LIMB_BITS) -1; | ||||
| b -= GF_LIT_LIMB_BITS; | b -= GF_LIT_LIMB_BITS; | ||||
| if (comma) printf(","); | if (comma) printf(","); | ||||
| @@ -49,8 +49,6 @@ public: | |||||
| /** Serialization size. */ | /** Serialization size. */ | ||||
| static const size_t SER_BYTES = sizeof(Wrapped); | static const size_t SER_BYTES = sizeof(Wrapped); | ||||
| /* TODO: convenience types like signature? */ | |||||
| /** Read a private key from a string*/ | /** Read a private key from a string*/ | ||||
| inline explicit PublicKey(const FixedBlock<SER_BYTES> &b) NOEXCEPT { | inline explicit PublicKey(const FixedBlock<SER_BYTES> &b) NOEXCEPT { | ||||
| memcpy(wrapped,b.data(),sizeof(wrapped)); | memcpy(wrapped,b.data(),sizeof(wrapped)); | ||||
| @@ -70,7 +68,7 @@ public: | |||||
| /** Serialization size. */ | /** Serialization size. */ | ||||
| inline size_t serSize() const NOEXCEPT { return SER_BYTES; } | inline size_t serSize() const NOEXCEPT { return SER_BYTES; } | ||||
| /* TODO: verify_strobe */ | |||||
| /* FUTURE: verify_strobe */ | |||||
| /** Verify a message */ | /** Verify a message */ | ||||
| inline void verify( | inline void verify( | ||||
| @@ -32,9 +32,6 @@ | |||||
| * a naive autovectorizer will do with constant_time_lookup on Intel). | * a naive autovectorizer will do with constant_time_lookup on Intel). | ||||
| * | * | ||||
| * Instead, we're putting our trust in the loop unroller and unswitcher. | * Instead, we're putting our trust in the loop unroller and unswitcher. | ||||
| * | |||||
| * TODO: verify correctness and performance on each platform, to make sure | |||||
| * that there are no regressions. | |||||
| */ | */ | ||||
| @@ -251,7 +251,7 @@ malloc_vector(size_t size) { | |||||
| /* PERF: vectorize vs unroll */ | /* PERF: vectorize vs unroll */ | ||||
| #ifdef __clang__ | #ifdef __clang__ | ||||
| #if 100*__clang_major__ + __clang_minor__ > 305 | #if 100*__clang_major__ + __clang_minor__ > 305 | ||||
| #define UNROLL _Pragma("clang loop unroll(full)") // PERF TODO: vectorize? | |||||
| #define UNROLL _Pragma("clang loop unroll(full)") | |||||
| #endif | #endif | ||||
| #endif | #endif | ||||
| @@ -87,7 +87,7 @@ void gf_mulw (gf_s *__restrict__ cs, const gf as, uint64_t b) { | |||||
| } | } | ||||
| void gf_sqr (gf_s *__restrict__ cs, const gf as) { | void gf_sqr (gf_s *__restrict__ cs, const gf as) { | ||||
| gf_mul(cs,as,as); // PERF | |||||
| gf_mul(cs,as,as); /* Performs better with dedicated square */ | |||||
| } | } | ||||
| @@ -57,5 +57,5 @@ void gf_mulw (gf_s *__restrict__ cs, const gf as, uint64_t b) { | |||||
| } | } | ||||
| void gf_sqr (gf_s *__restrict__ cs, const gf as) { | void gf_sqr (gf_s *__restrict__ cs, const gf as) { | ||||
| gf_mul(cs,as,as); // PERF | |||||
| gf_mul(cs,as,as); /* Performs better with dedicated square */ | |||||
| } | } | ||||
| @@ -100,6 +100,6 @@ void gf_mulw (gf_s *__restrict__ cs, const gf as, uint64_t b) { | |||||
| } | } | ||||
| void gf_sqr (gf_s *__restrict__ cs, const gf as) { | void gf_sqr (gf_s *__restrict__ cs, const gf as) { | ||||
| gf_mul(cs,as,as); /* PERF */ | |||||
| gf_mul(cs,as,as); /* Performs better with a dedicated square */ | |||||
| } | } | ||||
| @@ -6,19 +6,14 @@ | |||||
| * Released under the MIT License. See LICENSE.txt for license information. | * Released under the MIT License. See LICENSE.txt for license information. | ||||
| * @author Mike Hamburg | * @author Mike Hamburg | ||||
| * @brief SHA-3-n and SHAKE-n instances, C++ wrapper. | * @brief SHA-3-n and SHAKE-n instances, C++ wrapper. | ||||
| * @warning EXPERIMENTAL! The names, parameter orders etc are likely to change. | |||||
| */ | */ | ||||
| #ifndef __SHAKE_HXX__ | |||||
| #define __SHAKE_HXX__ | |||||
| #ifndef __DECAF_SHAKE_HXX__ | |||||
| #define __DECAF_SHAKE_HXX__ | |||||
| #include <decaf/shake.h> | #include <decaf/shake.h> | ||||
| #include <decaf/strobe.h> /* TODO remove */ | |||||
| #include <decaf/spongerng.h> /* TODO remove */ | |||||
| #include <string> | |||||
| #include <sys/types.h> | #include <sys/types.h> | ||||
| #include <errno.h> | |||||
| /** @cond internal */ | /** @cond internal */ | ||||
| #if __cplusplus >= 201103L | #if __cplusplus >= 201103L | ||||
| @@ -140,268 +135,10 @@ template<> inline const struct kparams_s *SHA3<256>::get_params() { return &SHA3 | |||||
| template<> inline const struct kparams_s *SHA3<384>::get_params() { return &SHA3_384_params_s; } | template<> inline const struct kparams_s *SHA3<384>::get_params() { return &SHA3_384_params_s; } | ||||
| template<> inline const struct kparams_s *SHA3<512>::get_params() { return &SHA3_512_params_s; } | template<> inline const struct kparams_s *SHA3<512>::get_params() { return &SHA3_512_params_s; } | ||||
| /** @endcond */ | /** @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 : public Rng { | |||||
| private: | |||||
| /** C wrapped object */ | |||||
| keccak_prng_t sp; | |||||
| public: | |||||
| /** Exception thrown when The RNG fails (to seed itself) */ | |||||
| class RngException : public std::exception { | |||||
| private: | |||||
| /** @cond internal */ | |||||
| const char *const what_; | |||||
| /** @endcond */ | |||||
| public: | |||||
| const int err_code; /**< errno that caused the reseed to fail. */ | |||||
| const char *what() const NOEXCEPT { return what_; } /**< Description of exception. */ | |||||
| RngException(int err_code, const char *what_) NOEXCEPT : what_(what_), err_code(err_code) {} /**< Construct */ | |||||
| }; | |||||
| /** Initialize, deterministically by default, from block */ | |||||
| inline SpongeRng( const Block &in, bool deterministic = true ) { | |||||
| spongerng_init_from_buffer(sp,in.data(),in.size(),deterministic); | |||||
| } | |||||
| /** Initialize, non-deterministically by default, from C/C++ filename */ | |||||
| inline SpongeRng( const std::string &in = "/dev/urandom", size_t len = 32, bool deterministic = false ) | |||||
| throw(RngException) { | |||||
| decaf_error_t ret = spongerng_init_from_file(sp,in.c_str(),len,deterministic); | |||||
| if (!decaf_successful(ret)) { | |||||
| throw RngException(errno, "Couldn't load from file"); | |||||
| } | |||||
| } | |||||
| /** Stir in new data */ | |||||
| inline void stir( const Block &data ) NOEXCEPT { | |||||
| spongerng_stir(sp,data.data(),data.size()); | |||||
| } | |||||
| /** Securely destroy by overwriting state. */ | |||||
| inline ~SpongeRng() NOEXCEPT { spongerng_destroy(sp); } | |||||
| using Rng::read; | |||||
| /** Read data to a buffer. */ | |||||
| virtual inline void read(Buffer buffer) NOEXCEPT | |||||
| #if __cplusplus >= 201103L | |||||
| final | |||||
| #endif | |||||
| { spongerng_next(sp,buffer.data(),buffer.size()); } | |||||
| private: | |||||
| SpongeRng(const SpongeRng &) DELETE; | |||||
| SpongeRng &operator=(const SpongeRng &) DELETE; | |||||
| }; | |||||
| /**@endcond*/ | |||||
| /** STROBE protocol framework object */ | |||||
| class Strobe { | |||||
| private: | |||||
| /** The wrapped object */ | |||||
| keccak_strobe_t sp; | |||||
| public: | |||||
| /** Number of bytes in a default authentication size. */ | |||||
| static const uint16_t DEFAULT_AUTH_SIZE = 16; | |||||
| /** Am I a server or a client? */ | |||||
| enum client_or_server { SERVER, CLIENT }; | |||||
| /** Create protocol object. */ | |||||
| inline Strobe ( | |||||
| const char *description, /**< Description of this protocol. */ | |||||
| client_or_server whoami, /**< Am I client or server? */ | |||||
| const kparams_s ¶ms = STROBE_256 /**< Strength parameters */ | |||||
| ) NOEXCEPT { | |||||
| strobe_init(sp, ¶ms, description, whoami == CLIENT); | |||||
| keyed = false; | |||||
| } | |||||
| /** Securely destroy by overwriting state. */ | |||||
| inline ~Strobe() NOEXCEPT { strobe_destroy(sp); } | |||||
| /** Stir in fixed key, from a C++ block. */ | |||||
| inline void fixed_key ( | |||||
| const Block &data /**< The key. */ | |||||
| ) throw(ProtocolException) { | |||||
| strobe_fixed_key(sp, data.data(), data.size()); | |||||
| keyed = true; | |||||
| } | |||||
| /** Stir in fixed key, from a serializeable object. */ | |||||
| template<class T> inline void fixed_key ( | |||||
| const Serializable<T> &data /**< The key. */ | |||||
| ) throw(ProtocolException) { | |||||
| fixed_key(data.serialize()); | |||||
| } | |||||
| /** Stir in DH key, from a C++ block. */ | |||||
| inline void dh_key ( | |||||
| const Block &data /**< The key. */ | |||||
| ) throw(ProtocolException) { | |||||
| strobe_dh_key(sp, data.data(), data.size()); | |||||
| keyed = true; | |||||
| } | |||||
| /** Stir in DH key, from a serializeable object. */ | |||||
| template<class T> inline void dh_key ( | |||||
| const Serializable<T> &data /**< The key. */ | |||||
| ) throw(ProtocolException) { | |||||
| dh_key(data.serialize()); | |||||
| } | |||||
| /** Stir in an explicit nonce. */ | |||||
| inline void nonce(const Block &data) NOEXCEPT { | |||||
| strobe_nonce(sp, data.data(), data.size()); | |||||
| } | |||||
| /** Stir in data we sent as plaintext. NB This doesn't actually send anything. */ | |||||
| inline void send_plaintext(const Block &data) NOEXCEPT { | |||||
| strobe_plaintext(sp, data.data(), data.size(), true); | |||||
| } | |||||
| /** Stir in serializeable data we sent as plaintext. NB This doesn't actually send anything. */ | |||||
| template<class T> inline void send_plaintext(const Serializable<T> &data) NOEXCEPT { | |||||
| send_plaintext(data.serialize()); | |||||
| } | |||||
| /** Stir in data we received as plaintext. NB This doesn't actually receive anything. */ | |||||
| inline void recv_plaintext(const Block &data) NOEXCEPT { | |||||
| strobe_plaintext(sp, data.data(), data.size(), false); | |||||
| } | |||||
| /** Stir in associated data. */ | |||||
| inline void ad(const Block &data) { | |||||
| strobe_ad(sp, data.data(), data.size()); | |||||
| } | |||||
| /** Stir in associated serializable data. */ | |||||
| template<class T> inline void ad(const Serializable<T> &data) NOEXCEPT { | |||||
| ad(data.serialize()); | |||||
| } | |||||
| /** Encrypt into a buffer, without appending authentication data */ | |||||
| inline void encrypt_no_auth(Buffer out, const Block &data) throw(LengthException,ProtocolException) { | |||||
| if (!keyed) throw ProtocolException(); | |||||
| if (out.size() != data.size()) throw LengthException(); | |||||
| strobe_encrypt(sp, out.data(), data.data(), data.size()); | |||||
| } | |||||
| /** Encrypt, without appending authentication data */ | |||||
| inline SecureBuffer encrypt_no_auth(const Block &data) throw(ProtocolException) { | |||||
| SecureBuffer out(data.size()); encrypt_no_auth(out, data); return out; | |||||
| } | |||||
| /** Encrypt a serializable object, without appending authentication data */ | |||||
| template<class T> inline SecureBuffer encrypt_no_auth(const Serializable<T> &data) throw(ProtocolException) { | |||||
| return encrypt_no_auth(data.serialize()); | |||||
| } | |||||
| /** Decrypt into a buffer, without checking authentication data. */ | |||||
| inline void decrypt_no_auth(Buffer out, const Block &data) throw(LengthException,ProtocolException) { | |||||
| if (!keyed) throw ProtocolException(); | |||||
| if (out.size() != data.size()) throw LengthException(); | |||||
| strobe_decrypt(sp, out.data(), data.data(), data.size()); | |||||
| } | |||||
| /** Decrypt, without checking authentication data. */ | |||||
| inline SecureBuffer decrypt_no_auth(const Block &data) throw(ProtocolException) { | |||||
| SecureBuffer out(data.size()); decrypt_no_auth(out, data); return out; | |||||
| } | |||||
| /** Produce an authenticator into a buffer. */ | |||||
| inline void produce_auth(Buffer out, bool even_though_unkeyed = false) throw(LengthException,ProtocolException) { | |||||
| if (!keyed && !even_though_unkeyed) throw ProtocolException(); | |||||
| if (out.size() > STROBE_MAX_AUTH_BYTES) throw LengthException(); | |||||
| strobe_produce_auth(sp, out.data(), out.size()); | |||||
| } | |||||
| /** Produce an authenticator. */ | |||||
| inline SecureBuffer produce_auth(uint8_t bytes = DEFAULT_AUTH_SIZE) throw(ProtocolException) { | |||||
| SecureBuffer out(bytes); produce_auth(out); return out; | |||||
| } | |||||
| /** Encrypt into a buffer and append authentication data */ | |||||
| inline void encrypt( | |||||
| Buffer out, const Block &data, uint8_t auth = DEFAULT_AUTH_SIZE | |||||
| ) throw(LengthException,ProtocolException) { | |||||
| if (out.size() < data.size() || out.size() != data.size() + auth) throw LengthException(); | |||||
| encrypt_no_auth(out.slice(0,data.size()), data); | |||||
| produce_auth(out.slice(data.size(),auth)); | |||||
| } | |||||
| /** Encrypt and append authentication data */ | |||||
| inline SecureBuffer encrypt ( | |||||
| const Block &data, uint8_t auth = DEFAULT_AUTH_SIZE | |||||
| ) throw(LengthException,ProtocolException,std::bad_alloc ){ | |||||
| SecureBuffer out(data.size() + auth); encrypt(out, data, auth); return out; | |||||
| } | |||||
| /** Encrypt a serializable object and append authentication data */ | |||||
| template<class T> inline SecureBuffer encrypt ( | |||||
| const Serializable<T> &data, uint8_t auth = DEFAULT_AUTH_SIZE | |||||
| ) throw(LengthException,ProtocolException,std::bad_alloc ){ | |||||
| return encrypt(data.serialize(), auth); | |||||
| } | |||||
| /** Decrypt into a buffer and check authentication data */ | |||||
| inline void decrypt ( | |||||
| Buffer out, const Block &data, uint8_t bytes = DEFAULT_AUTH_SIZE | |||||
| ) throw(LengthException, CryptoException, ProtocolException) { | |||||
| if (out.size() > data.size() || out.size() != data.size() - bytes) throw LengthException(); | |||||
| decrypt_no_auth(out, data.slice(0,out.size())); | |||||
| verify_auth(data.slice(out.size(),bytes)); | |||||
| } | |||||
| /** Decrypt and check authentication data */ | |||||
| inline SecureBuffer decrypt ( | |||||
| const Block &data, uint8_t bytes = DEFAULT_AUTH_SIZE | |||||
| ) throw(LengthException,CryptoException,ProtocolException,std::bad_alloc) { | |||||
| if (data.size() < bytes) throw LengthException(); | |||||
| SecureBuffer out(data.size() - bytes); decrypt(out, data, bytes); return out; | |||||
| } | |||||
| /** Check authentication data */ | |||||
| inline void verify_auth(const Block &auth) throw(LengthException,CryptoException) { | |||||
| if (auth.size() == 0 || auth.size() > STROBE_MAX_AUTH_BYTES) throw LengthException(); | |||||
| if (strobe_verify_auth(sp, auth.data(), auth.size()) != DECAF_SUCCESS) throw CryptoException(); | |||||
| } | |||||
| /** Fill pseudorandom data into a buffer */ | |||||
| inline void prng(Buffer out) NOEXCEPT { | |||||
| (void)strobe_prng(sp, out.data(), out.size()); | |||||
| } | |||||
| /** Return pseudorandom data */ | |||||
| inline SecureBuffer prng(size_t bytes) { | |||||
| SecureBuffer out(bytes); prng(out); return out; | |||||
| } | |||||
| /** Change specs, perhaps to a faster spec that takes advantage of being keyed. | |||||
| * @warning Experimental. | |||||
| */ | |||||
| inline void respec(const kparams_s ¶ms) throw(ProtocolException) { | |||||
| if (!keyed) throw(ProtocolException()); | |||||
| strobe_respec(sp, ¶ms); | |||||
| } | |||||
| private: | |||||
| bool keyed; | |||||
| }; | |||||
| } /* namespace decaf */ | } /* namespace decaf */ | ||||
| #undef NOEXCEPT | #undef NOEXCEPT | ||||
| #undef DELETE | #undef DELETE | ||||
| #endif /* __SHAKE_HXX__ */ | |||||
| #endif /* __DECAF_SHAKE_HXX__ */ | |||||
| @@ -0,0 +1,98 @@ | |||||
| /** | |||||
| * @file decaf/strobe.hxx | |||||
| * @copyright | |||||
| * Based on CC0 code by David Leon Gil, 2015 \n | |||||
| * Copyright (c) 2015 Cryptography Research, Inc. \n | |||||
| * Released under the MIT License. See LICENSE.txt for license information. | |||||
| * @author Mike Hamburg | |||||
| * @brief Sponge RNG instances, C++ wrapper. | |||||
| * @warning The guts of this are subject to change. Please don't implement | |||||
| * anything that depends on the deterministic RNG being stable across versions | |||||
| * of this library. | |||||
| */ | |||||
| #ifndef __DECAF_SPONGERNG_HXX__ | |||||
| #define __DECAF_SPONGERNG_HXX__ | |||||
| #include <decaf/spongerng.h> | |||||
| #include <string> | |||||
| #include <sys/types.h> | |||||
| #include <errno.h> | |||||
| /** @cond internal */ | |||||
| #if __cplusplus >= 201103L | |||||
| #define NOEXCEPT noexcept | |||||
| #define DELETE = delete | |||||
| #else | |||||
| #define NOEXCEPT throw() | |||||
| #define DELETE | |||||
| #endif | |||||
| /** @endcond */ | |||||
| namespace decaf { | |||||
| /** Sponge-based random-number generator */ | |||||
| class SpongeRng : public Rng { | |||||
| private: | |||||
| /** C wrapped object */ | |||||
| keccak_prng_t sp; | |||||
| public: | |||||
| /** Exception thrown when The RNG fails (to seed itself) */ | |||||
| class RngException : public std::exception { | |||||
| private: | |||||
| /** @cond internal */ | |||||
| const char *const what_; | |||||
| /** @endcond */ | |||||
| public: | |||||
| const int err_code; /**< errno that caused the reseed to fail. */ | |||||
| const char *what() const NOEXCEPT { return what_; } /**< Description of exception. */ | |||||
| RngException(int err_code, const char *what_) NOEXCEPT : what_(what_), err_code(err_code) {} /**< Construct */ | |||||
| }; | |||||
| /** Initialize, deterministically by default, from block */ | |||||
| inline SpongeRng( const Block &in, bool deterministic = true ) { | |||||
| spongerng_init_from_buffer(sp,in.data(),in.size(),deterministic); | |||||
| } | |||||
| /** Initialize, non-deterministically by default, from C/C++ filename */ | |||||
| inline SpongeRng( const std::string &in = "/dev/urandom", size_t len = 32, bool deterministic = false ) | |||||
| throw(RngException) { | |||||
| decaf_error_t ret = spongerng_init_from_file(sp,in.c_str(),len,deterministic); | |||||
| if (!decaf_successful(ret)) { | |||||
| throw RngException(errno, "Couldn't load from file"); | |||||
| } | |||||
| } | |||||
| /** Stir in new data */ | |||||
| inline void stir( const Block &data ) NOEXCEPT { | |||||
| spongerng_stir(sp,data.data(),data.size()); | |||||
| } | |||||
| /** Securely destroy by overwriting state. */ | |||||
| inline ~SpongeRng() NOEXCEPT { spongerng_destroy(sp); } | |||||
| using Rng::read; | |||||
| /** Read data to a buffer. */ | |||||
| virtual inline void read(Buffer buffer) NOEXCEPT | |||||
| #if __cplusplus >= 201103L | |||||
| final | |||||
| #endif | |||||
| { spongerng_next(sp,buffer.data(),buffer.size()); } | |||||
| private: | |||||
| SpongeRng(const SpongeRng &) DELETE; | |||||
| SpongeRng &operator=(const SpongeRng &) DELETE; | |||||
| }; | |||||
| /**@endcond*/ | |||||
| } /* namespace decaf */ | |||||
| #undef NOEXCEPT | |||||
| #undef DELETE | |||||
| #endif /* __DECAF_SPONGERNG_HXX__ */ | |||||
| @@ -0,0 +1,240 @@ | |||||
| /** | |||||
| * @file decaf/strobe.hxx | |||||
| * @copyright | |||||
| * Based on CC0 code by David Leon Gil, 2015 \n | |||||
| * Copyright (c) 2015 Cryptography Research, Inc. \n | |||||
| * Released under the MIT License. See LICENSE.txt for license information. | |||||
| * @author Mike Hamburg | |||||
| * @brief STROBE instances, C++ wrapper. | |||||
| * @warning This protocol framework is entirely experimental, and shouldn't be | |||||
| * relied on for anything serious yet. | |||||
| */ | |||||
| #ifndef __DECAF_STROBE_HXX__ | |||||
| #define __DECAF_STROBE_HXX__ | |||||
| #include <decaf/strobe.h> | |||||
| #include <sys/types.h> | |||||
| /** @cond internal */ | |||||
| #if __cplusplus >= 201103L | |||||
| #define NOEXCEPT noexcept | |||||
| #define DELETE = delete | |||||
| #else | |||||
| #define NOEXCEPT throw() | |||||
| #define DELETE | |||||
| #endif | |||||
| /** @endcond */ | |||||
| namespace decaf { | |||||
| /** @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"; } | |||||
| }; | |||||
| /** STROBE protocol framework object */ | |||||
| class Strobe { | |||||
| private: | |||||
| /** The wrapped object */ | |||||
| keccak_strobe_t sp; | |||||
| public: | |||||
| /** Number of bytes in a default authentication size. */ | |||||
| static const uint16_t DEFAULT_AUTH_SIZE = 16; | |||||
| /** Am I a server or a client? */ | |||||
| enum client_or_server { SERVER, CLIENT }; | |||||
| /** Create protocol object. */ | |||||
| inline Strobe ( | |||||
| const char *description, /**< Description of this protocol. */ | |||||
| client_or_server whoami, /**< Am I client or server? */ | |||||
| const kparams_s ¶ms = STROBE_256 /**< Strength parameters */ | |||||
| ) NOEXCEPT { | |||||
| strobe_init(sp, ¶ms, description, whoami == CLIENT); | |||||
| keyed = false; | |||||
| } | |||||
| /** Securely destroy by overwriting state. */ | |||||
| inline ~Strobe() NOEXCEPT { strobe_destroy(sp); } | |||||
| /** Stir in fixed key, from a C++ block. */ | |||||
| inline void fixed_key ( | |||||
| const Block &data /**< The key. */ | |||||
| ) throw(ProtocolException) { | |||||
| strobe_fixed_key(sp, data.data(), data.size()); | |||||
| keyed = true; | |||||
| } | |||||
| /** Stir in fixed key, from a serializeable object. */ | |||||
| template<class T> inline void fixed_key ( | |||||
| const Serializable<T> &data /**< The key. */ | |||||
| ) throw(ProtocolException) { | |||||
| fixed_key(data.serialize()); | |||||
| } | |||||
| /** Stir in DH key, from a C++ block. */ | |||||
| inline void dh_key ( | |||||
| const Block &data /**< The key. */ | |||||
| ) throw(ProtocolException) { | |||||
| strobe_dh_key(sp, data.data(), data.size()); | |||||
| keyed = true; | |||||
| } | |||||
| /** Stir in DH key, from a serializeable object. */ | |||||
| template<class T> inline void dh_key ( | |||||
| const Serializable<T> &data /**< The key. */ | |||||
| ) throw(ProtocolException) { | |||||
| dh_key(data.serialize()); | |||||
| } | |||||
| /** Stir in an explicit nonce. */ | |||||
| inline void nonce(const Block &data) NOEXCEPT { | |||||
| strobe_nonce(sp, data.data(), data.size()); | |||||
| } | |||||
| /** Stir in data we sent as plaintext. NB This doesn't actually send anything. */ | |||||
| inline void send_plaintext(const Block &data) NOEXCEPT { | |||||
| strobe_plaintext(sp, data.data(), data.size(), true); | |||||
| } | |||||
| /** Stir in serializeable data we sent as plaintext. NB This doesn't actually send anything. */ | |||||
| template<class T> inline void send_plaintext(const Serializable<T> &data) NOEXCEPT { | |||||
| send_plaintext(data.serialize()); | |||||
| } | |||||
| /** Stir in data we received as plaintext. NB This doesn't actually receive anything. */ | |||||
| inline void recv_plaintext(const Block &data) NOEXCEPT { | |||||
| strobe_plaintext(sp, data.data(), data.size(), false); | |||||
| } | |||||
| /** Stir in associated data. */ | |||||
| inline void ad(const Block &data) { | |||||
| strobe_ad(sp, data.data(), data.size()); | |||||
| } | |||||
| /** Stir in associated serializable data. */ | |||||
| template<class T> inline void ad(const Serializable<T> &data) NOEXCEPT { | |||||
| ad(data.serialize()); | |||||
| } | |||||
| /** Encrypt into a buffer, without appending authentication data */ | |||||
| inline void encrypt_no_auth(Buffer out, const Block &data) throw(LengthException,ProtocolException) { | |||||
| if (!keyed) throw ProtocolException(); | |||||
| if (out.size() != data.size()) throw LengthException(); | |||||
| strobe_encrypt(sp, out.data(), data.data(), data.size()); | |||||
| } | |||||
| /** Encrypt, without appending authentication data */ | |||||
| inline SecureBuffer encrypt_no_auth(const Block &data) throw(ProtocolException) { | |||||
| SecureBuffer out(data.size()); encrypt_no_auth(out, data); return out; | |||||
| } | |||||
| /** Encrypt a serializable object, without appending authentication data */ | |||||
| template<class T> inline SecureBuffer encrypt_no_auth(const Serializable<T> &data) throw(ProtocolException) { | |||||
| return encrypt_no_auth(data.serialize()); | |||||
| } | |||||
| /** Decrypt into a buffer, without checking authentication data. */ | |||||
| inline void decrypt_no_auth(Buffer out, const Block &data) throw(LengthException,ProtocolException) { | |||||
| if (!keyed) throw ProtocolException(); | |||||
| if (out.size() != data.size()) throw LengthException(); | |||||
| strobe_decrypt(sp, out.data(), data.data(), data.size()); | |||||
| } | |||||
| /** Decrypt, without checking authentication data. */ | |||||
| inline SecureBuffer decrypt_no_auth(const Block &data) throw(ProtocolException) { | |||||
| SecureBuffer out(data.size()); decrypt_no_auth(out, data); return out; | |||||
| } | |||||
| /** Produce an authenticator into a buffer. */ | |||||
| inline void produce_auth(Buffer out, bool even_though_unkeyed = false) throw(LengthException,ProtocolException) { | |||||
| if (!keyed && !even_though_unkeyed) throw ProtocolException(); | |||||
| if (out.size() > STROBE_MAX_AUTH_BYTES) throw LengthException(); | |||||
| strobe_produce_auth(sp, out.data(), out.size()); | |||||
| } | |||||
| /** Produce an authenticator. */ | |||||
| inline SecureBuffer produce_auth(uint8_t bytes = DEFAULT_AUTH_SIZE) throw(ProtocolException) { | |||||
| SecureBuffer out(bytes); produce_auth(out); return out; | |||||
| } | |||||
| /** Encrypt into a buffer and append authentication data */ | |||||
| inline void encrypt( | |||||
| Buffer out, const Block &data, uint8_t auth = DEFAULT_AUTH_SIZE | |||||
| ) throw(LengthException,ProtocolException) { | |||||
| if (out.size() < data.size() || out.size() != data.size() + auth) throw LengthException(); | |||||
| encrypt_no_auth(out.slice(0,data.size()), data); | |||||
| produce_auth(out.slice(data.size(),auth)); | |||||
| } | |||||
| /** Encrypt and append authentication data */ | |||||
| inline SecureBuffer encrypt ( | |||||
| const Block &data, uint8_t auth = DEFAULT_AUTH_SIZE | |||||
| ) throw(LengthException,ProtocolException,std::bad_alloc ){ | |||||
| SecureBuffer out(data.size() + auth); encrypt(out, data, auth); return out; | |||||
| } | |||||
| /** Encrypt a serializable object and append authentication data */ | |||||
| template<class T> inline SecureBuffer encrypt ( | |||||
| const Serializable<T> &data, uint8_t auth = DEFAULT_AUTH_SIZE | |||||
| ) throw(LengthException,ProtocolException,std::bad_alloc ){ | |||||
| return encrypt(data.serialize(), auth); | |||||
| } | |||||
| /** Decrypt into a buffer and check authentication data */ | |||||
| inline void decrypt ( | |||||
| Buffer out, const Block &data, uint8_t bytes = DEFAULT_AUTH_SIZE | |||||
| ) throw(LengthException, CryptoException, ProtocolException) { | |||||
| if (out.size() > data.size() || out.size() != data.size() - bytes) throw LengthException(); | |||||
| decrypt_no_auth(out, data.slice(0,out.size())); | |||||
| verify_auth(data.slice(out.size(),bytes)); | |||||
| } | |||||
| /** Decrypt and check authentication data */ | |||||
| inline SecureBuffer decrypt ( | |||||
| const Block &data, uint8_t bytes = DEFAULT_AUTH_SIZE | |||||
| ) throw(LengthException,CryptoException,ProtocolException,std::bad_alloc) { | |||||
| if (data.size() < bytes) throw LengthException(); | |||||
| SecureBuffer out(data.size() - bytes); decrypt(out, data, bytes); return out; | |||||
| } | |||||
| /** Check authentication data */ | |||||
| inline void verify_auth(const Block &auth) throw(LengthException,CryptoException) { | |||||
| if (auth.size() == 0 || auth.size() > STROBE_MAX_AUTH_BYTES) throw LengthException(); | |||||
| if (strobe_verify_auth(sp, auth.data(), auth.size()) != DECAF_SUCCESS) throw CryptoException(); | |||||
| } | |||||
| /** Fill pseudorandom data into a buffer */ | |||||
| inline void prng(Buffer out) NOEXCEPT { | |||||
| (void)strobe_prng(sp, out.data(), out.size()); | |||||
| } | |||||
| /** Return pseudorandom data */ | |||||
| inline SecureBuffer prng(size_t bytes) { | |||||
| SecureBuffer out(bytes); prng(out); return out; | |||||
| } | |||||
| /** Change specs, perhaps to a faster spec that takes advantage of being keyed. | |||||
| * @warning Experimental. | |||||
| */ | |||||
| inline void respec(const kparams_s ¶ms) throw(ProtocolException) { | |||||
| if (!keyed) throw(ProtocolException()); | |||||
| strobe_respec(sp, ¶ms); | |||||
| } | |||||
| private: | |||||
| bool keyed; | |||||
| }; | |||||
| } /* namespace decaf */ | |||||
| #undef NOEXCEPT | |||||
| #undef DELETE | |||||
| #endif /* __DECAF_STROBE_HXX__ */ | |||||
| @@ -11,6 +11,8 @@ | |||||
| #include <decaf.hxx> | #include <decaf.hxx> | ||||
| #include <decaf/shake.hxx> | #include <decaf/shake.hxx> | ||||
| #include <decaf/strobe.hxx> | |||||
| #include <decaf/spongerng.hxx> | |||||
| #include <decaf/crypto_255.h> | #include <decaf/crypto_255.h> | ||||
| #include <decaf/crypto_448.h> | #include <decaf/crypto_448.h> | ||||
| #include <decaf/crypto.hxx> | #include <decaf/crypto.hxx> | ||||
| @@ -10,7 +10,7 @@ | |||||
| */ | */ | ||||
| #include <decaf.hxx> | #include <decaf.hxx> | ||||
| #include <decaf/shake.hxx> | |||||
| #include <decaf/spongerng.hxx> | |||||
| #include <decaf/crypto.h> | #include <decaf/crypto.h> | ||||
| #include <decaf/crypto.hxx> | #include <decaf/crypto.hxx> | ||||
| #include <stdio.h> | #include <stdio.h> | ||||
| @@ -10,7 +10,7 @@ | |||||
| */ | */ | ||||
| #include <decaf.hxx> | #include <decaf.hxx> | ||||
| #include <decaf/shake.hxx> | |||||
| #include <decaf/spongerng.hxx> | |||||
| #include <decaf/crypto.h> | #include <decaf/crypto.h> | ||||
| #include <decaf/crypto.hxx> | #include <decaf/crypto.hxx> | ||||
| #include <stdio.h> | #include <stdio.h> | ||||