Browse Source

add FixedBuffer

master
Mike Hamburg 9 years ago
parent
commit
60b14fb0f1
5 changed files with 173 additions and 321 deletions
  1. +4
    -3
      Makefile
  2. +46
    -62
      src/public_include/decaf/decaf_255.hxx
  3. +74
    -239
      src/public_include/decaf/decaf_448.hxx
  4. +46
    -14
      src/public_include/decaf/secure_buffer.hxx
  5. +3
    -3
      test/test_decaf.cxx

+ 4
- 3
Makefile View File

@@ -216,11 +216,12 @@ $(BATNAME): include/* src/* src/*/* test/batarch.map $(BUILD_C)/decaf_tables.c #
(cd $(BATNAME)/.. && tar czf $(BATBASE).tgz $(BATBASE) )
# Finds todo items in .h and .c files
TODO_TYPES ?= HACK TODO FIXME BUG XXX PERF FUTURE REMOVE MAGIC
todo::
@(find * -name '*.h' -or -name '*.c' -or -name '*.cxx' -or -name '*.hxx') | xargs egrep --color=auto -w \
'HACK|TODO|FIXME|BUG|XXX|PERF|FUTURE|REMOVE|MAGIC'
`echo $(TODO_TYPES) | tr ' ' '|'`
@echo '============================='
@(for i in FIXME BUG XXX TODO HACK PERF FUTURE REMOVE MAGIC; do \
@(for i in $(TODO_TYPES); do \
(find * -name '*.h' -or -name '*.c' -or -name '*.cxx' -or -name '*.hxx') | xargs egrep -w $$i > /dev/null || continue; \
/bin/echo -n $$i' ' | head -c 10; \
(find * -name '*.h' -or -name '*.c' -or -name '*.cxx' -or -name '*.hxx') | xargs egrep -w $$i| wc -l; \
@@ -228,7 +229,7 @@ todo::
@echo '============================='
@echo -n 'Total '
@(find * -name '*.h' -or -name '*.c' -or -name '*.cxx' -or -name '*.hxx') | xargs egrep -w \
'HACK|TODO|FIXME|BUG|XXX|PERF|FUTURE|REMOVE|MAGIC' | wc -l
`echo $(TODO_TYPES) | tr ' ' '|'` | wc -l

bench: $(BUILD_IBIN)/bench
./$<


+ 46
- 62
src/public_include/decaf/decaf_255.hxx View File

@@ -10,7 +10,7 @@
*
* The Decaf library implements cryptographic operations on a an elliptic curve
* group of prime order p. It accomplishes this by using a twisted Edwards
* curve (isogenous to Ed255-Goldilocks) and wiping out the cofactor.
* curve (isogenous to Curve25519) and wiping out the cofactor.
*
* The formulas are all complete and have no special cases, except that
* decaf_255_decode can fail because not every sequence of bytes is a valid group
@@ -33,8 +33,6 @@
#include <sys/types.h>
#include <limits.h>

/* TODO: attribute nonnull */

/** @cond internal */
#if __cplusplus >= 201103L
#define NOEXCEPT noexcept
@@ -46,7 +44,7 @@
namespace decaf {

/**
* @brief Ed255-Goldilocks/Decaf instantiation of group.
* @brief Curve25519/Decaf instantiation of group.
*/
struct Ed255 {

@@ -60,12 +58,16 @@ class Precomputed;
* Supports the usual arithmetic operations, all in constant time.
*/
class Scalar {
private:
/** @brief wrapped C type */
typedef decaf_255_scalar_t Wrapped;
public:
/** @brief Size of a serialized element */
static const size_t SER_BYTES = DECAF_255_SCALAR_BYTES;
/** @brief access to the underlying scalar object */
decaf_255_scalar_t s;
Wrapped s;
/** @brief Don't initialize. */
inline Scalar(const NOINIT &) NOEXCEPT {}
@@ -83,7 +85,7 @@ public:
}
/** @brief Construct from decaf_scalar_t object. */
inline Scalar(const decaf_255_scalar_t &t = decaf_255_scalar_zero) NOEXCEPT { decaf_255_scalar_copy(s,t); }
inline Scalar(const Wrapped &t = decaf_255_scalar_zero) NOEXCEPT { decaf_255_scalar_copy(s,t); }
/** @brief Copy constructor. */
inline Scalar(const Scalar &x) NOEXCEPT { *this = x; }
@@ -118,26 +120,18 @@ public:
* @return DECAF_FAILURE if the scalar is greater than or equal to the group order q.
*/
static inline decaf_bool_t __attribute__((warn_unused_result)) decode (
Scalar &sc, const unsigned char buffer[SER_BYTES]
) NOEXCEPT {
return decaf_255_scalar_decode(sc.s,buffer);
}
/** @brief Decode from correct-length little-endian byte sequence in C++ string. */
static inline decaf_bool_t __attribute__((warn_unused_result)) decode (
Scalar &sc, const Block &buffer
Scalar &sc, const FixedBlock<SER_BYTES> buffer
) NOEXCEPT {
if (buffer.size() != SER_BYTES) return DECAF_FAILURE;
return decaf_255_scalar_decode(sc.s,buffer);
}
/** @brief Encode to fixed-length string */
inline operator SecureBuffer() const NOEXCEPT {
SecureBuffer buf(SER_BYTES); decaf_255_scalar_encode(buf,s); return buf;
SecureBuffer buf(SER_BYTES); encode(buf); return buf;
}
/** @brief Encode to fixed-length buffer */
inline void encode(unsigned char buffer[SER_BYTES]) const NOEXCEPT{
inline void encode(FixedBuffer<SER_BYTES> buffer) const NOEXCEPT{
decaf_255_scalar_encode(buffer, s);
}
@@ -188,12 +182,7 @@ public:
const Block &in,
decaf_bool_t allow_identity=DECAF_FALSE,
decaf_bool_t short_circuit=DECAF_TRUE
) const throw(CryptoException) {
SecureBuffer out(/*FIXME Point::*/SER_BYTES);
if (!decaf_255_direct_scalarmul(out, in.data(), s, allow_identity, short_circuit))
throw CryptoException();
return out;
}
) const throw(CryptoException);
};

/**
@@ -201,23 +190,25 @@ public:
*/
class Point {
public:
typedef decaf_255_point_t Wrapped;
/** @brief Size of a serialized element */
static const size_t SER_BYTES = DECAF_255_SER_BYTES;
/** @brief Size of a stegged element */
static const size_t STEG_BYTES = DECAF_255_SER_BYTES + 8;
/** @brief Bytes required for hash */
static const size_t HASH_BYTES = DECAF_255_SER_BYTES;
static const size_t HASH_BYTES = SER_BYTES;
/** @brief Size of a stegged element */
static const size_t STEG_BYTES = HASH_BYTES * 2;
/** The c-level object. */
decaf_255_point_t p;
Wrapped p;
/** @brief Don't initialize. */
inline Point(const NOINIT &) NOEXCEPT {}
/** @brief Constructor sets to identity by default. */
inline Point(const decaf_255_point_t &q = decaf_255_point_identity) NOEXCEPT { decaf_255_point_copy(p,q); }
inline Point(const Wrapped &q = decaf_255_point_identity) NOEXCEPT { decaf_255_point_copy(p,q); }
/** @brief Copy constructor. */
inline Point(const Point &q) NOEXCEPT { *this = q; }
@@ -251,29 +242,15 @@ public:
}
/**
* @brief Initialize from C fixed-length byte string.
* @brief 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,
* or was the identity and allow_identity was DECAF_FALSE.
*/
inline explicit Point(const unsigned char buffer[SER_BYTES], decaf_bool_t allow_identity=DECAF_TRUE)
inline explicit Point(const FixedBuffer<SER_BYTES> buffer, decaf_bool_t allow_identity=DECAF_TRUE)
throw(CryptoException) { if (!decode(*this,buffer,allow_identity)) throw CryptoException(); }
/**
* @brief Initialize from C fixed-length byte string.
* The all-zero string maps to the identity.
*
* @retval DECAF_SUCCESS the string was successfully decoded.
* @return DECAF_FAILURE the string wasn't the encoding of a point, or was the identity
* and allow_identity was DECAF_FALSE. Contents of the buffer are undefined.
*/
static inline decaf_bool_t __attribute__((warn_unused_result)) decode (
Point &p, const unsigned char buffer[SER_BYTES], decaf_bool_t allow_identity=DECAF_TRUE
) NOEXCEPT {
return decaf_255_point_decode(p.p,buffer,allow_identity);
}
/**
* @brief Initialize from C++ fixed-length byte string.
* The all-zero string maps to the identity.
@@ -283,9 +260,8 @@ public:
* or was the identity and allow_identity was DECAF_FALSE. Contents of the buffer are undefined.
*/
static inline decaf_bool_t __attribute__((warn_unused_result)) decode (
Point &p, const Block &buffer, decaf_bool_t allow_identity=DECAF_TRUE
Point &p, const FixedBlock<SER_BYTES> buffer, decaf_bool_t allow_identity=DECAF_TRUE
) NOEXCEPT {
if (buffer.size() != SER_BYTES) return DECAF_FAILURE;
return decaf_255_point_decode(p.p,buffer.data(),allow_identity);
}
@@ -325,15 +301,13 @@ public:
* @brief Encode to string. The identity encodes to the all-zero string.
*/
inline operator SecureBuffer() const NOEXCEPT {
SecureBuffer buffer(SER_BYTES);
decaf_255_point_encode(buffer, p);
return buffer;
SecureBuffer buffer(SER_BYTES); encode(buffer); return buffer;
}
/**
* @brief Encode to a C buffer. The identity encodes to all zeros.
*/
inline void encode(unsigned char buffer[SER_BYTES]) const NOEXCEPT{
inline void encode(FixedBuffer<SER_BYTES> buffer) const NOEXCEPT {
decaf_255_point_encode(buffer, p);
}
@@ -393,7 +367,7 @@ public:
static inline Point double_scalarmul (
const Scalar &qs, const Point &q, const Scalar &rs, const Point &r
) NOEXCEPT {
Point p((NOINIT())); decaf_255_point_double_scalarmul(p.p,q.p,qs.s,r.p,rs.s); return p;
return double_scalarmul(q,qs,r,rs);
}
/**
@@ -407,22 +381,17 @@ public:
/** @brief Return a point equal to *this, whose internal data is rotated by a torsion element. */
inline Point debugging_torque() const NOEXCEPT {
Point q;
decaf_255_point_debugging_torque(q.p,p);
return q;
Point q; decaf_255_point_debugging_torque(q.p,p); return q;
}
/** @brief Return a point equal to *this, whose internal data has a modified representation. */
inline Point debugging_pscale(const uint8_t factor[/*SER_BYTES*/]) const NOEXCEPT {
Point q;
decaf_255_point_debugging_pscale(q.p,p,factor);
return q;
inline Point debugging_pscale(const FixedBlock<SER_BYTES> factor) const NOEXCEPT {
Point q; decaf_255_point_debugging_pscale(q.p,p,factor); return q;
}
/** @brief Return a point equal to *this, whose internal data has a randomized representation. */
inline Point debugging_pscale(Rng &r) const NOEXCEPT {
StackBuffer<SER_BYTES> sb(r);
return debugging_pscale(sb);
StackBuffer<SER_BYTES> sb(r); return debugging_pscale(sb);
}
/**
@@ -564,7 +533,22 @@ public:
/** @endcond */
};

}; /* struct Decaf255 */
}; /* struct Ed255 */



/** @cond internal */
inline SecureBuffer Ed255::Scalar::direct_scalarmul (
const Block &in,
decaf_bool_t allow_identity,
decaf_bool_t short_circuit
) const throw(CryptoException) {
SecureBuffer out(Ed255::Point::SER_BYTES);
if (!decaf_255_direct_scalarmul(out, in.data(), s, allow_identity, short_circuit))
throw CryptoException();
return out;
}
/** endcond */

#undef NOEXCEPT
} /* namespace decaf */


+ 74
- 239
src/public_include/decaf/decaf_448.hxx View File

@@ -28,208 +28,21 @@
#include <string.h> /* for memcpy */

#include <decaf.h>
#include <decaf/secure_buffer.hxx>
#include <string>
#include <sys/types.h>
#include <limits.h>

/* TODO: This is incomplete */
/* TODO: attribute nonnull */

/** @cond internal */
#if __cplusplus >= 201103L
#define NOEXCEPT noexcept
#define EXPLICIT_CON explicit
#define GET_DATA(str) ((const unsigned char *)&(str)[0])
#else
#define NOEXCEPT throw()
#define EXPLICIT_CON
#define GET_DATA(str) ((const unsigned char *)((str).data()))
#endif
/** @endcond */

namespace decaf {

/** @brief An exception for when crypto (ie point decode) has failed. */
class CryptoException : public std::exception {
public:
/** @return "CryptoException" */
virtual const char * what() const NOEXCEPT { return "CryptoException"; }
};

/** @brief An exception for when crypto (ie point decode) has failed. */
class LengthException : public std::exception {
public:
/** @return "CryptoException" */
virtual const char * what() const NOEXCEPT { return "LengthException"; }
};

/**
* Securely erase contents of memory.
*/
static inline void really_bzero(void *data, size_t size) { decaf_bzero(data,size); }

/** Block object */
class Block {
protected:
unsigned char *data_;
size_t size_;

public:
/** Empty init */
inline Block() NOEXCEPT : data_(NULL), size_(0) {}
/** Init from C string */
inline Block(const char *data) NOEXCEPT : data_((unsigned char *)data), size_(strlen(data)) {}

/** Unowned init */
inline Block(const unsigned char *data, size_t size) NOEXCEPT : data_((unsigned char *)data), size_(size) {}
/** Block from std::string */
inline Block(const std::string &s) : data_((unsigned char *)GET_DATA(s)), size_(s.size()) {}

/** Get const data */
inline const unsigned char *data() const NOEXCEPT { return data_; }

/** Get the size */
inline size_t size() const NOEXCEPT { return size_; }

/** Autocast to const unsigned char * */
inline operator const unsigned char*() const NOEXCEPT { return data_; }

/** Convert to C++ string */
inline std::string get_string() const {
return std::string((const char *)data_,size_);
}

/** Slice the buffer*/
inline Block slice(size_t off, size_t length) const throw(LengthException) {
if (off > size() || length > size() - off)
throw LengthException();
return Block(data()+off, length);
}

/** Virtual destructor for SecureBlock. TODO: probably means vtable? Make bool? */
inline virtual ~Block() {};
};

class TmpBuffer;

class Buffer : public Block {
public:
/** Null init */
inline Buffer() NOEXCEPT : Block() {}

/** Unowned init */
inline Buffer(unsigned char *data, size_t size) NOEXCEPT : Block(data,size) {}

/** Get unconst data */
inline unsigned char *data() NOEXCEPT { return data_; }

/** Get const data */
inline const unsigned char *data() const NOEXCEPT { return data_; }

/** Autocast to const unsigned char * */
inline operator const unsigned char*() const NOEXCEPT { return data_; }

/** Autocast to unsigned char */
inline operator unsigned char*() NOEXCEPT { return data_; }

/** Slice the buffer*/
inline TmpBuffer slice(size_t off, size_t length) throw(LengthException);
};

class TmpBuffer : public Buffer {
public:
/** Unowned init */
inline TmpBuffer(unsigned char *data, size_t size) NOEXCEPT : Buffer(data,size) {}
};

TmpBuffer Buffer::slice(size_t off, size_t length) throw(LengthException) {
if (off > size() || length > size() - off) throw LengthException();
return TmpBuffer(data()+off, length);
}

/** A self-erasing block of data */
class SecureBuffer : public Buffer {
public:
/** Null secure block */
inline SecureBuffer() NOEXCEPT : Buffer() {}

/** Construct empty from size */
inline SecureBuffer(size_t size) {
data_ = new unsigned char[size_ = size];
memset(data_,0,size);
}

/** Construct from data */
inline SecureBuffer(const unsigned char *data, size_t size){
data_ = new unsigned char[size_ = size];
memcpy(data_, data, size);
}

/** Copy constructor */
inline SecureBuffer(const Block &copy) : Buffer() { *this = copy; }

/** Copy-assign constructor */
inline SecureBuffer& operator=(const Block &copy) throw(std::bad_alloc) {
if (&copy == this) return *this;
clear();
data_ = new unsigned char[size_ = copy.size()];
memcpy(data_,copy.data(),size_);
return *this;
}

/** Copy-assign constructor */
inline SecureBuffer& operator=(const SecureBuffer &copy) throw(std::bad_alloc) {
if (&copy == this) return *this;
clear();
data_ = new unsigned char[size_ = copy.size()];
memcpy(data_,copy.data(),size_);
return *this;
}

/** Destructor erases data */
~SecureBuffer() NOEXCEPT { clear(); }

/** Clear data */
inline void clear() NOEXCEPT {
if (data_ == NULL) return;
really_bzero(data_,size_);
delete[] data_;
data_ = NULL;
size_ = 0;
}

#if __cplusplus >= 201103L
/** Move constructor */
inline SecureBuffer(SecureBuffer &&move) { *this = move; }

/** Move non-constructor */
inline SecureBuffer(Block &&move) { *this = (Block &)move; }

/** Move-assign constructor. TODO: check that this actually gets used.*/
inline SecureBuffer& operator=(SecureBuffer &&move) {
clear();
data_ = move.data_; move.data_ = NULL;
size_ = move.size_; move.size_ = 0;
return *this;
}

/** C++11-only explicit cast */
inline explicit operator std::string() const { return get_string(); }
#endif
};


/** @brief Passed to constructors to avoid (conservative) initialization */
struct NOINIT {};

/**@cond internal*/
/** Forward-declare sponge RNG object */
class SpongeRng;
/**@endcond*/


/**
* @brief Ed448-Goldilocks/Decaf instantiation of group.
*/
@@ -245,12 +58,16 @@ class Precomputed;
* Supports the usual arithmetic operations, all in constant time.
*/
class Scalar {
private:
/** @brief wrapped C type */
typedef decaf_448_scalar_t Wrapped;
public:
/** @brief Size of a serialized element */
static const size_t SER_BYTES = DECAF_448_SCALAR_BYTES;
/** @brief access to the underlying scalar object */
decaf_448_scalar_t s;
Wrapped s;
/** @brief Don't initialize. */
inline Scalar(const NOINIT &) NOEXCEPT {}
@@ -262,7 +79,10 @@ public:
inline Scalar(const int w) NOEXCEPT { *this = w; }
/** @brief Construct from RNG */
inline explicit Scalar(SpongeRng &rng) NOEXCEPT;
inline explicit Scalar(Rng &rng) NOEXCEPT {
StackBuffer<SER_BYTES> sb(rng);
*this = sb;
}
/** @brief Construct from decaf_scalar_t object. */
inline Scalar(const decaf_448_scalar_t &t = decaf_448_scalar_zero) NOEXCEPT { decaf_448_scalar_copy(s,t); }
@@ -287,7 +107,7 @@ public:
return *this;
}
/** Destructor securely erases the scalar. */
/** Destructor securely zeorizes the scalar. */
inline ~Scalar() NOEXCEPT { decaf_448_scalar_destroy(s); }
/** @brief Assign from arbitrary-length little-endian byte sequence in a Block. */
@@ -300,26 +120,18 @@ public:
* @return DECAF_FAILURE if the scalar is greater than or equal to the group order q.
*/
static inline decaf_bool_t __attribute__((warn_unused_result)) decode (
Scalar &sc, const unsigned char buffer[SER_BYTES]
) NOEXCEPT {
return decaf_448_scalar_decode(sc.s,buffer);
}
/** @brief Decode from correct-length little-endian byte sequence in C++ string. */
static inline decaf_bool_t __attribute__((warn_unused_result)) decode (
Scalar &sc, const Block &buffer
Scalar &sc, const FixedBlock<SER_BYTES> buffer
) NOEXCEPT {
if (buffer.size() != SER_BYTES) return DECAF_FAILURE;
return decaf_448_scalar_decode(sc.s,buffer);
}
/** @brief Encode to fixed-length string */
inline EXPLICIT_CON operator SecureBuffer() const NOEXCEPT {
inline operator SecureBuffer() const NOEXCEPT {
SecureBuffer buf(SER_BYTES); decaf_448_scalar_encode(buf,s); return buf;
}
/** @brief Encode to fixed-length buffer */
inline void encode(unsigned char buffer[SER_BYTES]) const NOEXCEPT{
inline void encode(FixedBuffer<SER_BYTES> buffer) const NOEXCEPT{
decaf_448_scalar_encode(buffer, s);
}
@@ -402,16 +214,24 @@ public:
inline Point(const decaf_448_point_t &q = decaf_448_point_identity) NOEXCEPT { decaf_448_point_copy(p,q); }
/** @brief Copy constructor. */
inline Point(const Point &q) NOEXCEPT { decaf_448_point_copy(p,q.p); }
inline Point(const Point &q) NOEXCEPT { *this = q; }
/** @brief Assignment. */
inline Point& operator=(const Point &q) NOEXCEPT { decaf_448_point_copy(p,q.p); return *this; }
/** @brief Destructor securely erases the point. */
/** @brief Destructor securely zeorizes the point. */
inline ~Point() NOEXCEPT { decaf_448_point_destroy(p); }
/** @brief Construct from RNG */
inline explicit Point(SpongeRng &rng, bool uniform = true) NOEXCEPT;
inline explicit Point(Rng &rng, bool uniform = true) NOEXCEPT {
if (uniform) {
StackBuffer<2*HASH_BYTES> b(rng);
set_to_hash(b);
} else {
StackBuffer<HASH_BYTES> b(rng);
set_to_hash(b);
}
}
/**
* @brief Initialize from C++ fixed-length byte string.
@@ -425,29 +245,15 @@ public:
}
/**
* @brief Initialize from C fixed-length byte string.
* @brief 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,
* or was the identity and allow_identity was DECAF_FALSE.
*/
inline explicit Point(const unsigned char buffer[SER_BYTES], decaf_bool_t allow_identity=DECAF_TRUE)
inline explicit Point(const FixedBuffer<SER_BYTES> buffer, decaf_bool_t allow_identity=DECAF_TRUE)
throw(CryptoException) { if (!decode(*this,buffer,allow_identity)) throw CryptoException(); }
/**
* @brief Initialize from C fixed-length byte string.
* The all-zero string maps to the identity.
*
* @retval DECAF_SUCCESS the string was successfully decoded.
* @return DECAF_FAILURE the string wasn't the encoding of a point, or was the identity
* and allow_identity was DECAF_FALSE. Contents of the buffer are undefined.
*/
static inline decaf_bool_t __attribute__((warn_unused_result)) decode (
Point &p, const unsigned char buffer[SER_BYTES], decaf_bool_t allow_identity=DECAF_TRUE
) NOEXCEPT {
return decaf_448_point_decode(p.p,buffer,allow_identity);
}
/**
* @brief Initialize from C++ fixed-length byte string.
* The all-zero string maps to the identity.
@@ -457,9 +263,8 @@ public:
* or was the identity and allow_identity was DECAF_FALSE. Contents of the buffer are undefined.
*/
static inline decaf_bool_t __attribute__((warn_unused_result)) decode (
Point &p, const Block &buffer, decaf_bool_t allow_identity=DECAF_TRUE
Point &p, const FixedBlock<SER_BYTES> buffer, decaf_bool_t allow_identity=DECAF_TRUE
) NOEXCEPT {
if (buffer.size() != SER_BYTES) return DECAF_FAILURE;
return decaf_448_point_decode(p.p,buffer.data(),allow_identity);
}
@@ -479,26 +284,26 @@ public:
* 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.
*/
inline unsigned char set_to_hash( const Block &s ) NOEXCEPT {
inline void set_to_hash( const Block &s ) NOEXCEPT {
if (s.size() < HASH_BYTES) {
SecureBuffer b(HASH_BYTES);
memcpy(b.data(), s.data(), s.size());
return decaf_448_point_from_hash_nonuniform(p,b);
decaf_448_point_from_hash_nonuniform(p,b);
} else if (s.size() == HASH_BYTES) {
return decaf_448_point_from_hash_nonuniform(p,s);
decaf_448_point_from_hash_nonuniform(p,s);
} else if (s.size() < 2*HASH_BYTES) {
SecureBuffer b(2*HASH_BYTES);
memcpy(b.data(), s.data(), s.size());
return decaf_448_point_from_hash_uniform(p,b);
decaf_448_point_from_hash_uniform(p,b);
} else {
return decaf_448_point_from_hash_uniform(p,s);
decaf_448_point_from_hash_uniform(p,s);
}
}
/**
* @brief Encode to string. The identity encodes to the all-zero string.
*/
inline EXPLICIT_CON operator SecureBuffer() const NOEXCEPT {
inline operator SecureBuffer() const NOEXCEPT {
SecureBuffer buffer(SER_BYTES);
decaf_448_point_encode(buffer, p);
return buffer;
@@ -507,7 +312,7 @@ public:
/**
* @brief Encode to a C buffer. The identity encodes to all zeros.
*/
inline void encode(unsigned char buffer[SER_BYTES]) const NOEXCEPT{
inline void encode(FixedBuffer<SER_BYTES> buffer) const NOEXCEPT{
decaf_448_point_encode(buffer, p);
}
@@ -579,13 +384,32 @@ public:
Point r((NOINIT())); decaf_448_base_double_scalarmul_non_secret(r.p,s_base.s,p,s.s); return r;
}
inline Point& debugging_torque_in_place() {
decaf_448_point_debugging_torque(p,p);
return *this;
/** @brief Return a point equal to *this, whose internal data is rotated by a torsion element. */
inline Point debugging_torque() const NOEXCEPT {
Point q;
decaf_448_point_debugging_torque(q.p,p);
return q;
}
/** @brief 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;
decaf_448_point_debugging_pscale(q.p,p,factor);
return q;
}
/** @brief Return a point equal to *this, whose internal data has a randomized representation. */
inline Point debugging_pscale(Rng &r) const NOEXCEPT {
StackBuffer<SER_BYTES> sb(r);
return debugging_pscale(sb);
}
/**
* Modify buffer so that Point::from_hash(Buffer) == *this, and return true;
* or leave buf unmodified and return false.
*/
inline bool invert_elligator (
Buffer &buf, unsigned char hint
Buffer &buf, uint16_t hint
) const NOEXCEPT {
unsigned char buf2[2*HASH_BYTES];
memset(buf2,0,sizeof(buf2));
@@ -599,13 +423,24 @@ public:
if (buf.size() < HASH_BYTES) {
ret &= decaf_memeq(&buf2[buf.size()], &buf2[HASH_BYTES], HASH_BYTES - buf.size());
}
memcpy(buf,buf2,(buf.size() < HASH_BYTES) ? buf.size() : HASH_BYTES);
if (ret) {
/* TODO: make this constant time?? */
memcpy(buf,buf2,(buf.size() < HASH_BYTES) ? buf.size() : HASH_BYTES);
}
decaf_bzero(buf2,sizeof(buf2));
return !!ret;
}
/** @brief Steganographically encode this */
inline SecureBuffer steg_encode(SpongeRng &rng) const NOEXCEPT;
inline SecureBuffer steg_encode(Rng &rng) const throw(std::bad_alloc) {
SecureBuffer out(STEG_BYTES);
bool done;
do {
rng.read(out.slice(HASH_BYTES-1,STEG_BYTES-HASH_BYTES+1));
done = invert_elligator(out, out[HASH_BYTES-1]);
} while (!done);
return out;
}
/** @brief Return the base point */
static inline const Point base() NOEXCEPT { return Point(decaf_448_point_base); }
@@ -619,7 +454,9 @@ public:
* 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.
*//** @cond internal */
*/

/** @cond internal */
typedef decaf_448_precomputed_s Precomputed_U;
/** @endcond */
class Precomputed
@@ -709,8 +546,6 @@ public:
}; /* struct Decaf448 */

#undef NOEXCEPT
#undef EXPLICIT_CON
#undef GET_DATA
} /* namespace decaf */

#endif /* __DECAF_448_HXX__ */

+ 46
- 14
src/public_include/decaf/secure_buffer.hxx View File

@@ -87,8 +87,8 @@ protected:
size_t size_;

public:
/** Empty init */
inline Block() NOEXCEPT : data_(NULL), size_(0) {}
/** Null initialization */
inline Block() : data_(NULL), size_(0) {}
/** Init from C string */
inline Block(const char *data) NOEXCEPT : data_((unsigned char *)data), size_(strlen(data)) {}
@@ -148,6 +148,18 @@ public:
inline virtual ~Block() {};
};

/** A fixed-size block */
template<size_t Size> class FixedBlock : public Block {
public:
/** Check a block's length. */
inline FixedBlock(const Block &b) throw(LengthException) : Block(b,Size) {
if (Size != b.size()) throw LengthException();
}
/** Explicitly pass a C buffer. */
inline explicit FixedBlock(const uint8_t data[Size]) NOEXCEPT : Block(data,Size) {}
};

/** A reference to a writable block of data */
class Buffer : public Block {
public:
@@ -176,6 +188,24 @@ public:
inline void zeroize() NOEXCEPT { really_bzero(data(),size()); }
};


/** A fixed-size block */
template<size_t Size> class FixedBuffer : public Buffer {
public:
/** Check a block's length. */
inline FixedBuffer(Buffer &b) throw(LengthException) : Buffer(b,Size) {
if (Size != b.size()) throw LengthException();
}
/** Explicitly pass a C buffer. */
inline explicit FixedBuffer(uint8_t dat[Size]) NOEXCEPT : Buffer(dat,Size) {}
/** Cast to a FixedBlock. */
inline operator FixedBlock<Size>() const NOEXCEPT {
return FixedBlock<Size>(data());
}
};

/** A temporary reference to a writeable buffer, for converting C to C++. */
class TmpBuffer : public Buffer {
public:
@@ -184,18 +214,20 @@ public:
};

/** A fixed-size stack-allocated buffer (for NOEXCEPT semantics) */
template<size_t Size> class StackBuffer : public Buffer {
template<size_t Size> class StackBuffer : public FixedBuffer<Size> {
private:
uint8_t storage[Size];
public:
using Buffer::zeroize;
/** New buffer initialized to zero. */
inline StackBuffer() NOEXCEPT : Buffer(storage, Size) { memset(storage,0,Size); }
inline explicit StackBuffer() NOEXCEPT : FixedBuffer<Size>(storage) { memset(storage,0,Size); }

/** New uninitialized buffer. */
inline StackBuffer(const NOINIT &) NOEXCEPT : Buffer(storage, Size) { }
inline explicit StackBuffer(const NOINIT &) NOEXCEPT : FixedBuffer<Size>(storage) { }
/** New random buffer */
inline StackBuffer(Rng &r) NOEXCEPT : Buffer(storage, Size) { r.read(*this); }
inline explicit StackBuffer(Rng &r) NOEXCEPT : FixedBuffer<Size>(storage) { r.read(*this); }
/** Destroy the buffer */
~StackBuffer() NOEXCEPT { zeroize(); }
@@ -212,13 +244,13 @@ public:
inline SecureBuffer() NOEXCEPT : Buffer() {}

/** Construct empty from size */
inline SecureBuffer(size_t size) {
inline SecureBuffer(size_t size) throw(std::bad_alloc) {
data_ = new unsigned char[size_ = size];
memset(data_,0,size);
}

/** Construct from data */
inline SecureBuffer(const unsigned char *data, size_t size) {
inline SecureBuffer(const unsigned char *data, size_t size) throw(std::bad_alloc) {
data_ = new unsigned char[size_ = size];
memcpy(data_, data, size);
}
@@ -230,7 +262,7 @@ public:
}

/** Copy constructor */
inline SecureBuffer(const Block &copy) : Buffer() { *this = copy; }
inline SecureBuffer(const Block &copy) throw(std::bad_alloc) : Buffer() { *this = copy; }

/** Copy-assign constructor */
inline SecureBuffer& operator=(const Block &copy) throw(std::bad_alloc) {
@@ -297,12 +329,12 @@ inline SecureBuffer Rng::read(size_t length) throw(std::bad_alloc) {
/** A secure buffer which stores an owned or unowned underlying value.
* If it is owned, it will be securely zeroed.
*/
template <class T, class Underlying>
template <class T, class Wrapped>
class OwnedOrUnowned {
protected:
union {
Underlying *mine;
const Underlying *yours;
Wrapped *mine;
const Wrapped *yours;
} ours;
bool isMine;

@@ -323,10 +355,10 @@ protected:
}
isMine = true;
}
inline const Underlying *get() const NOEXCEPT { return isMine ? ours.mine : ours.yours; }
inline const Wrapped *get() const NOEXCEPT { return isMine ? ours.mine : ours.yours; }

inline OwnedOrUnowned(
const Underlying &yours = *T::defaultValue()
const Wrapped &yours = *T::defaultValue()
) NOEXCEPT {
ours.yours = &yours;
isMine = false;


+ 3
- 3
test/test_decaf.cxx View File

@@ -49,7 +49,7 @@ typedef typename Group::Precomputed Precomputed;

static void print(const char *name, const Scalar &x) {
unsigned char buffer[Scalar::SER_BYTES];
x.encode(buffer);
x.encode(decaf::FixedBuffer<Scalar::SER_BYTES>(buffer));
printf(" %s = 0x", name);
for (int i=sizeof(buffer)-1; i>=0; i--) {
printf("%02x", buffer[i]);
@@ -66,10 +66,10 @@ static void hexprint(const char *name, const decaf::SecureBuffer &buffer) {
}

static void print(const char *name, const Point &x) {
unsigned char buffer[Point::SER_BYTES];
decaf::StackBuffer<Point::SER_BYTES> buffer;
x.encode(buffer);
printf(" %s = 0x", name);
for (int i=sizeof(buffer)-1; i>=0; i--) {
for (int i=Point::SER_BYTES-1; i>=0; i--) {
printf("%02x", buffer[i]);
}
printf("\n");


Loading…
Cancel
Save