From 1a14abb4ddad77e0057bd51b998ef009e2dfd1fe Mon Sep 17 00:00:00 2001 From: Michael Hamburg Date: Mon, 11 Jan 2016 17:39:17 -0800 Subject: [PATCH] Separate .h files for SHA/SHAKE, STROBE and sponge RNG. TODO: .hxx. Also add a lot of docs --- Doxyfile | 4 +- Makefile | 4 +- src/gen_headers/crypto_h.py | 28 +- src/gen_headers/crypto_hxx.py | 63 ++-- src/gen_headers/decaf_h.py | 27 +- src/gen_headers/decaf_hxx.py | 168 +++++---- src/gen_headers/main.py | 10 +- src/public_include/decaf/common.h | 33 +- src/public_include/decaf/secure_buffer.hxx | 69 ++-- src/public_include/decaf/shake.h | 417 +-------------------- src/public_include/decaf/shake.hxx | 75 ++-- src/public_include/decaf/spongerng.h | 91 +++++ src/public_include/decaf/strobe.h | 337 +++++++++++++++++ src/shake.c | 2 + 14 files changed, 715 insertions(+), 613 deletions(-) create mode 100644 src/public_include/decaf/spongerng.h create mode 100644 src/public_include/decaf/strobe.h diff --git a/Doxyfile b/Doxyfile index 472d307..a86e46d 100644 --- a/Doxyfile +++ b/Doxyfile @@ -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 diff --git a/Makefile b/Makefile index 1af11e7..8c47889 100644 --- a/Makefile +++ b/Makefile @@ -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) diff --git a/src/gen_headers/crypto_h.py b/src/gen_headers/crypto_h.py index 3cd3f32..00a57ef 100644 --- a/src/gen_headers/crypto_h.py +++ b/src/gen_headers/crypto_h.py @@ -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 -#include +#include + +#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. diff --git a/src/gen_headers/crypto_hxx.py b/src/gen_headers/crypto_hxx.py index f84c109..0d31932 100644 --- a/src/gen_headers/crypto_hxx.py +++ b/src/gen_headers/crypto_hxx.py @@ -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 class PublicKey; + +/** A private key for crypto over some Group */ template 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 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 &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 @@ -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 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 &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 &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 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()); diff --git a/src/gen_headers/decaf_h.py b/src/gen_headers/decaf_h.py index 702665f..0ec1769 100644 --- a/src/gen_headers/decaf_h.py +++ b/src/gen_headers/decaf_h.py @@ -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. diff --git a/src/gen_headers/decaf_hxx.py b/src/gen_headers/decaf_hxx.py index 795bef1..3a59d8b 100644 --- a/src/gen_headers/decaf_hxx.py +++ b/src/gen_headers/decaf_hxx.py @@ -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 { 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 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 { 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 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 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::operator= (it); return *this; } - /** @brief Move constructor */ + /** Move constructor */ inline Precomputed(Precomputed &&it) NOEXCEPT : OwnedOrUnowned() { *this = it; } - /** @brief Undelete copy operator */ + /** Undelete copy operator */ inline Precomputed &operator=(const Precomputed &it) NOEXCEPT { OwnedOrUnowned::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() { *this = it; } /** - * @brief Constructor which initializes from point. + * Constructor which initializes from point. */ inline explicit Precomputed(const Point &it) throw(std::bad_alloc) : OwnedOrUnowned() { *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 */ diff --git a/src/gen_headers/main.py b/src/gen_headers/main.py index de945e9..4650893 100644 --- a/src/gen_headers/main.py +++ b/src/gen_headers/main.py @@ -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 diff --git a/src/public_include/decaf/common.h b/src/public_include/decaf/common.h index fbd9918..3db0cde 100644 --- a/src/public_include/decaf/common.h +++ b/src/public_include/decaf/common.h @@ -15,6 +15,10 @@ #include #include +#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; diff --git a/src/public_include/decaf/secure_buffer.hxx b/src/public_include/decaf/secure_buffer.hxx index ffe6496..ed1c2d1 100644 --- a/src/public_include/decaf/secure_buffer.hxx +++ b/src/public_include/decaf/secure_buffer.hxx @@ -48,46 +48,30 @@ public: typedef const T& const_reference; typedef size_t size_type; typedef std::ptrdiff_t difference_type; - + template struct rebind { typedef SanitizingAllocator other; }; inline SanitizingAllocator() NOEXCEPT {} inline ~SanitizingAllocator() NOEXCEPT {} inline SanitizingAllocator(const SanitizingAllocator &) NOEXCEPT {} template inline SanitizingAllocator(const SanitizingAllocator &) 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::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(v); - } - - inline void deallocate(T* p, size_t size) NOEXCEPT { - if (p==NULL) return; - really_bzero(reinterpret_cast(p), size); - free(reinterpret_cast(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::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 > 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 +T* SanitizingAllocator::allocate ( + size_type cnt, + typename std::allocator::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(v); +} + +template +void SanitizingAllocator::deallocate(T* p, size_t size) NOEXCEPT { + if (p==NULL) return; + really_bzero(reinterpret_cast(p), size); + free(reinterpret_cast(p)); +} + +/** @endcond */ + } /* namespace decaf */ diff --git a/src/public_include/decaf/shake.h b/src/public_include/decaf/shake.h index 527bb21..01955fe 100644 --- a/src/public_include/decaf/shake.h +++ b/src/public_include/decaf/shake.h @@ -18,19 +18,25 @@ #include +#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 diff --git a/src/public_include/decaf/shake.hxx b/src/public_include/decaf/shake.hxx index 87694af..8617d9d 100644 --- a/src/public_include/decaf/shake.hxx +++ b/src/public_include/decaf/shake.hxx @@ -13,6 +13,9 @@ #define __SHAKE_HXX__ #include +#include /* TODO remove */ +#include /* TODO remove */ + #include #include #include @@ -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 inline void fixed_key ( - const Serializable &data + const Serializable &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 inline void dh_key ( - const Serializable &data + const Serializable &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 inline void send_plaintext(const Serializable &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 inline void recv_plaintext(const Serializable &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 inline void ad(const Serializable &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 inline SecureBuffer encrypt_no_auth(const Serializable &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 inline SecureBuffer decrypt_no_auth(const Serializable &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 inline SecureBuffer encrypt ( const Serializable &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 inline SecureBuffer decrypt ( - const Serializable &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); diff --git a/src/public_include/decaf/spongerng.h b/src/public_include/decaf/spongerng.h new file mode 100644 index 0000000..e006850 --- /dev/null +++ b/src/public_include/decaf/spongerng.h @@ -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 + +#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__ */ diff --git a/src/public_include/decaf/strobe.h b/src/public_include/decaf/strobe.h new file mode 100644 index 0000000..7a55c1b --- /dev/null +++ b/src/public_include/decaf/strobe.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 + +#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__ */ diff --git a/src/shake.c b/src/shake.c index f9d1a0f..66dff04 100644 --- a/src/shake.c +++ b/src/shake.c @@ -67,6 +67,8 @@ typedef struct keccak_sponge_s { #define INTERNAL_SPONGE_STRUCT 1 #include +#include +#include #define FLAG_ABSORBING 'A' #define FLAG_SQUEEZING 'Z'