@@ -751,7 +751,7 @@ WARN_LOGFILE = | |||
# spaces. | |||
# Note: If this tag is empty the current directory is searched. | |||
INPUT = include | |||
INPUT = build/include | |||
# This tag can be used to specify the character encoding of the source files | |||
# that doxygen parses. Internally doxygen uses the UTF-8 encoding. Doxygen uses | |||
@@ -1548,7 +1548,7 @@ EXTRA_SEARCH_MAPPINGS = | |||
# If the GENERATE_LATEX tag is set to YES doxygen will generate LaTeX output. | |||
# The default value is: YES. | |||
GENERATE_LATEX = YES | |||
GENERATE_LATEX = NO | |||
# The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put. If a | |||
# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of | |||
@@ -243,8 +243,8 @@ $(BUILD_DOC)/timestamp: | |||
mkdir -p `dirname $@` | |||
touch $@ | |||
# | |||
# doc: Doxyfile $(BUILD_OBJ)/timestamp $(HEADERS) src/*.c src/$(FIELD)/$(ARCH)/*.c src/$(FIELD)/$(ARCH)/*.h | |||
# doxygen > /dev/null | |||
doc: Doxyfile $(BUILD_OBJ)/timestamp $(HEADERS) | |||
doxygen > /dev/null | |||
# # The eBATS benchmarking script | |||
# bat: $(BATNAME) | |||
@@ -3,14 +3,18 @@ from gen_file import gen_file | |||
crypto_h = gen_file( | |||
name = "decaf/crypto_%(shortname)s.h", | |||
doc = """ | |||
@brief Example Decaf crypto routines. | |||
Example Decaf crypto routines. | |||
@warning These are merely examples, though they ought to be secure. But real | |||
protocols will decide differently on magic numbers, formats, which items to | |||
hash, etc. | |||
@warning Experimental! The names, parameter orders etc are likely to change. | |||
""", code = """ | |||
#include <decaf/%(c_ns)s.h> | |||
#include <decaf/shake.h> | |||
#include <decaf/strobe.h> | |||
#ifdef __cplusplus | |||
extern "C" { | |||
#endif | |||
/** Number of bytes for a symmetric key (expanded to full key) */ | |||
#define %(C_NS)s_SYMMETRIC_KEY_BYTES 32 | |||
@@ -39,13 +43,9 @@ typedef struct { | |||
%(c_ns)s_private_key_s, | |||
/** A private key (gmp array[1] style). */ | |||
%(c_ns)s_private_key_t[1]; | |||
#ifdef __cplusplus | |||
extern "C" { | |||
#endif | |||
/** | |||
* @brief Derive a key from its compressed form. | |||
* Derive a key from its compressed form. | |||
* @param [out] priv The derived private key. | |||
* @param [in] proto The compressed or proto-key, which must be 32 random bytes. | |||
*/ | |||
@@ -55,14 +55,14 @@ void %(c_ns)s_derive_private_key ( | |||
) NONNULL2 API_VIS; | |||
/** | |||
* @brief Destroy a private key. | |||
* Destroy a private key. | |||
*/ | |||
void %(c_ns)s_destroy_private_key ( | |||
%(c_ns)s_private_key_t priv | |||
) NONNULL1 API_VIS; | |||
/** | |||
* @brief Convert a private key to a public one. | |||
* Convert a private key to a public one. | |||
* @param [out] pub The extracted private key. | |||
* @param [in] priv The private key. | |||
*/ | |||
@@ -72,7 +72,7 @@ void %(c_ns)s_private_to_public ( | |||
) NONNULL2 API_VIS; | |||
/** | |||
* @brief Compute a Diffie-Hellman shared secret. | |||
* Compute a Diffie-Hellman shared secret. | |||
* | |||
* This is an example routine; real protocols would use something | |||
* protocol-specific. | |||
@@ -96,7 +96,7 @@ decaf_error_t | |||
) NONNULL134 WARN_UNUSED API_VIS; | |||
/** | |||
* @brief Sign a message from a STROBE context. | |||
* Sign a message from a STROBE context. | |||
* | |||
* @param [out] sig The signature. | |||
* @param [in] priv Your private key. | |||
@@ -110,7 +110,7 @@ void | |||
) NONNULL3 API_VIS; | |||
/** | |||
* @brief Sign a message. | |||
* Sign a message. | |||
* | |||
* @param [out] sig The signature. | |||
* @param [in] priv Your private key. | |||
@@ -126,7 +126,7 @@ void | |||
) NONNULL3 API_VIS; | |||
/** | |||
* @brief Verify a signed message from its STROBE context. | |||
* Verify a signed message from its STROBE context. | |||
* | |||
* @param [in] sig The signature. | |||
* @param [in] pub The public key. | |||
@@ -143,7 +143,7 @@ decaf_error_t | |||
) NONNULL3 API_VIS WARN_UNUSED; | |||
/** | |||
* @brief Verify a signed message. | |||
* Verify a signed message. | |||
* | |||
* @param [in] sig The signature. | |||
* @param [in] pub The public key. | |||
@@ -3,7 +3,7 @@ from gen_file import gen_file | |||
crypto_hxx = gen_file( | |||
name = "decaf/crypto_%(shortname)s.hxx", | |||
doc = """ | |||
@brief Example Decaf cyrpto routines, C++ wrapper. | |||
Example Decaf cyrpto routines, C++ wrapper. | |||
@warning These are merely examples, though they ought to be secure. But real | |||
protocols will decide differently on magic numbers, formats, which items to | |||
hash, etc. | |||
@@ -21,51 +21,56 @@ crypto_hxx = gen_file( | |||
/** @endcond */ | |||
namespace decaf { | |||
/** A public key for crypto over some Group */ | |||
template <typename Group> class PublicKey; | |||
/** A private key for crypto over some Group */ | |||
template <typename Group> class PrivateKey; | |||
/** A public key for crypto over %(name)s */ | |||
template<> class PublicKey<%(cxx_ns)s> | |||
: public Serializable< PublicKey<%(cxx_ns)s> > { | |||
private: | |||
/** @cond internal */ | |||
typedef %(c_ns)s_public_key_t Wrapped; | |||
Wrapped wrapped; | |||
template<class Group> friend class PrivateKey; | |||
/** @endcond */ | |||
public: | |||
/** @brief Underlying group */ | |||
/** Underlying group */ | |||
typedef %(cxx_ns)s Group; | |||
/** @brief Signature size. */ | |||
/** Signature size. */ | |||
static const size_t SIG_BYTES = sizeof(%(c_ns)s_signature_t); | |||
/** @brief Serialization size. */ | |||
/** Serialization size. */ | |||
static const size_t SER_BYTES = sizeof(Wrapped); | |||
/* TODO: convenience types like signature? */ | |||
/** @brief Read a private key from a string*/ | |||
/** Read a private key from a string*/ | |||
inline explicit PublicKey(const FixedBlock<SER_BYTES> &b) NOEXCEPT { | |||
memcpy(wrapped,b.data(),sizeof(wrapped)); | |||
} | |||
/** @brief Read a private key from a string*/ | |||
/** Read a private key from a string*/ | |||
inline explicit PublicKey(const PrivateKey<%(cxx_ns)s> &b) NOEXCEPT; | |||
/** @brief Create but don't initialize */ | |||
/** Create but don't initialize */ | |||
inline explicit PublicKey(const NOINIT&) NOEXCEPT { } | |||
/** @brief Serialize into a buffer. */ | |||
/** Serialize into a buffer. */ | |||
inline void serializeInto(unsigned char *x) const NOEXCEPT { | |||
memcpy(x,wrapped,sizeof(wrapped)); | |||
} | |||
/** @brief Serialization size. */ | |||
/** Serialization size. */ | |||
inline size_t serSize() const NOEXCEPT { return SER_BYTES; } | |||
/* TODO: verify_strobe */ | |||
/** @brief Verify a message */ | |||
/** Verify a message */ | |||
inline void verify( | |||
const Block &message, | |||
const FixedBlock<SIG_BYTES> &sig | |||
@@ -76,71 +81,73 @@ public: | |||
} | |||
}; | |||
/** A private key for crypto over %(name)s */ | |||
template<> class PrivateKey<%(cxx_ns)s> | |||
: public Serializable< PrivateKey<%(cxx_ns)s> > { | |||
private: | |||
/** @cond internal */ | |||
typedef %(c_ns)s_private_key_t Wrapped; | |||
Wrapped wrapped; | |||
template<class Group> friend class PublicKey; | |||
/** @endcond */ | |||
public: | |||
/** @brief Underlying group */ | |||
/** Underlying group */ | |||
typedef %(cxx_ns)s Group; | |||
/** @brief Signature size. */ | |||
/** Signature size. */ | |||
static const size_t SIG_BYTES = sizeof(%(c_ns)s_signature_t); | |||
/** @brief Serialization size. */ | |||
/** Serialization size. */ | |||
static const size_t SER_BYTES = sizeof(Wrapped); | |||
/** @brief Compressed size. */ | |||
/** Compressed size. */ | |||
static const size_t SYM_BYTES = %(C_NS)s_SYMMETRIC_KEY_BYTES; | |||
/** @brief Create but don't initialize */ | |||
/** Create but don't initialize */ | |||
inline explicit PrivateKey(const NOINIT&) NOEXCEPT { } | |||
/** @brief Read a private key from a string*/ | |||
/** Read a private key from a string*/ | |||
inline explicit PrivateKey(const FixedBlock<SER_BYTES> &b) NOEXCEPT { | |||
memcpy(wrapped,b.data(),sizeof(wrapped)); | |||
} | |||
/** @brief Read a private key from a string*/ | |||
/** Read a private key from a string*/ | |||
inline explicit PrivateKey(const FixedBlock<SYM_BYTES> &b) NOEXCEPT { | |||
%(c_ns)s_derive_private_key(wrapped, b.data()); | |||
} | |||
/** @brief Create at random */ | |||
/** Create at random */ | |||
inline explicit PrivateKey(Rng &r) NOEXCEPT { | |||
FixedArrayBuffer<SYM_BYTES> tmp(r); | |||
%(c_ns)s_derive_private_key(wrapped, tmp.data()); | |||
} | |||
/** @brief Secure destructor */ | |||
/** Secure destructor */ | |||
inline ~PrivateKey() NOEXCEPT { | |||
%(c_ns)s_destroy_private_key(wrapped); | |||
} | |||
/** @brief Serialization size. */ | |||
/** Serialization size. */ | |||
inline size_t serSize() const NOEXCEPT { return SER_BYTES; } | |||
/** @brief Serialize into a buffer. */ | |||
/** Serialize into a buffer. */ | |||
inline void serializeInto(unsigned char *x) const NOEXCEPT { | |||
memcpy(x,wrapped,sizeof(wrapped)); | |||
} | |||
/** @brief Compressed serialize. */ | |||
/** Compressed serialize. */ | |||
inline SecureBuffer compress() const throw(std::bad_alloc) { | |||
SecureBuffer ret(sizeof(wrapped->sym)); | |||
memcpy(ret.data(),wrapped->sym,sizeof(wrapped->sym)); | |||
return ret; | |||
} | |||
/** @brief Get the public key */ | |||
/** Get the public key */ | |||
inline PublicKey<%(cxx_ns)s> pub() const NOEXCEPT { | |||
PublicKey<%(cxx_ns)s> ret(*this); return ret; | |||
} | |||
/** @brief Derive a shared secret */ | |||
/** Derive a shared secret */ | |||
inline SecureBuffer sharedSecret( | |||
const PublicKey<%(cxx_ns)s> &pub, | |||
size_t bytes, | |||
@@ -153,7 +160,7 @@ public: | |||
return ret; | |||
} | |||
/** @brief Sign a message. */ | |||
/** Sign a message. */ | |||
inline SecureBuffer sign(const Block &message) const { | |||
SecureBuffer sig(SIG_BYTES); | |||
%(c_ns)s_sign(sig.data(), wrapped, message.data(), message.size()); | |||
@@ -10,19 +10,23 @@ decaf_h = gen_file( | |||
extern "C" { | |||
#endif | |||
/** @cond internal */ | |||
#define %(C_NS)s_LIMBS (%(gf_bits)d/DECAF_WORD_BITS) | |||
#define %(C_NS)s_SCALAR_BITS %(scalar_bits)d | |||
#define %(C_NS)s_SCALAR_LIMBS ((%(scalar_bits)d-1)/DECAF_WORD_BITS+1) | |||
/** @endcond */ | |||
/** The number of bits in a scalar */ | |||
#define %(C_NS)s_SCALAR_BITS %(scalar_bits)d | |||
/** Galois field element internal structure */ | |||
/** @cond internal */ | |||
#ifndef __%(C_NS)s_GF_DEFINED__ | |||
#define __%(C_NS)s_GF_DEFINED__ 1 | |||
/** @brief Galois field element internal structure */ | |||
typedef struct gf_%(longnum)s_s { | |||
/** @cond internal */ | |||
decaf_word_t limb[%(C_NS)s_LIMBS]; | |||
/** @endcond */ | |||
} __attribute__((aligned(32))) gf_%(longnum)s_s, gf_%(longnum)s_t[1]; | |||
#endif /* __%(C_NS)s_GF_DEFINED__ */ | |||
/** @endcond */ | |||
/** Number of bytes in a serialized point. */ | |||
#define %(C_NS)s_SER_BYTES %(ser_bytes)d | |||
@@ -393,16 +397,17 @@ void %(c_ns)s_point_double_scalarmul ( | |||
const %(c_ns)s_scalar_t scalar2 | |||
) API_VIS NONNULL5 NOINLINE; | |||
/* | |||
* @brief Multiply one base point by two scalars: | |||
/** | |||
* Multiply one base point by two scalars: | |||
* | |||
* a1 = scalar1 * base | |||
* a2 = scalar2 * base | |||
* | |||
* Equivalent to two calls to %(c_ns)s_point_scalarmul, but may be | |||
* faster. | |||
* | |||
* @param [out] a1 The first multiple | |||
* @param [out] a2 The second multiple | |||
* @param [out] a1 The first multiple. It may be the same as the input point. | |||
* @param [out] a2 The second multiple. It may be the same as the input point. | |||
* @param [in] base1 A point to be scaled. | |||
* @param [in] scalar1 A first scalar to multiply by. | |||
* @param [in] scalar2 A second scalar to multiply by. | |||
@@ -410,7 +415,7 @@ void %(c_ns)s_point_double_scalarmul ( | |||
void %(c_ns)s_point_dual_scalarmul ( | |||
%(c_ns)s_point_t a1, | |||
%(c_ns)s_point_t a2, | |||
const %(c_ns)s_point_t b, | |||
const %(c_ns)s_point_t base1, | |||
const %(c_ns)s_scalar_t scalar1, | |||
const %(c_ns)s_scalar_t scalar2 | |||
) API_VIS NONNULL5 NOINLINE; | |||
@@ -441,7 +446,7 @@ void %(c_ns)s_base_double_scalarmul_non_secret ( | |||
* @brief Constant-time decision between two points. If pick_b | |||
* is zero, out = a; else out = b. | |||
* | |||
* @param [out] q The output. It may be the same as either input. | |||
* @param [out] out The output. It may be the same as either input. | |||
* @param [in] a Any point. | |||
* @param [in] b Any point. | |||
* @param [in] pick_b If nonzero, choose point b. | |||
@@ -457,7 +462,7 @@ void %(c_ns)s_point_cond_sel ( | |||
* @brief Constant-time decision between two scalars. If pick_b | |||
* is zero, out = a; else out = b. | |||
* | |||
* @param [out] q The output. It may be the same as either input. | |||
* @param [out] out The output. It may be the same as either input. | |||
* @param [in] a Any scalar. | |||
* @param [in] b Any scalar. | |||
* @param [in] pick_b If nonzero, choose scalar b. | |||
@@ -3,7 +3,7 @@ from gen_file import gen_file | |||
decaf_hxx = gen_file( | |||
name = "decaf/%(c_ns)s.hxx", | |||
doc = """ | |||
@brief A group of prime order p, C++ wrapper. | |||
A group of prime order p, C++ wrapper. | |||
The Decaf library implements cryptographic operations on a an elliptic curve | |||
group of prime order p. It accomplishes this by using a twisted Edwards | |||
@@ -40,7 +40,7 @@ decaf_hxx = gen_file( | |||
namespace decaf { | |||
/** | |||
* @brief %(iso_to)s/Decaf instantiation of group. | |||
* %(iso_to)s/Decaf instantiation of group. | |||
*/ | |||
struct %(cxx_ns)s { | |||
@@ -59,61 +59,63 @@ class Precomputed; | |||
/** @endcond */ | |||
/** | |||
* @brief A scalar modulo the curve order. | |||
* A scalar modulo the curve order. | |||
* Supports the usual arithmetic operations, all in constant time. | |||
*/ | |||
class Scalar : public Serializable<Scalar> { | |||
private: | |||
/** @brief wrapped C type */ | |||
/** wrapped C type */ | |||
typedef %(c_ns)s_scalar_t Wrapped; | |||
public: | |||
/** @brief Size of a serialized element */ | |||
/** Size of a serialized element */ | |||
static const size_t SER_BYTES = %(C_NS)s_SCALAR_BYTES; | |||
/** @brief access to the underlying scalar object */ | |||
/** access to the underlying scalar object */ | |||
Wrapped s; | |||
/** @brief Don't initialize. */ | |||
/** @cond internal */ | |||
/** Don't initialize. */ | |||
inline Scalar(const NOINIT &) NOEXCEPT {} | |||
/** @endcond */ | |||
/** @brief Set to an unsigned word */ | |||
/** Set to an unsigned word */ | |||
inline Scalar(const decaf_word_t w) NOEXCEPT { *this = w; } | |||
/** @brief Set to a signed word */ | |||
/** Set to a signed word */ | |||
inline Scalar(const int w) NOEXCEPT { *this = w; } | |||
/** @brief Construct from RNG */ | |||
/** Construct from RNG */ | |||
inline explicit Scalar(Rng &rng) NOEXCEPT { | |||
FixedArrayBuffer<SER_BYTES> sb(rng); | |||
*this = sb; | |||
} | |||
/** @brief Construct from decaf_scalar_t object. */ | |||
/** Construct from decaf_scalar_t object. */ | |||
inline Scalar(const Wrapped &t = %(c_ns)s_scalar_zero) NOEXCEPT { %(c_ns)s_scalar_copy(s,t); } | |||
/** @brief Copy constructor. */ | |||
/** Copy constructor. */ | |||
inline Scalar(const Scalar &x) NOEXCEPT { *this = x; } | |||
/** @brief Construct from arbitrary-length little-endian byte sequence. */ | |||
/** Construct from arbitrary-length little-endian byte sequence. */ | |||
inline Scalar(const Block &buffer) NOEXCEPT { *this = buffer; } | |||
/** @brief Serializable instance */ | |||
/** Serializable instance */ | |||
inline size_t serSize() const NOEXCEPT { return SER_BYTES; } | |||
/** @brief Serializable instance */ | |||
/** Serializable instance */ | |||
inline void serializeInto(unsigned char *buffer) const NOEXCEPT { | |||
%(c_ns)s_scalar_encode(buffer, s); | |||
} | |||
/** @brief Assignment. */ | |||
/** Assignment. */ | |||
inline Scalar& operator=(const Scalar &x) NOEXCEPT { %(c_ns)s_scalar_copy(s,x.s); return *this; } | |||
/** @brief Assign from unsigned word. */ | |||
/** Assign from unsigned word. */ | |||
inline Scalar& operator=(decaf_word_t w) NOEXCEPT { %(c_ns)s_scalar_set_unsigned(s,w); return *this; } | |||
/** @brief Assign from signed int. */ | |||
/** Assign from signed int. */ | |||
inline Scalar& operator=(int w) NOEXCEPT { | |||
Scalar t(-(decaf_word_t)INT_MIN); | |||
%(c_ns)s_scalar_set_unsigned(s,(decaf_word_t)w - (decaf_word_t)INT_MIN); | |||
@@ -124,13 +126,13 @@ public: | |||
/** Destructor securely zeorizes the scalar. */ | |||
inline ~Scalar() NOEXCEPT { %(c_ns)s_scalar_destroy(s); } | |||
/** @brief Assign from arbitrary-length little-endian byte sequence in a Block. */ | |||
/** Assign from arbitrary-length little-endian byte sequence in a Block. */ | |||
inline Scalar &operator=(const Block &bl) NOEXCEPT { | |||
%(c_ns)s_scalar_decode_long(s,bl.data(),bl.size()); return *this; | |||
} | |||
/** | |||
* @brief Decode from correct-length little-endian byte sequence. | |||
* Decode from correct-length little-endian byte sequence. | |||
* @return DECAF_FAILURE if the scalar is greater than or equal to the group order q. | |||
*/ | |||
static inline decaf_error_t __attribute__((warn_unused_result)) decode ( | |||
@@ -160,7 +162,7 @@ public: | |||
/** Negate */ | |||
inline Scalar operator- () const NOEXCEPT { Scalar r((NOINIT())); %(c_ns)s_scalar_sub(r.s,%(c_ns)s_scalar_zero,s); return r; } | |||
/** @brief Invert with Fermat's Little Theorem (slow!). If *this == 0, return 0. */ | |||
/** Invert with Fermat's Little Theorem (slow!). If *this == 0, return 0. */ | |||
inline Scalar inverse() const throw(CryptoException) { | |||
Scalar r; | |||
if (DECAF_SUCCESS != %(c_ns)s_scalar_invert(r.s,s)) { | |||
@@ -169,25 +171,25 @@ public: | |||
return r; | |||
} | |||
/** @brief Divide by inverting q. If q == 0, return 0. */ | |||
/** Divide by inverting q. If q == 0, return 0. */ | |||
inline Scalar operator/ (const Scalar &q) const throw(CryptoException) { return *this * q.inverse(); } | |||
/** @brief Divide by inverting q. If q == 0, return 0. */ | |||
/** Divide by inverting q. If q == 0, return 0. */ | |||
inline Scalar &operator/=(const Scalar &q) throw(CryptoException) { return *this *= q.inverse(); } | |||
/** @brief Compare in constant time */ | |||
/** Compare in constant time */ | |||
inline bool operator!=(const Scalar &q) const NOEXCEPT { return !(*this == q); } | |||
/** @brief Compare in constant time */ | |||
/** Compare in constant time */ | |||
inline bool operator==(const Scalar &q) const NOEXCEPT { return !!%(c_ns)s_scalar_eq(s,q.s); } | |||
/** @brief Scalarmul with scalar on left. */ | |||
/** Scalarmul with scalar on left. */ | |||
inline Point operator* (const Point &q) const NOEXCEPT { return q * (*this); } | |||
/** @brief Scalarmul-precomputed with scalar on left. */ | |||
/** Scalarmul-precomputed with scalar on left. */ | |||
inline Point operator* (const Precomputed &q) const NOEXCEPT { return q * (*this); } | |||
/** @brief Direct scalar multiplication. */ | |||
/** Direct scalar multiplication. */ | |||
inline SecureBuffer direct_scalarmul( | |||
const Block &in, | |||
decaf_bool_t allow_identity=DECAF_FALSE, | |||
@@ -196,42 +198,44 @@ public: | |||
}; | |||
/** | |||
* @brief Element of prime-order group. | |||
* Element of prime-order group. | |||
*/ | |||
class Point : public Serializable<Point> { | |||
private: | |||
/** @brief wrapped C type */ | |||
/** wrapped C type */ | |||
typedef %(c_ns)s_point_t Wrapped; | |||
public: | |||
/** @brief Size of a serialized element */ | |||
/** Size of a serialized element */ | |||
static const size_t SER_BYTES = %(C_NS)s_SER_BYTES; | |||
/** @brief Bytes required for hash */ | |||
/** Bytes required for hash */ | |||
static const size_t HASH_BYTES = SER_BYTES; | |||
/** @brief Size of a stegged element */ | |||
/** Size of a stegged element */ | |||
static const size_t STEG_BYTES = HASH_BYTES * 2; | |||
/** The c-level object. */ | |||
Wrapped p; | |||
/** @brief Don't initialize. */ | |||
/** @cond internal */ | |||
/** Don't initialize. */ | |||
inline Point(const NOINIT &) NOEXCEPT {} | |||
/** @endcond */ | |||
/** @brief Constructor sets to identity by default. */ | |||
/** Constructor sets to identity by default. */ | |||
inline Point(const Wrapped &q = %(c_ns)s_point_identity) NOEXCEPT { %(c_ns)s_point_copy(p,q); } | |||
/** @brief Copy constructor. */ | |||
/** Copy constructor. */ | |||
inline Point(const Point &q) NOEXCEPT { *this = q; } | |||
/** @brief Assignment. */ | |||
/** Assignment. */ | |||
inline Point& operator=(const Point &q) NOEXCEPT { %(c_ns)s_point_copy(p,q.p); return *this; } | |||
/** @brief Destructor securely zeorizes the point. */ | |||
/** Destructor securely zeorizes the point. */ | |||
inline ~Point() NOEXCEPT { %(c_ns)s_point_destroy(p); } | |||
/** @brief Construct from RNG */ | |||
/** Construct from RNG */ | |||
inline explicit Point(Rng &rng, bool uniform = true) NOEXCEPT { | |||
if (uniform) { | |||
FixedArrayBuffer<2*HASH_BYTES> b(rng); | |||
@@ -243,7 +247,7 @@ public: | |||
} | |||
/** | |||
* @brief Initialize from a fixed-length byte string. | |||
* Initialize from a fixed-length byte string. | |||
* The all-zero string maps to the identity. | |||
* | |||
* @throw CryptoException the string was the wrong length, or wasn't the encoding of a point, | |||
@@ -257,7 +261,7 @@ public: | |||
} | |||
/** | |||
* @brief Initialize from C++ fixed-length byte string. | |||
* Initialize from C++ fixed-length byte string. | |||
* The all-zero string maps to the identity. | |||
* | |||
* @retval DECAF_SUCCESS the string was successfully decoded. | |||
@@ -271,7 +275,7 @@ public: | |||
} | |||
/** | |||
* @brief Map uniformly to the curve from a hash buffer. | |||
* Map uniformly to the curve from a hash buffer. | |||
* The empty or all-zero string maps to the identity, as does the string "\\x01". | |||
* If the buffer is shorter than 2*HASH_BYTES, well, it won't be as uniform, | |||
* but the buffer will be zero-padded on the right. | |||
@@ -281,7 +285,7 @@ public: | |||
} | |||
/** | |||
* @brief Map to the curve from a hash buffer. | |||
* Map to the curve from a hash buffer. | |||
* The empty or all-zero string maps to the identity, as does the string "\\x01". | |||
* If the buffer is shorter than 2*HASH_BYTES, well, it won't be as uniform, | |||
* but the buffer will be zero-padded on the right. | |||
@@ -303,7 +307,7 @@ public: | |||
} | |||
/** | |||
* @brief Encode to string. The identity encodes to the all-zero string. | |||
* Encode to string. The identity encodes to the all-zero string. | |||
*/ | |||
inline operator SecureBuffer() const { | |||
SecureBuffer buffer(SER_BYTES); | |||
@@ -311,64 +315,64 @@ public: | |||
return buffer; | |||
} | |||
/** @brief Serializable instance */ | |||
/** Serializable instance */ | |||
inline size_t serSize() const NOEXCEPT { return SER_BYTES; } | |||
/** @brief Serializable instance */ | |||
/** Serializable instance */ | |||
inline void serializeInto(unsigned char *buffer) const NOEXCEPT { | |||
%(c_ns)s_point_encode(buffer, p); | |||
} | |||
/** @brief Point add. */ | |||
/** Point add. */ | |||
inline Point operator+ (const Point &q) const NOEXCEPT { Point r((NOINIT())); %(c_ns)s_point_add(r.p,p,q.p); return r; } | |||
/** @brief Point add. */ | |||
/** Point add. */ | |||
inline Point &operator+=(const Point &q) NOEXCEPT { %(c_ns)s_point_add(p,p,q.p); return *this; } | |||
/** @brief Point subtract. */ | |||
/** Point subtract. */ | |||
inline Point operator- (const Point &q) const NOEXCEPT { Point r((NOINIT())); %(c_ns)s_point_sub(r.p,p,q.p); return r; } | |||
/** @brief Point subtract. */ | |||
/** Point subtract. */ | |||
inline Point &operator-=(const Point &q) NOEXCEPT { %(c_ns)s_point_sub(p,p,q.p); return *this; } | |||
/** @brief Point negate. */ | |||
/** Point negate. */ | |||
inline Point operator- () const NOEXCEPT { Point r((NOINIT())); %(c_ns)s_point_negate(r.p,p); return r; } | |||
/** @brief Double the point out of place. */ | |||
/** Double the point out of place. */ | |||
inline Point times_two () const NOEXCEPT { Point r((NOINIT())); %(c_ns)s_point_double(r.p,p); return r; } | |||
/** @brief Double the point in place. */ | |||
/** Double the point in place. */ | |||
inline Point &double_in_place() NOEXCEPT { %(c_ns)s_point_double(p,p); return *this; } | |||
/** @brief Constant-time compare. */ | |||
/** Constant-time compare. */ | |||
inline bool operator!=(const Point &q) const NOEXCEPT { return ! %(c_ns)s_point_eq(p,q.p); } | |||
/** @brief Constant-time compare. */ | |||
/** Constant-time compare. */ | |||
inline bool operator==(const Point &q) const NOEXCEPT { return !!%(c_ns)s_point_eq(p,q.p); } | |||
/** @brief Scalar multiply. */ | |||
/** Scalar multiply. */ | |||
inline Point operator* (const Scalar &s) const NOEXCEPT { Point r((NOINIT())); %(c_ns)s_point_scalarmul(r.p,p,s.s); return r; } | |||
/** @brief Scalar multiply in place. */ | |||
/** Scalar multiply in place. */ | |||
inline Point &operator*=(const Scalar &s) NOEXCEPT { %(c_ns)s_point_scalarmul(p,p,s.s); return *this; } | |||
/** @brief Multiply by s.inverse(). If s=0, maps to the identity. */ | |||
/** Multiply by s.inverse(). If s=0, maps to the identity. */ | |||
inline Point operator/ (const Scalar &s) const throw(CryptoException) { return (*this) * s.inverse(); } | |||
/** @brief Multiply by s.inverse(). If s=0, maps to the identity. */ | |||
/** Multiply by s.inverse(). If s=0, maps to the identity. */ | |||
inline Point &operator/=(const Scalar &s) throw(CryptoException) { return (*this) *= s.inverse(); } | |||
/** @brief Validate / sanity check */ | |||
/** Validate / sanity check */ | |||
inline bool validate() const NOEXCEPT { return %(c_ns)s_point_valid(p); } | |||
/** @brief Double-scalar multiply, equivalent to q*qs + r*rs but faster. */ | |||
/** Double-scalar multiply, equivalent to q*qs + r*rs but faster. */ | |||
static inline Point double_scalarmul ( | |||
const Point &q, const Scalar &qs, const Point &r, const Scalar &rs | |||
) NOEXCEPT { | |||
Point p((NOINIT())); %(c_ns)s_point_double_scalarmul(p.p,q.p,qs.s,r.p,rs.s); return p; | |||
} | |||
/** @brief Dual-scalar multiply, equivalent to this*r1, this*r2 but faster. */ | |||
/** Dual-scalar multiply, equivalent to this*r1, this*r2 but faster. */ | |||
inline void dual_scalarmul ( | |||
Point &q1, Point &q2, const Scalar &r1, const Scalar &r2 | |||
) const NOEXCEPT { | |||
@@ -376,7 +380,7 @@ public: | |||
} | |||
/** | |||
* @brief Double-scalar multiply, equivalent to q*qs + r*rs but faster. | |||
* Double-scalar multiply, equivalent to q*qs + r*rs but faster. | |||
* For those who like their scalars before the point. | |||
*/ | |||
static inline Point double_scalarmul ( | |||
@@ -386,7 +390,7 @@ public: | |||
} | |||
/** | |||
* @brief Double-scalar multiply: this point by the first scalar and base by the second scalar. | |||
* Double-scalar multiply: this point by the first scalar and base by the second scalar. | |||
* @warning This function takes variable time, and may leak the scalars (or points, but currently | |||
* it doesn't). | |||
*/ | |||
@@ -394,21 +398,21 @@ public: | |||
Point r((NOINIT())); %(c_ns)s_base_double_scalarmul_non_secret(r.p,s_base.s,p,s.s); return r; | |||
} | |||
/** @brief Return a point equal to *this, whose internal data is rotated by a torsion element. */ | |||
/** Return a point equal to *this, whose internal data is rotated by a torsion element. */ | |||
inline Point debugging_torque() const NOEXCEPT { | |||
Point q; | |||
%(c_ns)s_point_debugging_torque(q.p,p); | |||
return q; | |||
} | |||
/** @brief Return a point equal to *this, whose internal data has a modified representation. */ | |||
/** Return a point equal to *this, whose internal data has a modified representation. */ | |||
inline Point debugging_pscale(const FixedBlock<SER_BYTES> factor) const NOEXCEPT { | |||
Point q; | |||
%(c_ns)s_point_debugging_pscale(q.p,p,factor.data()); | |||
return q; | |||
} | |||
/** @brief Return a point equal to *this, whose internal data has a randomized representation. */ | |||
/** Return a point equal to *this, whose internal data has a randomized representation. */ | |||
inline Point debugging_pscale(Rng &r) const NOEXCEPT { | |||
FixedArrayBuffer<SER_BYTES> sb(r); | |||
return debugging_pscale(sb); | |||
@@ -441,7 +445,7 @@ public: | |||
return decaf_succeed_if(ret); | |||
} | |||
/** @brief Steganographically encode this */ | |||
/** Steganographically encode this */ | |||
inline SecureBuffer steg_encode(Rng &rng, size_t size=STEG_BYTES) const throw(std::bad_alloc, LengthException) { | |||
if (size <= HASH_BYTES + 4 || size > 2*HASH_BYTES) throw LengthException(); | |||
SecureBuffer out(STEG_BYTES); | |||
@@ -453,15 +457,15 @@ public: | |||
return out; | |||
} | |||
/** @brief Return the base point */ | |||
/** Return the base point */ | |||
static inline const Point base() NOEXCEPT { return Point(%(c_ns)s_point_base); } | |||
/** @brief Return the identity point */ | |||
/** Return the identity point */ | |||
static inline const Point identity() NOEXCEPT { return Point(%(c_ns)s_point_identity); } | |||
}; | |||
/** | |||
* @brief Precomputed table of points. | |||
* Precomputed table of points. | |||
* Minor difficulties arise here because the decaf API doesn't expose, as a constant, how big such an object is. | |||
* Therefore we have to call malloc() or friends, but that's probably for the best, because you don't want to | |||
* stack-allocate a 15kiB object anyway. | |||
@@ -481,7 +485,7 @@ public: | |||
inline ~Precomputed() NOEXCEPT { clear(); } | |||
/** | |||
* @brief Initialize from underlying type, declared as a reference to prevent | |||
* Initialize from underlying type, declared as a reference to prevent | |||
* it from being called with 0, thereby breaking override. | |||
* | |||
* The underlying object must remain valid throughout the lifetime of this one. | |||
@@ -497,18 +501,18 @@ public: | |||
#if __cplusplus >= 201103L | |||
/** @brief Move-assign operator */ | |||
/** Move-assign operator */ | |||
inline Precomputed &operator=(Precomputed &&it) NOEXCEPT { | |||
OwnedOrUnowned<Precomputed,Precomputed_U>::operator= (it); | |||
return *this; | |||
} | |||
/** @brief Move constructor */ | |||
/** Move constructor */ | |||
inline Precomputed(Precomputed &&it) NOEXCEPT : OwnedOrUnowned<Precomputed,Precomputed_U>() { | |||
*this = it; | |||
} | |||
/** @brief Undelete copy operator */ | |||
/** Undelete copy operator */ | |||
inline Precomputed &operator=(const Precomputed &it) NOEXCEPT { | |||
OwnedOrUnowned<Precomputed,Precomputed_U>::operator= (it); | |||
return *this; | |||
@@ -516,7 +520,7 @@ public: | |||
#endif | |||
/** | |||
* @brief Initilaize from point. Must allocate memory, and may throw. | |||
* Initilaize from point. Must allocate memory, and may throw. | |||
*/ | |||
inline Precomputed &operator=(const Point &it) throw(std::bad_alloc) { | |||
alloc(); | |||
@@ -525,24 +529,24 @@ public: | |||
} | |||
/** | |||
* @brief Copy constructor. | |||
* Copy constructor. | |||
*/ | |||
inline Precomputed(const Precomputed &it) throw(std::bad_alloc) | |||
: OwnedOrUnowned<Precomputed,Precomputed_U>() { *this = it; } | |||
/** | |||
* @brief Constructor which initializes from point. | |||
* Constructor which initializes from point. | |||
*/ | |||
inline explicit Precomputed(const Point &it) throw(std::bad_alloc) | |||
: OwnedOrUnowned<Precomputed,Precomputed_U>() { *this = it; } | |||
/** @brief Fixed base scalarmul. */ | |||
/** Fixed base scalarmul. */ | |||
inline Point operator* (const Scalar &s) const NOEXCEPT { Point r; %(c_ns)s_precomputed_scalarmul(r.p,get(),s.s); return r; } | |||
/** @brief Multiply by s.inverse(). If s=0, maps to the identity. */ | |||
/** Multiply by s.inverse(). If s=0, maps to the identity. */ | |||
inline Point operator/ (const Scalar &s) const throw(CryptoException) { return (*this) * s.inverse(); } | |||
/** @brief Return the table for the base point. */ | |||
/** Return the table for the base point. */ | |||
static inline const Precomputed base() NOEXCEPT { return Precomputed(); } | |||
public: | |||
@@ -570,7 +574,7 @@ inline SecureBuffer %(cxx_ns)s::Scalar::direct_scalarmul ( | |||
} | |||
return out; | |||
} | |||
/** endcond */ | |||
/** @endcond */ | |||
#undef NOEXCEPT | |||
} /* namespace decaf */ | |||
@@ -34,8 +34,8 @@ crypto_h_code = "\n".join(( | |||
)) | |||
crypto_h = gen_file( | |||
name = "decaf/crypto.h", | |||
doc = """@brief | |||
@brief Example Decaf crypto routines, metaheader. | |||
doc = """ | |||
Example Decaf crypto routines, metaheader. | |||
@warning These are merely examples, though they ought to be secure. But real | |||
protocols will decide differently on magic numbers, formats, which items to | |||
hash, etc. | |||
@@ -50,8 +50,8 @@ crypto_hxx_code = "\n".join(( | |||
)) | |||
crypto_hxx = gen_file( | |||
name = "decaf/crypto.hxx", | |||
doc = """@brief | |||
@brief Example Decaf crypto routines, C++, metaheader. | |||
doc = """ | |||
Example Decaf crypto routines, C++, metaheader. | |||
@warning These are merely examples, though they ought to be secure. But real | |||
protocols will decide differently on magic numbers, formats, which items to | |||
hash, etc. | |||
@@ -67,7 +67,7 @@ root_h_code = "\n".join(( | |||
decaf_root_hxx = gen_file( | |||
name = "decaf.h", | |||
doc = """ | |||
@brief Master header for Decaf library. | |||
Master header for Decaf library. | |||
The Decaf library implements cryptographic operations on a elliptic curve | |||
groups of prime order p. It accomplishes this by using a twisted Edwards | |||
@@ -15,6 +15,10 @@ | |||
#include <stdint.h> | |||
#include <sys/types.h> | |||
#ifdef __cplusplus | |||
extern "C" { | |||
#endif | |||
/* Goldilocks' build flags default to hidden and stripping executables. */ | |||
/** @cond internal */ | |||
#if defined(DOXYGEN) && !defined(__attribute__) | |||
@@ -43,27 +47,28 @@ | |||
*/ | |||
#if (defined(__ILP64__) || defined(__amd64__) || defined(__x86_64__) || (((__UINT_FAST32_MAX__)>>30)>>30)) \ | |||
&& !defined(DECAF_FORCE_32_BIT) | |||
#define DECAF_WORD_BITS 64 | |||
typedef uint64_t decaf_word_t, decaf_bool_t; | |||
typedef __uint128_t decaf_dword_t; | |||
#define DECAF_WORD_BITS 64 /**< The number of bits in a word */ | |||
typedef uint64_t decaf_word_t; /**< Word size for internal computations */ | |||
typedef uint64_t decaf_bool_t; /**< "Boolean" type, will be set to all-zero or all-one (i.e. -1u) */ | |||
typedef __uint128_t decaf_dword_t; /**< Double-word size for internal computations */ | |||
#else | |||
#define DECAF_WORD_BITS 32 | |||
typedef uint32_t decaf_word_t, decaf_bool_t; | |||
typedef uint64_t decaf_dword_t; | |||
#endif | |||
#ifdef __cplusplus | |||
extern "C" { | |||
#define DECAF_WORD_BITS 32 /**< The number of bits in a word */ | |||
typedef uint32_t decaf_word_t; /**< Word size for internal computations */ | |||
typedef uint32_t decaf_bool_t; /**< "Boolean" type, will be set to all-zero or all-one (i.e. -1u) */ | |||
typedef uint64_t decaf_dword_t; /**< Double-word size for internal computations */ | |||
#endif | |||
/** DECAF_TRUE = -1 so that DECAF_TRUE & x = x */ | |||
static const decaf_bool_t DECAF_TRUE = -(decaf_bool_t)1, DECAF_FALSE = 0; | |||
static const decaf_bool_t DECAF_TRUE = -(decaf_bool_t)1; | |||
/** DECAF_FALSE = 0 so that DECAF_FALSE & x = 0 */ | |||
static const decaf_bool_t DECAF_FALSE = 0; | |||
/* Success or failure */ | |||
/** Another boolean type used to indicate success or failure. */ | |||
// FIXME: deploy project-wide | |||
typedef enum { | |||
DECAF_SUCCESS = -1, | |||
DECAF_FAILURE = 0 | |||
DECAF_SUCCESS = -1, /**< The operation succeeded. */ | |||
DECAF_FAILURE = 0 /**< The operation failed. */ | |||
} decaf_error_t; | |||
@@ -48,46 +48,30 @@ public: | |||
typedef const T& const_reference; | |||
typedef size_t size_type; | |||
typedef std::ptrdiff_t difference_type; | |||
template<typename U> struct rebind { typedef SanitizingAllocator<U> other; }; | |||
inline SanitizingAllocator() NOEXCEPT {} | |||
inline ~SanitizingAllocator() NOEXCEPT {} | |||
inline SanitizingAllocator(const SanitizingAllocator &) NOEXCEPT {} | |||
template<typename U, size_t a> inline SanitizingAllocator(const SanitizingAllocator<U, a> &) NOEXCEPT {} | |||
inline T* address(T& r) const NOEXCEPT { return &r; } | |||
inline const T* address(const T& r) const NOEXCEPT { return &r; } | |||
inline T* allocate ( | |||
size_type cnt, | |||
size_type cnt, | |||
typename std::allocator<void>::const_pointer = 0 | |||
) throw(std::bad_alloc) { | |||
void *v; | |||
int ret = 0; | |||
if (alignment) ret = posix_memalign(&v, alignment, cnt * sizeof(T)); | |||
else v = malloc(cnt * sizeof(T)); | |||
if (ret || v==NULL) throw(std::bad_alloc()); | |||
return reinterpret_cast<T*>(v); | |||
} | |||
inline void deallocate(T* p, size_t size) NOEXCEPT { | |||
if (p==NULL) return; | |||
really_bzero(reinterpret_cast<void*>(p), size); | |||
free(reinterpret_cast<void*>(p)); | |||
} | |||
) throw(std::bad_alloc); | |||
inline void deallocate(T* p, size_t size) NOEXCEPT; | |||
inline size_t max_size() const NOEXCEPT { return std::numeric_limits<size_t>::max() / sizeof(T); } | |||
inline void construct(T* p, const T& t) { new(p) T(t); } | |||
inline void destroy(T* p) { p->~T(); } | |||
inline bool operator==(SanitizingAllocator const&) const NOEXCEPT { return true; } | |||
inline bool operator!=(SanitizingAllocator const&) const NOEXCEPT { return false; } | |||
/** @endcond */ | |||
}; | |||
/** A variant of std::vector which securely zerozes its state when destructed. */ | |||
typedef std::vector<unsigned char, SanitizingAllocator<unsigned char, 0> > SecureBuffer; | |||
/** Constant-time compare two buffers */ | |||
@@ -170,8 +154,10 @@ public: | |||
/** A reference to a block of data, which (when accessed through this base class) is const. */ | |||
class Block { | |||
protected: | |||
/** @cond internal */ | |||
unsigned char *data_; | |||
size_t size_; | |||
/** @endcond */ | |||
public: | |||
/** Null initialization */ | |||
@@ -219,13 +205,13 @@ public: | |||
return Block(data()+off, length); | |||
} | |||
/* Content-wise comparison; constant-time if they are the same length. */ | |||
/** Content-wise comparison; constant-time if they are the same length. */ | |||
inline decaf_bool_t contents_equal(const Block &b) const NOEXCEPT { | |||
if (b.size() != size()) return false; | |||
return decaf_memeq(b.data(),data(),size()); | |||
} | |||
/* Create new block from this */ | |||
/** Create new block from this */ | |||
inline operator SecureBuffer() const throw(std::bad_alloc) { | |||
return SecureBuffer(data_,data_+size_); | |||
} | |||
@@ -304,7 +290,9 @@ public: | |||
inline void zeroize() NOEXCEPT { really_bzero(data(),size()); } | |||
private: | |||
/** @cond internal */ | |||
inline void operator= (const Block &b) const NOEXCEPT DELETE; | |||
/** @endcond */ | |||
}; | |||
@@ -330,7 +318,9 @@ public: | |||
} | |||
private: | |||
/** @cond internal */ | |||
inline void operator= (const Block &b) const NOEXCEPT DELETE; | |||
/** @endcond */ | |||
}; | |||
/** A fixed-size stack-allocated buffer (for NOEXCEPT semantics) */ | |||
@@ -464,6 +454,35 @@ protected: | |||
}; | |||
/** @endcond */ | |||
/*******************************************/ | |||
/* Inline implementations below this point */ | |||
/*******************************************/ | |||
/** @cond internal */ | |||
template<typename T, size_t alignment> | |||
T* SanitizingAllocator<T,alignment>::allocate ( | |||
size_type cnt, | |||
typename std::allocator<void>::const_pointer | |||
) throw(std::bad_alloc) { | |||
void *v; | |||
int ret = 0; | |||
if (alignment) ret = posix_memalign(&v, alignment, cnt * sizeof(T)); | |||
else v = malloc(cnt * sizeof(T)); | |||
if (ret || v==NULL) throw(std::bad_alloc()); | |||
return reinterpret_cast<T*>(v); | |||
} | |||
template<typename T, size_t alignment> | |||
void SanitizingAllocator<T,alignment>::deallocate(T* p, size_t size) NOEXCEPT { | |||
if (p==NULL) return; | |||
really_bzero(reinterpret_cast<void*>(p), size); | |||
free(reinterpret_cast<void*>(p)); | |||
} | |||
/** @endcond */ | |||
} /* namespace decaf */ | |||
@@ -18,19 +18,25 @@ | |||
#include <decaf/common.h> | |||
#ifdef __cplusplus | |||
extern "C" { | |||
#endif | |||
#ifndef INTERNAL_SPONGE_STRUCT | |||
/** Sponge container object for the various primitives. */ | |||
typedef struct keccak_sponge_s { | |||
/** @cond internal */ | |||
uint64_t opaque[26]; | |||
/** @endcond */ | |||
} keccak_sponge_t[1]; | |||
struct kparams_s; | |||
#endif | |||
typedef struct keccak_sponge_s keccak_strobe_t[1], keccak_prng_t[1]; | |||
} keccak_sponge_s; | |||
#ifdef __cplusplus | |||
extern "C" { | |||
/** Convenience GMP-style one-element array version */ | |||
typedef struct keccak_sponge_s keccak_sponge_t[1]; | |||
/** Parameters for sponge construction, distinguishing SHA3 and | |||
* SHAKE instances. | |||
*/ | |||
struct kparams_s; | |||
#endif | |||
/** | |||
@@ -131,7 +137,7 @@ void sponge_hash ( | |||
static inline void NONNULL1 shake##n##_destroy( shake##n##_ctx_t sponge ) { \ | |||
sponge_destroy(sponge->s); \ | |||
} | |||
#define DECSHA3(n) \ | |||
extern const struct kparams_s SHA3_##n##_params_s API_VIS; \ | |||
typedef struct sha3_##n##_ctx_s { keccak_sponge_t s; } sha3_##n##_ctx_t[1]; \ | |||
@@ -163,403 +169,6 @@ DECSHA3(256) | |||
DECSHA3(384) | |||
DECSHA3(512) | |||
/** | |||
* @brief Initialize a sponge-based CSPRNG from a buffer. | |||
* | |||
* @param [out] prng The prng object. | |||
* @param [in] in The initial data. | |||
* @param [in] len The length of the initial data. | |||
* @param [in] deterministic If zero, allow RNG to stir in nondeterministic | |||
* data from RDRAND or RDTSC. | |||
*/ | |||
void spongerng_init_from_buffer ( | |||
keccak_prng_t prng, | |||
const uint8_t * __restrict__ in, | |||
size_t len, | |||
int deterministic | |||
) NONNULL2 API_VIS; | |||
/** | |||
* @brief Initialize a sponge-based CSPRNG from a file. | |||
* | |||
* @param [out] prng The prng object. | |||
* @param [in] file A name of a file containing initial data. | |||
* @param [in] len The length of the initial data. Must be positive. | |||
* @param [in] deterministic If zero, allow RNG to stir in nondeterministic | |||
* data from RDRAND or RDTSC. | |||
* | |||
* @retval DECAF_SUCCESS success. | |||
* @retval DECAF_FAILURE failure. | |||
* @note On failure, errno can be used to determine the cause. | |||
*/ | |||
decaf_error_t spongerng_init_from_file ( | |||
keccak_prng_t prng, | |||
const char *file, | |||
size_t len, | |||
int deterministic | |||
) NONNULL2 API_VIS WARN_UNUSED; | |||
/** | |||
* @brief Initialize a nondeterministic sponge-based CSPRNG from /dev/urandom. | |||
* | |||
* @param [out] sponge The sponge object. | |||
* | |||
* @retval DECAF_SUCCESS success. | |||
* @retval DECAF_FAILURE failure. | |||
* @note On failure, errno can be used to determine the cause. | |||
*/ | |||
decaf_error_t spongerng_init_from_dev_urandom ( | |||
keccak_prng_t prng | |||
) API_VIS WARN_UNUSED; | |||
/** | |||
* @brief Output bytes from a sponge-based CSPRNG. | |||
* | |||
* @param [inout] sponge The sponge object. | |||
* @param [out] out The output buffer. | |||
* @param [in] len The output buffer's length. | |||
*/ | |||
void spongerng_next ( | |||
keccak_prng_t prng, | |||
uint8_t * __restrict__ out, | |||
size_t len | |||
) API_VIS; | |||
/** | |||
* @brief Stir entropy data into a sponge-based CSPRNG from a buffer. | |||
* | |||
* @param [out] sponge The sponge object. | |||
* @param [in] in The entropy data. | |||
* @param [in] len The length of the initial data. | |||
*/ | |||
void spongerng_stir ( | |||
keccak_prng_t prng, | |||
const uint8_t * __restrict__ in, | |||
size_t len | |||
) NONNULL2 API_VIS; | |||
extern const struct kparams_s STROBE_128 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; | |||
typedef enum { | |||
STROBE_MODE_ABSORB = 0, | |||
STROBE_MODE_DUPLEX = 1, | |||
STROBE_MODE_ABSORB_R = 2, | |||
STROBE_MODE_DUPLEX_R = 3, | |||
/* FIXME: no bits allocated in .py version */ | |||
STROBE_MODE_PLAINTEXT = 4, | |||
STROBE_MODE_SQUEEZE = 5, | |||
STROBE_MODE_FORGET = 6, | |||
STROBE_MODE_SQUEEZE_R = 7 | |||
} strobe_mode_t; | |||
#define STROBE_FLAG_CLIENT_SENT (1<<8) | |||
#define STROBE_FLAG_IMPLICIT (1<<9) | |||
#define STROBE_FLAG_FORGET (1<<12) | |||
#define STROBE_FLAG_NO_LENGTH (1<<15) | |||
/* After 1<<16, flags don't go to the sponge anymore, they just affect the handling */ | |||
#define STROBE_FLAG_RECV (1<<16) | |||
#define STROBE_FLAG_RUN_F (1<<17) | |||
#define STROBE_FLAG_MORE (1<<18) | |||
#define STROBE_FLAG_LENGTH_64 (1<<19) | |||
#define STROBE_FLAG_NONDIR (STROBE_FLAG_IMPLICIT) | |||
/** Automatic flags implied by the mode */ | |||
/* HACK: SQUEEZE_R is treated as directional because its' MAC */ | |||
#define STROBE_AUTO_FLAGS(_mode) \ | |||
( (((_mode)&1) ? STROBE_FLAG_RUN_F : 0) \ | |||
| (( ((_mode) & ~2) == STROBE_MODE_ABSORB \ | |||
|| (_mode) == STROBE_MODE_SQUEEZE \ | |||
|| (_mode) == STROBE_MODE_FORGET \ | |||
) ? STROBE_FLAG_IMPLICIT|STROBE_FLAG_NONDIR : 0) \ | |||
) | |||
#define STROBE_CONTROL_WORD(_name,_id,_mode,_flags) \ | |||
static const uint32_t _name = _id | (_mode<<10) | (_mode<<29) | _flags | STROBE_AUTO_FLAGS(_mode) | |||
STROBE_CONTROL_WORD(STROBE_CW_INIT, 0x00, STROBE_MODE_ABSORB, 0); | |||
/* Ciphers */ | |||
STROBE_CONTROL_WORD(STROBE_CW_FIXED_KEY, 0x10, STROBE_MODE_ABSORB, 0); | |||
STROBE_CONTROL_WORD(STROBE_CW_STATIC_PUB, 0x11, STROBE_MODE_PLAINTEXT, 0); | |||
STROBE_CONTROL_WORD(STROBE_CW_DH_EPH, 0x12, STROBE_MODE_PLAINTEXT, 0); | |||
STROBE_CONTROL_WORD(STROBE_CW_DH_KEY, 0x13, STROBE_MODE_ABSORB, 0); | |||
STROBE_CONTROL_WORD(STROBE_CW_PRNG, 0x18, STROBE_MODE_SQUEEZE, STROBE_FLAG_FORGET); | |||
STROBE_CONTROL_WORD(STROBE_CW_SESSION_HASH, 0x19, STROBE_MODE_SQUEEZE, 0); | |||
/* Reuse for PRNG */ | |||
STROBE_CONTROL_WORD(STROBE_CW_PRNG_INITIAL_SEED, 0x10, STROBE_MODE_ABSORB, STROBE_FLAG_NO_LENGTH); | |||
STROBE_CONTROL_WORD(STROBE_CW_PRNG_RESEED, 0x11, STROBE_MODE_ABSORB, STROBE_FLAG_NO_LENGTH); | |||
STROBE_CONTROL_WORD(STROBE_CW_PRNG_CPU_SEED, 0x12, STROBE_MODE_ABSORB, 0); | |||
STROBE_CONTROL_WORD(STROBE_CW_PRNG_USER_SEED, 0x13, STROBE_MODE_ABSORB, STROBE_FLAG_LENGTH_64); | |||
STROBE_CONTROL_WORD(STROBE_CW_PRNG_PRNG, 0x14, STROBE_MODE_SQUEEZE, STROBE_FLAG_LENGTH_64 | STROBE_FLAG_FORGET); | |||
/* Signatures */ | |||
STROBE_CONTROL_WORD(STROBE_CW_SIG_SCHEME, 0x20, STROBE_MODE_ABSORB, 0); | |||
STROBE_CONTROL_WORD(STROBE_CW_SIG_PK, 0x21, STROBE_MODE_ABSORB, 0); | |||
STROBE_CONTROL_WORD(STROBE_CW_SIG_EPH, 0x22, STROBE_MODE_PLAINTEXT, 0); | |||
STROBE_CONTROL_WORD(STROBE_CW_SIG_CHAL, 0x23, STROBE_MODE_SQUEEZE, 0); | |||
STROBE_CONTROL_WORD(STROBE_CW_SIG_RESP, 0x24, STROBE_MODE_DUPLEX, 0); | |||
/* Payloads and encrypted data */ | |||
STROBE_CONTROL_WORD(STROBE_CW_PAYLOAD_PLAINTEXT, 0x30, STROBE_MODE_PLAINTEXT, 0); | |||
STROBE_CONTROL_WORD(STROBE_CW_PAYLOAD_CIPHERTEXT, 0x31, STROBE_MODE_DUPLEX, 0); | |||
STROBE_CONTROL_WORD(STROBE_CW_MAC, 0x32, STROBE_MODE_SQUEEZE_R, STROBE_FLAG_FORGET); | |||
STROBE_CONTROL_WORD(STROBE_CW_AD_EXPLICIT, 0x34, STROBE_MODE_PLAINTEXT, 0); | |||
STROBE_CONTROL_WORD(STROBE_CW_AD_IMPLICIT, 0x35, STROBE_MODE_ABSORB, 0); | |||
STROBE_CONTROL_WORD(STROBE_CW_NONCE_EXPLICIT, 0x36, STROBE_MODE_PLAINTEXT, 0); | |||
STROBE_CONTROL_WORD(STROBE_CW_NONCE_IMPLICIT, 0x37, STROBE_MODE_ABSORB, 0); | |||
STROBE_CONTROL_WORD(STROBE_CW_STREAMING_PLAINTEXT,0x30, STROBE_MODE_PLAINTEXT, STROBE_FLAG_NO_LENGTH); /* TODO: orly? */ | |||
/* Change spec, control flow, etc */ | |||
STROBE_CONTROL_WORD(STROBE_CW_COMPRESS, 0x40, STROBE_MODE_ABSORB_R, 0); | |||
/* FIXME: adjust this respec logic */ | |||
STROBE_CONTROL_WORD(STROBE_CW_RESPEC_INFO, 0x41, STROBE_MODE_ABSORB, STROBE_FLAG_RUN_F | STROBE_FLAG_FORGET); | |||
STROBE_CONTROL_WORD(STROBE_CW_RESPEC, 0x42, STROBE_MODE_ABSORB_R, STROBE_FLAG_RUN_F); | |||
STROBE_CONTROL_WORD(STROBE_CW_FORK, 0x43, STROBE_MODE_ABSORB_R, STROBE_FLAG_RUN_F | STROBE_FLAG_FORGET); | |||
/* FIXME: instance can be rolled back to recover other INSTANCEs */ | |||
STROBE_CONTROL_WORD(STROBE_CW_INSTANCE, 0x44, STROBE_MODE_ABSORB_R, STROBE_FLAG_FORGET); | |||
STROBE_CONTROL_WORD(STROBE_CW_ACKNOWLEDGE, 0x45, STROBE_MODE_PLAINTEXT, 0); | |||
static INLINE UNUSED WARN_UNUSED uint32_t | |||
strobe_cw_recv(uint32_t cw) { | |||
uint32_t recv_toggle = (cw & STROBE_FLAG_NONDIR) ? 0 : STROBE_FLAG_RECV; | |||
if (cw & STROBE_FLAG_IMPLICIT) { | |||
return cw ^ recv_toggle; | |||
} else { | |||
uint32_t modes_2[8] = { | |||
/* Note: most of these really shouldn't happen... */ | |||
STROBE_MODE_ABSORB, | |||
STROBE_MODE_DUPLEX_R, | |||
STROBE_MODE_ABSORB_R, | |||
STROBE_MODE_DUPLEX, | |||
STROBE_MODE_PLAINTEXT, | |||
STROBE_MODE_SQUEEZE, | |||
STROBE_MODE_FORGET, | |||
STROBE_MODE_ABSORB | |||
}; | |||
return ((cw & ((1<<29)-1)) | (modes_2[cw>>29]<<29)) ^ recv_toggle; | |||
} | |||
} | |||
#define STROBE_MAX_AUTH_BYTES 32 | |||
/** | |||
* @brief Initialize Strobe protocol context. | |||
* @param [out] strobe The uninitialized strobe object. | |||
* @param [in] Strobe parameter descriptor | |||
* @param [in] am_client Nonzero if this party | |||
* is the client. | |||
*/ | |||
void strobe_init ( | |||
keccak_strobe_t strobe, | |||
const struct kparams_s *params, | |||
const char *proto, | |||
uint8_t am_client | |||
) NONNULL2 API_VIS; | |||
/** | |||
* @brief Run a transaction against a STROBE state. | |||
* @param [inout] strobe The initialized STROBE object. | |||
* @param [out] out The output. | |||
* @param [in] in The input. | |||
* @param [in] len The length of the input/output. | |||
* @param [in] cw_flags The control word with flags. | |||
*/ | |||
void strobe_transact ( | |||
keccak_strobe_t strobe, | |||
unsigned char *out, | |||
const unsigned char *in, | |||
size_t len, | |||
uint32_t cw_flags | |||
) NONNULL1 API_VIS; | |||
/** | |||
* @brief Send plaintext in strobe context. | |||
* @param [inout] The initialized strobe object. | |||
* @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. | |||
*/ | |||
static INLINE UNUSED void strobe_plaintext ( | |||
keccak_strobe_t strobe, | |||
const unsigned char *in, | |||
uint16_t len, | |||
uint8_t iSent | |||
) { | |||
strobe_transact( | |||
strobe, NULL, in, len, | |||
iSent ? STROBE_CW_PAYLOAD_PLAINTEXT | |||
: strobe_cw_recv(STROBE_CW_PAYLOAD_PLAINTEXT) | |||
); | |||
} | |||
/** | |||
* @brief Report authenticated data in strobe context. | |||
* @param [inout] The initialized strobe object. | |||
* @param [in] in The plaintext. | |||
* @param [in] len The length of the ad. | |||
*/ | |||
static INLINE UNUSED void strobe_ad ( | |||
keccak_strobe_t strobe, | |||
const unsigned char *in, | |||
size_t len | |||
) { | |||
strobe_transact( strobe, NULL, in, len, STROBE_CW_AD_EXPLICIT ); | |||
} | |||
/** | |||
* @brief Set nonce in strobe context. | |||
* @param [inout] The initialized strobe object. | |||
* @param [in] in The nonce. | |||
* @param [in] len The length of the nonce. | |||
*/ | |||
static INLINE UNUSED void strobe_nonce ( | |||
keccak_strobe_t strobe, | |||
const unsigned char *in, | |||
uint16_t len | |||
) { | |||
strobe_transact( strobe, NULL, in, len, STROBE_CW_NONCE_EXPLICIT ); | |||
} | |||
/** | |||
* @brief Set fixed key in strobe context. | |||
* @param [inout] The initialized strobe object. | |||
* @param [in] in The key. | |||
* @param [in] len The length of the key. | |||
*/ | |||
static INLINE UNUSED void | |||
strobe_fixed_key ( | |||
keccak_strobe_t strobe, | |||
const unsigned char *in, | |||
uint16_t len | |||
) { | |||
strobe_transact( strobe, NULL, in, len, STROBE_CW_FIXED_KEY ); | |||
} | |||
/** | |||
* @brief Set Diffie-Hellman key in strobe context. | |||
* @param [inout] The initialized strobe object. | |||
* @param [in] in The key. | |||
* @param [in] len The length of the key. | |||
*/ | |||
static INLINE UNUSED void | |||
strobe_dh_key ( | |||
keccak_strobe_t strobe, | |||
const unsigned char *in, | |||
uint16_t len | |||
) { | |||
strobe_transact( strobe, NULL, in, len, STROBE_CW_DH_KEY ); | |||
} | |||
/** | |||
* @brief Produce an authenticator. | |||
* @param [inout] strobe The Strobe protocol context. | |||
* @param [out] out The authenticator | |||
* @param len The length. | |||
*/ | |||
static INLINE UNUSED void | |||
strobe_produce_auth ( | |||
keccak_strobe_t strobe, | |||
unsigned char *out, | |||
uint16_t len | |||
) { | |||
strobe_transact( strobe, out, NULL, len, STROBE_CW_MAC ); | |||
} | |||
/** | |||
* @brief Encrypt bytes from in to out. | |||
* @warning Doesn't produce an auth tag. | |||
* @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. | |||
*/ | |||
static INLINE UNUSED void | |||
strobe_encrypt ( | |||
keccak_strobe_t strobe, | |||
unsigned char *out, | |||
const unsigned char *in, | |||
uint16_t len | |||
) { | |||
strobe_transact(strobe, out, in, len, STROBE_CW_PAYLOAD_CIPHERTEXT); | |||
} | |||
/** | |||
* @brief Decrypt bytes from in to out. | |||
* @warning Doesn't check an auth tag. | |||
* @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. | |||
*/ | |||
static INLINE UNUSED void | |||
strobe_decrypt ( | |||
keccak_strobe_t strobe, | |||
unsigned char *out, | |||
const unsigned char *in, | |||
uint16_t len | |||
) { | |||
strobe_transact(strobe, out, in, len, strobe_cw_recv(STROBE_CW_PAYLOAD_CIPHERTEXT)); | |||
} | |||
/** | |||
* @brief Produce a session-bound pseudorandom value. | |||
* | |||
* @warning This "prng" value is NOT suitable for | |||
* refreshing forward secrecy! It's to replace things | |||
* like TCP session hash. | |||
* | |||
* @param [inout] strobe The Strobe protocol context | |||
* @param [out] out The output random data. | |||
* @param len The length. | |||
*/ | |||
static inline void strobe_prng ( | |||
keccak_strobe_t strobe, | |||
unsigned char *out, | |||
uint16_t len | |||
) { | |||
strobe_transact( strobe, out, NULL, len, STROBE_CW_PRNG ); | |||
} | |||
/** | |||
* @brief Verify an authenticator. | |||
* @param [inout] strobe The Strobe protocol context | |||
* @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_error_t strobe_verify_auth ( | |||
keccak_strobe_t strobe, | |||
const unsigned char *in, | |||
uint16_t len | |||
) WARN_UNUSED NONNULL2 API_VIS; | |||
/** | |||
* @brief Respecify Strobe protocol object's crypto. | |||
* @param [inout] The initialized strobe context. | |||
* @param [in] Strobe parameter descriptor | |||
* @param [in] am_client Nonzero if this party | |||
* is the client. | |||
*/ | |||
void strobe_respec ( | |||
keccak_strobe_t strobe, | |||
const struct kparams_s *params | |||
) NONNULL2 API_VIS; | |||
#define strobe_destroy sponge_destroy | |||
#ifdef __cplusplus | |||
} /* extern "C" */ | |||
#endif | |||
@@ -13,6 +13,9 @@ | |||
#define __SHAKE_HXX__ | |||
#include <decaf/shake.h> | |||
#include <decaf/strobe.h> /* TODO remove */ | |||
#include <decaf/spongerng.h> /* TODO remove */ | |||
#include <string> | |||
#include <sys/types.h> | |||
#include <errno.h> | |||
@@ -32,6 +35,7 @@ namespace decaf { | |||
/** A Keccak sponge internal class */ | |||
class KeccakSponge { | |||
protected: | |||
/** @cond internal */ | |||
/** The C-wrapper sponge state */ | |||
keccak_sponge_t sp; | |||
@@ -40,6 +44,7 @@ protected: | |||
/** No initialization */ | |||
inline KeccakSponge(const NOINIT &) NOEXCEPT { } | |||
/** @endcond */ | |||
public: | |||
/** Destructor zeroizes state */ | |||
@@ -149,13 +154,16 @@ public: | |||
/** Sponge-based random-number generator */ | |||
class SpongeRng : public Rng, private KeccakSponge { | |||
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; | |||
const char *what() const NOEXCEPT { return what_; } | |||
RngException(int err_code, const char *what_) NOEXCEPT : what_(what_), err_code(err_code) {} | |||
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 */ | |||
@@ -189,116 +197,127 @@ private: | |||
}; | |||
/**@endcond*/ | |||
/** STROBE protocol framework object */ | |||
class Strobe : private KeccakSponge { | |||
public: | |||
/* TODO: pull out parameters */ | |||
/** 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, | |||
client_or_server whoami, | |||
const kparams_s ¶ms = STROBE_256 | |||
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 : KeccakSponge(NOINIT()) { | |||
strobe_init(sp, ¶ms, description, whoami == CLIENT); | |||
keyed = false; | |||
} | |||
/** Stir in fixed key, from a C++ block. */ | |||
inline void fixed_key ( | |||
const Block &data | |||
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 | |||
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 | |||
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 | |||
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()); | |||
} | |||
/* TODO: this doesn't actually send ... maybe think about gluing to socket code? */ | |||
/** 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); | |||
} | |||
template<class T> inline void recv_plaintext(const Serializable<T> &data) NOEXCEPT { | |||
recv_plaintext(data.serialize()); | |||
} | |||
/** 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; | |||
} | |||
template<class T> inline SecureBuffer decrypt_no_auth(const Serializable<T> &data) throw(ProtocolException) { | |||
return decrypt_no_auth(data.serialize()); | |||
} | |||
/** Produce an authenticator into a buffer. */ | |||
inline void produce_auth(Buffer out) throw(LengthException,ProtocolException) { | |||
if (!keyed) throw ProtocolException(); /* TODO: maybe. Could use for eg sanity or dos protection */ | |||
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) { | |||
@@ -307,18 +326,21 @@ public: | |||
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) { | |||
@@ -327,12 +349,7 @@ public: | |||
verify_auth(data.slice(out.size(),bytes)); | |||
} | |||
template<class T> inline SecureBuffer decrypt ( | |||
const Serializable<T> &data, uint8_t auth = DEFAULT_AUTH_SIZE | |||
) throw(LengthException,ProtocolException,CryptoException, std::bad_alloc ){ | |||
return decrypt(data.serialize(), auth); | |||
} | |||
/** Decrypt and check authentication data */ | |||
inline SecureBuffer decrypt ( | |||
const Block &data, uint8_t bytes = DEFAULT_AUTH_SIZE | |||
) throw(LengthException,CryptoException,ProtocolException,std::bad_alloc) { | |||
@@ -340,19 +357,25 @@ public: | |||
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); | |||
@@ -0,0 +1,91 @@ | |||
/** | |||
* @file decaf/spongerng.h | |||
* @copyright | |||
* Copyright (c) 2015-2016 Cryptography Research, Inc. \n | |||
* Released under the MIT License. See LICENSE.txt for license information. | |||
* @author Mike Hamburg | |||
* @brief Sponge-based RNGs. | |||
* @warning This construction isn't final. In particular, | |||
* the outputs of deterministic RNGs from this mechanism might change in future versions. | |||
*/ | |||
#ifndef __DECAF_SPONGERNG_H__ | |||
#define __DECAF_SPONGERNG_H__ | |||
#include <decaf/shake.h> | |||
#ifdef __cplusplus | |||
extern "C" { | |||
#endif | |||
/** Keccak CSPRNG structure as struct. FUTURE: distinguish. */ | |||
typedef struct keccak_sponge_s keccak_prng_s; | |||
/** Keccak CSPRNG structure as one-element array */ | |||
typedef keccak_prng_s keccak_prng_t[1]; | |||
/** Initialize a sponge-based CSPRNG from a buffer. */ | |||
void spongerng_init_from_buffer ( | |||
keccak_prng_t prng, /**< [out] The PRNG object. */ | |||
const uint8_t *__restrict__ in, /**< [in] The initialization data. */ | |||
size_t len, /**< [in] The length of the initialization data. */ | |||
int deterministic /**< [in] If zero, allow RNG to stir in nondeterministic data from RDRAND or RDTSC.*/ | |||
) NONNULL2 API_VIS; | |||
/** | |||
* @brief Initialize a sponge-based CSPRNG from a file. | |||
* @retval DECAF_SUCCESS success. | |||
* @retval DECAF_FAILURE failure. | |||
* @note On failure, errno can be used to determine the cause. | |||
*/ | |||
decaf_error_t spongerng_init_from_file ( | |||
keccak_prng_t prng, /**< [out] The PRNG object. */ | |||
const char *file, /**< [in] A name of a file containing initial data. */ | |||
size_t len, /**< [in] The length of the initial data. Must be positive. */ | |||
int deterministic /**< [in] If zero, allow RNG to stir in nondeterministic data from RDRAND or RDTSC. */ | |||
) NONNULL2 API_VIS WARN_UNUSED; | |||
/** | |||
* @brief Initialize a nondeterministic sponge-based CSPRNG from /dev/urandom. | |||
* @retval DECAF_SUCCESS success. | |||
* @retval DECAF_FAILURE failure. | |||
* @note On failure, errno can be used to determine the cause. | |||
*/ | |||
decaf_error_t spongerng_init_from_dev_urandom ( | |||
keccak_prng_t prng /**< [out] sponge The sponge object. */ | |||
) API_VIS WARN_UNUSED; | |||
/** Output bytes from a sponge-based CSPRNG. */ | |||
void spongerng_next ( | |||
keccak_prng_t prng, /**< [inout] The PRNG object. */ | |||
uint8_t * __restrict__ out, /**< [out] Output buffer. */ | |||
size_t len /**< [in] Number of bytes to output. */ | |||
) API_VIS; | |||
/** Stir entropy data into a sponge-based CSPRNG from a buffer. */ | |||
void spongerng_stir ( | |||
keccak_prng_t prng, /**< [out] The PRNG object. */ | |||
const uint8_t * __restrict__ in, /**< [in] The entropy data. */ | |||
size_t len /**< [in] The length of the initial data. */ | |||
) NONNULL2 API_VIS; | |||
/** Securely destroy a sponge RNG object by overwriting it. */ | |||
static INLINE UNUSED void | |||
spongerng_destroy ( | |||
keccak_prng_t doomed /**< [in] The object to destroy. */ | |||
); | |||
/** @cond internal */ | |||
/***************************************/ | |||
/* Implementations of inline functions */ | |||
/***************************************/ | |||
void spongerng_destroy (keccak_prng_t doomed) { | |||
sponge_destroy(doomed); | |||
} | |||
/** @endcond */ /* internal */ | |||
#ifdef __cplusplus | |||
} /* extern "C" */ | |||
#endif | |||
#endif /* __DECAF_SPONGERNG_H__ */ |
@@ -0,0 +1,337 @@ | |||
/** | |||
* @file decaf/strobe.h | |||
* @copyright | |||
* Copyright (c) 2015-2016 Cryptography Research, Inc. \n | |||
* Released under the MIT License. See LICENSE.txt for license information. | |||
* @author Mike Hamburg | |||
* @brief STROBE experimental protocol framework. | |||
* @warning EXPERIMENTAL! The names, parameter orders etc are likely to change. | |||
*/ | |||
#ifndef __DECAF_STROBE_H__ | |||
#define __DECAF_STROBE_H__ | |||
#include <decaf/shake.h> | |||
#ifdef __cplusplus | |||
extern "C" { | |||
#endif | |||
/** Keccak STROBE structure as struct. FUTURE: distinguish. */ | |||
typedef struct keccak_sponge_s keccak_strobe_s; | |||
/** Keccak STROBE structure as one-element array */ | |||
typedef keccak_strobe_s keccak_strobe_t[1]; | |||
/** STROBE parameters, 128-bit estimated security for hashing and encryption */ | |||
extern const struct kparams_s STROBE_128 API_VIS; | |||
/** STROBE parameters, 256-bit estimated security for hashing and encryption */ | |||
extern const struct kparams_s STROBE_256 API_VIS; | |||
/** STROBE parameters, 128-bit estimated security for encryption only (not hashing) */ | |||
extern const struct kparams_s STROBE_KEYED_128 API_VIS; | |||
/** STROBE parameters, 256-bit estimated security for encryption only (not hashing) */ | |||
extern const struct kparams_s STROBE_KEYED_256 API_VIS; | |||
/** Initialize Strobe protocol context. */ | |||
void strobe_init ( | |||
keccak_strobe_t strobe, /**< [out] The uninitialized strobe object. */ | |||
const struct kparams_s *params, /**< [in] Parameter set descriptor. */ | |||
const char *proto, /**< [in] Unique identifier for the protocol. TODO: define namespaces for this */ | |||
uint8_t am_client /**< [in] Nonzero if this party. */ | |||
) NONNULL2 API_VIS; | |||
/** Run a transaction against a STROBE state. */ | |||
void strobe_transact ( | |||
keccak_strobe_t strobe, /**< [inout] The initialized STROBE object. */ | |||
unsigned char *out, /**< [out] The output. */ | |||
const unsigned char *in, /**< [in] The input. */ | |||
size_t len, /**< [in] The length of the input/output. */ | |||
uint32_t cw_flags /**< [in] The control word with flags. */ | |||
) NONNULL1 API_VIS; | |||
/** Record a message sent in plaintext */ | |||
static INLINE UNUSED void strobe_plaintext ( | |||
keccak_strobe_t strobe, /**< [inout] The STROBE object */ | |||
const unsigned char *in, /**< [in] The message. */ | |||
uint16_t len, /**< [in] The length of the message. */ | |||
uint8_t iSent /**< [in] If nonzero, I sent the message. */ | |||
); | |||
/** Report authenticated data in strobe context. */ | |||
static INLINE UNUSED void | |||
strobe_ad ( | |||
keccak_strobe_t strobe, /**< [inout] The strobe object. */ | |||
const unsigned char *in, /**< [in] The plaintext. */ | |||
size_t len /**< [in] The length of the ad. */ | |||
); | |||
/** Set nonce in strobe context. */ | |||
static INLINE UNUSED void | |||
strobe_nonce ( | |||
keccak_strobe_t strobe, /**< [inout] The initialized strobe object. */ | |||
const unsigned char *in, /**< [in] The nonce. */ | |||
uint16_t len /**< [in] The length of the nonce. */ | |||
); | |||
/** Set fixed key in strobe context. */ | |||
static INLINE UNUSED void | |||
strobe_fixed_key ( | |||
keccak_strobe_t strobe, /**< [inout] The initialized strobe object. */ | |||
const unsigned char *in, /**< [in] The key. */ | |||
uint16_t len /**< [in] The length of the key. */ | |||
); | |||
/** Set Diffie-Hellman key in strobe context. */ | |||
static INLINE UNUSED void | |||
strobe_dh_key ( | |||
keccak_strobe_t strobe, /**< [inout] The initialized strobe object. */ | |||
const unsigned char *in, /**< [in] The key. */ | |||
uint16_t len /**< [in] The length of the key. */ | |||
); | |||
/** The maximum number of bytes that strobe_produce_auth can spit out. */ | |||
#define STROBE_MAX_AUTH_BYTES 32 | |||
/** Produce an authenticator. */ | |||
static INLINE UNUSED void | |||
strobe_produce_auth ( | |||
keccak_strobe_t strobe, /**< [inout] The Strobe protocol context. */ | |||
unsigned char *out, /**< [out] The authenticator. */ | |||
uint16_t len /**< [in] The length, at most STROBE_MAX_AUTH_BYTES. */ | |||
); | |||
/** | |||
* @brief Verify an authenticator. | |||
* @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_error_t strobe_verify_auth ( | |||
keccak_strobe_t strobe, /**< [inout] The Strobe protocol context */ | |||
const unsigned char *in, /**< [in] The authenticator */ | |||
uint16_t len /**< [in] The length, at most STROBE_MAX_AUTH_BYTES. */ | |||
) WARN_UNUSED NONNULL2 API_VIS; | |||
/** | |||
* @brief Encrypt bytes from in to out. | |||
* @warning Doesn't produce an auth tag. | |||
*/ | |||
static INLINE UNUSED void | |||
strobe_encrypt ( | |||
keccak_strobe_t strobe, /**< [inout] strobe The Strobe protocol context. */ | |||
unsigned char *out, /**< [out] The ciphertext. */ | |||
const unsigned char *in, /**< [in] The plaintext. */ | |||
uint16_t len /**< [in] The length of plaintext and ciphertext. */ | |||
); | |||
/** | |||
* Decrypt bytes from in to out. | |||
* @warning Doesn't check an auth tag. | |||
*/ | |||
static INLINE UNUSED void | |||
strobe_decrypt ( | |||
keccak_strobe_t strobe, /**< [inout] The Strobe protocol context. */ | |||
unsigned char *out, /**< [out] The plaintext. */ | |||
const unsigned char *in, /**< [in] The ciphertext. */ | |||
uint16_t len /**< [in] The length of plaintext and ciphertext. */ | |||
); | |||
/** | |||
* @brief Produce a session-bound pseudorandom value. | |||
* | |||
* @warning This "prng" value is NOT suitable for | |||
* refreshing forward secrecy! It's to replace things | |||
* like TCP session hash. | |||
*/ | |||
static inline void strobe_prng ( | |||
keccak_strobe_t strobe, /**< [inout] The Strobe protocol context */ | |||
unsigned char *out, /**< [out] The output random data. */ | |||
uint16_t len /**< The length. */ | |||
); | |||
/** Respecify Strobe protocol object's crypto. */ | |||
void strobe_respec ( | |||
keccak_strobe_t strobe, /**< [inout] The initialized strobe context. */ | |||
const struct kparams_s *params /**< [in] Strobe parameter descriptor. */ | |||
) NONNULL2 API_VIS; | |||
/** Securely destroy a STROBE object by overwriting it. */ | |||
static INLINE UNUSED void | |||
strobe_destroy ( | |||
keccak_strobe_t doomed /**< [in] The object to destroy. */ | |||
); | |||
/** @cond internal */ | |||
/************************************************************************/ | |||
/* Declarations of various constants and operating modes, for extension */ | |||
/************************************************************************/ | |||
/** STROBE modes of operation */ | |||
typedef enum { | |||
STROBE_MODE_ABSORB = 0, | |||
STROBE_MODE_DUPLEX = 1, | |||
STROBE_MODE_ABSORB_R = 2, | |||
STROBE_MODE_DUPLEX_R = 3, | |||
/* FIXME: no bits allocated in .py version */ | |||
STROBE_MODE_PLAINTEXT = 4, | |||
STROBE_MODE_SQUEEZE = 5, | |||
STROBE_MODE_FORGET = 6, | |||
STROBE_MODE_SQUEEZE_R = 7 | |||
} strobe_mode_t; | |||
#define STROBE_FLAG_CLIENT_SENT (1<<8) /**< Set if the client this message. */ | |||
#define STROBE_FLAG_IMPLICIT (1<<9) /**< Set if nobody set this message. */ | |||
#define STROBE_FLAG_FORGET (1<<12) /**< After this operation, destroy bytes to prevent rollback. */ | |||
/* TODO: maybe just make STROBE heavy non-invertible? */ | |||
#define STROBE_FLAG_NO_LENGTH (1<<15) /**< This operation has an unknown length (for streaming). */ | |||
/* After 1<<16, flags don't go to the sponge anymore, they just affect the handling */ | |||
#define STROBE_FLAG_RECV (1<<16) /**< I received this packet, so reverse directions. */ | |||
#define STROBE_FLAG_RUN_F (1<<17) /**< Must run F between control word and data. */ | |||
#define STROBE_FLAG_MORE (1<<18) /**< Set for all operations in an unknown-length streaming operation after the first */ | |||
#define STROBE_FLAG_LENGTH_64 (1<<19) /**< Length is a 64-bit word instead of a 16-bit one. */ | |||
#define STROBE_FLAG_NONDIR (STROBE_FLAG_IMPLICIT) | |||
/** Automatic flags implied by the mode */ | |||
/* HACK: SQUEEZE_R is treated as directional because its' MAC */ | |||
#define STROBE_AUTO_FLAGS(_mode) \ | |||
( (((_mode)&1) ? STROBE_FLAG_RUN_F : 0) \ | |||
| (( ((_mode) & ~2) == STROBE_MODE_ABSORB \ | |||
|| (_mode) == STROBE_MODE_SQUEEZE \ | |||
|| (_mode) == STROBE_MODE_FORGET \ | |||
) ? STROBE_FLAG_IMPLICIT|STROBE_FLAG_NONDIR : 0) \ | |||
) | |||
/**@ Define a control word for STROBE protocols. */ | |||
#define STROBE_CONTROL_WORD(_name,_id,_mode,_flags) \ | |||
static const uint32_t _name = _id | (_mode<<10) | (_mode<<29) | _flags | STROBE_AUTO_FLAGS(_mode) | |||
STROBE_CONTROL_WORD(STROBE_CW_INIT, 0x00, STROBE_MODE_ABSORB, 0); /**< Initialization with protocol name */ | |||
/* Ciphers */ | |||
STROBE_CONTROL_WORD(STROBE_CW_FIXED_KEY, 0x10, STROBE_MODE_ABSORB, 0); /**< Fixed symmetric/preshared key */ | |||
STROBE_CONTROL_WORD(STROBE_CW_STATIC_PUB, 0x11, STROBE_MODE_PLAINTEXT, 0); /**< Static public key of other party */ | |||
STROBE_CONTROL_WORD(STROBE_CW_DH_EPH, 0x12, STROBE_MODE_PLAINTEXT, 0); /**< DH ephemeral key on the wire */ | |||
STROBE_CONTROL_WORD(STROBE_CW_DH_KEY, 0x13, STROBE_MODE_ABSORB, 0); /**< DH shared secret key */ | |||
STROBE_CONTROL_WORD(STROBE_CW_PRNG, 0x18, STROBE_MODE_SQUEEZE, STROBE_FLAG_FORGET); /**< Generate random bits (for PRNG) */ | |||
STROBE_CONTROL_WORD(STROBE_CW_SESSION_HASH, 0x19, STROBE_MODE_SQUEEZE, 0); /**< Generate session hash */ | |||
/* Reuse for PRNG */ | |||
STROBE_CONTROL_WORD(STROBE_CW_PRNG_INITIAL_SEED, 0x10, STROBE_MODE_ABSORB, STROBE_FLAG_NO_LENGTH); /**< Initial seeding for PRNG */ | |||
STROBE_CONTROL_WORD(STROBE_CW_PRNG_RESEED, 0x11, STROBE_MODE_ABSORB, STROBE_FLAG_NO_LENGTH); /**< Later seeding for PRNG */ | |||
STROBE_CONTROL_WORD(STROBE_CW_PRNG_CPU_SEED, 0x12, STROBE_MODE_ABSORB, 0); /**< Seed from CPU-builin RNG */ | |||
STROBE_CONTROL_WORD(STROBE_CW_PRNG_USER_SEED, 0x13, STROBE_MODE_ABSORB, STROBE_FLAG_LENGTH_64); /**< Seed from user */ | |||
STROBE_CONTROL_WORD(STROBE_CW_PRNG_PRNG, 0x14, STROBE_MODE_SQUEEZE, STROBE_FLAG_LENGTH_64 | STROBE_FLAG_FORGET); /**< Call to generate bits */ | |||
/* Signatures */ | |||
STROBE_CONTROL_WORD(STROBE_CW_SIG_SCHEME, 0x20, STROBE_MODE_ABSORB, 0); /**< Name of the signature scheme we're using. */ | |||
STROBE_CONTROL_WORD(STROBE_CW_SIG_PK, 0x21, STROBE_MODE_ABSORB, 0); /**< Public (verification key) */ | |||
STROBE_CONTROL_WORD(STROBE_CW_SIG_EPH, 0x22, STROBE_MODE_PLAINTEXT, 0); /**< Schnorr ephemeral. */ | |||
STROBE_CONTROL_WORD(STROBE_CW_SIG_CHAL, 0x23, STROBE_MODE_SQUEEZE, 0); /**< Schnorr challenge. */ | |||
STROBE_CONTROL_WORD(STROBE_CW_SIG_RESP, 0x24, STROBE_MODE_DUPLEX, 0); /**< Schnoll response. */ | |||
/* Payloads and encrypted data */ | |||
STROBE_CONTROL_WORD(STROBE_CW_PAYLOAD_PLAINTEXT, 0x30, STROBE_MODE_PLAINTEXT, 0); | |||
STROBE_CONTROL_WORD(STROBE_CW_PAYLOAD_CIPHERTEXT, 0x31, STROBE_MODE_DUPLEX, 0); | |||
STROBE_CONTROL_WORD(STROBE_CW_MAC, 0x32, STROBE_MODE_SQUEEZE_R, STROBE_FLAG_FORGET); | |||
STROBE_CONTROL_WORD(STROBE_CW_AD_EXPLICIT, 0x34, STROBE_MODE_PLAINTEXT, 0); | |||
STROBE_CONTROL_WORD(STROBE_CW_AD_IMPLICIT, 0x35, STROBE_MODE_ABSORB, 0); | |||
STROBE_CONTROL_WORD(STROBE_CW_NONCE_EXPLICIT, 0x36, STROBE_MODE_PLAINTEXT, 0); | |||
STROBE_CONTROL_WORD(STROBE_CW_NONCE_IMPLICIT, 0x37, STROBE_MODE_ABSORB, 0); | |||
STROBE_CONTROL_WORD(STROBE_CW_STREAMING_PLAINTEXT,0x30, STROBE_MODE_PLAINTEXT, STROBE_FLAG_NO_LENGTH); /* TODO: orly? */ | |||
/* Change spec, control flow, etc */ | |||
STROBE_CONTROL_WORD(STROBE_CW_COMPRESS, 0x40, STROBE_MODE_ABSORB_R, 0); | |||
/* FIXME: adjust this respec logic */ | |||
STROBE_CONTROL_WORD(STROBE_CW_RESPEC_INFO, 0x41, STROBE_MODE_ABSORB, STROBE_FLAG_RUN_F | STROBE_FLAG_FORGET); | |||
STROBE_CONTROL_WORD(STROBE_CW_RESPEC, 0x42, STROBE_MODE_ABSORB_R, STROBE_FLAG_RUN_F); | |||
STROBE_CONTROL_WORD(STROBE_CW_FORK, 0x43, STROBE_MODE_ABSORB_R, STROBE_FLAG_RUN_F | STROBE_FLAG_FORGET); | |||
/* FIXME: instance can be rolled back to recover other INSTANCEs */ | |||
STROBE_CONTROL_WORD(STROBE_CW_INSTANCE, 0x44, STROBE_MODE_ABSORB_R, STROBE_FLAG_FORGET); | |||
STROBE_CONTROL_WORD(STROBE_CW_ACKNOWLEDGE, 0x45, STROBE_MODE_PLAINTEXT, 0); | |||
/** Reverse a keyword because it's being received instead of sent */ | |||
static INLINE UNUSED WARN_UNUSED uint32_t | |||
strobe_cw_recv(uint32_t cw) { | |||
uint32_t recv_toggle = (cw & STROBE_FLAG_NONDIR) ? 0 : STROBE_FLAG_RECV; | |||
if (cw & STROBE_FLAG_IMPLICIT) { | |||
return cw ^ recv_toggle; | |||
} else { | |||
uint32_t modes_2[8] = { | |||
/* Note: most of these really shouldn't happen... */ | |||
STROBE_MODE_ABSORB, | |||
STROBE_MODE_DUPLEX_R, | |||
STROBE_MODE_ABSORB_R, | |||
STROBE_MODE_DUPLEX, | |||
STROBE_MODE_PLAINTEXT, | |||
STROBE_MODE_SQUEEZE, | |||
STROBE_MODE_FORGET, | |||
STROBE_MODE_ABSORB | |||
}; | |||
return ((cw & ((1<<29)-1)) | (modes_2[cw>>29]<<29)) ^ recv_toggle; | |||
} | |||
} | |||
/***************************************/ | |||
/* Implementations of inline functions */ | |||
/***************************************/ | |||
void strobe_plaintext(keccak_strobe_t strobe, const unsigned char *in, uint16_t len, uint8_t iSent) { | |||
strobe_transact( | |||
strobe, NULL, in, len, | |||
iSent ? STROBE_CW_PAYLOAD_PLAINTEXT | |||
: strobe_cw_recv(STROBE_CW_PAYLOAD_PLAINTEXT) | |||
); | |||
} | |||
void strobe_ad(keccak_strobe_t strobe, const unsigned char *in, size_t len) { | |||
strobe_transact( strobe, NULL, in, len, STROBE_CW_AD_EXPLICIT ); | |||
} | |||
void strobe_nonce (keccak_strobe_t strobe, const unsigned char *in, uint16_t len) { | |||
strobe_transact( strobe, NULL, in, len, STROBE_CW_NONCE_EXPLICIT ); | |||
} | |||
void strobe_fixed_key (keccak_strobe_t strobe, const unsigned char *in, uint16_t len) { | |||
strobe_transact( strobe, NULL, in, len, STROBE_CW_FIXED_KEY ); | |||
} | |||
void strobe_dh_key (keccak_strobe_t strobe, const unsigned char *in, uint16_t len) { | |||
strobe_transact( strobe, NULL, in, len, STROBE_CW_DH_KEY ); | |||
} | |||
void strobe_produce_auth (keccak_strobe_t strobe, unsigned char *out, uint16_t len) { | |||
strobe_transact( strobe, out, NULL, len, STROBE_CW_MAC ); | |||
} | |||
void strobe_encrypt (keccak_strobe_t strobe, unsigned char *out, const unsigned char *in, uint16_t len) { | |||
strobe_transact(strobe, out, in, len, STROBE_CW_PAYLOAD_CIPHERTEXT); | |||
} | |||
void strobe_decrypt(keccak_strobe_t strobe, unsigned char *out, const unsigned char *in, uint16_t len) { | |||
strobe_transact(strobe, out, in, len, strobe_cw_recv(STROBE_CW_PAYLOAD_CIPHERTEXT)); | |||
} | |||
void strobe_prng(keccak_strobe_t strobe, unsigned char *out, uint16_t len) { | |||
strobe_transact( strobe, out, NULL, len, STROBE_CW_PRNG ); | |||
} | |||
void strobe_destroy (keccak_strobe_t doomed) { | |||
sponge_destroy(doomed); | |||
} | |||
/** @endcond */ /* internal */ | |||
#ifdef __cplusplus | |||
} /* extern "C" */ | |||
#endif | |||
#endif /* __DECAF_STROBE_H__ */ |
@@ -67,6 +67,8 @@ typedef struct keccak_sponge_s { | |||
#define INTERNAL_SPONGE_STRUCT 1 | |||
#include <decaf/shake.h> | |||
#include <decaf/strobe.h> | |||
#include <decaf/spongerng.h> | |||
#define FLAG_ABSORBING 'A' | |||
#define FLAG_SQUEEZING 'Z' | |||