Explorar el Código

using SecureBuffer instead of std::string (todo change documentation; remove ptr+len?

master
Mike Hamburg hace 9 años
padre
commit
2eb89045d5
Se han modificado 4 ficheros con 212 adiciones y 86 borrados
  1. +192
    -65
      include/decaf.hxx
  2. +15
    -16
      include/shake.hxx
  3. +3
    -3
      test/bench_decaf.cxx
  4. +2
    -2
      test/test_decaf.cxx

+ 192
- 65
include/decaf.hxx Ver fichero

@@ -49,16 +49,141 @@

namespace decaf {

typedef uint32_t GroupId;

static const GroupId Ed448Goldilocks = 448;

/**
* 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() : data_(NULL), size_(0) {}

/** Unowned init */
inline Block(const unsigned char *data, size_t size) NOEXCEPT : data_((unsigned char *)data), size_(size) {}
/**
* @brief Group with prime order.
* @todo Move declarations of functions up here?
*/
template<unsigned int bits = 448> struct decaf;
/** 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_);
}

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

class Buffer : public Block {
public:
/** Null init */
inline Buffer() : 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_; }
};

/** 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(const Block &&move) { *this = (Block &)move; }

/** Move-assign constructor */
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 {};
@@ -68,10 +193,17 @@ struct NOINIT {};
class SpongeRng;
/**@endcond*/


/**
* @brief Group with prime order.
* @todo Move declarations of functions up here?
*/
template<GroupId group = Ed448Goldilocks> struct decaf;

/**
* @brief Ed448-Goldilocks/Decaf instantiation of group.
*/
template<> struct decaf<448> {
template<> struct decaf<Ed448Goldilocks> {

/** @brief An exception for when crypto (ie point decode) has failed. */
class CryptoException : public std::exception {
@@ -116,16 +248,13 @@ public:
inline Scalar(const Scalar &x) NOEXCEPT { *this = x; }
/** @brief Construct from arbitrary-length little-endian byte sequence. */
inline explicit Scalar(const std::string &str) NOEXCEPT { *this = str; }
/** @brief Construct from arbitrary-length little-endian byte sequence. */
inline Scalar(const unsigned char *buffer, size_t n) NOEXCEPT { decaf_448_scalar_decode_long(s,buffer,n); }
/** @brief Construct from arbitrary-length little-endian byte sequence. */
inline Scalar(const char *buffer, size_t n) NOEXCEPT { decaf_448_scalar_decode_long(s,(const unsigned char *)buffer,n); }
inline Scalar(const unsigned char *buffer, size_t n) NOEXCEPT { decode(buffer,n); }
/** @brief Construct from arbitrary-length little-endian byte sequence. */
inline Scalar(const void *buffer, size_t n) NOEXCEPT { decaf_448_scalar_decode_long(s,(const unsigned char *)buffer,n); }
inline Scalar(const Block &buffer) NOEXCEPT { decode(buffer.data(),buffer.size()); }

/** @brief Decode from long buffer. */
inline void decode(const unsigned char *buffer, size_t n) NOEXCEPT { decaf_448_scalar_decode_long(s,buffer,n); }
/** @brief Assignment. */
inline Scalar& operator=(const Scalar &x) NOEXCEPT { decaf_448_scalar_copy(s,x.s); return *this; }
@@ -144,9 +273,9 @@ public:
/** Destructor securely erases the scalar. */
inline ~Scalar() NOEXCEPT { decaf_448_scalar_destroy(s); }
/** @brief Assign from arbitrary-length little-endian byte sequence in C++ string. */
inline Scalar &operator=(const std::string &str) NOEXCEPT {
decaf_448_scalar_decode_long(s,GET_DATA(str),str.size()); return *this;
/** @brief Assign from arbitrary-length little-endian byte sequence in a Block. */
inline Scalar &operator=(const Block &bl) NOEXCEPT {
decaf_448_scalar_decode_long(s,bl.data(),bl.size()); return *this;
}
/**
@@ -161,17 +290,15 @@ public:
/** @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 std::string buffer
Scalar &sc, const Block &buffer
) NOEXCEPT {
if (buffer.size() != SER_BYTES) return DECAF_FAILURE;
return decaf_448_scalar_decode(sc.s,GET_DATA(buffer));
return decaf_448_scalar_decode(sc.s,buffer);
}
/** @brief Encode to fixed-length string */
inline EXPLICIT_CON operator std::string() const NOEXCEPT {
unsigned char buffer[SER_BYTES];
decaf_448_scalar_encode(buffer, s);
return std::string((char*)buffer,sizeof(buffer));
inline EXPLICIT_CON operator SecureBuffer() const NOEXCEPT {
SecureBuffer buf(SER_BYTES); decaf_448_scalar_encode(buf,s); return buf;
}
/** @brief Encode to fixed-length buffer */
@@ -204,13 +331,13 @@ public:
inline Scalar inverse() const NOEXCEPT { Scalar r; decaf_448_scalar_invert(r.s,s); return r; }
/** @brief Divide by inverting q. If q == 0, return 0. */
inline Scalar operator/ (const Scalar &q) const NOEXCEPT { Scalar r((NOINIT())); decaf_448_scalar_mul(r.s,s,q.inverse().s); return r; }
inline Scalar operator/ (const Scalar &q) const NOEXCEPT { return *this * q.inverse(); }
/** @brief Divide by inverting q. If q == 0, return 0. */
inline Scalar &operator/=(const Scalar &q) NOEXCEPT { decaf_448_scalar_mul(s,s,q.inverse().s); return *this; }
inline Scalar &operator/=(const Scalar &q) NOEXCEPT { return *this *= q.inverse(); }
/** @brief Compare in constant time */
inline bool operator!=(const Scalar &q) const NOEXCEPT { return ! decaf_448_scalar_eq(s,q.s); }
inline bool operator!=(const Scalar &q) const NOEXCEPT { return !(*this == q); }
/** @brief Compare in constant time */
inline bool operator==(const Scalar &q) const NOEXCEPT { return !!decaf_448_scalar_eq(s,q.s); }
@@ -221,33 +348,17 @@ public:
/** @brief Scalarmul-precomputed with scalar on left. */
inline Point operator* (const Precomputed &q) const NOEXCEPT { return q * (*this); }
/** @brief Direct scalar multiplication.
* @todo Fix up bools.
*/
inline decaf_bool_t direct_scalarmul(
unsigned char out[SER_BYTES],
const unsigned char in[SER_BYTES],
/** @brief Direct scalar multiplication. */
inline SecureBuffer direct_scalarmul(
const Block &in,
decaf_bool_t allow_identity=DECAF_FALSE,
decaf_bool_t short_circuit=DECAF_TRUE
) const NOEXCEPT {
return decaf_448_direct_scalarmul(out, in, s, allow_identity, short_circuit);
) const throw(CryptoException) {
SecureBuffer out(/*FIXME Point::*/SER_BYTES);
if (!decaf_448_direct_scalarmul(out, in.data(), s, allow_identity, short_circuit))
throw CryptoException();
return out;
}
/** @brief Direct scalar multiplication.
* @todo Fix up bools.
*/
inline std::string direct_scalarmul(
const std::string in,
decaf_bool_t allow_identity=DECAF_FALSE,
decaf_bool_t short_circuit=DECAF_TRUE
) const NOEXCEPT {
unsigned char out[SER_BYTES];
if (decaf_448_direct_scalarmul(out, GET_DATA(in), s, allow_identity, short_circuit)) {
return std::string((char *)out,sizeof(out));
} else {
return "";
}
}
};

/**
@@ -289,7 +400,7 @@ public:
* @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 std::string &s, decaf_bool_t allow_identity=DECAF_TRUE) throw(CryptoException) {
inline explicit Point(const Block &s, decaf_bool_t allow_identity=DECAF_TRUE) throw(CryptoException) {
if (!decode(*this,s,allow_identity)) throw CryptoException();
}
@@ -326,15 +437,16 @@ 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 std::string &buffer, decaf_bool_t allow_identity=DECAF_TRUE
Point &p, const Block &buffer, decaf_bool_t allow_identity=DECAF_TRUE
) NOEXCEPT {
if (buffer.size() != SER_BYTES) return DECAF_FAILURE;
return decaf_448_point_decode(p.p,GET_DATA(buffer),allow_identity);
return decaf_448_point_decode(p.p,buffer.data(),allow_identity);
}

/**
* @brief Map to the curve from a C buffer.
* The all-zero buffer maps to the identity, as does the buffer {1,0...}
* @todo remove?
*/
static inline Point from_hash_nonuniform ( const unsigned char buffer[SER_BYTES] ) NOEXCEPT {
Point p((NOINIT())); decaf_448_point_from_hash_nonuniform(p.p,buffer); return p;
@@ -345,10 +457,16 @@ public:
* The empty or all-zero string maps to the identity, as does the string "\x01".
* If the buffer is shorter than (TODO) SER_BYTES, it will be zero-padded on the right.
*/
static inline Point from_hash_nonuniform ( const std::string &s ) NOEXCEPT {
std::string t = s;
if (t.size() < SER_BYTES) t.insert(t.size(),SER_BYTES-t.size(),0);
Point p((NOINIT())); decaf_448_point_from_hash_nonuniform(p.p,GET_DATA(t)); return p;
static inline Point from_hash_nonuniform ( const Block &s ) NOEXCEPT {
Point p((NOINIT()));
if (s.size() < SER_BYTES) {
SecureBuffer b(SER_BYTES);
memcpy(b.data(), s.data(), s.size());
decaf_448_point_from_hash_nonuniform(p.p,b);
} else {
decaf_448_point_from_hash_nonuniform(p.p,s);
}
return p;
}
@@ -366,20 +484,29 @@ public:
* If the buffer is shorter than (TODO) 2*SER_BYTES, well, it won't be as uniform,
* but the buffer will be zero-padded on the right.
*/
static inline Point from_hash ( const std::string &s ) NOEXCEPT {
std::string t = s;
if (t.size() <= SER_BYTES) return from_hash_nonuniform(s);
if (t.size() < 2*SER_BYTES) t.insert(t.size(),2*SER_BYTES-t.size(),0);
Point p((NOINIT())); decaf_448_point_from_hash_uniform(p.p,GET_DATA(t)); return p;
static inline Point from_hash ( const Block &s ) NOEXCEPT {
if (s.size() <= SER_BYTES) {
return from_hash_nonuniform(s);
}
Point p((NOINIT()));
if (s.size() < 2*SER_BYTES) {
SecureBuffer b(SER_BYTES);
memcpy(b.data(), s.data(), s.size());
decaf_448_point_from_hash_nonuniform(p.p,b);
} else {
decaf_448_point_from_hash_nonuniform(p.p,s);
}
return p;
}
/**
* @brief Encode to string. The identity encodes to the all-zero string.
*/
inline EXPLICIT_CON operator std::string() const NOEXCEPT {
unsigned char buffer[SER_BYTES];
inline EXPLICIT_CON operator SecureBuffer() const NOEXCEPT {
SecureBuffer buffer(SER_BYTES);
decaf_448_point_encode(buffer, p);
return std::string((char*)buffer,sizeof(buffer));
return buffer;
}
/**


+ 15
- 16
include/shake.hxx Ver fichero

@@ -65,13 +65,13 @@ public:
inline void update(const uint8_t *__restrict__ in, size_t len) { sha3_update(sp,in,len); }

/** Add more data to running hash, C++ version. */
inline void update(const std::string &s) { sha3_update(sp,GET_DATA(s),s.size()); }
inline void update(const Block &s) { sha3_update(sp,s.data(),s.size()); }
/** Add more data, stream version. */
inline KeccakHash &operator<<(const std::string &s) { update(s); return *this; }
inline KeccakHash &operator<<(const Block &s) { update(s); return *this; }
/** Same as <<. */
inline KeccakHash &operator+=(const std::string &s) { return *this << s; }
inline KeccakHash &operator+=(const Block &s) { return *this << s; }
/**
* @brief Output bytes from the sponge.
@@ -82,12 +82,10 @@ public:
}
/** @brief Output bytes from the sponge. */
inline std::string output(size_t len) {
unsigned char *buffer = new unsigned char[len];
inline SecureBuffer output(size_t len) {
SecureBuffer buffer(len);
sha3_output(sp,buffer,len);
std::string out((char *)buffer, len);
delete[] buffer;
return out;
return buffer;
}
/** @brief Return the sponge's default output size. */
@@ -96,7 +94,7 @@ public:
}
/** Output the default number of bytes. */
inline std::string output() {
inline SecureBuffer output() {
return output(default_output_size());
}
};
@@ -157,6 +155,12 @@ public:
spongerng_init_from_buffer(sp,GET_DATA(in),in.size(),deterministic);
}
/** Initialize, deterministically by default, from block */
inline SpongeRng( const FROM_BUFFER &, const Block &in, bool deterministic = true )
: KeccakSponge((NOINIT())) {
spongerng_init_from_buffer(sp,in.data(),in.size(),deterministic);
}
/** Initialize, non-deterministically by default, from C/C++ filename */
inline SpongeRng( const FROM_FILE &, const std::string &in = "/dev/urandom", size_t len = 32, bool deterministic = false )
throw(RngException)
@@ -179,12 +183,8 @@ public:
* @warning TODO Future versions of this function may throw RngException if a
* nondeterministic RNG fails a reseed.
*/
inline std::string read(size_t length) throw(std::bad_alloc) {
uint8_t *buffer = new uint8_t[length];
spongerng_next(sp,buffer,length);
std::string out((const char *)buffer, length);
delete[] buffer;
return out;
inline SecureBuffer read(size_t length) throw(std::bad_alloc) {
SecureBuffer out(length); spongerng_next(sp,out,length); return out;
}
private:
@@ -193,7 +193,6 @@ private:
};

/**@cond internal*/
/* FIXME: MAGIC; should use buffer or erase temporary string */
/* FIXME: multiple sizes */
decaf<448>::Scalar::Scalar(SpongeRng &rng) {
uint8_t buffer[SER_BYTES];


+ 3
- 3
test/bench_decaf.cxx Ver fichero

@@ -131,7 +131,7 @@ int main(int argc, char **argv) {
Precomputed pBase;
Point p,q;
Scalar s,t;
std::string ep;
decaf::SecureBuffer ep, ep2(Point::SER_BYTES*2);
printf("Micro-benchmarks:\n");
for (Benchmark b("Scalar add", 1000); b.iter(); ) { s+=t; }
@@ -140,11 +140,11 @@ int main(int argc, char **argv) {
for (Benchmark b("Point add", 100); b.iter(); ) { p += q; }
for (Benchmark b("Point double", 100); b.iter(); ) { p.double_in_place(); }
for (Benchmark b("Point scalarmul"); b.iter(); ) { p * s; }
for (Benchmark b("Point encode"); b.iter(); ) { ep = std::string(p); }
for (Benchmark b("Point encode"); b.iter(); ) { ep = decaf::SecureBuffer(p); }
for (Benchmark b("Point decode"); b.iter(); ) { p = Point(ep); }
for (Benchmark b("Point create/destroy"); b.iter(); ) { Point r; }
for (Benchmark b("Point hash nonuniform"); b.iter(); ) { Point::from_hash(ep); }
for (Benchmark b("Point hash uniform"); b.iter(); ) { Point::from_hash(ep+ep); }
for (Benchmark b("Point hash uniform"); b.iter(); ) { Point::from_hash(ep2); }
for (Benchmark b("Point double scalarmul"); b.iter(); ) { Point::double_scalarmul(p,s,q,t); }
for (Benchmark b("Point precmp scalarmul"); b.iter(); ) { pBase * s; }
/* TODO: scalarmul for verif, etc */


+ 2
- 2
test/test_decaf.cxx Ver fichero

@@ -170,7 +170,7 @@ static void test_ec() {
rng.read(buffer, 2*DECAF_448_SER_BYTES);
Point r = Point::from_hash(buffer);
point_check(test,p,q,r,0,0,p,Point((std::string)p),"round-trip");
point_check(test,p,q,r,0,0,p,Point((decaf::SecureBuffer)p),"round-trip");
point_check(test,p,q,r,0,0,p+q,q+p,"commute add");
point_check(test,p,q,r,0,0,p+(q+r),(p+q)+r,"assoc add");
@@ -187,7 +187,7 @@ static void test_ec() {
);

point_check(test,p,q,r,x,0,Point(x.direct_scalarmul(p)),x*p,"direct mul");
point_check(test,p,q,r,x,0,Point(x.direct_scalarmul(decaf::SecureBuffer(p))),x*p,"direct mul");
}
}



Cargando…
Cancelar
Guardar