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