@@ -211,7 +211,7 @@ public: | |||||
/** Move non-constructor */ | /** Move non-constructor */ | ||||
inline SecureBuffer(Block &&move) { *this = (Block &)move; } | 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) { | inline SecureBuffer& operator=(SecureBuffer &&move) { | ||||
clear(); | clear(); | ||||
data_ = move.data_; move.data_ = NULL; | data_ = move.data_; move.data_ = NULL; | ||||
@@ -21,6 +21,10 @@ | |||||
/** @cond internal */ | /** @cond internal */ | ||||
#define API_VIS __attribute__((visibility("default"))) | #define API_VIS __attribute__((visibility("default"))) | ||||
#define WARN_UNUSED __attribute__((warn_unused_result)) | #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 */ | /** @endcond */ | ||||
/* TODO: different containing structs for each primitive? */ | /* TODO: different containing structs for each primitive? */ | ||||
@@ -32,14 +36,8 @@ | |||||
/** @endcond */ | /** @endcond */ | ||||
} keccak_sponge_t[1]; | } keccak_sponge_t[1]; | ||||
struct kparams_s; | struct kparams_s; | ||||
typedef struct { uint64_t opaque; } strobe_params_t[1]; | |||||
#endif | #endif | ||||
typedef struct strobe_s { | |||||
keccak_sponge_t sponge; | |||||
strobe_params_t params; | |||||
} strobe_s, strobe_t[1]; | |||||
#ifdef __cplusplus | #ifdef __cplusplus | ||||
extern "C" { | extern "C" { | ||||
#endif | #endif | ||||
@@ -122,39 +120,39 @@ void sponge_hash ( | |||||
/** @cond internal */ | /** @cond internal */ | ||||
#define DECSHAKE(n) \ | #define DECSHAKE(n) \ | ||||
extern const struct kparams_s SHAKE##n##_params_s API_VIS; \ | 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); \ | 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); \ | 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); \ | sha3_output(sponge, out, outlen); \ | ||||
sponge_init(sponge, &SHAKE##n##_params_s); \ | 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); \ | 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); \ | sponge_destroy(sponge); \ | ||||
} | } | ||||
#define DECSHA3(n) \ | #define DECSHA3(n) \ | ||||
extern const struct kparams_s SHA3_##n##_params_s API_VIS; \ | 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); \ | 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); \ | 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); \ | sha3_output(sponge, out, outlen); \ | ||||
sponge_init(sponge, &SHA3_##n##_params_s); \ | 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); \ | 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); \ | sponge_destroy(sponge); \ | ||||
} | } | ||||
/** @endcond */ | /** @endcond */ | ||||
@@ -180,7 +178,7 @@ void spongerng_init_from_buffer ( | |||||
const uint8_t * __restrict__ in, | const uint8_t * __restrict__ in, | ||||
size_t len, | size_t len, | ||||
int deterministic | int deterministic | ||||
) API_VIS; | |||||
) NONNULL2 API_VIS; | |||||
/* FIXME!! This interface has the opposite retval convention from other functions | /* FIXME!! This interface has the opposite retval convention from other functions | ||||
* in the library. (0=success). Should they be harmonized? | * in the library. (0=success). Should they be harmonized? | ||||
@@ -205,7 +203,7 @@ int spongerng_init_from_file ( | |||||
const char *file, | const char *file, | ||||
size_t len, | size_t len, | ||||
int deterministic | int deterministic | ||||
) API_VIS WARN_UNUSED; | |||||
) NONNULL2 API_VIS WARN_UNUSED; | |||||
/* FIXME!! This interface has the opposite retval convention from other functions | /* FIXME!! This interface has the opposite retval convention from other functions | ||||
@@ -249,7 +247,16 @@ void spongerng_stir ( | |||||
keccak_sponge_t sponge, | keccak_sponge_t sponge, | ||||
const uint8_t * __restrict__ in, | const uint8_t * __restrict__ in, | ||||
size_t len | 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. | * @brief Initialize Strobe protocol context. | ||||
@@ -258,11 +265,88 @@ void spongerng_stir ( | |||||
* @param [in] am_client Nonzero if this party | * @param [in] am_client Nonzero if this party | ||||
* is the client. | * is the client. | ||||
*/ | */ | ||||
void strobe_init( | |||||
strobe_t strobe, | |||||
void strobe_init ( | |||||
keccak_sponge_t sponge, | |||||
const struct kparams_s *params, | const struct kparams_s *params, | ||||
uint8_t am_client | 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. | * @brief Produce an authenticator. | ||||
@@ -270,12 +354,61 @@ void strobe_init( | |||||
* @param [out] out The authenticator | * @param [out] out The authenticator | ||||
* @param len The length, which must be no more than | * @param len The length, which must be no more than | ||||
* @todo 32? | * @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, | unsigned char *out, | ||||
size_t len | 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. | * @brief Produce a session-bound pseudorandom value. | ||||
@@ -289,12 +422,19 @@ void strobe_produce_auth ( | |||||
* @param [inout] strobe The Strobe protocol context | * @param [inout] strobe The Strobe protocol context | ||||
* @param [out] out The authenticator | * @param [out] out The authenticator | ||||
* @param len The length. | * @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, | unsigned char *out, | ||||
size_t len | |||||
); | |||||
size_t len, | |||||
uint8_t more | |||||
) NONNULL2 API_VIS; | |||||
/** | /** | ||||
* @brief Verify an authenticator. | * @brief Verify an authenticator. | ||||
@@ -302,12 +442,15 @@ void strobe_prng ( | |||||
* @param [in] in The authenticator | * @param [in] in The authenticator | ||||
* @param len The length, which must be no more than | * @param len The length, which must be no more than | ||||
* @todo 32? | * @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 ( | decaf_bool_t strobe_verify_auth ( | ||||
strobe_t strobe, | |||||
keccak_sponge_t sponge, | |||||
const unsigned char *in, | const unsigned char *in, | ||||
size_t len | size_t len | ||||
); | |||||
) WARN_UNUSED NONNULL2 API_VIS; | |||||
/** | /** | ||||
* @brief Respecify Strobe protocol object's crypto. | * @brief Respecify Strobe protocol object's crypto. | ||||
@@ -315,19 +458,14 @@ decaf_bool_t strobe_verify_auth ( | |||||
* @param [in] Strobe parameter descriptor | * @param [in] Strobe parameter descriptor | ||||
* @param [in] am_client Nonzero if this party | * @param [in] am_client Nonzero if this party | ||||
* is the client. | * is the client. | ||||
* @retval DECAF_SUCCESS The operation applied successfully. | |||||
* @retval DECAF_FAILURE The operation failed because of a | |||||
* bad validator (or because you aren't keyed) | |||||
*/ | */ | ||||
void strobe_respec ( | |||||
strobe_t strobe, | |||||
decaf_bool_t strobe_respec ( | |||||
keccak_sponge_t sponge, | |||||
const struct kparams_s *params | 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 | #ifdef __cplusplus | ||||
} /* extern "C" */ | } /* extern "C" */ | ||||
@@ -335,5 +473,9 @@ void strobe_destroy ( | |||||
#undef API_VIS | #undef API_VIS | ||||
#undef WARN_UNUSED | #undef WARN_UNUSED | ||||
#undef NONNULL1 | |||||
#undef NONNULL13 | |||||
#undef NONNULL2 | |||||
#undef NONNULL3 | |||||
#endif /* __SHAKE_H__ */ | #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<384>::get_params() { return &SHA3_384_params_s; } | ||||
template<> const struct kparams_s *SHA3<512>::get_params() { return &SHA3_512_params_s; } | template<> 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 */ | /** Sponge-based random-number generator */ | ||||
class SpongeRng : private KeccakSponge { | class SpongeRng : private KeccakSponge { | ||||
@@ -194,6 +201,157 @@ decaf<448>::Point::Point(SpongeRng &rng, bool uniform) { | |||||
} | } | ||||
} | } | ||||
/**@endcond*/ | /**@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 */ | } /* namespace decaf */ | ||||
@@ -58,13 +58,9 @@ typedef union { | |||||
} kdomain_t[1]; | } kdomain_t[1]; | ||||
typedef struct kparams_s { | 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]; | } kparams_t[1]; | ||||
typedef struct strobe_params_s { | |||||
uint8_t client, _[7]; | |||||
} strobe_params_t[1]; | |||||
typedef struct keccak_sponge_s { | typedef struct keccak_sponge_s { | ||||
kdomain_t state; | kdomain_t state; | ||||
kparams_t params; | kparams_t params; | ||||
@@ -451,14 +447,18 @@ int spongerng_init_from_dev_urandom ( | |||||
return spongerng_init_from_file(sponge, "/dev/urandom", 64, 0); | 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. */ | /* Strobe is different in that its rate is padded by one byte. */ | ||||
void strobe_init( | void strobe_init( | ||||
strobe_t strobe, | |||||
keccak_sponge_t sponge, | |||||
const struct kparams_s *params, | const struct kparams_s *params, | ||||
uint8_t am_client | 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 ( | 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 ( | static void strobe_unduplex ( | ||||
keccak_sponge_t sponge, | keccak_sponge_t sponge, | ||||
unsigned char *out, | 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 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, | unsigned char *out, | ||||
const unsigned char *in, | 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, | unsigned char *out, | ||||
const unsigned char *in, | 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, | const unsigned char *in, | ||||
size_t len, | 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 | #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, | unsigned char *out, | ||||
size_t len | 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, | 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? */ | /* TODO: remove reliance on decaf? */ | ||||
decaf_bool_t strobe_verify_auth ( | decaf_bool_t strobe_verify_auth ( | ||||
strobe_t strobe, | |||||
keccak_sponge_t sponge, | |||||
const unsigned char *in, | const unsigned char *in, | ||||
size_t len | 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]; | 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 */ | /* Check for 0 */ | ||||
decaf_bool_t chain=0; | |||||
unsigned i; | unsigned i; | ||||
for (i=0; i<len; i++) { | for (i=0; i<len; i++) { | ||||
chain |= zero[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 | 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 */ | /* TODO: Keyak instances, etc */ |
@@ -66,6 +66,7 @@ static void printSI(double x, const char *unit, const char *spacer = " ") { | |||||
class Benchmark { | class Benchmark { | ||||
static const int NTESTS = 1000; | static const int NTESTS = 1000; | ||||
static double totalCy, totalS; | static double totalCy, totalS; | ||||
/* FIXME Tcy if get descheduled */ | |||||
public: | public: | ||||
int i, ntests; | int i, ntests; | ||||
double begin; | double begin; | ||||
@@ -138,10 +139,19 @@ int main(int argc, char **argv) { | |||||
decaf::SHAKE<128> shake1; | decaf::SHAKE<128> shake1; | ||||
decaf::SHAKE<256> shake2; | decaf::SHAKE<256> shake2; | ||||
decaf::SHA3<512> sha5; | decaf::SHA3<512> sha5; | ||||
decaf::Strobe strobe(decaf::Strobe::CLIENT); | |||||
unsigned char b1024[1024] = {1}; | unsigned char b1024[1024] = {1}; | ||||
for (Benchmark b("SHAKE128 1kiB", 30); b.iter(); ) { shake1 += decaf::TmpBuffer(b1024,1024); } | 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("SHAKE256 1kiB", 30); b.iter(); ) { shake2 += decaf::TmpBuffer(b1024,1024); } | ||||
for (Benchmark b("SHA3-512 1kiB", 30); b.iter(); ) { sha5 += 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 add", 1000); b.iter(); ) { s+=t; } | ||||
for (Benchmark b("Scalar times", 100); b.iter(); ) { s*=t; } | for (Benchmark b("Scalar times", 100); b.iter(); ) { s*=t; } | ||||
for (Benchmark b("Scalar inv", 1); b.iter(); ) { s.inverse(); } | for (Benchmark b("Scalar inv", 1); b.iter(); ) { s.inverse(); } | ||||