| @@ -751,7 +751,7 @@ WARN_LOGFILE = | |||||
| # spaces. | # spaces. | ||||
| # Note: If this tag is empty the current directory is searched. | # 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 | # 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 | # 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. | # If the GENERATE_LATEX tag is set to YES doxygen will generate LaTeX output. | ||||
| # The default value is: YES. | # 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 | # 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 | # 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 $@` | mkdir -p `dirname $@` | ||||
| touch $@ | 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 | # # The eBATS benchmarking script | ||||
| # bat: $(BATNAME) | # bat: $(BATNAME) | ||||
| @@ -3,14 +3,18 @@ from gen_file import gen_file | |||||
| crypto_h = gen_file( | crypto_h = gen_file( | ||||
| name = "decaf/crypto_%(shortname)s.h", | name = "decaf/crypto_%(shortname)s.h", | ||||
| doc = """ | doc = """ | ||||
| @brief Example Decaf crypto routines. | |||||
| Example Decaf crypto routines. | |||||
| @warning These are merely examples, though they ought to be secure. But real | @warning These are merely examples, though they ought to be secure. But real | ||||
| protocols will decide differently on magic numbers, formats, which items to | protocols will decide differently on magic numbers, formats, which items to | ||||
| hash, etc. | hash, etc. | ||||
| @warning Experimental! The names, parameter orders etc are likely to change. | @warning Experimental! The names, parameter orders etc are likely to change. | ||||
| """, code = """ | """, code = """ | ||||
| #include <decaf/%(c_ns)s.h> | #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) */ | /** Number of bytes for a symmetric key (expanded to full key) */ | ||||
| #define %(C_NS)s_SYMMETRIC_KEY_BYTES 32 | #define %(C_NS)s_SYMMETRIC_KEY_BYTES 32 | ||||
| @@ -39,13 +43,9 @@ typedef struct { | |||||
| %(c_ns)s_private_key_s, | %(c_ns)s_private_key_s, | ||||
| /** A private key (gmp array[1] style). */ | /** A private key (gmp array[1] style). */ | ||||
| %(c_ns)s_private_key_t[1]; | %(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 [out] priv The derived private key. | ||||
| * @param [in] proto The compressed or proto-key, which must be 32 random bytes. | * @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; | ) NONNULL2 API_VIS; | ||||
| /** | /** | ||||
| * @brief Destroy a private key. | |||||
| * Destroy a private key. | |||||
| */ | */ | ||||
| void %(c_ns)s_destroy_private_key ( | void %(c_ns)s_destroy_private_key ( | ||||
| %(c_ns)s_private_key_t priv | %(c_ns)s_private_key_t priv | ||||
| ) NONNULL1 API_VIS; | ) 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 [out] pub The extracted private key. | ||||
| * @param [in] priv The private key. | * @param [in] priv The private key. | ||||
| */ | */ | ||||
| @@ -72,7 +72,7 @@ void %(c_ns)s_private_to_public ( | |||||
| ) NONNULL2 API_VIS; | ) 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 | * This is an example routine; real protocols would use something | ||||
| * protocol-specific. | * protocol-specific. | ||||
| @@ -96,7 +96,7 @@ decaf_error_t | |||||
| ) NONNULL134 WARN_UNUSED API_VIS; | ) 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 [out] sig The signature. | ||||
| * @param [in] priv Your private key. | * @param [in] priv Your private key. | ||||
| @@ -110,7 +110,7 @@ void | |||||
| ) NONNULL3 API_VIS; | ) NONNULL3 API_VIS; | ||||
| /** | /** | ||||
| * @brief Sign a message. | |||||
| * Sign a message. | |||||
| * | * | ||||
| * @param [out] sig The signature. | * @param [out] sig The signature. | ||||
| * @param [in] priv Your private key. | * @param [in] priv Your private key. | ||||
| @@ -126,7 +126,7 @@ void | |||||
| ) NONNULL3 API_VIS; | ) 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] sig The signature. | ||||
| * @param [in] pub The public key. | * @param [in] pub The public key. | ||||
| @@ -143,7 +143,7 @@ decaf_error_t | |||||
| ) NONNULL3 API_VIS WARN_UNUSED; | ) NONNULL3 API_VIS WARN_UNUSED; | ||||
| /** | /** | ||||
| * @brief Verify a signed message. | |||||
| * Verify a signed message. | |||||
| * | * | ||||
| * @param [in] sig The signature. | * @param [in] sig The signature. | ||||
| * @param [in] pub The public key. | * @param [in] pub The public key. | ||||
| @@ -3,7 +3,7 @@ from gen_file import gen_file | |||||
| crypto_hxx = gen_file( | crypto_hxx = gen_file( | ||||
| name = "decaf/crypto_%(shortname)s.hxx", | name = "decaf/crypto_%(shortname)s.hxx", | ||||
| doc = """ | 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 | @warning These are merely examples, though they ought to be secure. But real | ||||
| protocols will decide differently on magic numbers, formats, which items to | protocols will decide differently on magic numbers, formats, which items to | ||||
| hash, etc. | hash, etc. | ||||
| @@ -21,51 +21,56 @@ crypto_hxx = gen_file( | |||||
| /** @endcond */ | /** @endcond */ | ||||
| namespace decaf { | namespace decaf { | ||||
| /** A public key for crypto over some Group */ | |||||
| template <typename Group> class PublicKey; | template <typename Group> class PublicKey; | ||||
| /** A private key for crypto over some Group */ | |||||
| template <typename Group> class PrivateKey; | template <typename Group> class PrivateKey; | ||||
| /** A public key for crypto over %(name)s */ | |||||
| template<> class PublicKey<%(cxx_ns)s> | template<> class PublicKey<%(cxx_ns)s> | ||||
| : public Serializable< PublicKey<%(cxx_ns)s> > { | : public Serializable< PublicKey<%(cxx_ns)s> > { | ||||
| private: | private: | ||||
| /** @cond internal */ | |||||
| typedef %(c_ns)s_public_key_t Wrapped; | typedef %(c_ns)s_public_key_t Wrapped; | ||||
| Wrapped wrapped; | Wrapped wrapped; | ||||
| template<class Group> friend class PrivateKey; | template<class Group> friend class PrivateKey; | ||||
| /** @endcond */ | |||||
| public: | public: | ||||
| /** @brief Underlying group */ | |||||
| /** Underlying group */ | |||||
| typedef %(cxx_ns)s Group; | typedef %(cxx_ns)s Group; | ||||
| /** @brief Signature size. */ | |||||
| /** Signature size. */ | |||||
| static const size_t SIG_BYTES = sizeof(%(c_ns)s_signature_t); | 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); | static const size_t SER_BYTES = sizeof(Wrapped); | ||||
| /* TODO: convenience types like signature? */ | /* 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 { | inline explicit PublicKey(const FixedBlock<SER_BYTES> &b) NOEXCEPT { | ||||
| memcpy(wrapped,b.data(),sizeof(wrapped)); | 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; | 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 { } | inline explicit PublicKey(const NOINIT&) NOEXCEPT { } | ||||
| /** @brief Serialize into a buffer. */ | |||||
| /** Serialize into a buffer. */ | |||||
| inline void serializeInto(unsigned char *x) const NOEXCEPT { | inline void serializeInto(unsigned char *x) const NOEXCEPT { | ||||
| memcpy(x,wrapped,sizeof(wrapped)); | memcpy(x,wrapped,sizeof(wrapped)); | ||||
| } | } | ||||
| /** @brief Serialization size. */ | |||||
| /** Serialization size. */ | |||||
| inline size_t serSize() const NOEXCEPT { return SER_BYTES; } | inline size_t serSize() const NOEXCEPT { return SER_BYTES; } | ||||
| /* TODO: verify_strobe */ | /* TODO: verify_strobe */ | ||||
| /** @brief Verify a message */ | |||||
| /** Verify a message */ | |||||
| inline void verify( | inline void verify( | ||||
| const Block &message, | const Block &message, | ||||
| const FixedBlock<SIG_BYTES> &sig | const FixedBlock<SIG_BYTES> &sig | ||||
| @@ -76,71 +81,73 @@ public: | |||||
| } | } | ||||
| }; | }; | ||||
| /** A private key for crypto over %(name)s */ | |||||
| template<> class PrivateKey<%(cxx_ns)s> | template<> class PrivateKey<%(cxx_ns)s> | ||||
| : public Serializable< PrivateKey<%(cxx_ns)s> > { | : public Serializable< PrivateKey<%(cxx_ns)s> > { | ||||
| private: | private: | ||||
| /** @cond internal */ | |||||
| typedef %(c_ns)s_private_key_t Wrapped; | typedef %(c_ns)s_private_key_t Wrapped; | ||||
| Wrapped wrapped; | Wrapped wrapped; | ||||
| template<class Group> friend class PublicKey; | template<class Group> friend class PublicKey; | ||||
| /** @endcond */ | |||||
| public: | public: | ||||
| /** @brief Underlying group */ | |||||
| /** Underlying group */ | |||||
| typedef %(cxx_ns)s Group; | typedef %(cxx_ns)s Group; | ||||
| /** @brief Signature size. */ | |||||
| /** Signature size. */ | |||||
| static const size_t SIG_BYTES = sizeof(%(c_ns)s_signature_t); | 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); | 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; | 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 { } | 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 { | inline explicit PrivateKey(const FixedBlock<SER_BYTES> &b) NOEXCEPT { | ||||
| memcpy(wrapped,b.data(),sizeof(wrapped)); | 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 { | inline explicit PrivateKey(const FixedBlock<SYM_BYTES> &b) NOEXCEPT { | ||||
| %(c_ns)s_derive_private_key(wrapped, b.data()); | %(c_ns)s_derive_private_key(wrapped, b.data()); | ||||
| } | } | ||||
| /** @brief Create at random */ | |||||
| /** Create at random */ | |||||
| inline explicit PrivateKey(Rng &r) NOEXCEPT { | inline explicit PrivateKey(Rng &r) NOEXCEPT { | ||||
| FixedArrayBuffer<SYM_BYTES> tmp(r); | FixedArrayBuffer<SYM_BYTES> tmp(r); | ||||
| %(c_ns)s_derive_private_key(wrapped, tmp.data()); | %(c_ns)s_derive_private_key(wrapped, tmp.data()); | ||||
| } | } | ||||
| /** @brief Secure destructor */ | |||||
| /** Secure destructor */ | |||||
| inline ~PrivateKey() NOEXCEPT { | inline ~PrivateKey() NOEXCEPT { | ||||
| %(c_ns)s_destroy_private_key(wrapped); | %(c_ns)s_destroy_private_key(wrapped); | ||||
| } | } | ||||
| /** @brief Serialization size. */ | |||||
| /** Serialization size. */ | |||||
| inline size_t serSize() const NOEXCEPT { return SER_BYTES; } | 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 { | inline void serializeInto(unsigned char *x) const NOEXCEPT { | ||||
| memcpy(x,wrapped,sizeof(wrapped)); | memcpy(x,wrapped,sizeof(wrapped)); | ||||
| } | } | ||||
| /** @brief Compressed serialize. */ | |||||
| /** Compressed serialize. */ | |||||
| inline SecureBuffer compress() const throw(std::bad_alloc) { | inline SecureBuffer compress() const throw(std::bad_alloc) { | ||||
| SecureBuffer ret(sizeof(wrapped->sym)); | SecureBuffer ret(sizeof(wrapped->sym)); | ||||
| memcpy(ret.data(),wrapped->sym,sizeof(wrapped->sym)); | memcpy(ret.data(),wrapped->sym,sizeof(wrapped->sym)); | ||||
| return ret; | return ret; | ||||
| } | } | ||||
| /** @brief Get the public key */ | |||||
| /** Get the public key */ | |||||
| inline PublicKey<%(cxx_ns)s> pub() const NOEXCEPT { | inline PublicKey<%(cxx_ns)s> pub() const NOEXCEPT { | ||||
| PublicKey<%(cxx_ns)s> ret(*this); return ret; | PublicKey<%(cxx_ns)s> ret(*this); return ret; | ||||
| } | } | ||||
| /** @brief Derive a shared secret */ | |||||
| /** Derive a shared secret */ | |||||
| inline SecureBuffer sharedSecret( | inline SecureBuffer sharedSecret( | ||||
| const PublicKey<%(cxx_ns)s> &pub, | const PublicKey<%(cxx_ns)s> &pub, | ||||
| size_t bytes, | size_t bytes, | ||||
| @@ -153,7 +160,7 @@ public: | |||||
| return ret; | return ret; | ||||
| } | } | ||||
| /** @brief Sign a message. */ | |||||
| /** Sign a message. */ | |||||
| inline SecureBuffer sign(const Block &message) const { | inline SecureBuffer sign(const Block &message) const { | ||||
| SecureBuffer sig(SIG_BYTES); | SecureBuffer sig(SIG_BYTES); | ||||
| %(c_ns)s_sign(sig.data(), wrapped, message.data(), message.size()); | %(c_ns)s_sign(sig.data(), wrapped, message.data(), message.size()); | ||||
| @@ -10,19 +10,23 @@ decaf_h = gen_file( | |||||
| extern "C" { | extern "C" { | ||||
| #endif | #endif | ||||
| /** @cond internal */ | |||||
| #define %(C_NS)s_LIMBS (%(gf_bits)d/DECAF_WORD_BITS) | #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) | #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__ | #ifndef __%(C_NS)s_GF_DEFINED__ | ||||
| #define __%(C_NS)s_GF_DEFINED__ 1 | #define __%(C_NS)s_GF_DEFINED__ 1 | ||||
| /** @brief Galois field element internal structure */ | |||||
| typedef struct gf_%(longnum)s_s { | typedef struct gf_%(longnum)s_s { | ||||
| /** @cond internal */ | |||||
| decaf_word_t limb[%(C_NS)s_LIMBS]; | decaf_word_t limb[%(C_NS)s_LIMBS]; | ||||
| /** @endcond */ | |||||
| } __attribute__((aligned(32))) gf_%(longnum)s_s, gf_%(longnum)s_t[1]; | } __attribute__((aligned(32))) gf_%(longnum)s_s, gf_%(longnum)s_t[1]; | ||||
| #endif /* __%(C_NS)s_GF_DEFINED__ */ | #endif /* __%(C_NS)s_GF_DEFINED__ */ | ||||
| /** @endcond */ | |||||
| /** Number of bytes in a serialized point. */ | /** Number of bytes in a serialized point. */ | ||||
| #define %(C_NS)s_SER_BYTES %(ser_bytes)d | #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 | const %(c_ns)s_scalar_t scalar2 | ||||
| ) API_VIS NONNULL5 NOINLINE; | ) API_VIS NONNULL5 NOINLINE; | ||||
| /* | |||||
| * @brief Multiply one base point by two scalars: | |||||
| /** | |||||
| * Multiply one base point by two scalars: | |||||
| * | |||||
| * a1 = scalar1 * base | * a1 = scalar1 * base | ||||
| * a2 = scalar2 * base | * a2 = scalar2 * base | ||||
| * | * | ||||
| * Equivalent to two calls to %(c_ns)s_point_scalarmul, but may be | * Equivalent to two calls to %(c_ns)s_point_scalarmul, but may be | ||||
| * faster. | * 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] base1 A point to be scaled. | ||||
| * @param [in] scalar1 A first scalar to multiply by. | * @param [in] scalar1 A first scalar to multiply by. | ||||
| * @param [in] scalar2 A second 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 ( | void %(c_ns)s_point_dual_scalarmul ( | ||||
| %(c_ns)s_point_t a1, | %(c_ns)s_point_t a1, | ||||
| %(c_ns)s_point_t a2, | %(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 scalar1, | ||||
| const %(c_ns)s_scalar_t scalar2 | const %(c_ns)s_scalar_t scalar2 | ||||
| ) API_VIS NONNULL5 NOINLINE; | ) 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 | * @brief Constant-time decision between two points. If pick_b | ||||
| * is zero, out = a; else out = 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] a Any point. | ||||
| * @param [in] b Any point. | * @param [in] b Any point. | ||||
| * @param [in] pick_b If nonzero, choose point b. | * @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 | * @brief Constant-time decision between two scalars. If pick_b | ||||
| * is zero, out = a; else out = 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] a Any scalar. | ||||
| * @param [in] b Any scalar. | * @param [in] b Any scalar. | ||||
| * @param [in] pick_b If nonzero, choose scalar b. | * @param [in] pick_b If nonzero, choose scalar b. | ||||
| @@ -3,7 +3,7 @@ from gen_file import gen_file | |||||
| decaf_hxx = gen_file( | decaf_hxx = gen_file( | ||||
| name = "decaf/%(c_ns)s.hxx", | name = "decaf/%(c_ns)s.hxx", | ||||
| doc = """ | 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 | The Decaf library implements cryptographic operations on a an elliptic curve | ||||
| group of prime order p. It accomplishes this by using a twisted Edwards | group of prime order p. It accomplishes this by using a twisted Edwards | ||||
| @@ -40,7 +40,7 @@ decaf_hxx = gen_file( | |||||
| namespace decaf { | namespace decaf { | ||||
| /** | /** | ||||
| * @brief %(iso_to)s/Decaf instantiation of group. | |||||
| * %(iso_to)s/Decaf instantiation of group. | |||||
| */ | */ | ||||
| struct %(cxx_ns)s { | struct %(cxx_ns)s { | ||||
| @@ -59,61 +59,63 @@ class Precomputed; | |||||
| /** @endcond */ | /** @endcond */ | ||||
| /** | /** | ||||
| * @brief A scalar modulo the curve order. | |||||
| * A scalar modulo the curve order. | |||||
| * Supports the usual arithmetic operations, all in constant time. | * Supports the usual arithmetic operations, all in constant time. | ||||
| */ | */ | ||||
| class Scalar : public Serializable<Scalar> { | class Scalar : public Serializable<Scalar> { | ||||
| private: | private: | ||||
| /** @brief wrapped C type */ | |||||
| /** wrapped C type */ | |||||
| typedef %(c_ns)s_scalar_t Wrapped; | typedef %(c_ns)s_scalar_t Wrapped; | ||||
| public: | public: | ||||
| /** @brief Size of a serialized element */ | |||||
| /** Size of a serialized element */ | |||||
| static const size_t SER_BYTES = %(C_NS)s_SCALAR_BYTES; | 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; | Wrapped s; | ||||
| /** @brief Don't initialize. */ | |||||
| /** @cond internal */ | |||||
| /** Don't initialize. */ | |||||
| inline Scalar(const NOINIT &) NOEXCEPT {} | 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; } | 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; } | inline Scalar(const int w) NOEXCEPT { *this = w; } | ||||
| /** @brief Construct from RNG */ | |||||
| /** Construct from RNG */ | |||||
| inline explicit Scalar(Rng &rng) NOEXCEPT { | inline explicit Scalar(Rng &rng) NOEXCEPT { | ||||
| FixedArrayBuffer<SER_BYTES> sb(rng); | FixedArrayBuffer<SER_BYTES> sb(rng); | ||||
| *this = sb; | *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); } | 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; } | 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; } | inline Scalar(const Block &buffer) NOEXCEPT { *this = buffer; } | ||||
| /** @brief Serializable instance */ | |||||
| /** Serializable instance */ | |||||
| inline size_t serSize() const NOEXCEPT { return SER_BYTES; } | inline size_t serSize() const NOEXCEPT { return SER_BYTES; } | ||||
| /** @brief Serializable instance */ | |||||
| /** Serializable instance */ | |||||
| inline void serializeInto(unsigned char *buffer) const NOEXCEPT { | inline void serializeInto(unsigned char *buffer) const NOEXCEPT { | ||||
| %(c_ns)s_scalar_encode(buffer, s); | %(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; } | 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; } | 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 { | inline Scalar& operator=(int w) NOEXCEPT { | ||||
| Scalar t(-(decaf_word_t)INT_MIN); | Scalar t(-(decaf_word_t)INT_MIN); | ||||
| %(c_ns)s_scalar_set_unsigned(s,(decaf_word_t)w - (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. */ | /** Destructor securely zeorizes the scalar. */ | ||||
| inline ~Scalar() NOEXCEPT { %(c_ns)s_scalar_destroy(s); } | 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 { | inline Scalar &operator=(const Block &bl) NOEXCEPT { | ||||
| %(c_ns)s_scalar_decode_long(s,bl.data(),bl.size()); return *this; | %(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. | * @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 ( | static inline decaf_error_t __attribute__((warn_unused_result)) decode ( | ||||
| @@ -160,7 +162,7 @@ public: | |||||
| /** Negate */ | /** Negate */ | ||||
| inline Scalar operator- () const NOEXCEPT { Scalar r((NOINIT())); %(c_ns)s_scalar_sub(r.s,%(c_ns)s_scalar_zero,s); return r; } | 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) { | inline Scalar inverse() const throw(CryptoException) { | ||||
| Scalar r; | Scalar r; | ||||
| if (DECAF_SUCCESS != %(c_ns)s_scalar_invert(r.s,s)) { | if (DECAF_SUCCESS != %(c_ns)s_scalar_invert(r.s,s)) { | ||||
| @@ -169,25 +171,25 @@ public: | |||||
| return r; | 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(); } | 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(); } | 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); } | 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); } | 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); } | 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); } | inline Point operator* (const Precomputed &q) const NOEXCEPT { return q * (*this); } | ||||
| /** @brief Direct scalar multiplication. */ | |||||
| /** Direct scalar multiplication. */ | |||||
| inline SecureBuffer direct_scalarmul( | inline SecureBuffer direct_scalarmul( | ||||
| const Block &in, | const Block &in, | ||||
| decaf_bool_t allow_identity=DECAF_FALSE, | 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> { | class Point : public Serializable<Point> { | ||||
| private: | private: | ||||
| /** @brief wrapped C type */ | |||||
| /** wrapped C type */ | |||||
| typedef %(c_ns)s_point_t Wrapped; | typedef %(c_ns)s_point_t Wrapped; | ||||
| public: | public: | ||||
| /** @brief Size of a serialized element */ | |||||
| /** Size of a serialized element */ | |||||
| static const size_t SER_BYTES = %(C_NS)s_SER_BYTES; | 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; | 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; | static const size_t STEG_BYTES = HASH_BYTES * 2; | ||||
| /** The c-level object. */ | /** The c-level object. */ | ||||
| Wrapped p; | Wrapped p; | ||||
| /** @brief Don't initialize. */ | |||||
| /** @cond internal */ | |||||
| /** Don't initialize. */ | |||||
| inline Point(const NOINIT &) NOEXCEPT {} | 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); } | 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; } | 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; } | 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); } | 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 { | inline explicit Point(Rng &rng, bool uniform = true) NOEXCEPT { | ||||
| if (uniform) { | if (uniform) { | ||||
| FixedArrayBuffer<2*HASH_BYTES> b(rng); | 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. | * The all-zero string maps to the identity. | ||||
| * | * | ||||
| * @throw CryptoException the string was the wrong length, or wasn't the encoding of a point, | * @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. | * The all-zero string maps to the identity. | ||||
| * | * | ||||
| * @retval DECAF_SUCCESS the string was successfully decoded. | * @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". | * 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, | * 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. | * 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". | * 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, | * 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. | * 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 { | inline operator SecureBuffer() const { | ||||
| SecureBuffer buffer(SER_BYTES); | SecureBuffer buffer(SER_BYTES); | ||||
| @@ -311,64 +315,64 @@ public: | |||||
| return buffer; | return buffer; | ||||
| } | } | ||||
| /** @brief Serializable instance */ | |||||
| /** Serializable instance */ | |||||
| inline size_t serSize() const NOEXCEPT { return SER_BYTES; } | inline size_t serSize() const NOEXCEPT { return SER_BYTES; } | ||||
| /** @brief Serializable instance */ | |||||
| /** Serializable instance */ | |||||
| inline void serializeInto(unsigned char *buffer) const NOEXCEPT { | inline void serializeInto(unsigned char *buffer) const NOEXCEPT { | ||||
| %(c_ns)s_point_encode(buffer, p); | %(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; } | 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; } | 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; } | 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; } | 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; } | 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; } | 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; } | 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); } | 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); } | 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; } | 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; } | 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(); } | 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(); } | 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); } | 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 ( | static inline Point double_scalarmul ( | ||||
| const Point &q, const Scalar &qs, const Point &r, const Scalar &rs | const Point &q, const Scalar &qs, const Point &r, const Scalar &rs | ||||
| ) NOEXCEPT { | ) NOEXCEPT { | ||||
| Point p((NOINIT())); %(c_ns)s_point_double_scalarmul(p.p,q.p,qs.s,r.p,rs.s); return p; | 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 ( | inline void dual_scalarmul ( | ||||
| Point &q1, Point &q2, const Scalar &r1, const Scalar &r2 | Point &q1, Point &q2, const Scalar &r1, const Scalar &r2 | ||||
| ) const NOEXCEPT { | ) 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. | * For those who like their scalars before the point. | ||||
| */ | */ | ||||
| static inline Point double_scalarmul ( | 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 | * @warning This function takes variable time, and may leak the scalars (or points, but currently | ||||
| * it doesn't). | * 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; | 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 { | inline Point debugging_torque() const NOEXCEPT { | ||||
| Point q; | Point q; | ||||
| %(c_ns)s_point_debugging_torque(q.p,p); | %(c_ns)s_point_debugging_torque(q.p,p); | ||||
| return q; | 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 { | inline Point debugging_pscale(const FixedBlock<SER_BYTES> factor) const NOEXCEPT { | ||||
| Point q; | Point q; | ||||
| %(c_ns)s_point_debugging_pscale(q.p,p,factor.data()); | %(c_ns)s_point_debugging_pscale(q.p,p,factor.data()); | ||||
| return q; | 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 { | inline Point debugging_pscale(Rng &r) const NOEXCEPT { | ||||
| FixedArrayBuffer<SER_BYTES> sb(r); | FixedArrayBuffer<SER_BYTES> sb(r); | ||||
| return debugging_pscale(sb); | return debugging_pscale(sb); | ||||
| @@ -441,7 +445,7 @@ public: | |||||
| return decaf_succeed_if(ret); | 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) { | 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(); | if (size <= HASH_BYTES + 4 || size > 2*HASH_BYTES) throw LengthException(); | ||||
| SecureBuffer out(STEG_BYTES); | SecureBuffer out(STEG_BYTES); | ||||
| @@ -453,15 +457,15 @@ public: | |||||
| return out; | return out; | ||||
| } | } | ||||
| /** @brief Return the base point */ | |||||
| /** Return the base point */ | |||||
| static inline const Point base() NOEXCEPT { return Point(%(c_ns)s_point_base); } | 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); } | 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. | * 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 | * 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. | * stack-allocate a 15kiB object anyway. | ||||
| @@ -481,7 +485,7 @@ public: | |||||
| inline ~Precomputed() NOEXCEPT { clear(); } | 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. | * it from being called with 0, thereby breaking override. | ||||
| * | * | ||||
| * The underlying object must remain valid throughout the lifetime of this one. | * The underlying object must remain valid throughout the lifetime of this one. | ||||
| @@ -497,18 +501,18 @@ public: | |||||
| #if __cplusplus >= 201103L | #if __cplusplus >= 201103L | ||||
| /** @brief Move-assign operator */ | |||||
| /** Move-assign operator */ | |||||
| inline Precomputed &operator=(Precomputed &&it) NOEXCEPT { | inline Precomputed &operator=(Precomputed &&it) NOEXCEPT { | ||||
| OwnedOrUnowned<Precomputed,Precomputed_U>::operator= (it); | OwnedOrUnowned<Precomputed,Precomputed_U>::operator= (it); | ||||
| return *this; | return *this; | ||||
| } | } | ||||
| /** @brief Move constructor */ | |||||
| /** Move constructor */ | |||||
| inline Precomputed(Precomputed &&it) NOEXCEPT : OwnedOrUnowned<Precomputed,Precomputed_U>() { | inline Precomputed(Precomputed &&it) NOEXCEPT : OwnedOrUnowned<Precomputed,Precomputed_U>() { | ||||
| *this = it; | *this = it; | ||||
| } | } | ||||
| /** @brief Undelete copy operator */ | |||||
| /** Undelete copy operator */ | |||||
| inline Precomputed &operator=(const Precomputed &it) NOEXCEPT { | inline Precomputed &operator=(const Precomputed &it) NOEXCEPT { | ||||
| OwnedOrUnowned<Precomputed,Precomputed_U>::operator= (it); | OwnedOrUnowned<Precomputed,Precomputed_U>::operator= (it); | ||||
| return *this; | return *this; | ||||
| @@ -516,7 +520,7 @@ public: | |||||
| #endif | #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) { | inline Precomputed &operator=(const Point &it) throw(std::bad_alloc) { | ||||
| alloc(); | alloc(); | ||||
| @@ -525,24 +529,24 @@ public: | |||||
| } | } | ||||
| /** | /** | ||||
| * @brief Copy constructor. | |||||
| * Copy constructor. | |||||
| */ | */ | ||||
| inline Precomputed(const Precomputed &it) throw(std::bad_alloc) | inline Precomputed(const Precomputed &it) throw(std::bad_alloc) | ||||
| : OwnedOrUnowned<Precomputed,Precomputed_U>() { *this = it; } | : 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) | inline explicit Precomputed(const Point &it) throw(std::bad_alloc) | ||||
| : OwnedOrUnowned<Precomputed,Precomputed_U>() { *this = it; } | : 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; } | 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(); } | 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(); } | static inline const Precomputed base() NOEXCEPT { return Precomputed(); } | ||||
| public: | public: | ||||
| @@ -570,7 +574,7 @@ inline SecureBuffer %(cxx_ns)s::Scalar::direct_scalarmul ( | |||||
| } | } | ||||
| return out; | return out; | ||||
| } | } | ||||
| /** endcond */ | |||||
| /** @endcond */ | |||||
| #undef NOEXCEPT | #undef NOEXCEPT | ||||
| } /* namespace decaf */ | } /* namespace decaf */ | ||||
| @@ -34,8 +34,8 @@ crypto_h_code = "\n".join(( | |||||
| )) | )) | ||||
| crypto_h = gen_file( | crypto_h = gen_file( | ||||
| name = "decaf/crypto.h", | 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 | @warning These are merely examples, though they ought to be secure. But real | ||||
| protocols will decide differently on magic numbers, formats, which items to | protocols will decide differently on magic numbers, formats, which items to | ||||
| hash, etc. | hash, etc. | ||||
| @@ -50,8 +50,8 @@ crypto_hxx_code = "\n".join(( | |||||
| )) | )) | ||||
| crypto_hxx = gen_file( | crypto_hxx = gen_file( | ||||
| name = "decaf/crypto.hxx", | 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 | @warning These are merely examples, though they ought to be secure. But real | ||||
| protocols will decide differently on magic numbers, formats, which items to | protocols will decide differently on magic numbers, formats, which items to | ||||
| hash, etc. | hash, etc. | ||||
| @@ -67,7 +67,7 @@ root_h_code = "\n".join(( | |||||
| decaf_root_hxx = gen_file( | decaf_root_hxx = gen_file( | ||||
| name = "decaf.h", | name = "decaf.h", | ||||
| doc = """ | doc = """ | ||||
| @brief Master header for Decaf library. | |||||
| Master header for Decaf library. | |||||
| The Decaf library implements cryptographic operations on a elliptic curve | The Decaf library implements cryptographic operations on a elliptic curve | ||||
| groups of prime order p. It accomplishes this by using a twisted Edwards | groups of prime order p. It accomplishes this by using a twisted Edwards | ||||
| @@ -15,6 +15,10 @@ | |||||
| #include <stdint.h> | #include <stdint.h> | ||||
| #include <sys/types.h> | #include <sys/types.h> | ||||
| #ifdef __cplusplus | |||||
| extern "C" { | |||||
| #endif | |||||
| /* Goldilocks' build flags default to hidden and stripping executables. */ | /* Goldilocks' build flags default to hidden and stripping executables. */ | ||||
| /** @cond internal */ | /** @cond internal */ | ||||
| #if defined(DOXYGEN) && !defined(__attribute__) | #if defined(DOXYGEN) && !defined(__attribute__) | ||||
| @@ -43,27 +47,28 @@ | |||||
| */ | */ | ||||
| #if (defined(__ILP64__) || defined(__amd64__) || defined(__x86_64__) || (((__UINT_FAST32_MAX__)>>30)>>30)) \ | #if (defined(__ILP64__) || defined(__amd64__) || defined(__x86_64__) || (((__UINT_FAST32_MAX__)>>30)>>30)) \ | ||||
| && !defined(DECAF_FORCE_32_BIT) | && !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 | #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 | #endif | ||||
| /** DECAF_TRUE = -1 so that DECAF_TRUE & x = x */ | /** 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 | // FIXME: deploy project-wide | ||||
| typedef enum { | typedef enum { | ||||
| DECAF_SUCCESS = -1, | |||||
| DECAF_FAILURE = 0 | |||||
| DECAF_SUCCESS = -1, /**< The operation succeeded. */ | |||||
| DECAF_FAILURE = 0 /**< The operation failed. */ | |||||
| } decaf_error_t; | } decaf_error_t; | ||||
| @@ -48,46 +48,30 @@ public: | |||||
| typedef const T& const_reference; | typedef const T& const_reference; | ||||
| typedef size_t size_type; | typedef size_t size_type; | ||||
| typedef std::ptrdiff_t difference_type; | typedef std::ptrdiff_t difference_type; | ||||
| template<typename U> struct rebind { typedef SanitizingAllocator<U> other; }; | template<typename U> struct rebind { typedef SanitizingAllocator<U> other; }; | ||||
| inline SanitizingAllocator() NOEXCEPT {} | inline SanitizingAllocator() NOEXCEPT {} | ||||
| inline ~SanitizingAllocator() NOEXCEPT {} | inline ~SanitizingAllocator() NOEXCEPT {} | ||||
| inline SanitizingAllocator(const SanitizingAllocator &) NOEXCEPT {} | inline SanitizingAllocator(const SanitizingAllocator &) NOEXCEPT {} | ||||
| template<typename U, size_t a> inline SanitizingAllocator(const SanitizingAllocator<U, a> &) NOEXCEPT {} | template<typename U, size_t a> inline SanitizingAllocator(const SanitizingAllocator<U, a> &) NOEXCEPT {} | ||||
| inline T* address(T& r) const NOEXCEPT { return &r; } | inline T* address(T& r) const NOEXCEPT { return &r; } | ||||
| inline const T* address(const T& r) const NOEXCEPT { return &r; } | inline const T* address(const T& r) const NOEXCEPT { return &r; } | ||||
| inline T* allocate ( | inline T* allocate ( | ||||
| size_type cnt, | |||||
| size_type cnt, | |||||
| typename std::allocator<void>::const_pointer = 0 | 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 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 construct(T* p, const T& t) { new(p) T(t); } | ||||
| inline void destroy(T* p) { p->~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 true; } | ||||
| inline bool operator!=(SanitizingAllocator const&) const NOEXCEPT { return false; } | inline bool operator!=(SanitizingAllocator const&) const NOEXCEPT { return false; } | ||||
| /** @endcond */ | /** @endcond */ | ||||
| }; | }; | ||||
| /** A variant of std::vector which securely zerozes its state when destructed. */ | |||||
| typedef std::vector<unsigned char, SanitizingAllocator<unsigned char, 0> > SecureBuffer; | typedef std::vector<unsigned char, SanitizingAllocator<unsigned char, 0> > SecureBuffer; | ||||
| /** Constant-time compare two buffers */ | /** 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. */ | /** A reference to a block of data, which (when accessed through this base class) is const. */ | ||||
| class Block { | class Block { | ||||
| protected: | protected: | ||||
| /** @cond internal */ | |||||
| unsigned char *data_; | unsigned char *data_; | ||||
| size_t size_; | size_t size_; | ||||
| /** @endcond */ | |||||
| public: | public: | ||||
| /** Null initialization */ | /** Null initialization */ | ||||
| @@ -219,13 +205,13 @@ public: | |||||
| return Block(data()+off, length); | 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 { | inline decaf_bool_t contents_equal(const Block &b) const NOEXCEPT { | ||||
| if (b.size() != size()) return false; | if (b.size() != size()) return false; | ||||
| return decaf_memeq(b.data(),data(),size()); | 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) { | inline operator SecureBuffer() const throw(std::bad_alloc) { | ||||
| return SecureBuffer(data_,data_+size_); | return SecureBuffer(data_,data_+size_); | ||||
| } | } | ||||
| @@ -304,7 +290,9 @@ public: | |||||
| inline void zeroize() NOEXCEPT { really_bzero(data(),size()); } | inline void zeroize() NOEXCEPT { really_bzero(data(),size()); } | ||||
| private: | private: | ||||
| /** @cond internal */ | |||||
| inline void operator= (const Block &b) const NOEXCEPT DELETE; | inline void operator= (const Block &b) const NOEXCEPT DELETE; | ||||
| /** @endcond */ | |||||
| }; | }; | ||||
| @@ -330,7 +318,9 @@ public: | |||||
| } | } | ||||
| private: | private: | ||||
| /** @cond internal */ | |||||
| inline void operator= (const Block &b) const NOEXCEPT DELETE; | inline void operator= (const Block &b) const NOEXCEPT DELETE; | ||||
| /** @endcond */ | |||||
| }; | }; | ||||
| /** A fixed-size stack-allocated buffer (for NOEXCEPT semantics) */ | /** A fixed-size stack-allocated buffer (for NOEXCEPT semantics) */ | ||||
| @@ -464,6 +454,35 @@ protected: | |||||
| }; | }; | ||||
| /** @endcond */ | /** @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 */ | } /* namespace decaf */ | ||||
| @@ -18,19 +18,25 @@ | |||||
| #include <decaf/common.h> | #include <decaf/common.h> | ||||
| #ifdef __cplusplus | |||||
| extern "C" { | |||||
| #endif | |||||
| #ifndef INTERNAL_SPONGE_STRUCT | #ifndef INTERNAL_SPONGE_STRUCT | ||||
| /** Sponge container object for the various primitives. */ | /** Sponge container object for the various primitives. */ | ||||
| typedef struct keccak_sponge_s { | typedef struct keccak_sponge_s { | ||||
| /** @cond internal */ | /** @cond internal */ | ||||
| uint64_t opaque[26]; | uint64_t opaque[26]; | ||||
| /** @endcond */ | /** @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 | #endif | ||||
| /** | /** | ||||
| @@ -131,7 +137,7 @@ void sponge_hash ( | |||||
| static inline void NONNULL1 shake##n##_destroy( shake##n##_ctx_t sponge ) { \ | static inline void NONNULL1 shake##n##_destroy( shake##n##_ctx_t sponge ) { \ | ||||
| sponge_destroy(sponge->s); \ | sponge_destroy(sponge->s); \ | ||||
| } | } | ||||
| #define DECSHA3(n) \ | #define DECSHA3(n) \ | ||||
| extern const struct kparams_s SHA3_##n##_params_s API_VIS; \ | extern const struct kparams_s SHA3_##n##_params_s API_VIS; \ | ||||
| typedef struct sha3_##n##_ctx_s { keccak_sponge_t s; } sha3_##n##_ctx_t[1]; \ | typedef struct sha3_##n##_ctx_s { keccak_sponge_t s; } sha3_##n##_ctx_t[1]; \ | ||||
| @@ -163,403 +169,6 @@ DECSHA3(256) | |||||
| DECSHA3(384) | DECSHA3(384) | ||||
| DECSHA3(512) | 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 | #ifdef __cplusplus | ||||
| } /* extern "C" */ | } /* extern "C" */ | ||||
| #endif | #endif | ||||
| @@ -13,6 +13,9 @@ | |||||
| #define __SHAKE_HXX__ | #define __SHAKE_HXX__ | ||||
| #include <decaf/shake.h> | #include <decaf/shake.h> | ||||
| #include <decaf/strobe.h> /* TODO remove */ | |||||
| #include <decaf/spongerng.h> /* TODO remove */ | |||||
| #include <string> | #include <string> | ||||
| #include <sys/types.h> | #include <sys/types.h> | ||||
| #include <errno.h> | #include <errno.h> | ||||
| @@ -32,6 +35,7 @@ namespace decaf { | |||||
| /** A Keccak sponge internal class */ | /** A Keccak sponge internal class */ | ||||
| class KeccakSponge { | class KeccakSponge { | ||||
| protected: | protected: | ||||
| /** @cond internal */ | |||||
| /** The C-wrapper sponge state */ | /** The C-wrapper sponge state */ | ||||
| keccak_sponge_t sp; | keccak_sponge_t sp; | ||||
| @@ -40,6 +44,7 @@ protected: | |||||
| /** No initialization */ | /** No initialization */ | ||||
| inline KeccakSponge(const NOINIT &) NOEXCEPT { } | inline KeccakSponge(const NOINIT &) NOEXCEPT { } | ||||
| /** @endcond */ | |||||
| public: | public: | ||||
| /** Destructor zeroizes state */ | /** Destructor zeroizes state */ | ||||
| @@ -149,13 +154,16 @@ public: | |||||
| /** Sponge-based random-number generator */ | /** Sponge-based random-number generator */ | ||||
| class SpongeRng : public Rng, private KeccakSponge { | class SpongeRng : public Rng, private KeccakSponge { | ||||
| public: | public: | ||||
| /** Exception thrown when The RNG fails (to seed itself) */ | |||||
| class RngException : public std::exception { | class RngException : public std::exception { | ||||
| private: | private: | ||||
| /** @cond internal */ | |||||
| const char *const what_; | const char *const what_; | ||||
| /** @endcond */ | |||||
| public: | 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 */ | /** Initialize, deterministically by default, from block */ | ||||
| @@ -189,116 +197,127 @@ private: | |||||
| }; | }; | ||||
| /**@endcond*/ | /**@endcond*/ | ||||
| /** STROBE protocol framework object */ | |||||
| class Strobe : private KeccakSponge { | class Strobe : private KeccakSponge { | ||||
| public: | public: | ||||
| /* TODO: pull out parameters */ | |||||
| /** Number of bytes in a default authentication size. */ | |||||
| static const uint16_t DEFAULT_AUTH_SIZE = 16; | static const uint16_t DEFAULT_AUTH_SIZE = 16; | ||||
| /** Am I a server or a client? */ | /** Am I a server or a client? */ | ||||
| enum client_or_server { SERVER, CLIENT }; | enum client_or_server { SERVER, CLIENT }; | ||||
| /** Create protocol object. */ | |||||
| inline Strobe ( | 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()) { | ) NOEXCEPT : KeccakSponge(NOINIT()) { | ||||
| strobe_init(sp, ¶ms, description, whoami == CLIENT); | strobe_init(sp, ¶ms, description, whoami == CLIENT); | ||||
| keyed = false; | keyed = false; | ||||
| } | } | ||||
| /** Stir in fixed key, from a C++ block. */ | |||||
| inline void fixed_key ( | inline void fixed_key ( | ||||
| const Block &data | |||||
| const Block &data /**< The key. */ | |||||
| ) throw(ProtocolException) { | ) throw(ProtocolException) { | ||||
| strobe_fixed_key(sp, data.data(), data.size()); | strobe_fixed_key(sp, data.data(), data.size()); | ||||
| keyed = true; | keyed = true; | ||||
| } | } | ||||
| /** Stir in fixed key, from a serializeable object. */ | |||||
| template<class T> inline void fixed_key ( | template<class T> inline void fixed_key ( | ||||
| const Serializable<T> &data | |||||
| const Serializable<T> &data /**< The key. */ | |||||
| ) throw(ProtocolException) { | ) throw(ProtocolException) { | ||||
| fixed_key(data.serialize()); | fixed_key(data.serialize()); | ||||
| } | } | ||||
| /** Stir in DH key, from a C++ block. */ | |||||
| inline void dh_key ( | inline void dh_key ( | ||||
| const Block &data | |||||
| const Block &data /**< The key. */ | |||||
| ) throw(ProtocolException) { | ) throw(ProtocolException) { | ||||
| strobe_dh_key(sp, data.data(), data.size()); | strobe_dh_key(sp, data.data(), data.size()); | ||||
| keyed = true; | keyed = true; | ||||
| } | } | ||||
| /** Stir in DH key, from a serializeable object. */ | |||||
| template<class T> inline void dh_key ( | template<class T> inline void dh_key ( | ||||
| const Serializable<T> &data | |||||
| const Serializable<T> &data /**< The key. */ | |||||
| ) throw(ProtocolException) { | ) throw(ProtocolException) { | ||||
| dh_key(data.serialize()); | dh_key(data.serialize()); | ||||
| } | } | ||||
| /** Stir in an explicit nonce. */ | |||||
| inline void nonce(const Block &data) NOEXCEPT { | inline void nonce(const Block &data) NOEXCEPT { | ||||
| strobe_nonce(sp, data.data(), data.size()); | 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 { | inline void send_plaintext(const Block &data) NOEXCEPT { | ||||
| strobe_plaintext(sp, data.data(), data.size(), true); | 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 { | template<class T> inline void send_plaintext(const Serializable<T> &data) NOEXCEPT { | ||||
| send_plaintext(data.serialize()); | 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 { | inline void recv_plaintext(const Block &data) NOEXCEPT { | ||||
| strobe_plaintext(sp, data.data(), data.size(), false); | 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) { | inline void ad(const Block &data) { | ||||
| strobe_ad(sp, data.data(), data.size()); | strobe_ad(sp, data.data(), data.size()); | ||||
| } | } | ||||
| /** Stir in associated serializable data. */ | |||||
| template<class T> inline void ad(const Serializable<T> &data) NOEXCEPT { | template<class T> inline void ad(const Serializable<T> &data) NOEXCEPT { | ||||
| ad(data.serialize()); | ad(data.serialize()); | ||||
| } | } | ||||
| /** Encrypt into a buffer, without appending authentication data */ | |||||
| inline void encrypt_no_auth(Buffer out, const Block &data) throw(LengthException,ProtocolException) { | inline void encrypt_no_auth(Buffer out, const Block &data) throw(LengthException,ProtocolException) { | ||||
| if (!keyed) throw ProtocolException(); | if (!keyed) throw ProtocolException(); | ||||
| if (out.size() != data.size()) throw LengthException(); | if (out.size() != data.size()) throw LengthException(); | ||||
| strobe_encrypt(sp, out.data(), data.data(), data.size()); | strobe_encrypt(sp, out.data(), data.data(), data.size()); | ||||
| } | } | ||||
| /** Encrypt, without appending authentication data */ | |||||
| inline SecureBuffer encrypt_no_auth(const Block &data) throw(ProtocolException) { | inline SecureBuffer encrypt_no_auth(const Block &data) throw(ProtocolException) { | ||||
| SecureBuffer out(data.size()); encrypt_no_auth(out, data); return out; | 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) { | template<class T> inline SecureBuffer encrypt_no_auth(const Serializable<T> &data) throw(ProtocolException) { | ||||
| return encrypt_no_auth(data.serialize()); | 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) { | inline void decrypt_no_auth(Buffer out, const Block &data) throw(LengthException,ProtocolException) { | ||||
| if (!keyed) throw ProtocolException(); | if (!keyed) throw ProtocolException(); | ||||
| if (out.size() != data.size()) throw LengthException(); | if (out.size() != data.size()) throw LengthException(); | ||||
| strobe_decrypt(sp, out.data(), data.data(), data.size()); | strobe_decrypt(sp, out.data(), data.data(), data.size()); | ||||
| } | } | ||||
| /** Decrypt, without checking authentication data. */ | |||||
| inline SecureBuffer decrypt_no_auth(const Block &data) throw(ProtocolException) { | inline SecureBuffer decrypt_no_auth(const Block &data) throw(ProtocolException) { | ||||
| SecureBuffer out(data.size()); decrypt_no_auth(out, data); return out; | 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) { | inline void produce_auth(Buffer out) throw(LengthException,ProtocolException) { | ||||
| if (!keyed) throw ProtocolException(); /* TODO: maybe. Could use for eg sanity or dos protection */ | if (!keyed) throw ProtocolException(); /* TODO: maybe. Could use for eg sanity or dos protection */ | ||||
| if (out.size() > STROBE_MAX_AUTH_BYTES) throw LengthException(); | if (out.size() > STROBE_MAX_AUTH_BYTES) throw LengthException(); | ||||
| strobe_produce_auth(sp, out.data(), out.size()); | strobe_produce_auth(sp, out.data(), out.size()); | ||||
| } | } | ||||
| /** Produce an authenticator. */ | |||||
| inline SecureBuffer produce_auth(uint8_t bytes = DEFAULT_AUTH_SIZE) throw(ProtocolException) { | inline SecureBuffer produce_auth(uint8_t bytes = DEFAULT_AUTH_SIZE) throw(ProtocolException) { | ||||
| SecureBuffer out(bytes); produce_auth(out); return out; | SecureBuffer out(bytes); produce_auth(out); return out; | ||||
| } | } | ||||
| /** Encrypt into a buffer and append authentication data */ | |||||
| inline void encrypt( | inline void encrypt( | ||||
| Buffer out, const Block &data, uint8_t auth = DEFAULT_AUTH_SIZE | Buffer out, const Block &data, uint8_t auth = DEFAULT_AUTH_SIZE | ||||
| ) throw(LengthException,ProtocolException) { | ) throw(LengthException,ProtocolException) { | ||||
| @@ -307,18 +326,21 @@ public: | |||||
| produce_auth(out.slice(data.size(),auth)); | produce_auth(out.slice(data.size(),auth)); | ||||
| } | } | ||||
| /** Encrypt and append authentication data */ | |||||
| inline SecureBuffer encrypt ( | inline SecureBuffer encrypt ( | ||||
| const Block &data, uint8_t auth = DEFAULT_AUTH_SIZE | const Block &data, uint8_t auth = DEFAULT_AUTH_SIZE | ||||
| ) throw(LengthException,ProtocolException,std::bad_alloc ){ | ) throw(LengthException,ProtocolException,std::bad_alloc ){ | ||||
| SecureBuffer out(data.size() + auth); encrypt(out, data, auth); return out; | 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 ( | template<class T> inline SecureBuffer encrypt ( | ||||
| const Serializable<T> &data, uint8_t auth = DEFAULT_AUTH_SIZE | const Serializable<T> &data, uint8_t auth = DEFAULT_AUTH_SIZE | ||||
| ) throw(LengthException,ProtocolException,std::bad_alloc ){ | ) throw(LengthException,ProtocolException,std::bad_alloc ){ | ||||
| return encrypt(data.serialize(), auth); | return encrypt(data.serialize(), auth); | ||||
| } | } | ||||
| /** Decrypt into a buffer and check authentication data */ | |||||
| inline void decrypt ( | inline void decrypt ( | ||||
| Buffer out, const Block &data, uint8_t bytes = DEFAULT_AUTH_SIZE | Buffer out, const Block &data, uint8_t bytes = DEFAULT_AUTH_SIZE | ||||
| ) throw(LengthException, CryptoException, ProtocolException) { | ) throw(LengthException, CryptoException, ProtocolException) { | ||||
| @@ -327,12 +349,7 @@ public: | |||||
| verify_auth(data.slice(out.size(),bytes)); | 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 ( | inline SecureBuffer decrypt ( | ||||
| const Block &data, uint8_t bytes = DEFAULT_AUTH_SIZE | const Block &data, uint8_t bytes = DEFAULT_AUTH_SIZE | ||||
| ) throw(LengthException,CryptoException,ProtocolException,std::bad_alloc) { | ) throw(LengthException,CryptoException,ProtocolException,std::bad_alloc) { | ||||
| @@ -340,19 +357,25 @@ public: | |||||
| SecureBuffer out(data.size() - bytes); decrypt(out, data, bytes); return out; | SecureBuffer out(data.size() - bytes); decrypt(out, data, bytes); return out; | ||||
| } | } | ||||
| /** Check authentication data */ | |||||
| inline void verify_auth(const Block &auth) throw(LengthException,CryptoException) { | inline void verify_auth(const Block &auth) throw(LengthException,CryptoException) { | ||||
| if (auth.size() == 0 || auth.size() > STROBE_MAX_AUTH_BYTES) throw LengthException(); | 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(); | 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 { | inline void prng(Buffer out) NOEXCEPT { | ||||
| (void)strobe_prng(sp, out.data(), out.size()); | (void)strobe_prng(sp, out.data(), out.size()); | ||||
| } | } | ||||
| /** Return pseudorandom data */ | |||||
| inline SecureBuffer prng(size_t bytes) { | inline SecureBuffer prng(size_t bytes) { | ||||
| SecureBuffer out(bytes); prng(out); return out; | 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) { | inline void respec(const kparams_s ¶ms) throw(ProtocolException) { | ||||
| if (!keyed) throw(ProtocolException()); | if (!keyed) throw(ProtocolException()); | ||||
| strobe_respec(sp, ¶ms); | 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 | #define INTERNAL_SPONGE_STRUCT 1 | ||||
| #include <decaf/shake.h> | #include <decaf/shake.h> | ||||
| #include <decaf/strobe.h> | |||||
| #include <decaf/spongerng.h> | |||||
| #define FLAG_ABSORBING 'A' | #define FLAG_ABSORBING 'A' | ||||
| #define FLAG_SQUEEZING 'Z' | #define FLAG_SQUEEZING 'Z' | ||||