Commit f92d14e0 authored by Michael Hamburg's avatar Michael Hamburg

crypto.hxx is now a thin wrapper around crypto.h

parent ca68bb36
......@@ -3,7 +3,7 @@ from gen_file import gen_file
crypto_h = gen_file(
name = "decaf/crypto_%(shortname)s.h",
doc = """
@brief Example Decaf cyrpto routines.
@brief 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.
......@@ -25,7 +25,7 @@ typedef unsigned char %(c_ns)s_public_key_t[%(C_NS)s_SER_BYTES];
typedef unsigned char %(c_ns)s_signature_t[%(C_NS)s_SER_BYTES + %(C_NS)s_SCALAR_BYTES];
typedef struct {
/** @cond intetrnal */
/** @cond internal */
/** The symmetric key from which everything is expanded */
%(c_ns)s_symmetric_key_t sym;
......
from gen_file import gen_file
crypto_hxx = gen_file(
name = "decaf/crypto_%(shortname)s.hxx",
doc = """
@brief 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.
@warning Experimental! The names, parameter orders etc are likely to change.
""", code = """
#include <decaf.hxx>
#include <decaf/shake.hxx>
/** @cond internal */
#if __cplusplus >= 201103L
#define NOEXCEPT noexcept
#else
#define NOEXCEPT throw()
#endif
/** @endcond */
namespace decaf {
template <typename Group> class PublicKey;
template <typename Group> class PrivateKey;
template<> class PublicKey<%(cxx_ns)s>
: public Serializable< PublicKey<%(cxx_ns)s> > {
private:
typedef %(c_ns)s_public_key_t Wrapped;
Wrapped wrapped;
template<class Group> friend class PrivateKey;
public:
/** @brief Underlying group */
typedef %(cxx_ns)s Group;
/** @brief Signature size. */
static const size_t SIG_BYTES = sizeof(%(c_ns)s_signature_t);
/** @brief Serialization size. */
static const size_t SER_BYTES = sizeof(Wrapped);
/* TODO: convenience types like signature? */
/** @brief 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*/
inline explicit PublicKey(const PrivateKey<%(cxx_ns)s> &b) NOEXCEPT;
/** @brief Create but don't initialize */
inline explicit PublicKey(const NOINIT&) NOEXCEPT { }
/** @brief Serialize into a buffer. */
inline void serializeInto(unsigned char *x) const NOEXCEPT {
memcpy(x,wrapped,sizeof(wrapped));
}
/** @brief Serialization size. */
inline size_t serSize() const NOEXCEPT { return SER_BYTES; }
/* TODO: verify_strobe? */
/** @brief Verify a message */
inline void verify(
const Block &message,
const FixedBlock<SIG_BYTES> &sig
) const throw(CryptoException) {
if (DECAF_SUCCESS != %(c_ns)s_verify(sig.data(),wrapped,message.data(),message.size())) {
throw(CryptoException());
}
}
};
template<> class PrivateKey<%(cxx_ns)s>
: public Serializable< PrivateKey<%(cxx_ns)s> > {
private:
typedef %(c_ns)s_private_key_t Wrapped;
Wrapped wrapped;
template<class Group> friend class PublicKey;
public:
/** @brief Underlying group */
typedef %(cxx_ns)s Group;
/** @brief Signature size. */
static const size_t SIG_BYTES = sizeof(%(c_ns)s_signature_t);
/** @brief Serialization size. */
static const size_t SER_BYTES = sizeof(Wrapped);
/** @brief Compressed size. */
static const size_t SYM_BYTES = %(C_NS)s_SYMMETRIC_KEY_BYTES;
/** @brief Create but don't initialize */
inline explicit PrivateKey(const NOINIT&) NOEXCEPT { }
/** @brief 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*/
inline explicit PrivateKey(const FixedBlock<SYM_BYTES> &b) NOEXCEPT {
%(c_ns)s_derive_private_key(wrapped, b.data());
}
/** @brief 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 */
inline ~PrivateKey() NOEXCEPT {
%(c_ns)s_destroy_private_key(wrapped);
}
/** @brief Serialization size. */
inline size_t serSize() const NOEXCEPT { return SER_BYTES; }
/** @brief Serialize into a buffer. */
inline void serializeInto(unsigned char *x) const NOEXCEPT {
memcpy(x,wrapped,sizeof(wrapped));
}
/** @brief 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 */
inline PublicKey<%(cxx_ns)s> pub() const NOEXCEPT {
PublicKey<%(cxx_ns)s> ret(*this); return ret;
}
/** @brief Derive a shared secret */
inline SecureBuffer sharedSecret(
const PublicKey<%(cxx_ns)s> &pub,
size_t bytes,
bool me_first
) const throw(CryptoException,std::bad_alloc) {
SecureBuffer ret(bytes);
if (DECAF_SUCCESS != %(c_ns)s_shared_secret(ret.data(),bytes,wrapped,pub.wrapped,me_first)) {
throw(CryptoException());
}
return ret;
}
/** @brief 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());
return sig;
}
};
/** @cond internal */
PublicKey<%(cxx_ns)s>::PublicKey(const PrivateKey<%(cxx_ns)s> &b) NOEXCEPT {
%(c_ns)s_private_to_public(wrapped,b.wrapped);
}
/** @endcond */
#undef NOEXCEPT
} /* namespace decaf */
""")
\ No newline at end of file
......@@ -14,6 +14,7 @@ prefixes = { "h" : args.hpre, "hxx" : args.hpre, "c" : args.cpre }
from decaf_hxx import decaf_hxx
from decaf_h import decaf_h
from crypto_h import crypto_h
from crypto_hxx import crypto_hxx
root_hxx_code = "\n".join((
"#include <%s>" % name
......@@ -34,7 +35,7 @@ crypto_h_code = "\n".join((
crypto_h = gen_file(
name = "decaf/crypto.h",
doc = """@brief
@brief Example Decaf cyrpto routines, metaheader.
@brief 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.
......@@ -42,6 +43,22 @@ crypto_h = gen_file(
code = "\n"+crypto_h_code+"\n"
)
crypto_hxx_code = "\n".join((
"#include <%s>" % name
for name in sorted(gend_files)
if re.match("^decaf/crypto_\d+.hxx$",name)
))
crypto_hxx = gen_file(
name = "decaf/crypto.hxx",
doc = """@brief
@brief 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.
""",
code = "\n"+crypto_hxx_code+"\n"
)
root_h_code = "\n".join((
"#include <%s>" % name
for name in sorted(gend_files)
......
/**
* @file decaf/crypto.hxx
* @author Mike Hamburg
*
* @copyright
* Copyright (c) 2015 Cryptography Research, Inc. \n
* Released under the MIT License. See LICENSE.txt for license information.
*
* @brief Example cryptography using Decaf.
* @warning FIXME: this is out of sync with crypto_*.h
*/
#ifndef __DECAF_CRYPTO_HXX__
#define __DECAF_CRYPTO_HXX__ 1
#include <decaf.hxx>
#include <decaf/shake.hxx>
/** @cond internal */
#if __cplusplus >= 201103L
#define NOEXCEPT noexcept
#else
#define NOEXCEPT throw()
#endif
/** @endcond */
/* TODO: decide on copy vs reference */
namespace decaf {
template <typename Group> class PrivateKey;
/** @brief A public key using a particular EC group */
template <typename Group> class PublicKey : public Serializable<PublicKey<Group> > {
private:
/** @cond internal */
friend class PrivateKey<Group>;
static const size_t CHALLENGE_BYTES = Group::Scalar::SER_BYTES;
//const typename Group::Point p;
FixedArrayBuffer<Group::Point::SER_BYTES> ser;
/** @endcond */
public:
/** Create without init */
PublicKey(NOINIT) : ser(NOINIT()) {}
/** SHAKE instance size for sigs etc */
static const size_t SHAKE_BITS = 256;
/** Size of a signature */
static const size_t SIG_BYTES = Group::Point::SER_BYTES + Group::Scalar::SER_BYTES;
/** @brief Set the public key to a point */
inline explicit PublicKey(const typename Group::Point &p) NOEXCEPT : ser(p.serialize()) {}
/** @brief Get the private key for a given public key */
inline explicit PublicKey(const PrivateKey<Group> &priv) NOEXCEPT;
/** @brief Read a private key from a string*/
inline explicit PublicKey(const FixedBlock<Group::Point::SER_BYTES> &b) NOEXCEPT : ser(b) {}
/** @brief Return the corresponding EC point */
inline typename Group::Point point() const throw(CryptoException) {
return typename Group::Point(ser);
}
/** @brief Verify a sig. TODO: nothrow version? */
inline void verify_shake(const SHAKE<SHAKE_BITS> &ctx_, const FixedBlock<SIG_BYTES> &sig) throw(CryptoException) {
SHAKE<SHAKE_BITS> ctx(ctx_);
ctx << ser << sig.slice(0,Group::Point::SER_BYTES);
FixedArrayBuffer<CHALLENGE_BYTES> challenge;
ctx.output(challenge);
typename Group::Scalar response;
decaf_error_t scalar_OK = Group::Scalar::decode(
response,
sig.slice(Group::Point::SER_BYTES, Group::Scalar::SER_BYTES)
);
const typename Group::Point combo = point().non_secret_combo_with_base(
typename Group::Scalar(challenge), response
);
if (!decaf_successful(scalar_OK)
|| combo != typename Group::Point(sig.slice(0,Group::Point::SER_BYTES)))
throw CryptoException();
//return scalar_OK & (combo == typename Group::Point(sig.slice(0,Group::Point::SER_BYTES)));
}
/** @brief Sign from a message. */
inline void verify(const Block &message, const FixedBlock<SIG_BYTES> &sig) throw(CryptoException) {
SHAKE<SHAKE_BITS> ctx;
ctx << message;
verify_shake(ctx,sig);
}
/** @brief Serialize into a buffer. */
inline void serializeInto(unsigned char *x) const NOEXCEPT {
memcpy(x,ser.data(),Group::Point::SER_BYTES);
}
/** @brief Serialize into a buffer. */
inline size_t serSize() const NOEXCEPT {
return Group::Point::SER_BYTES;
}
/** @brief Copy operator */
inline PublicKey &operator=(const PublicKey &x) NOEXCEPT { ser = x.ser; return *this; }
};
/** @brief A private key using a particular EC group */
template <typename Group> class PrivateKey : public Serializable<PrivateKey<Group> > {
public:
/** Size of associated symmetric key */
static const size_t SYM_BYTES = 32;
/** SHAKE instance size for sigs etc */
static const size_t SHAKE_BITS = PublicKey<Group>::SHAKE_BITS;
private:
/** @cond internal */
static const size_t SCALAR_HASH_BYTES = Group::Scalar::SER_BYTES + 8;
friend class PublicKey<Group>;
FixedArrayBuffer<SYM_BYTES> sym;
typename Group::Scalar scalar;
PublicKey<Group> pub_;
/** @endcond */
public:
/** @brief Don't initialize */
inline PrivateKey(const NOINIT &ni) NOEXCEPT : sym(ni), scalar(ni), pub_(ni) {}
/** @brief Construct at random */
inline PrivateKey(Rng &r) :
sym(r),
scalar(SHAKE<SHAKE_BITS>::hash(sym, SCALAR_HASH_BYTES)),
pub_((Group::Precomputed::base() * scalar).serialize()) {}
/** @brief Construct from buffer */
inline PrivateKey(const FixedBlock<SYM_BYTES> &sym_) :
sym(sym_),
scalar(SHAKE<SHAKE_BITS>::hash(sym, SCALAR_HASH_BYTES)),
pub_(SecureBuffer(Group::Precomputed::Base * scalar)) {}
/** @brief Compressed representation */
inline const FixedBlock<SYM_BYTES> &ser_compressed() const NOEXCEPT {
return sym;
}
/** @brief Serialize */
inline size_t serSize() const NOEXCEPT {
return SYM_BYTES;
}
/** @brief Serialize */
inline void serializeInto(unsigned char *target) const NOEXCEPT {
memcpy(target,sym.data(),serSize());
}
/** @brief Uncompressed representation */
inline SecureBuffer ser_uncompressed() const throw(std::bad_alloc) {
SecureBuffer b(SYM_BYTES + Group::Scalar::SER_BYTES + Group::Point::SER_BYTES);
Buffer(b).slice(0,SYM_BYTES).assign(sym);
Buffer(b).slice(SYM_BYTES,Group::Scalar::SER_BYTES).assign(scalar);
Buffer(b).slice(SYM_BYTES+Group::Scalar::SER_BYTES,Group::Point::SER_BYTES).assign(pub_.ser);
return b;
}
/** @brief Sign from a SHAKE context. TODO: double check random oracle eval of this; destructive version? */
inline SecureBuffer sign_shake(const SHAKE<SHAKE_BITS> &ctx_) throw(std::bad_alloc) {
SHAKE<SHAKE_BITS> ctx(ctx_);
ctx << sym << "decaf_255_sign_shake";
typename Group::Scalar nonce(ctx.output(SCALAR_HASH_BYTES));
SecureBuffer g_nonce = (Group::Precomputed::base() * nonce).serialize();
ctx = ctx_;
ctx << pub_.ser << g_nonce;
SecureBuffer challenge(ctx.output(PublicKey<Group>::CHALLENGE_BYTES));
SecureBuffer response((nonce - scalar * typename Group::Scalar(challenge)).serialize());
SecureBuffer ret(PublicKey<Group>::SIG_BYTES);
Buffer(ret).slice(0,Group::Point::SER_BYTES).assign(g_nonce);
Buffer(ret).slice(Group::Point::SER_BYTES, Group::Scalar::SER_BYTES).assign(response);
return ret;
}
/** @brief Sign from a message. */
inline SecureBuffer sign(const Block &message) {
SHAKE<SHAKE_BITS> ctx;
ctx << message;
return sign_shake(ctx);
}
/** @brief Get the corresponding public key */
inline const PublicKey<Group> &pub() const { return pub_; }
/** @brief Copy operator */
inline PrivateKey &operator=(const PrivateKey &x) NOEXCEPT {
sym = x.sym;
scalar = x.scalar;
pub_ = x.pub_;
return *this;
}
};
/** @cond internal */
template <typename Group>
inline PublicKey<Group>::PublicKey(
const PrivateKey<Group> &priv
) NOEXCEPT : ser(priv.pub_.ser){}
/** @endcond */
#undef NOEXCEPT
} /* namespace decaf */
#endif /* __DECAF_CRYPTO_HXX__ */
......@@ -376,14 +376,6 @@ int main(int argc, char **argv) {
if (argc >= 2 && !strcmp(argv[1], "--micro"))
micro = true;
decaf_255_symmetric_key_t r1,r2;
memset(r1,1,sizeof(r1));
memset(r2,2,sizeof(r2));
unsigned char umessage[] = {1,2,3,4,5};
size_t lmessage = sizeof(umessage);
SpongeRng rng(Block("micro-benchmarks"));
if (micro) {
printf("\nMicro-benchmarks:\n");
......@@ -417,76 +409,10 @@ int main(int argc, char **argv) {
Benches<Ed448Goldilocks>::micro();
}
{
decaf_255_public_key_t p1,p2;
decaf_255_private_key_t s1,s2;
decaf_255_signature_t sig1;
unsigned char ss[32];
printf("\nMacro-benchmarks for IsoEd25519:\n");
for (Benchmark b("Keygen"); b.iter(); ) {
decaf_255_derive_private_key(s1,r1);
}
decaf_255_private_to_public(p1,s1);
decaf_255_derive_private_key(s2,r2);
decaf_255_private_to_public(p2,s2);
for (Benchmark b("Shared secret"); b.iter(); ) {
decaf_bool_t ret = decaf_255_shared_secret(ss,sizeof(ss),s1,p2,1);
ignore_result(ret);
assert(ret);
}
for (Benchmark b("Sign"); b.iter(); ) {
decaf_255_sign(sig1,s1,umessage,lmessage);
}
for (Benchmark b("Verify"); b.iter(); ) {
decaf_bool_t ret = decaf_255_verify(sig1,p1,umessage,lmessage);
rng.read(Buffer(umessage,lmessage));
// umessage[0]++;
// umessage[1]^=umessage[0];
ignore_result(ret);
}
}
{
decaf_448_public_key_t p1,p2;
decaf_448_private_key_t s1,s2;
decaf_448_signature_t sig1;
unsigned char ss[32];
printf("\nMacro-benchmarks for Ed448-Goldilocks:\n");
for (Benchmark b("Keygen"); b.iter(); ) {
decaf_448_derive_private_key(s1,r1);
}
decaf_448_private_to_public(p1,s1);
decaf_448_derive_private_key(s2,r2);
decaf_448_private_to_public(p2,s2);
for (Benchmark b("Shared secret"); b.iter(); ) {
decaf_bool_t ret = decaf_448_shared_secret(ss,sizeof(ss),s1,p2,1);
ignore_result(ret);
assert(ret);
}
for (Benchmark b("Sign"); b.iter(); ) {
decaf_448_sign(sig1,s1,umessage,lmessage);
}
for (Benchmark b("Verify"); b.iter(); ) {
decaf_bool_t ret = decaf_448_verify(sig1,p1,umessage,lmessage);
rng.read(Buffer(umessage,lmessage));
// umessage[0]++;
// umessage[1]^=umessage[0];
ignore_result(ret);
}
}
Benches<IsoEd25519>::macro();
Benches<Ed448Goldilocks>::macro();
printf("\n");
Benchmark::calib();
......
......@@ -11,8 +11,7 @@
#include <decaf.hxx>
#include <decaf/shake.hxx>
#include <decaf/crypto_255.h>
#include <decaf/crypto_448.h>
#include <decaf/crypto.h>
#include <decaf/crypto.hxx>
#include <stdio.h>
......@@ -342,75 +341,6 @@ static void test_crypto() {
}; // template<GroupId GROUP>
static void test_decaf_255() {
Test test("Sample crypto");
SpongeRng rng(Block("test_decaf"));
decaf_255_symmetric_key_t proto1,proto2;
decaf_255_private_key_t s1,s2;
decaf_255_public_key_t p1,p2;
decaf_255_signature_t sig;
unsigned char shared1[1234],shared2[1234];
const char *message = "Hello, world!";
for (int i=0; i<NTESTS && test.passing_now; i++) {
rng.read(Buffer(proto1,sizeof(proto1)));
rng.read(Buffer(proto2,sizeof(proto2)));
decaf_255_derive_private_key(s1,proto1);
decaf_255_private_to_public(p1,s1);
decaf_255_derive_private_key(s2,proto2);
decaf_255_private_to_public(p2,s2);
if (DECAF_SUCCESS != decaf_255_shared_secret (shared1,sizeof(shared1),s1,p2,0)) {
test.fail(); printf("Fail ss12\n");
}
if (DECAF_SUCCESS != decaf_255_shared_secret (shared2,sizeof(shared2),s2,p1,1)) {
test.fail(); printf("Fail ss21\n");
}
if (memcmp(shared1,shared2,sizeof(shared1))) {
test.fail(); printf("Fail ss21 == ss12\n");
}
decaf_255_sign (sig,s1,(const unsigned char *)message,strlen(message));
if (DECAF_SUCCESS != decaf_255_verify (sig,p1,(const unsigned char *)message,strlen(message))) {
test.fail(); printf("Fail sig ver\n");
}
}
}
/* TODO: don't copy-paste */
static void test_decaf_448() {
Test test("Sample crypto");
SpongeRng rng(Block("test_decaf"));
decaf_448_symmetric_key_t proto1,proto2;
decaf_448_private_key_t s1,s2;
decaf_448_public_key_t p1,p2;
decaf_448_signature_t sig;
unsigned char shared1[1234],shared2[1234];
const char *message = "Hello, world!";
for (int i=0; i<NTESTS && test.passing_now; i++) {
rng.read(Buffer(proto1,sizeof(proto1)));
rng.read(Buffer(proto2,sizeof(proto2)));
decaf_448_derive_private_key(s1,proto1);
decaf_448_private_to_public(p1,s1);
decaf_448_derive_private_key(s2,proto2);
decaf_448_private_to_public(p2,s2);
if (DECAF_SUCCESS != decaf_448_shared_secret (shared1,sizeof(shared1),s1,p2,0)) {
test.fail(); printf("Fail ss12\n");
}
if (DECAF_SUCCESS != decaf_448_shared_secret (shared2,sizeof(shared2),s2,p1,1)) {
test.fail(); printf("Fail ss21\n");
}
if (memcmp(shared1,shared2,sizeof(shared1))) {
test.fail(); printf("Fail ss21 == ss12\n");
}
decaf_448_sign (sig,s1,(const unsigned char *)message,strlen(message));
if (DECAF_SUCCESS != decaf_448_verify (sig,p1,(const unsigned char *)message,strlen(message))) {
test.fail(); printf("Fail sig ver\n");
}
}
}
int main(int argc, char **argv) {
(void) argc; (void) argv;
......@@ -419,7 +349,6 @@ int main(int argc, char **argv) {
Tests<IsoEd25519>::test_elligator();
Tests<IsoEd25519>::test_ec();
Tests<IsoEd25519>::test_crypto();
test_decaf_255();
printf("\n");
printf("Testing %s:\n", Ed448Goldilocks::name());
......@@ -427,7 +356,6 @@ int main(int argc, char **argv) {
Tests<Ed448Goldilocks>::test_elligator();
Tests<Ed448Goldilocks>::test_ec();
Tests<Ed448Goldilocks>::test_crypto();
test_decaf_448();
if (passing) printf("Passed all tests.\n");
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment