Bläddra i källkod

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

master
Michael Hamburg 8 år sedan
förälder
incheckning
1a14abb4dd
14 ändrade filer med 715 tillägg och 613 borttagningar
  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 Visa fil

@@ -751,7 +751,7 @@ WARN_LOGFILE =
# spaces.
# Note: If this tag is empty the current directory is searched.

INPUT = include
INPUT = build/include

# This tag can be used to specify the character encoding of the source files
# that doxygen parses. Internally doxygen uses the UTF-8 encoding. Doxygen uses
@@ -1548,7 +1548,7 @@ EXTRA_SEARCH_MAPPINGS =
# If the GENERATE_LATEX tag is set to YES doxygen will generate LaTeX output.
# The default value is: YES.

GENERATE_LATEX = YES
GENERATE_LATEX = NO

# The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put. If a
# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of


+ 2
- 2
Makefile Visa fil

@@ -243,8 +243,8 @@ $(BUILD_DOC)/timestamp:
mkdir -p `dirname $@`
touch $@
#
# doc: Doxyfile $(BUILD_OBJ)/timestamp $(HEADERS) src/*.c src/$(FIELD)/$(ARCH)/*.c src/$(FIELD)/$(ARCH)/*.h
# doxygen > /dev/null
doc: Doxyfile $(BUILD_OBJ)/timestamp $(HEADERS)
doxygen > /dev/null

# # The eBATS benchmarking script
# bat: $(BATNAME)


+ 14
- 14
src/gen_headers/crypto_h.py Visa fil

@@ -3,14 +3,18 @@ from gen_file import gen_file
crypto_h = gen_file(
name = "decaf/crypto_%(shortname)s.h",
doc = """
@brief Example Decaf crypto routines.
Example Decaf crypto routines.
@warning These are merely examples, though they ought to be secure. But real
protocols will decide differently on magic numbers, formats, which items to
hash, etc.
@warning Experimental! The names, parameter orders etc are likely to change.
""", code = """
#include <decaf/%(c_ns)s.h>
#include <decaf/shake.h>
#include <decaf/strobe.h>

#ifdef __cplusplus
extern "C" {
#endif

/** Number of bytes for a symmetric key (expanded to full key) */
#define %(C_NS)s_SYMMETRIC_KEY_BYTES 32
@@ -39,13 +43,9 @@ typedef struct {
%(c_ns)s_private_key_s,
/** A private key (gmp array[1] style). */
%(c_ns)s_private_key_t[1];

#ifdef __cplusplus
extern "C" {
#endif
/**
* @brief Derive a key from its compressed form.
* Derive a key from its compressed form.
* @param [out] priv The derived private key.
* @param [in] proto The compressed or proto-key, which must be 32 random bytes.
*/
@@ -55,14 +55,14 @@ void %(c_ns)s_derive_private_key (
) NONNULL2 API_VIS;

/**
* @brief Destroy a private key.
* Destroy a private key.
*/
void %(c_ns)s_destroy_private_key (
%(c_ns)s_private_key_t priv
) NONNULL1 API_VIS;

/**
* @brief Convert a private key to a public one.
* Convert a private key to a public one.
* @param [out] pub The extracted private key.
* @param [in] priv The private key.
*/
@@ -72,7 +72,7 @@ void %(c_ns)s_private_to_public (
) NONNULL2 API_VIS;
/**
* @brief Compute a Diffie-Hellman shared secret.
* Compute a Diffie-Hellman shared secret.
*
* This is an example routine; real protocols would use something
* protocol-specific.
@@ -96,7 +96,7 @@ decaf_error_t
) NONNULL134 WARN_UNUSED API_VIS;
/**
* @brief Sign a message from a STROBE context.
* Sign a message from a STROBE context.
*
* @param [out] sig The signature.
* @param [in] priv Your private key.
@@ -110,7 +110,7 @@ void
) NONNULL3 API_VIS;

/**
* @brief Sign a message.
* Sign a message.
*
* @param [out] sig The signature.
* @param [in] priv Your private key.
@@ -126,7 +126,7 @@ void
) NONNULL3 API_VIS;

/**
* @brief Verify a signed message from its STROBE context.
* Verify a signed message from its STROBE context.
*
* @param [in] sig The signature.
* @param [in] pub The public key.
@@ -143,7 +143,7 @@ decaf_error_t
) NONNULL3 API_VIS WARN_UNUSED;

/**
* @brief Verify a signed message.
* Verify a signed message.
*
* @param [in] sig The signature.
* @param [in] pub The public key.


+ 35
- 28
src/gen_headers/crypto_hxx.py Visa fil

@@ -3,7 +3,7 @@ from gen_file import gen_file
crypto_hxx = gen_file(
name = "decaf/crypto_%(shortname)s.hxx",
doc = """
@brief Example Decaf cyrpto routines, C++ wrapper.
Example Decaf cyrpto routines, C++ wrapper.
@warning These are merely examples, though they ought to be secure. But real
protocols will decide differently on magic numbers, formats, which items to
hash, etc.
@@ -21,51 +21,56 @@ crypto_hxx = gen_file(
/** @endcond */

namespace decaf {

/** A public key for crypto over some Group */
template <typename Group> class PublicKey;

/** A private key for crypto over some Group */
template <typename Group> class PrivateKey;

/** A public key for crypto over %(name)s */
template<> class PublicKey<%(cxx_ns)s>
: public Serializable< PublicKey<%(cxx_ns)s> > {
private:
/** @cond internal */
typedef %(c_ns)s_public_key_t Wrapped;
Wrapped wrapped;
template<class Group> friend class PrivateKey;
/** @endcond */
public:
/** @brief Underlying group */
/** Underlying group */
typedef %(cxx_ns)s Group;
/** @brief Signature size. */
/** Signature size. */
static const size_t SIG_BYTES = sizeof(%(c_ns)s_signature_t);
/** @brief Serialization size. */
/** Serialization size. */
static const size_t SER_BYTES = sizeof(Wrapped);
/* TODO: convenience types like signature? */
/** @brief Read a private key from a string*/
/** Read a private key from a string*/
inline explicit PublicKey(const FixedBlock<SER_BYTES> &b) NOEXCEPT {
memcpy(wrapped,b.data(),sizeof(wrapped));
}
/** @brief Read a private key from a string*/
/** Read a private key from a string*/
inline explicit PublicKey(const PrivateKey<%(cxx_ns)s> &b) NOEXCEPT;
/** @brief Create but don't initialize */
/** Create but don't initialize */
inline explicit PublicKey(const NOINIT&) NOEXCEPT { }
/** @brief Serialize into a buffer. */
/** Serialize into a buffer. */
inline void serializeInto(unsigned char *x) const NOEXCEPT {
memcpy(x,wrapped,sizeof(wrapped));
}
/** @brief Serialization size. */
/** Serialization size. */
inline size_t serSize() const NOEXCEPT { return SER_BYTES; }
/* TODO: verify_strobe */
/** @brief Verify a message */
/** Verify a message */
inline void verify(
const Block &message,
const FixedBlock<SIG_BYTES> &sig
@@ -76,71 +81,73 @@ public:
}
};

/** A private key for crypto over %(name)s */
template<> class PrivateKey<%(cxx_ns)s>
: public Serializable< PrivateKey<%(cxx_ns)s> > {
private:
/** @cond internal */
typedef %(c_ns)s_private_key_t Wrapped;
Wrapped wrapped;
template<class Group> friend class PublicKey;
/** @endcond */
public:
/** @brief Underlying group */
/** Underlying group */
typedef %(cxx_ns)s Group;
/** @brief Signature size. */
/** Signature size. */
static const size_t SIG_BYTES = sizeof(%(c_ns)s_signature_t);
/** @brief Serialization size. */
/** Serialization size. */
static const size_t SER_BYTES = sizeof(Wrapped);
/** @brief Compressed size. */
/** Compressed size. */
static const size_t SYM_BYTES = %(C_NS)s_SYMMETRIC_KEY_BYTES;
/** @brief Create but don't initialize */
/** Create but don't initialize */
inline explicit PrivateKey(const NOINIT&) NOEXCEPT { }
/** @brief Read a private key from a string*/
/** Read a private key from a string*/
inline explicit PrivateKey(const FixedBlock<SER_BYTES> &b) NOEXCEPT {
memcpy(wrapped,b.data(),sizeof(wrapped));
}
/** @brief Read a private key from a string*/
/** Read a private key from a string*/
inline explicit PrivateKey(const FixedBlock<SYM_BYTES> &b) NOEXCEPT {
%(c_ns)s_derive_private_key(wrapped, b.data());
}
/** @brief Create at random */
/** Create at random */
inline explicit PrivateKey(Rng &r) NOEXCEPT {
FixedArrayBuffer<SYM_BYTES> tmp(r);
%(c_ns)s_derive_private_key(wrapped, tmp.data());
}
/** @brief Secure destructor */
/** Secure destructor */
inline ~PrivateKey() NOEXCEPT {
%(c_ns)s_destroy_private_key(wrapped);
}
/** @brief Serialization size. */
/** Serialization size. */
inline size_t serSize() const NOEXCEPT { return SER_BYTES; }
/** @brief Serialize into a buffer. */
/** Serialize into a buffer. */
inline void serializeInto(unsigned char *x) const NOEXCEPT {
memcpy(x,wrapped,sizeof(wrapped));
}
/** @brief Compressed serialize. */
/** Compressed serialize. */
inline SecureBuffer compress() const throw(std::bad_alloc) {
SecureBuffer ret(sizeof(wrapped->sym));
memcpy(ret.data(),wrapped->sym,sizeof(wrapped->sym));
return ret;
}
/** @brief Get the public key */
/** Get the public key */
inline PublicKey<%(cxx_ns)s> pub() const NOEXCEPT {
PublicKey<%(cxx_ns)s> ret(*this); return ret;
}
/** @brief Derive a shared secret */
/** Derive a shared secret */
inline SecureBuffer sharedSecret(
const PublicKey<%(cxx_ns)s> &pub,
size_t bytes,
@@ -153,7 +160,7 @@ public:
return ret;
}

/** @brief Sign a message. */
/** Sign a message. */
inline SecureBuffer sign(const Block &message) const {
SecureBuffer sig(SIG_BYTES);
%(c_ns)s_sign(sig.data(), wrapped, message.data(), message.size());


+ 16
- 11
src/gen_headers/decaf_h.py Visa fil

@@ -10,19 +10,23 @@ decaf_h = gen_file(
extern "C" {
#endif

/** @cond internal */
#define %(C_NS)s_LIMBS (%(gf_bits)d/DECAF_WORD_BITS)
#define %(C_NS)s_SCALAR_BITS %(scalar_bits)d
#define %(C_NS)s_SCALAR_LIMBS ((%(scalar_bits)d-1)/DECAF_WORD_BITS+1)
/** @endcond */

/** The number of bits in a scalar */
#define %(C_NS)s_SCALAR_BITS %(scalar_bits)d

/** Galois field element internal structure */
/** @cond internal */
#ifndef __%(C_NS)s_GF_DEFINED__
#define __%(C_NS)s_GF_DEFINED__ 1
/** @brief Galois field element internal structure */
typedef struct gf_%(longnum)s_s {
/** @cond internal */
decaf_word_t limb[%(C_NS)s_LIMBS];
/** @endcond */
} __attribute__((aligned(32))) gf_%(longnum)s_s, gf_%(longnum)s_t[1];
#endif /* __%(C_NS)s_GF_DEFINED__ */
/** @endcond */

/** Number of bytes in a serialized point. */
#define %(C_NS)s_SER_BYTES %(ser_bytes)d
@@ -393,16 +397,17 @@ void %(c_ns)s_point_double_scalarmul (
const %(c_ns)s_scalar_t scalar2
) API_VIS NONNULL5 NOINLINE;
/*
* @brief Multiply one base point by two scalars:
/**
* Multiply one base point by two scalars:
*
* a1 = scalar1 * base
* a2 = scalar2 * base
*
* Equivalent to two calls to %(c_ns)s_point_scalarmul, but may be
* faster.
*
* @param [out] a1 The first multiple
* @param [out] a2 The second multiple
* @param [out] a1 The first multiple. It may be the same as the input point.
* @param [out] a2 The second multiple. It may be the same as the input point.
* @param [in] base1 A point to be scaled.
* @param [in] scalar1 A first scalar to multiply by.
* @param [in] scalar2 A second scalar to multiply by.
@@ -410,7 +415,7 @@ void %(c_ns)s_point_double_scalarmul (
void %(c_ns)s_point_dual_scalarmul (
%(c_ns)s_point_t a1,
%(c_ns)s_point_t a2,
const %(c_ns)s_point_t b,
const %(c_ns)s_point_t base1,
const %(c_ns)s_scalar_t scalar1,
const %(c_ns)s_scalar_t scalar2
) API_VIS NONNULL5 NOINLINE;
@@ -441,7 +446,7 @@ void %(c_ns)s_base_double_scalarmul_non_secret (
* @brief Constant-time decision between two points. If pick_b
* is zero, out = a; else out = b.
*
* @param [out] q The output. It may be the same as either input.
* @param [out] out The output. It may be the same as either input.
* @param [in] a Any point.
* @param [in] b Any point.
* @param [in] pick_b If nonzero, choose point b.
@@ -457,7 +462,7 @@ void %(c_ns)s_point_cond_sel (
* @brief Constant-time decision between two scalars. If pick_b
* is zero, out = a; else out = b.
*
* @param [out] q The output. It may be the same as either input.
* @param [out] out The output. It may be the same as either input.
* @param [in] a Any scalar.
* @param [in] b Any scalar.
* @param [in] pick_b If nonzero, choose scalar b.


+ 86
- 82
src/gen_headers/decaf_hxx.py Visa fil

@@ -3,7 +3,7 @@ from gen_file import gen_file
decaf_hxx = gen_file(
name = "decaf/%(c_ns)s.hxx",
doc = """
@brief A group of prime order p, C++ wrapper.
A group of prime order p, C++ wrapper.

The Decaf library implements cryptographic operations on a an elliptic curve
group of prime order p. It accomplishes this by using a twisted Edwards
@@ -40,7 +40,7 @@ decaf_hxx = gen_file(
namespace decaf {

/**
* @brief %(iso_to)s/Decaf instantiation of group.
* %(iso_to)s/Decaf instantiation of group.
*/
struct %(cxx_ns)s {

@@ -59,61 +59,63 @@ class Precomputed;
/** @endcond */

/**
* @brief A scalar modulo the curve order.
* A scalar modulo the curve order.
* Supports the usual arithmetic operations, all in constant time.
*/
class Scalar : public Serializable<Scalar> {
private:
/** @brief wrapped C type */
/** wrapped C type */
typedef %(c_ns)s_scalar_t Wrapped;

public:
/** @brief Size of a serialized element */
/** Size of a serialized element */
static const size_t SER_BYTES = %(C_NS)s_SCALAR_BYTES;

/** @brief access to the underlying scalar object */
/** access to the underlying scalar object */
Wrapped s;

/** @brief Don't initialize. */
/** @cond internal */
/** Don't initialize. */
inline Scalar(const NOINIT &) NOEXCEPT {}
/** @endcond */

/** @brief Set to an unsigned word */
/** Set to an unsigned word */
inline Scalar(const decaf_word_t w) NOEXCEPT { *this = w; }

/** @brief Set to a signed word */
/** Set to a signed word */
inline Scalar(const int w) NOEXCEPT { *this = w; }

/** @brief Construct from RNG */
/** Construct from RNG */
inline explicit Scalar(Rng &rng) NOEXCEPT {
FixedArrayBuffer<SER_BYTES> sb(rng);
*this = sb;
}

/** @brief Construct from decaf_scalar_t object. */
/** Construct from decaf_scalar_t object. */
inline Scalar(const Wrapped &t = %(c_ns)s_scalar_zero) NOEXCEPT { %(c_ns)s_scalar_copy(s,t); }

/** @brief Copy constructor. */
/** Copy constructor. */
inline Scalar(const Scalar &x) NOEXCEPT { *this = x; }

/** @brief Construct from arbitrary-length little-endian byte sequence. */
/** Construct from arbitrary-length little-endian byte sequence. */
inline Scalar(const Block &buffer) NOEXCEPT { *this = buffer; }

/** @brief Serializable instance */
/** Serializable instance */
inline size_t serSize() const NOEXCEPT { return SER_BYTES; }

/** @brief Serializable instance */
/** Serializable instance */
inline void serializeInto(unsigned char *buffer) const NOEXCEPT {
%(c_ns)s_scalar_encode(buffer, s);
}

/** @brief Assignment. */
/** Assignment. */
inline Scalar& operator=(const Scalar &x) NOEXCEPT { %(c_ns)s_scalar_copy(s,x.s); return *this; }

/** @brief Assign from unsigned word. */
/** Assign from unsigned word. */
inline Scalar& operator=(decaf_word_t w) NOEXCEPT { %(c_ns)s_scalar_set_unsigned(s,w); return *this; }


/** @brief Assign from signed int. */
/** Assign from signed int. */
inline Scalar& operator=(int w) NOEXCEPT {
Scalar t(-(decaf_word_t)INT_MIN);
%(c_ns)s_scalar_set_unsigned(s,(decaf_word_t)w - (decaf_word_t)INT_MIN);
@@ -124,13 +126,13 @@ public:
/** Destructor securely zeorizes the scalar. */
inline ~Scalar() NOEXCEPT { %(c_ns)s_scalar_destroy(s); }

/** @brief Assign from arbitrary-length little-endian byte sequence in a Block. */
/** Assign from arbitrary-length little-endian byte sequence in a Block. */
inline Scalar &operator=(const Block &bl) NOEXCEPT {
%(c_ns)s_scalar_decode_long(s,bl.data(),bl.size()); return *this;
}

/**
* @brief Decode from correct-length little-endian byte sequence.
* Decode from correct-length little-endian byte sequence.
* @return DECAF_FAILURE if the scalar is greater than or equal to the group order q.
*/
static inline decaf_error_t __attribute__((warn_unused_result)) decode (
@@ -160,7 +162,7 @@ public:
/** Negate */
inline Scalar operator- () const NOEXCEPT { Scalar r((NOINIT())); %(c_ns)s_scalar_sub(r.s,%(c_ns)s_scalar_zero,s); return r; }

/** @brief Invert with Fermat's Little Theorem (slow!). If *this == 0, return 0. */
/** Invert with Fermat's Little Theorem (slow!). If *this == 0, return 0. */
inline Scalar inverse() const throw(CryptoException) {
Scalar r;
if (DECAF_SUCCESS != %(c_ns)s_scalar_invert(r.s,s)) {
@@ -169,25 +171,25 @@ public:
return r;
}

/** @brief Divide by inverting q. If q == 0, return 0. */
/** Divide by inverting q. If q == 0, return 0. */
inline Scalar operator/ (const Scalar &q) const throw(CryptoException) { return *this * q.inverse(); }

/** @brief Divide by inverting q. If q == 0, return 0. */
/** Divide by inverting q. If q == 0, return 0. */
inline Scalar &operator/=(const Scalar &q) throw(CryptoException) { return *this *= q.inverse(); }

/** @brief Compare in constant time */
/** Compare in constant time */
inline bool operator!=(const Scalar &q) const NOEXCEPT { return !(*this == q); }

/** @brief Compare in constant time */
/** Compare in constant time */
inline bool operator==(const Scalar &q) const NOEXCEPT { return !!%(c_ns)s_scalar_eq(s,q.s); }

/** @brief Scalarmul with scalar on left. */
/** Scalarmul with scalar on left. */
inline Point operator* (const Point &q) const NOEXCEPT { return q * (*this); }

/** @brief Scalarmul-precomputed with scalar on left. */
/** Scalarmul-precomputed with scalar on left. */
inline Point operator* (const Precomputed &q) const NOEXCEPT { return q * (*this); }

/** @brief Direct scalar multiplication. */
/** Direct scalar multiplication. */
inline SecureBuffer direct_scalarmul(
const Block &in,
decaf_bool_t allow_identity=DECAF_FALSE,
@@ -196,42 +198,44 @@ public:
};

/**
* @brief Element of prime-order group.
* Element of prime-order group.
*/
class Point : public Serializable<Point> {
private:
/** @brief wrapped C type */
/** wrapped C type */
typedef %(c_ns)s_point_t Wrapped;
public:
/** @brief Size of a serialized element */
/** Size of a serialized element */
static const size_t SER_BYTES = %(C_NS)s_SER_BYTES;

/** @brief Bytes required for hash */
/** Bytes required for hash */
static const size_t HASH_BYTES = SER_BYTES;

/** @brief Size of a stegged element */
/** Size of a stegged element */
static const size_t STEG_BYTES = HASH_BYTES * 2;

/** The c-level object. */
Wrapped p;

/** @brief Don't initialize. */
/** @cond internal */
/** Don't initialize. */
inline Point(const NOINIT &) NOEXCEPT {}
/** @endcond */

/** @brief Constructor sets to identity by default. */
/** Constructor sets to identity by default. */
inline Point(const Wrapped &q = %(c_ns)s_point_identity) NOEXCEPT { %(c_ns)s_point_copy(p,q); }

/** @brief Copy constructor. */
/** Copy constructor. */
inline Point(const Point &q) NOEXCEPT { *this = q; }

/** @brief Assignment. */
/** Assignment. */
inline Point& operator=(const Point &q) NOEXCEPT { %(c_ns)s_point_copy(p,q.p); return *this; }

/** @brief Destructor securely zeorizes the point. */
/** Destructor securely zeorizes the point. */
inline ~Point() NOEXCEPT { %(c_ns)s_point_destroy(p); }

/** @brief Construct from RNG */
/** Construct from RNG */
inline explicit Point(Rng &rng, bool uniform = true) NOEXCEPT {
if (uniform) {
FixedArrayBuffer<2*HASH_BYTES> b(rng);
@@ -243,7 +247,7 @@ public:
}

/**
* @brief Initialize from a fixed-length byte string.
* Initialize from a fixed-length byte string.
* The all-zero string maps to the identity.
*
* @throw CryptoException the string was the wrong length, or wasn't the encoding of a point,
@@ -257,7 +261,7 @@ public:
}

/**
* @brief Initialize from C++ fixed-length byte string.
* Initialize from C++ fixed-length byte string.
* The all-zero string maps to the identity.
*
* @retval DECAF_SUCCESS the string was successfully decoded.
@@ -271,7 +275,7 @@ public:
}

/**
* @brief Map uniformly to the curve from a hash buffer.
* Map uniformly to the curve from a hash buffer.
* The empty or all-zero string maps to the identity, as does the string "\\x01".
* If the buffer is shorter than 2*HASH_BYTES, well, it won't be as uniform,
* but the buffer will be zero-padded on the right.
@@ -281,7 +285,7 @@ public:
}

/**
* @brief Map to the curve from a hash buffer.
* Map to the curve from a hash buffer.
* The empty or all-zero string maps to the identity, as does the string "\\x01".
* If the buffer is shorter than 2*HASH_BYTES, well, it won't be as uniform,
* but the buffer will be zero-padded on the right.
@@ -303,7 +307,7 @@ public:
}

/**
* @brief Encode to string. The identity encodes to the all-zero string.
* Encode to string. The identity encodes to the all-zero string.
*/
inline operator SecureBuffer() const {
SecureBuffer buffer(SER_BYTES);
@@ -311,64 +315,64 @@ public:
return buffer;
}

/** @brief Serializable instance */
/** Serializable instance */
inline size_t serSize() const NOEXCEPT { return SER_BYTES; }

/** @brief Serializable instance */
/** Serializable instance */
inline void serializeInto(unsigned char *buffer) const NOEXCEPT {
%(c_ns)s_point_encode(buffer, p);
}

/** @brief Point add. */
/** Point add. */
inline Point operator+ (const Point &q) const NOEXCEPT { Point r((NOINIT())); %(c_ns)s_point_add(r.p,p,q.p); return r; }

/** @brief Point add. */
/** Point add. */
inline Point &operator+=(const Point &q) NOEXCEPT { %(c_ns)s_point_add(p,p,q.p); return *this; }

/** @brief Point subtract. */
/** Point subtract. */
inline Point operator- (const Point &q) const NOEXCEPT { Point r((NOINIT())); %(c_ns)s_point_sub(r.p,p,q.p); return r; }

/** @brief Point subtract. */
/** Point subtract. */
inline Point &operator-=(const Point &q) NOEXCEPT { %(c_ns)s_point_sub(p,p,q.p); return *this; }

/** @brief Point negate. */
/** Point negate. */
inline Point operator- () const NOEXCEPT { Point r((NOINIT())); %(c_ns)s_point_negate(r.p,p); return r; }

/** @brief Double the point out of place. */
/** Double the point out of place. */
inline Point times_two () const NOEXCEPT { Point r((NOINIT())); %(c_ns)s_point_double(r.p,p); return r; }

/** @brief Double the point in place. */
/** Double the point in place. */
inline Point &double_in_place() NOEXCEPT { %(c_ns)s_point_double(p,p); return *this; }

/** @brief Constant-time compare. */
/** Constant-time compare. */
inline bool operator!=(const Point &q) const NOEXCEPT { return ! %(c_ns)s_point_eq(p,q.p); }

/** @brief Constant-time compare. */
/** Constant-time compare. */
inline bool operator==(const Point &q) const NOEXCEPT { return !!%(c_ns)s_point_eq(p,q.p); }

/** @brief Scalar multiply. */
/** Scalar multiply. */
inline Point operator* (const Scalar &s) const NOEXCEPT { Point r((NOINIT())); %(c_ns)s_point_scalarmul(r.p,p,s.s); return r; }

/** @brief Scalar multiply in place. */
/** Scalar multiply in place. */
inline Point &operator*=(const Scalar &s) NOEXCEPT { %(c_ns)s_point_scalarmul(p,p,s.s); return *this; }

/** @brief Multiply by s.inverse(). If s=0, maps to the identity. */
/** Multiply by s.inverse(). If s=0, maps to the identity. */
inline Point operator/ (const Scalar &s) const throw(CryptoException) { return (*this) * s.inverse(); }

/** @brief Multiply by s.inverse(). If s=0, maps to the identity. */
/** Multiply by s.inverse(). If s=0, maps to the identity. */
inline Point &operator/=(const Scalar &s) throw(CryptoException) { return (*this) *= s.inverse(); }

/** @brief Validate / sanity check */
/** Validate / sanity check */
inline bool validate() const NOEXCEPT { return %(c_ns)s_point_valid(p); }

/** @brief Double-scalar multiply, equivalent to q*qs + r*rs but faster. */
/** Double-scalar multiply, equivalent to q*qs + r*rs but faster. */
static inline Point double_scalarmul (
const Point &q, const Scalar &qs, const Point &r, const Scalar &rs
) NOEXCEPT {
Point p((NOINIT())); %(c_ns)s_point_double_scalarmul(p.p,q.p,qs.s,r.p,rs.s); return p;
}

/** @brief Dual-scalar multiply, equivalent to this*r1, this*r2 but faster. */
/** Dual-scalar multiply, equivalent to this*r1, this*r2 but faster. */
inline void dual_scalarmul (
Point &q1, Point &q2, const Scalar &r1, const Scalar &r2
) const NOEXCEPT {
@@ -376,7 +380,7 @@ public:
}

/**
* @brief Double-scalar multiply, equivalent to q*qs + r*rs but faster.
* Double-scalar multiply, equivalent to q*qs + r*rs but faster.
* For those who like their scalars before the point.
*/
static inline Point double_scalarmul (
@@ -386,7 +390,7 @@ public:
}

/**
* @brief Double-scalar multiply: this point by the first scalar and base by the second scalar.
* Double-scalar multiply: this point by the first scalar and base by the second scalar.
* @warning This function takes variable time, and may leak the scalars (or points, but currently
* it doesn't).
*/
@@ -394,21 +398,21 @@ public:
Point r((NOINIT())); %(c_ns)s_base_double_scalarmul_non_secret(r.p,s_base.s,p,s.s); return r;
}

/** @brief Return a point equal to *this, whose internal data is rotated by a torsion element. */
/** Return a point equal to *this, whose internal data is rotated by a torsion element. */
inline Point debugging_torque() const NOEXCEPT {
Point q;
%(c_ns)s_point_debugging_torque(q.p,p);
return q;
}

/** @brief Return a point equal to *this, whose internal data has a modified representation. */
/** Return a point equal to *this, whose internal data has a modified representation. */
inline Point debugging_pscale(const FixedBlock<SER_BYTES> factor) const NOEXCEPT {
Point q;
%(c_ns)s_point_debugging_pscale(q.p,p,factor.data());
return q;
}

/** @brief Return a point equal to *this, whose internal data has a randomized representation. */
/** Return a point equal to *this, whose internal data has a randomized representation. */
inline Point debugging_pscale(Rng &r) const NOEXCEPT {
FixedArrayBuffer<SER_BYTES> sb(r);
return debugging_pscale(sb);
@@ -441,7 +445,7 @@ public:
return decaf_succeed_if(ret);
}

/** @brief Steganographically encode this */
/** Steganographically encode this */
inline SecureBuffer steg_encode(Rng &rng, size_t size=STEG_BYTES) const throw(std::bad_alloc, LengthException) {
if (size <= HASH_BYTES + 4 || size > 2*HASH_BYTES) throw LengthException();
SecureBuffer out(STEG_BYTES);
@@ -453,15 +457,15 @@ public:
return out;
}

/** @brief Return the base point */
/** Return the base point */
static inline const Point base() NOEXCEPT { return Point(%(c_ns)s_point_base); }

/** @brief Return the identity point */
/** Return the identity point */
static inline const Point identity() NOEXCEPT { return Point(%(c_ns)s_point_identity); }
};

/**
* @brief Precomputed table of points.
* Precomputed table of points.
* Minor difficulties arise here because the decaf API doesn't expose, as a constant, how big such an object is.
* Therefore we have to call malloc() or friends, but that's probably for the best, because you don't want to
* stack-allocate a 15kiB object anyway.
@@ -481,7 +485,7 @@ public:
inline ~Precomputed() NOEXCEPT { clear(); }

/**
* @brief Initialize from underlying type, declared as a reference to prevent
* Initialize from underlying type, declared as a reference to prevent
* it from being called with 0, thereby breaking override.
*
* The underlying object must remain valid throughout the lifetime of this one.
@@ -497,18 +501,18 @@ public:


#if __cplusplus >= 201103L
/** @brief Move-assign operator */
/** Move-assign operator */
inline Precomputed &operator=(Precomputed &&it) NOEXCEPT {
OwnedOrUnowned<Precomputed,Precomputed_U>::operator= (it);
return *this;
}

/** @brief Move constructor */
/** Move constructor */
inline Precomputed(Precomputed &&it) NOEXCEPT : OwnedOrUnowned<Precomputed,Precomputed_U>() {
*this = it;
}

/** @brief Undelete copy operator */
/** Undelete copy operator */
inline Precomputed &operator=(const Precomputed &it) NOEXCEPT {
OwnedOrUnowned<Precomputed,Precomputed_U>::operator= (it);
return *this;
@@ -516,7 +520,7 @@ public:
#endif

/**
* @brief Initilaize from point. Must allocate memory, and may throw.
* Initilaize from point. Must allocate memory, and may throw.
*/
inline Precomputed &operator=(const Point &it) throw(std::bad_alloc) {
alloc();
@@ -525,24 +529,24 @@ public:
}

/**
* @brief Copy constructor.
* Copy constructor.
*/
inline Precomputed(const Precomputed &it) throw(std::bad_alloc)
: OwnedOrUnowned<Precomputed,Precomputed_U>() { *this = it; }

/**
* @brief Constructor which initializes from point.
* Constructor which initializes from point.
*/
inline explicit Precomputed(const Point &it) throw(std::bad_alloc)
: OwnedOrUnowned<Precomputed,Precomputed_U>() { *this = it; }

/** @brief Fixed base scalarmul. */
/** Fixed base scalarmul. */
inline Point operator* (const Scalar &s) const NOEXCEPT { Point r; %(c_ns)s_precomputed_scalarmul(r.p,get(),s.s); return r; }

/** @brief Multiply by s.inverse(). If s=0, maps to the identity. */
/** Multiply by s.inverse(). If s=0, maps to the identity. */
inline Point operator/ (const Scalar &s) const throw(CryptoException) { return (*this) * s.inverse(); }

/** @brief Return the table for the base point. */
/** Return the table for the base point. */
static inline const Precomputed base() NOEXCEPT { return Precomputed(); }

public:
@@ -570,7 +574,7 @@ inline SecureBuffer %(cxx_ns)s::Scalar::direct_scalarmul (
}
return out;
}
/** endcond */
/** @endcond */

#undef NOEXCEPT
} /* namespace decaf */


+ 5
- 5
src/gen_headers/main.py Visa fil

@@ -34,8 +34,8 @@ crypto_h_code = "\n".join((
))
crypto_h = gen_file(
name = "decaf/crypto.h",
doc = """@brief
@brief Example Decaf crypto routines, metaheader.
doc = """
Example Decaf crypto routines, metaheader.
@warning These are merely examples, though they ought to be secure. But real
protocols will decide differently on magic numbers, formats, which items to
hash, etc.
@@ -50,8 +50,8 @@ crypto_hxx_code = "\n".join((
))
crypto_hxx = gen_file(
name = "decaf/crypto.hxx",
doc = """@brief
@brief Example Decaf crypto routines, C++, metaheader.
doc = """
Example Decaf crypto routines, C++, metaheader.
@warning These are merely examples, though they ought to be secure. But real
protocols will decide differently on magic numbers, formats, which items to
hash, etc.
@@ -67,7 +67,7 @@ root_h_code = "\n".join((
decaf_root_hxx = gen_file(
name = "decaf.h",
doc = """
@brief Master header for Decaf library.
Master header for Decaf library.
The Decaf library implements cryptographic operations on a elliptic curve
groups of prime order p. It accomplishes this by using a twisted Edwards


+ 19
- 14
src/public_include/decaf/common.h Visa fil

@@ -15,6 +15,10 @@
#include <stdint.h>
#include <sys/types.h>

#ifdef __cplusplus
extern "C" {
#endif

/* Goldilocks' build flags default to hidden and stripping executables. */
/** @cond internal */
#if defined(DOXYGEN) && !defined(__attribute__)
@@ -43,27 +47,28 @@
*/
#if (defined(__ILP64__) || defined(__amd64__) || defined(__x86_64__) || (((__UINT_FAST32_MAX__)>>30)>>30)) \
&& !defined(DECAF_FORCE_32_BIT)
#define DECAF_WORD_BITS 64
typedef uint64_t decaf_word_t, decaf_bool_t;
typedef __uint128_t decaf_dword_t;
#define DECAF_WORD_BITS 64 /**< The number of bits in a word */
typedef uint64_t decaf_word_t; /**< Word size for internal computations */
typedef uint64_t decaf_bool_t; /**< "Boolean" type, will be set to all-zero or all-one (i.e. -1u) */
typedef __uint128_t decaf_dword_t; /**< Double-word size for internal computations */
#else
#define DECAF_WORD_BITS 32
typedef uint32_t decaf_word_t, decaf_bool_t;
typedef uint64_t decaf_dword_t;
#endif

#ifdef __cplusplus
extern "C" {
#define DECAF_WORD_BITS 32 /**< The number of bits in a word */
typedef uint32_t decaf_word_t; /**< Word size for internal computations */
typedef uint32_t decaf_bool_t; /**< "Boolean" type, will be set to all-zero or all-one (i.e. -1u) */
typedef uint64_t decaf_dword_t; /**< Double-word size for internal computations */
#endif
/** DECAF_TRUE = -1 so that DECAF_TRUE & x = x */
static const decaf_bool_t DECAF_TRUE = -(decaf_bool_t)1, DECAF_FALSE = 0;
static const decaf_bool_t DECAF_TRUE = -(decaf_bool_t)1;

/** DECAF_FALSE = 0 so that DECAF_FALSE & x = 0 */
static const decaf_bool_t DECAF_FALSE = 0;

/* Success or failure */
/** Another boolean type used to indicate success or failure. */
// FIXME: deploy project-wide
typedef enum {
DECAF_SUCCESS = -1,
DECAF_FAILURE = 0
DECAF_SUCCESS = -1, /**< The operation succeeded. */
DECAF_FAILURE = 0 /**< The operation failed. */
} decaf_error_t;




+ 44
- 25
src/public_include/decaf/secure_buffer.hxx Visa fil

@@ -48,46 +48,30 @@ public:
typedef const T& const_reference;
typedef size_t size_type;
typedef std::ptrdiff_t difference_type;
template<typename U> struct rebind { typedef SanitizingAllocator<U> other; };
inline SanitizingAllocator() NOEXCEPT {}
inline ~SanitizingAllocator() NOEXCEPT {}
inline SanitizingAllocator(const SanitizingAllocator &) NOEXCEPT {}
template<typename U, size_t a> inline SanitizingAllocator(const SanitizingAllocator<U, a> &) NOEXCEPT {}
inline T* address(T& r) const NOEXCEPT { return &r; }
inline const T* address(const T& r) const NOEXCEPT { return &r; }

inline T* allocate (
size_type cnt,
size_type cnt,
typename std::allocator<void>::const_pointer = 0
) throw(std::bad_alloc) {
void *v;
int ret = 0;
if (alignment) ret = posix_memalign(&v, alignment, cnt * sizeof(T));
else v = malloc(cnt * sizeof(T));
if (ret || v==NULL) throw(std::bad_alloc());
return reinterpret_cast<T*>(v);
}

inline void deallocate(T* p, size_t size) NOEXCEPT {
if (p==NULL) return;
really_bzero(reinterpret_cast<void*>(p), size);
free(reinterpret_cast<void*>(p));
}

) throw(std::bad_alloc);
inline void deallocate(T* p, size_t size) NOEXCEPT;
inline size_t max_size() const NOEXCEPT { return std::numeric_limits<size_t>::max() / sizeof(T); }

inline void construct(T* p, const T& t) { new(p) T(t); }
inline void destroy(T* p) { p->~T(); }
inline bool operator==(SanitizingAllocator const&) const NOEXCEPT { return true; }
inline bool operator!=(SanitizingAllocator const&) const NOEXCEPT { return false; }
/** @endcond */
};

/** A variant of std::vector which securely zerozes its state when destructed. */
typedef std::vector<unsigned char, SanitizingAllocator<unsigned char, 0> > SecureBuffer;

/** Constant-time compare two buffers */
@@ -170,8 +154,10 @@ public:
/** A reference to a block of data, which (when accessed through this base class) is const. */
class Block {
protected:
/** @cond internal */
unsigned char *data_;
size_t size_;
/** @endcond */

public:
/** Null initialization */
@@ -219,13 +205,13 @@ public:
return Block(data()+off, length);
}
/* Content-wise comparison; constant-time if they are the same length. */
/** Content-wise comparison; constant-time if they are the same length. */
inline decaf_bool_t contents_equal(const Block &b) const NOEXCEPT {
if (b.size() != size()) return false;
return decaf_memeq(b.data(),data(),size());
}
/* Create new block from this */
/** Create new block from this */
inline operator SecureBuffer() const throw(std::bad_alloc) {
return SecureBuffer(data_,data_+size_);
}
@@ -304,7 +290,9 @@ public:
inline void zeroize() NOEXCEPT { really_bzero(data(),size()); }
private:
/** @cond internal */
inline void operator= (const Block &b) const NOEXCEPT DELETE;
/** @endcond */
};


@@ -330,7 +318,9 @@ public:
}
private:
/** @cond internal */
inline void operator= (const Block &b) const NOEXCEPT DELETE;
/** @endcond */
};

/** A fixed-size stack-allocated buffer (for NOEXCEPT semantics) */
@@ -464,6 +454,35 @@ protected:
};
/** @endcond */

/*******************************************/
/* Inline implementations below this point */
/*******************************************/

/** @cond internal */
template<typename T, size_t alignment>
T* SanitizingAllocator<T,alignment>::allocate (
size_type cnt,
typename std::allocator<void>::const_pointer
) throw(std::bad_alloc) {
void *v;
int ret = 0;
if (alignment) ret = posix_memalign(&v, alignment, cnt * sizeof(T));
else v = malloc(cnt * sizeof(T));
if (ret || v==NULL) throw(std::bad_alloc());
return reinterpret_cast<T*>(v);
}

template<typename T, size_t alignment>
void SanitizingAllocator<T,alignment>::deallocate(T* p, size_t size) NOEXCEPT {
if (p==NULL) return;
really_bzero(reinterpret_cast<void*>(p), size);
free(reinterpret_cast<void*>(p));
}

/** @endcond */

} /* namespace decaf */




+ 13
- 404
src/public_include/decaf/shake.h Visa fil

@@ -18,19 +18,25 @@

#include <decaf/common.h>

#ifdef __cplusplus
extern "C" {
#endif

#ifndef INTERNAL_SPONGE_STRUCT
/** Sponge container object for the various primitives. */
typedef struct keccak_sponge_s {
/** @cond internal */
uint64_t opaque[26];
/** @endcond */
} keccak_sponge_t[1];
struct kparams_s;
#endif
typedef struct keccak_sponge_s keccak_strobe_t[1], keccak_prng_t[1];
} keccak_sponge_s;

#ifdef __cplusplus
extern "C" {
/** Convenience GMP-style one-element array version */
typedef struct keccak_sponge_s keccak_sponge_t[1];

/** Parameters for sponge construction, distinguishing SHA3 and
* SHAKE instances.
*/
struct kparams_s;
#endif

/**
@@ -131,7 +137,7 @@ void sponge_hash (
static inline void NONNULL1 shake##n##_destroy( shake##n##_ctx_t sponge ) { \
sponge_destroy(sponge->s); \
}
#define DECSHA3(n) \
extern const struct kparams_s SHA3_##n##_params_s API_VIS; \
typedef struct sha3_##n##_ctx_s { keccak_sponge_t s; } sha3_##n##_ctx_t[1]; \
@@ -163,403 +169,6 @@ DECSHA3(256)
DECSHA3(384)
DECSHA3(512)

/**
* @brief Initialize a sponge-based CSPRNG from a buffer.
*
* @param [out] prng The prng object.
* @param [in] in The initial data.
* @param [in] len The length of the initial data.
* @param [in] deterministic If zero, allow RNG to stir in nondeterministic
* data from RDRAND or RDTSC.
*/
void spongerng_init_from_buffer (
keccak_prng_t prng,
const uint8_t * __restrict__ in,
size_t len,
int deterministic
) NONNULL2 API_VIS;
/**
* @brief Initialize a sponge-based CSPRNG from a file.
*
* @param [out] prng The prng object.
* @param [in] file A name of a file containing initial data.
* @param [in] len The length of the initial data. Must be positive.
* @param [in] deterministic If zero, allow RNG to stir in nondeterministic
* data from RDRAND or RDTSC.
*
* @retval DECAF_SUCCESS success.
* @retval DECAF_FAILURE failure.
* @note On failure, errno can be used to determine the cause.
*/
decaf_error_t spongerng_init_from_file (
keccak_prng_t prng,
const char *file,
size_t len,
int deterministic
) NONNULL2 API_VIS WARN_UNUSED;

/**
* @brief Initialize a nondeterministic sponge-based CSPRNG from /dev/urandom.
*
* @param [out] sponge The sponge object.
*
* @retval DECAF_SUCCESS success.
* @retval DECAF_FAILURE failure.
* @note On failure, errno can be used to determine the cause.
*/
decaf_error_t spongerng_init_from_dev_urandom (
keccak_prng_t prng
) API_VIS WARN_UNUSED;

/**
* @brief Output bytes from a sponge-based CSPRNG.
*
* @param [inout] sponge The sponge object.
* @param [out] out The output buffer.
* @param [in] len The output buffer's length.
*/
void spongerng_next (
keccak_prng_t prng,
uint8_t * __restrict__ out,
size_t len
) API_VIS;

/**
* @brief Stir entropy data into a sponge-based CSPRNG from a buffer.
*
* @param [out] sponge The sponge object.
* @param [in] in The entropy data.
* @param [in] len The length of the initial data.
*/
void spongerng_stir (
keccak_prng_t prng,
const uint8_t * __restrict__ in,
size_t len
) NONNULL2 API_VIS;

extern const struct kparams_s STROBE_128 API_VIS;
extern const struct kparams_s STROBE_256 API_VIS;
extern const struct kparams_s STROBE_KEYED_128 API_VIS;
extern const struct kparams_s STROBE_KEYED_256 API_VIS;

typedef enum {
STROBE_MODE_ABSORB = 0,
STROBE_MODE_DUPLEX = 1,
STROBE_MODE_ABSORB_R = 2,
STROBE_MODE_DUPLEX_R = 3,
/* FIXME: no bits allocated in .py version */
STROBE_MODE_PLAINTEXT = 4,
STROBE_MODE_SQUEEZE = 5,
STROBE_MODE_FORGET = 6,
STROBE_MODE_SQUEEZE_R = 7
} strobe_mode_t;

#define STROBE_FLAG_CLIENT_SENT (1<<8)
#define STROBE_FLAG_IMPLICIT (1<<9)
#define STROBE_FLAG_FORGET (1<<12)
#define STROBE_FLAG_NO_LENGTH (1<<15)

/* After 1<<16, flags don't go to the sponge anymore, they just affect the handling */
#define STROBE_FLAG_RECV (1<<16)
#define STROBE_FLAG_RUN_F (1<<17)
#define STROBE_FLAG_MORE (1<<18)
#define STROBE_FLAG_LENGTH_64 (1<<19)
#define STROBE_FLAG_NONDIR (STROBE_FLAG_IMPLICIT)

/** Automatic flags implied by the mode */
/* HACK: SQUEEZE_R is treated as directional because its' MAC */
#define STROBE_AUTO_FLAGS(_mode) \
( (((_mode)&1) ? STROBE_FLAG_RUN_F : 0) \
| (( ((_mode) & ~2) == STROBE_MODE_ABSORB \
|| (_mode) == STROBE_MODE_SQUEEZE \
|| (_mode) == STROBE_MODE_FORGET \
) ? STROBE_FLAG_IMPLICIT|STROBE_FLAG_NONDIR : 0) \
)

#define STROBE_CONTROL_WORD(_name,_id,_mode,_flags) \
static const uint32_t _name = _id | (_mode<<10) | (_mode<<29) | _flags | STROBE_AUTO_FLAGS(_mode)

STROBE_CONTROL_WORD(STROBE_CW_INIT, 0x00, STROBE_MODE_ABSORB, 0);
/* Ciphers */
STROBE_CONTROL_WORD(STROBE_CW_FIXED_KEY, 0x10, STROBE_MODE_ABSORB, 0);
STROBE_CONTROL_WORD(STROBE_CW_STATIC_PUB, 0x11, STROBE_MODE_PLAINTEXT, 0);
STROBE_CONTROL_WORD(STROBE_CW_DH_EPH, 0x12, STROBE_MODE_PLAINTEXT, 0);
STROBE_CONTROL_WORD(STROBE_CW_DH_KEY, 0x13, STROBE_MODE_ABSORB, 0);
STROBE_CONTROL_WORD(STROBE_CW_PRNG, 0x18, STROBE_MODE_SQUEEZE, STROBE_FLAG_FORGET);
STROBE_CONTROL_WORD(STROBE_CW_SESSION_HASH, 0x19, STROBE_MODE_SQUEEZE, 0);

/* Reuse for PRNG */
STROBE_CONTROL_WORD(STROBE_CW_PRNG_INITIAL_SEED, 0x10, STROBE_MODE_ABSORB, STROBE_FLAG_NO_LENGTH);
STROBE_CONTROL_WORD(STROBE_CW_PRNG_RESEED, 0x11, STROBE_MODE_ABSORB, STROBE_FLAG_NO_LENGTH);
STROBE_CONTROL_WORD(STROBE_CW_PRNG_CPU_SEED, 0x12, STROBE_MODE_ABSORB, 0);
STROBE_CONTROL_WORD(STROBE_CW_PRNG_USER_SEED, 0x13, STROBE_MODE_ABSORB, STROBE_FLAG_LENGTH_64);
STROBE_CONTROL_WORD(STROBE_CW_PRNG_PRNG, 0x14, STROBE_MODE_SQUEEZE, STROBE_FLAG_LENGTH_64 | STROBE_FLAG_FORGET);

/* Signatures */
STROBE_CONTROL_WORD(STROBE_CW_SIG_SCHEME, 0x20, STROBE_MODE_ABSORB, 0);
STROBE_CONTROL_WORD(STROBE_CW_SIG_PK, 0x21, STROBE_MODE_ABSORB, 0);
STROBE_CONTROL_WORD(STROBE_CW_SIG_EPH, 0x22, STROBE_MODE_PLAINTEXT, 0);
STROBE_CONTROL_WORD(STROBE_CW_SIG_CHAL, 0x23, STROBE_MODE_SQUEEZE, 0);
STROBE_CONTROL_WORD(STROBE_CW_SIG_RESP, 0x24, STROBE_MODE_DUPLEX, 0);


/* Payloads and encrypted data */

STROBE_CONTROL_WORD(STROBE_CW_PAYLOAD_PLAINTEXT, 0x30, STROBE_MODE_PLAINTEXT, 0);
STROBE_CONTROL_WORD(STROBE_CW_PAYLOAD_CIPHERTEXT, 0x31, STROBE_MODE_DUPLEX, 0);
STROBE_CONTROL_WORD(STROBE_CW_MAC, 0x32, STROBE_MODE_SQUEEZE_R, STROBE_FLAG_FORGET);
STROBE_CONTROL_WORD(STROBE_CW_AD_EXPLICIT, 0x34, STROBE_MODE_PLAINTEXT, 0);
STROBE_CONTROL_WORD(STROBE_CW_AD_IMPLICIT, 0x35, STROBE_MODE_ABSORB, 0);
STROBE_CONTROL_WORD(STROBE_CW_NONCE_EXPLICIT, 0x36, STROBE_MODE_PLAINTEXT, 0);
STROBE_CONTROL_WORD(STROBE_CW_NONCE_IMPLICIT, 0x37, STROBE_MODE_ABSORB, 0);

STROBE_CONTROL_WORD(STROBE_CW_STREAMING_PLAINTEXT,0x30, STROBE_MODE_PLAINTEXT, STROBE_FLAG_NO_LENGTH); /* TODO: orly? */

/* Change spec, control flow, etc */
STROBE_CONTROL_WORD(STROBE_CW_COMPRESS, 0x40, STROBE_MODE_ABSORB_R, 0);
/* FIXME: adjust this respec logic */
STROBE_CONTROL_WORD(STROBE_CW_RESPEC_INFO, 0x41, STROBE_MODE_ABSORB, STROBE_FLAG_RUN_F | STROBE_FLAG_FORGET);
STROBE_CONTROL_WORD(STROBE_CW_RESPEC, 0x42, STROBE_MODE_ABSORB_R, STROBE_FLAG_RUN_F);
STROBE_CONTROL_WORD(STROBE_CW_FORK, 0x43, STROBE_MODE_ABSORB_R, STROBE_FLAG_RUN_F | STROBE_FLAG_FORGET);
/* FIXME: instance can be rolled back to recover other INSTANCEs */
STROBE_CONTROL_WORD(STROBE_CW_INSTANCE, 0x44, STROBE_MODE_ABSORB_R, STROBE_FLAG_FORGET);
STROBE_CONTROL_WORD(STROBE_CW_ACKNOWLEDGE, 0x45, STROBE_MODE_PLAINTEXT, 0);

static INLINE UNUSED WARN_UNUSED uint32_t
strobe_cw_recv(uint32_t cw) {
uint32_t recv_toggle = (cw & STROBE_FLAG_NONDIR) ? 0 : STROBE_FLAG_RECV;
if (cw & STROBE_FLAG_IMPLICIT) {
return cw ^ recv_toggle;
} else {
uint32_t modes_2[8] = {
/* Note: most of these really shouldn't happen... */
STROBE_MODE_ABSORB,
STROBE_MODE_DUPLEX_R,
STROBE_MODE_ABSORB_R,
STROBE_MODE_DUPLEX,
STROBE_MODE_PLAINTEXT,
STROBE_MODE_SQUEEZE,
STROBE_MODE_FORGET,
STROBE_MODE_ABSORB
};
return ((cw & ((1<<29)-1)) | (modes_2[cw>>29]<<29)) ^ recv_toggle;
}
}

#define STROBE_MAX_AUTH_BYTES 32


/**
* @brief Initialize Strobe protocol context.
* @param [out] strobe The uninitialized strobe object.
* @param [in] Strobe parameter descriptor
* @param [in] am_client Nonzero if this party
* is the client.
*/
void strobe_init (
keccak_strobe_t strobe,
const struct kparams_s *params,
const char *proto,
uint8_t am_client
) NONNULL2 API_VIS;

/**
* @brief Run a transaction against a STROBE state.
* @param [inout] strobe The initialized STROBE object.
* @param [out] out The output.
* @param [in] in The input.
* @param [in] len The length of the input/output.
* @param [in] cw_flags The control word with flags.
*/
void strobe_transact (
keccak_strobe_t strobe,
unsigned char *out,
const unsigned char *in,
size_t len,
uint32_t cw_flags
) NONNULL1 API_VIS;

/**
* @brief Send plaintext in strobe context.
* @param [inout] The initialized strobe object.
* @param [in] in The plaintext.
* @param [in] len The length of the plaintext.
* @param [in] iSent Nonzero if this side of exchange sent the plaintext.
*/
static INLINE UNUSED void strobe_plaintext (
keccak_strobe_t strobe,
const unsigned char *in,
uint16_t len,
uint8_t iSent
) {
strobe_transact(
strobe, NULL, in, len,
iSent ? STROBE_CW_PAYLOAD_PLAINTEXT
: strobe_cw_recv(STROBE_CW_PAYLOAD_PLAINTEXT)
);
}
/**
* @brief Report authenticated data in strobe context.
* @param [inout] The initialized strobe object.
* @param [in] in The plaintext.
* @param [in] len The length of the ad.
*/
static INLINE UNUSED void strobe_ad (
keccak_strobe_t strobe,
const unsigned char *in,
size_t len
) {
strobe_transact( strobe, NULL, in, len, STROBE_CW_AD_EXPLICIT );
}
/**
* @brief Set nonce in strobe context.
* @param [inout] The initialized strobe object.
* @param [in] in The nonce.
* @param [in] len The length of the nonce.
*/
static INLINE UNUSED void strobe_nonce (
keccak_strobe_t strobe,
const unsigned char *in,
uint16_t len
) {
strobe_transact( strobe, NULL, in, len, STROBE_CW_NONCE_EXPLICIT );
}
/**
* @brief Set fixed key in strobe context.
* @param [inout] The initialized strobe object.
* @param [in] in The key.
* @param [in] len The length of the key.
*/
static INLINE UNUSED void
strobe_fixed_key (
keccak_strobe_t strobe,
const unsigned char *in,
uint16_t len
) {
strobe_transact( strobe, NULL, in, len, STROBE_CW_FIXED_KEY );
}
/**
* @brief Set Diffie-Hellman key in strobe context.
* @param [inout] The initialized strobe object.
* @param [in] in The key.
* @param [in] len The length of the key.
*/
static INLINE UNUSED void
strobe_dh_key (
keccak_strobe_t strobe,
const unsigned char *in,
uint16_t len
) {
strobe_transact( strobe, NULL, in, len, STROBE_CW_DH_KEY );
}

/**
* @brief Produce an authenticator.
* @param [inout] strobe The Strobe protocol context.
* @param [out] out The authenticator
* @param len The length.
*/
static INLINE UNUSED void
strobe_produce_auth (
keccak_strobe_t strobe,
unsigned char *out,
uint16_t len
) {
strobe_transact( strobe, out, NULL, len, STROBE_CW_MAC );
}
/**
* @brief Encrypt bytes from in to out.
* @warning Doesn't produce an auth tag.
* @param [inout] strobe The Strobe protocol context.
* @param [in] in The plaintext.
* @param [out] out The ciphertext.
* @param [in] len The length of plaintext and ciphertext.
*/
static INLINE UNUSED void
strobe_encrypt (
keccak_strobe_t strobe,
unsigned char *out,
const unsigned char *in,
uint16_t len
) {
strobe_transact(strobe, out, in, len, STROBE_CW_PAYLOAD_CIPHERTEXT);
}
/**
* @brief Decrypt bytes from in to out.
* @warning Doesn't check an auth tag.
* @param [inout] strobe The Strobe protocol context.
* @param [in] in The ciphertext.
* @param [out] out The plaintext.
* @param [in] len The length of plaintext and ciphertext.
*/
static INLINE UNUSED void
strobe_decrypt (
keccak_strobe_t strobe,
unsigned char *out,
const unsigned char *in,
uint16_t len
) {
strobe_transact(strobe, out, in, len, strobe_cw_recv(STROBE_CW_PAYLOAD_CIPHERTEXT));
}

/**
* @brief Produce a session-bound pseudorandom value.
*
* @warning This "prng" value is NOT suitable for
* refreshing forward secrecy! It's to replace things
* like TCP session hash.
*
* @param [inout] strobe The Strobe protocol context
* @param [out] out The output random data.
* @param len The length.
*/
static inline void strobe_prng (
keccak_strobe_t strobe,
unsigned char *out,
uint16_t len
) {
strobe_transact( strobe, out, NULL, len, STROBE_CW_PRNG );
}

/**
* @brief Verify an authenticator.
* @param [inout] strobe The Strobe protocol context
* @param [in] in The authenticator
* @param len The length, which must be no more than
* @todo 32?
* @retval DECAF_SUCCESS The operation applied successfully.
* @retval DECAF_FAILURE The operation failed because of a
* bad validator (or because you aren't keyed)
*/
decaf_error_t strobe_verify_auth (
keccak_strobe_t strobe,
const unsigned char *in,
uint16_t len
) WARN_UNUSED NONNULL2 API_VIS;

/**
* @brief Respecify Strobe protocol object's crypto.
* @param [inout] The initialized strobe context.
* @param [in] Strobe parameter descriptor
* @param [in] am_client Nonzero if this party
* is the client.
*/
void strobe_respec (
keccak_strobe_t strobe,
const struct kparams_s *params
) NONNULL2 API_VIS;
#define strobe_destroy sponge_destroy

#ifdef __cplusplus
} /* extern "C" */
#endif


+ 49
- 26
src/public_include/decaf/shake.hxx Visa fil

@@ -13,6 +13,9 @@
#define __SHAKE_HXX__

#include <decaf/shake.h>
#include <decaf/strobe.h> /* TODO remove */
#include <decaf/spongerng.h> /* TODO remove */

#include <string>
#include <sys/types.h>
#include <errno.h>
@@ -32,6 +35,7 @@ namespace decaf {
/** A Keccak sponge internal class */
class KeccakSponge {
protected:
/** @cond internal */
/** The C-wrapper sponge state */
keccak_sponge_t sp;

@@ -40,6 +44,7 @@ protected:
/** No initialization */
inline KeccakSponge(const NOINIT &) NOEXCEPT { }
/** @endcond */

public:
/** Destructor zeroizes state */
@@ -149,13 +154,16 @@ public:
/** Sponge-based random-number generator */
class SpongeRng : public Rng, private KeccakSponge {
public:
/** Exception thrown when The RNG fails (to seed itself) */
class RngException : public std::exception {
private:
/** @cond internal */
const char *const what_;
/** @endcond */
public:
const int err_code;
const char *what() const NOEXCEPT { return what_; }
RngException(int err_code, const char *what_) NOEXCEPT : what_(what_), err_code(err_code) {}
const int err_code; /**< errno that caused the reseed to fail. */
const char *what() const NOEXCEPT { return what_; } /**< Description of exception. */
RngException(int err_code, const char *what_) NOEXCEPT : what_(what_), err_code(err_code) {} /**< Construct */
};
/** Initialize, deterministically by default, from block */
@@ -189,116 +197,127 @@ private:
};
/**@endcond*/

/** STROBE protocol framework object */
class Strobe : private KeccakSponge {
public:
/* TODO: pull out parameters */
/** Number of bytes in a default authentication size. */
static const uint16_t DEFAULT_AUTH_SIZE = 16;
/** Am I a server or a client? */
enum client_or_server { SERVER, CLIENT };
/** Create protocol object. */
inline Strobe (
const char *description,
client_or_server whoami,
const kparams_s &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()) {
strobe_init(sp, &params, description, whoami == CLIENT);
keyed = false;
}

/** Stir in fixed key, from a C++ block. */
inline void fixed_key (
const Block &data
const Block &data /**< The key. */
) throw(ProtocolException) {
strobe_fixed_key(sp, data.data(), data.size());
keyed = true;
}

/** Stir in fixed key, from a serializeable object. */
template<class T> inline void fixed_key (
const Serializable<T> &data
const Serializable<T> &data /**< The key. */
) throw(ProtocolException) {
fixed_key(data.serialize());
}

/** Stir in DH key, from a C++ block. */
inline void dh_key (
const Block &data
const Block &data /**< The key. */
) throw(ProtocolException) {
strobe_dh_key(sp, data.data(), data.size());
keyed = true;
}

/** Stir in DH key, from a serializeable object. */
template<class T> inline void dh_key (
const Serializable<T> &data
const Serializable<T> &data /**< The key. */
) throw(ProtocolException) {
dh_key(data.serialize());
}

/** Stir in an explicit nonce. */
inline void nonce(const Block &data) NOEXCEPT {
strobe_nonce(sp, data.data(), data.size());
}

/* TODO: this doesn't actually send ... maybe think about gluing to socket code? */
/** Stir in data we sent as plaintext. NB This doesn't actually send anything. */
inline void send_plaintext(const Block &data) NOEXCEPT {
strobe_plaintext(sp, data.data(), data.size(), true);
}

/** Stir in serializeable data we sent as plaintext. NB This doesn't actually send anything. */
template<class T> inline void send_plaintext(const Serializable<T> &data) NOEXCEPT {
send_plaintext(data.serialize());
}

/** Stir in data we received as plaintext. NB This doesn't actually receive anything. */
inline void recv_plaintext(const Block &data) NOEXCEPT {
strobe_plaintext(sp, data.data(), data.size(), false);
}

template<class T> inline void recv_plaintext(const Serializable<T> &data) NOEXCEPT {
recv_plaintext(data.serialize());
}

/** Stir in associated data. */
inline void ad(const Block &data) {
strobe_ad(sp, data.data(), data.size());
}

/** Stir in associated serializable data. */
template<class T> inline void ad(const Serializable<T> &data) NOEXCEPT {
ad(data.serialize());
}
/** Encrypt into a buffer, without appending authentication data */
inline void encrypt_no_auth(Buffer out, const Block &data) throw(LengthException,ProtocolException) {
if (!keyed) throw ProtocolException();
if (out.size() != data.size()) throw LengthException();
strobe_encrypt(sp, out.data(), data.data(), data.size());
}
/** Encrypt, without appending authentication data */
inline SecureBuffer encrypt_no_auth(const Block &data) throw(ProtocolException) {
SecureBuffer out(data.size()); encrypt_no_auth(out, data); return out;
}
/** Encrypt a serializable object, without appending authentication data */
template<class T> inline SecureBuffer encrypt_no_auth(const Serializable<T> &data) throw(ProtocolException) {
return encrypt_no_auth(data.serialize());
}
/** Decrypt into a buffer, without checking authentication data. */
inline void decrypt_no_auth(Buffer out, const Block &data) throw(LengthException,ProtocolException) {
if (!keyed) throw ProtocolException();
if (out.size() != data.size()) throw LengthException();
strobe_decrypt(sp, out.data(), data.data(), data.size());
}
/** Decrypt, without checking authentication data. */
inline SecureBuffer decrypt_no_auth(const Block &data) throw(ProtocolException) {
SecureBuffer out(data.size()); decrypt_no_auth(out, data); return out;
}
template<class T> inline SecureBuffer decrypt_no_auth(const Serializable<T> &data) throw(ProtocolException) {
return decrypt_no_auth(data.serialize());
}
/** Produce an authenticator into a buffer. */
inline void produce_auth(Buffer out) throw(LengthException,ProtocolException) {
if (!keyed) throw ProtocolException(); /* TODO: maybe. Could use for eg sanity or dos protection */
if (out.size() > STROBE_MAX_AUTH_BYTES) throw LengthException();
strobe_produce_auth(sp, out.data(), out.size());
}
/** Produce an authenticator. */
inline SecureBuffer produce_auth(uint8_t bytes = DEFAULT_AUTH_SIZE) throw(ProtocolException) {
SecureBuffer out(bytes); produce_auth(out); return out;
}
/** Encrypt into a buffer and append authentication data */
inline void encrypt(
Buffer out, const Block &data, uint8_t auth = DEFAULT_AUTH_SIZE
) throw(LengthException,ProtocolException) {
@@ -307,18 +326,21 @@ public:
produce_auth(out.slice(data.size(),auth));
}
/** Encrypt and append authentication data */
inline SecureBuffer encrypt (
const Block &data, uint8_t auth = DEFAULT_AUTH_SIZE
) throw(LengthException,ProtocolException,std::bad_alloc ){
SecureBuffer out(data.size() + auth); encrypt(out, data, auth); return out;
}
/** Encrypt a serializable object and append authentication data */
template<class T> inline SecureBuffer encrypt (
const Serializable<T> &data, uint8_t auth = DEFAULT_AUTH_SIZE
) throw(LengthException,ProtocolException,std::bad_alloc ){
return encrypt(data.serialize(), auth);
}
/** Decrypt into a buffer and check authentication data */
inline void decrypt (
Buffer out, const Block &data, uint8_t bytes = DEFAULT_AUTH_SIZE
) throw(LengthException, CryptoException, ProtocolException) {
@@ -327,12 +349,7 @@ public:
verify_auth(data.slice(out.size(),bytes));
}
template<class T> inline SecureBuffer decrypt (
const Serializable<T> &data, uint8_t auth = DEFAULT_AUTH_SIZE
) throw(LengthException,ProtocolException,CryptoException, std::bad_alloc ){
return decrypt(data.serialize(), auth);
}
/** Decrypt and check authentication data */
inline SecureBuffer decrypt (
const Block &data, uint8_t bytes = DEFAULT_AUTH_SIZE
) throw(LengthException,CryptoException,ProtocolException,std::bad_alloc) {
@@ -340,19 +357,25 @@ public:
SecureBuffer out(data.size() - bytes); decrypt(out, data, bytes); return out;
}
/** Check authentication data */
inline void verify_auth(const Block &auth) throw(LengthException,CryptoException) {
if (auth.size() == 0 || auth.size() > STROBE_MAX_AUTH_BYTES) throw LengthException();
if (strobe_verify_auth(sp, auth.data(), auth.size()) != DECAF_SUCCESS) throw CryptoException();
}
/** Fill pseudorandom data into a buffer */
inline void prng(Buffer out) NOEXCEPT {
(void)strobe_prng(sp, out.data(), out.size());
}
/** Return pseudorandom data */
inline SecureBuffer prng(size_t bytes) {
SecureBuffer out(bytes); prng(out); return out;
}
/** Change specs, perhaps to a faster spec that takes advantage of being keyed.
* @warning Experimental.
*/
inline void respec(const kparams_s &params) throw(ProtocolException) {
if (!keyed) throw(ProtocolException());
strobe_respec(sp, &params);


+ 91
- 0
src/public_include/decaf/spongerng.h Visa fil

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

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

@@ -67,6 +67,8 @@ typedef struct keccak_sponge_s {

#define INTERNAL_SPONGE_STRUCT 1
#include <decaf/shake.h>
#include <decaf/strobe.h>
#include <decaf/spongerng.h>

#define FLAG_ABSORBING 'A'
#define FLAG_SQUEEZING 'Z'


Laddar…
Avbryt
Spara