@@ -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(); } | |||