Преглед на файлове

Separate .h files for SHA/SHAKE, STROBE and sponge RNG. TODO: .hxx. Also add a lot of docs

master
Michael Hamburg преди 8 години
родител
ревизия
1a14abb4dd
променени са 14 файла, в които са добавени 715 реда и са изтрити 613 реда
  1. +2
    -2
      Doxyfile
  2. +2
    -2
      Makefile
  3. +14
    -14
      src/gen_headers/crypto_h.py
  4. +35
    -28
      src/gen_headers/crypto_hxx.py
  5. +16
    -11
      src/gen_headers/decaf_h.py
  6. +86
    -82
      src/gen_headers/decaf_hxx.py
  7. +5
    -5
      src/gen_headers/main.py
  8. +19
    -14
      src/public_include/decaf/common.h
  9. +44
    -25
      src/public_include/decaf/secure_buffer.hxx
  10. +13
    -404
      src/public_include/decaf/shake.h
  11. +49
    -26
      src/public_include/decaf/shake.hxx
  12. +91
    -0
      src/public_include/decaf/spongerng.h
  13. +337
    -0
      src/public_include/decaf/strobe.h
  14. +2
    -0
      src/shake.c

+ 2
- 2
Doxyfile Целия файл

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


+ 2
- 2
Makefile Целия файл

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


+ 14
- 14
src/gen_headers/crypto_h.py Целия файл

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


+ 35
- 28
src/gen_headers/crypto_hxx.py Целия файл

@@ -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());


+ 16
- 11
src/gen_headers/decaf_h.py Целия файл

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


+ 86
- 82
src/gen_headers/decaf_hxx.py Целия файл

@@ -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 */


+ 5
- 5
src/gen_headers/main.py Целия файл

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


+ 19
- 14
src/public_include/decaf/common.h Целия файл

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






+ 44
- 25
src/public_include/decaf/secure_buffer.hxx Целия файл

@@ -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 */






+ 13
- 404
src/public_include/decaf/shake.h Целия файл

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


+ 49
- 26
src/public_include/decaf/shake.hxx Целия файл

@@ -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 &params = STROBE_256
const char *description, /**< Description of this protocol. */
client_or_server whoami, /**< Am I client or server? */
const kparams_s &params = STROBE_256 /**< Strength parameters */
) NOEXCEPT : KeccakSponge(NOINIT()) { ) NOEXCEPT : KeccakSponge(NOINIT()) {
strobe_init(sp, &params, description, whoami == CLIENT); strobe_init(sp, &params, 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 &params) throw(ProtocolException) { inline void respec(const kparams_s &params) throw(ProtocolException) {
if (!keyed) throw(ProtocolException()); if (!keyed) throw(ProtocolException());
strobe_respec(sp, &params); strobe_respec(sp, &params);


+ 91
- 0
src/public_include/decaf/spongerng.h Целия файл

@@ -0,0 +1,91 @@
/**
* @file decaf/spongerng.h
* @copyright
* Copyright (c) 2015-2016 Cryptography Research, Inc. \n
* Released under the MIT License. See LICENSE.txt for license information.
* @author Mike Hamburg
* @brief Sponge-based RNGs.
* @warning This construction isn't final. In particular,
* the outputs of deterministic RNGs from this mechanism might change in future versions.
*/

#ifndef __DECAF_SPONGERNG_H__
#define __DECAF_SPONGERNG_H__

#include <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__ */

+ 337
- 0
src/public_include/decaf/strobe.h Целия файл

@@ -0,0 +1,337 @@
/**
* @file decaf/strobe.h
* @copyright
* Copyright (c) 2015-2016 Cryptography Research, Inc. \n
* Released under the MIT License. See LICENSE.txt for license information.
* @author Mike Hamburg
* @brief STROBE experimental protocol framework.
* @warning EXPERIMENTAL! The names, parameter orders etc are likely to change.
*/

#ifndef __DECAF_STROBE_H__
#define __DECAF_STROBE_H__

#include <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__ */

+ 2
- 0
src/shake.c Целия файл

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


Зареждане…
Отказ
Запис