| @@ -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' | |||