construct/ircd/sodium.cc

268 lines
4.8 KiB
C++

// Matrix Construct
//
// Copyright (C) Matrix Construct Developers, Authors & Contributors
// Copyright (C) 2016-2018 Jason Volk <jason@zemos.net>
//
// Permission to use, copy, modify, and/or distribute this software for any
// purpose with or without fee is hereby granted, provided that the above
// copyright notice and this permission notice is present in all copies. The
// full license for this software is available in the LICENSE file.
#include <sodium.h>
namespace ircd::nacl
{
struct throw_on_error;
static void init() __attribute__((constructor));
}
struct ircd::nacl::throw_on_error
{
throw_on_error(const int &val);
};
///////////////////////////////////////////////////////////////////////////////
//
// ircd/nacl.h
//
decltype(ircd::nacl::version_api)
ircd::nacl::version_api
{
"sodium", info::versions::API, 0,
{
SODIUM_LIBRARY_VERSION_MAJOR,
SODIUM_LIBRARY_VERSION_MINOR,
0
},
SODIUM_VERSION_STRING,
};
decltype(ircd::nacl::version_abi)
ircd::nacl::version_abi
{
"sodium", info::versions::ABI, 0,
{
::sodium_library_version_major(),
::sodium_library_version_minor(),
0
},
::sodium_version_string(),
};
///////////////////////////////////////////////////////////////////////////////
//
// ircd/buffer.h
//
size_t
ircd::buffer::zero(const mutable_buffer &buf)
{
sodium_memzero(data(buf), size(buf));
return size(buf);
}
///////////////////////////////////////////////////////////////////////////////
//
// ircd/ed25519
//
static_assert(ircd::ed25519::SK_SZ == crypto_sign_ed25519_SECRETKEYBYTES);
static_assert(ircd::ed25519::PK_SZ == crypto_sign_ed25519_PUBLICKEYBYTES);
ircd::ed25519::sk::sk(pk *const &pk_arg,
const const_buffer &seed)
:key
{
reinterpret_cast<uint8_t *>(::sodium_malloc(crypto_sign_ed25519_SECRETKEYBYTES)),
&::sodium_free
}
{
assert(size(seed) >= SEED_SZ);
pk discard, &pk
{
pk_arg? *pk_arg : discard
};
const auto pk_data
{
reinterpret_cast<uint8_t *>(pk.data())
};
const auto seed_data
{
reinterpret_cast<const uint8_t *>(data(seed))
};
nacl::throw_on_error
{
::crypto_sign_ed25519_seed_keypair(pk_data, key.get(), seed_data)
};
}
ircd::ed25519::sk::sk(const string_view &filename,
pk *const &pk_arg,
const bool &create)
try
:key
{
reinterpret_cast<uint8_t *>(::sodium_malloc(crypto_sign_ed25519_SECRETKEYBYTES)),
&::sodium_free
}
{
pk discard, &pk
{
pk_arg? *pk_arg : discard
};
const auto pk_data
{
reinterpret_cast<uint8_t *>(pk.data())
};
const mutable_buffer key_data
{
reinterpret_cast<char *>(key.get()), SK_SZ
};
const bool exists
{
filename && fs::exists(filename)
};
if(!exists && create)
{
nacl::throw_on_error
{
::crypto_sign_ed25519_keypair(pk_data, key.get())
};
fs::write(filename, key_data);
}
else if(!exists)
{
zero(pk);
key.reset();
return;
}
else fs::read(filename, key_data);
nacl::throw_on_error
{
::crypto_sign_ed25519_sk_to_pk(pk_data, key.get())
};
}
catch(const std::exception &e)
{
throw error
{
"Failed to read existing ed25519 secret key in: %s :%s",
filename,
e.what()
};
}
ircd::ed25519::sig
ircd::ed25519::sk::sign(const const_buffer &msg)
const
{
if(unlikely(!key))
throw error
{
"No ed25519 secret key is loaded."
};
struct sig sig;
unsigned long long sig_sz;
const auto sig_data
{
reinterpret_cast<uint8_t *>(sig.data())
};
const auto msg_data
{
reinterpret_cast<const uint8_t *>(buffer::data(msg))
};
nacl::throw_on_error
{
::crypto_sign_ed25519_detached(sig_data,
&sig_sz,
msg_data,
buffer::size(msg),
key.get())
};
assert(sig_sz <= sig.size());
assert(sig.size() >= sig_sz);
memset(sig.data() + sig.size() - sig_sz, 0, sig.size() - sig_sz);
return sig;
}
bool
ircd::ed25519::pk::verify(const const_buffer &msg,
const sig &sig)
const
{
const auto sig_data
{
reinterpret_cast<const uint8_t *>(sig.data())
};
const auto msg_data
{
reinterpret_cast<const uint8_t *>(buffer::data(msg))
};
const auto key_data
{
reinterpret_cast<const uint8_t *>(data())
};
const int ret
{
::crypto_sign_ed25519_verify_detached(sig_data,
msg_data,
buffer::size(msg),
key_data)
};
if(likely(ret == 0))
return true;
if(likely(ret == -1))
return false;
throw nacl::error
{
"verify failed: %d", ret
};
}
///////////////////////////////////////////////////////////////////////////////
//
// Internal
//
void
ircd::nacl::init()
{
if(::sodium_init() < 0)
throw std::runtime_error
{
"sodium_init(): error"
};
}
ircd::nacl::throw_on_error::throw_on_error(const int &val)
{
if(unlikely(val != 0))
throw ircd::nacl::error
{
"sodium error"
};
}