aboutsummaryrefslogtreecommitdiff
path: root/src/crypto
diff options
context:
space:
mode:
Diffstat (limited to 'src/crypto')
-rw-r--r--src/crypto/CMakeLists.txt1
-rw-r--r--src/crypto/chacha.h23
-rw-r--r--src/crypto/crypto.cpp3
-rw-r--r--src/crypto/crypto.h10
-rw-r--r--src/crypto/generic-ops.h28
-rw-r--r--src/crypto/keccak.c74
-rw-r--r--src/crypto/keccak.h14
7 files changed, 135 insertions, 18 deletions
diff --git a/src/crypto/CMakeLists.txt b/src/crypto/CMakeLists.txt
index 71dcedcab..0c635e7cb 100644
--- a/src/crypto/CMakeLists.txt
+++ b/src/crypto/CMakeLists.txt
@@ -78,6 +78,7 @@ target_link_libraries(cncrypto
PUBLIC
epee
${Boost_SYSTEM_LIBRARY}
+ ${SODIUM_LIBRARY}
PRIVATE
${EXTRA_LIBRARIES})
diff --git a/src/crypto/chacha.h b/src/crypto/chacha.h
index 2b3ed8043..6e85ad0e9 100644
--- a/src/crypto/chacha.h
+++ b/src/crypto/chacha.h
@@ -40,6 +40,7 @@
#include <memory.h>
#include "memwipe.h"
+#include "mlocker.h"
#include "hash.h"
namespace crypto {
@@ -50,7 +51,7 @@ namespace crypto {
#if defined(__cplusplus)
}
- using chacha_key = tools::scrubbed_arr<uint8_t, CHACHA_KEY_SIZE>;
+ using chacha_key = epee::mlocked<tools::scrubbed_arr<uint8_t, CHACHA_KEY_SIZE>>;
#pragma pack(push, 1)
// MS VC 2012 doesn't interpret `class chacha_iv` as POD in spite of [9.0.10], so it is a struct
@@ -69,22 +70,26 @@ namespace crypto {
chacha20(data, length, key.data(), reinterpret_cast<const uint8_t*>(&iv), cipher);
}
- inline void generate_chacha_key(const void *data, size_t size, chacha_key& key) {
+ inline void generate_chacha_key(const void *data, size_t size, chacha_key& key, uint64_t kdf_rounds) {
static_assert(sizeof(chacha_key) <= sizeof(hash), "Size of hash must be at least that of chacha_key");
- tools::scrubbed_arr<char, HASH_SIZE> pwd_hash;
+ epee::mlocked<tools::scrubbed_arr<char, HASH_SIZE>> pwd_hash;
crypto::cn_slow_hash(data, size, pwd_hash.data(), 0/*variant*/, 0/*prehashed*/);
- memcpy(&unwrap(key), pwd_hash.data(), sizeof(key));
+ for (uint64_t n = 1; n < kdf_rounds; ++n)
+ crypto::cn_slow_hash(pwd_hash.data(), pwd_hash.size(), pwd_hash.data(), 0/*variant*/, 0/*prehashed*/);
+ memcpy(&unwrap(unwrap(key)), pwd_hash.data(), sizeof(key));
}
- inline void generate_chacha_key_prehashed(const void *data, size_t size, chacha_key& key) {
+ inline void generate_chacha_key_prehashed(const void *data, size_t size, chacha_key& key, uint64_t kdf_rounds) {
static_assert(sizeof(chacha_key) <= sizeof(hash), "Size of hash must be at least that of chacha_key");
- tools::scrubbed_arr<char, HASH_SIZE> pwd_hash;
+ epee::mlocked<tools::scrubbed_arr<char, HASH_SIZE>> pwd_hash;
crypto::cn_slow_hash(data, size, pwd_hash.data(), 0/*variant*/, 1/*prehashed*/);
- memcpy(&unwrap(key), pwd_hash.data(), sizeof(key));
+ for (uint64_t n = 1; n < kdf_rounds; ++n)
+ crypto::cn_slow_hash(pwd_hash.data(), pwd_hash.size(), pwd_hash.data(), 0/*variant*/, 0/*prehashed*/);
+ memcpy(&unwrap(unwrap(key)), pwd_hash.data(), sizeof(key));
}
- inline void generate_chacha_key(std::string password, chacha_key& key) {
- return generate_chacha_key(password.data(), password.size(), key);
+ inline void generate_chacha_key(std::string password, chacha_key& key, uint64_t kdf_rounds) {
+ return generate_chacha_key(password.data(), password.size(), key, kdf_rounds);
}
}
diff --git a/src/crypto/crypto.cpp b/src/crypto/crypto.cpp
index 0c019938d..4243c71fd 100644
--- a/src/crypto/crypto.cpp
+++ b/src/crypto/crypto.cpp
@@ -70,6 +70,9 @@ namespace crypto {
#include "random.h"
}
+ const crypto::public_key null_pkey = crypto::public_key{};
+ const crypto::secret_key null_skey = crypto::secret_key{};
+
static inline unsigned char *operator &(ec_point &point) {
return &reinterpret_cast<unsigned char &>(point);
}
diff --git a/src/crypto/crypto.h b/src/crypto/crypto.h
index 449af8f6d..33cc0a25a 100644
--- a/src/crypto/crypto.h
+++ b/src/crypto/crypto.h
@@ -34,7 +34,6 @@
#include <iostream>
#include <boost/thread/mutex.hpp>
#include <boost/thread/lock_guard.hpp>
-#include <boost/utility/value_init.hpp>
#include <boost/optional.hpp>
#include <type_traits>
#include <vector>
@@ -42,6 +41,7 @@
#include "common/pod-class.h"
#include "common/util.h"
#include "memwipe.h"
+#include "mlocker.h"
#include "generic-ops.h"
#include "hex.h"
#include "span.h"
@@ -66,7 +66,7 @@ namespace crypto {
friend class crypto_ops;
};
- using secret_key = tools::scrubbed<ec_scalar>;
+ using secret_key = epee::mlocked<tools::scrubbed<ec_scalar>>;
POD_CLASS public_keyV {
std::vector<public_key> keys;
@@ -278,11 +278,11 @@ namespace crypto {
epee::to_hex::formatted(o, epee::as_byte_span(v)); return o;
}
- const static crypto::public_key null_pkey = boost::value_initialized<crypto::public_key>();
- const static crypto::secret_key null_skey = boost::value_initialized<crypto::secret_key>();
+ const extern crypto::public_key null_pkey;
+ const extern crypto::secret_key null_skey;
}
CRYPTO_MAKE_HASHABLE(public_key)
-CRYPTO_MAKE_HASHABLE(secret_key)
+CRYPTO_MAKE_HASHABLE_CONSTANT_TIME(secret_key)
CRYPTO_MAKE_HASHABLE(key_image)
CRYPTO_MAKE_COMPARABLE(signature)
diff --git a/src/crypto/generic-ops.h b/src/crypto/generic-ops.h
index 62bc758c9..42b98706e 100644
--- a/src/crypto/generic-ops.h
+++ b/src/crypto/generic-ops.h
@@ -33,19 +33,30 @@
#include <cstddef>
#include <cstring>
#include <functional>
+#include <sodium/crypto_verify_32.h>
#define CRYPTO_MAKE_COMPARABLE(type) \
namespace crypto { \
inline bool operator==(const type &_v1, const type &_v2) { \
- return std::memcmp(&_v1, &_v2, sizeof(type)) == 0; \
+ return !memcmp(&_v1, &_v2, sizeof(_v1)); \
} \
inline bool operator!=(const type &_v1, const type &_v2) { \
- return std::memcmp(&_v1, &_v2, sizeof(type)) != 0; \
+ return !operator==(_v1, _v2); \
} \
}
-#define CRYPTO_MAKE_HASHABLE(type) \
-CRYPTO_MAKE_COMPARABLE(type) \
+#define CRYPTO_MAKE_COMPARABLE_CONSTANT_TIME(type) \
+namespace crypto { \
+ inline bool operator==(const type &_v1, const type &_v2) { \
+ static_assert(sizeof(_v1) == 32, "constant time comparison is only implenmted for 32 bytes"); \
+ return crypto_verify_32((const unsigned char*)&_v1, (const unsigned char*)&_v2) == 0; \
+ } \
+ inline bool operator!=(const type &_v1, const type &_v2) { \
+ return !operator==(_v1, _v2); \
+ } \
+}
+
+#define CRYPTO_DEFINE_HASH_FUNCTIONS(type) \
namespace crypto { \
static_assert(sizeof(std::size_t) <= sizeof(type), "Size of " #type " must be at least that of size_t"); \
inline std::size_t hash_value(const type &_v) { \
@@ -60,3 +71,12 @@ namespace std { \
} \
}; \
}
+
+#define CRYPTO_MAKE_HASHABLE(type) \
+CRYPTO_MAKE_COMPARABLE(type) \
+CRYPTO_DEFINE_HASH_FUNCTIONS(type)
+
+#define CRYPTO_MAKE_HASHABLE_CONSTANT_TIME(type) \
+CRYPTO_MAKE_COMPARABLE_CONSTANT_TIME(type) \
+CRYPTO_DEFINE_HASH_FUNCTIONS(type)
+
diff --git a/src/crypto/keccak.c b/src/crypto/keccak.c
index de8e2a5b3..8fcd2138e 100644
--- a/src/crypto/keccak.c
+++ b/src/crypto/keccak.c
@@ -132,3 +132,77 @@ void keccak1600(const uint8_t *in, size_t inlen, uint8_t *md)
{
keccak(in, inlen, md, sizeof(state_t));
}
+
+#define KECCAK_FINALIZED 0x80000000
+#define KECCAK_BLOCKLEN 136
+#define KECCAK_WORDS 17
+#define KECCAK_DIGESTSIZE 32
+#define IS_ALIGNED_64(p) (0 == (7 & ((const char*)(p) - (const char*)0)))
+#define KECCAK_PROCESS_BLOCK(st, block) { \
+ for (int i_ = 0; i_ < KECCAK_WORDS; i_++){ \
+ ((st))[i_] ^= ((block))[i_]; \
+ }; \
+ keccakf(st, KECCAK_ROUNDS); }
+
+
+void keccak_init(KECCAK_CTX * ctx){
+ memset(ctx, 0, sizeof(KECCAK_CTX));
+}
+
+void keccak_update(KECCAK_CTX * ctx, const uint8_t *in, size_t inlen){
+ if (ctx->rest & KECCAK_FINALIZED) {
+ local_abort("Bad keccak use");
+ }
+
+ const size_t idx = ctx->rest;
+ ctx->rest = (ctx->rest + inlen) % KECCAK_BLOCKLEN;
+
+ // fill partial block
+ if (idx) {
+ size_t left = KECCAK_BLOCKLEN - idx;
+ memcpy((char*)ctx->message + idx, in, (inlen < left ? inlen : left));
+ if (inlen < left) return;
+
+ KECCAK_PROCESS_BLOCK(ctx->hash, ctx->message);
+
+ in += left;
+ inlen -= left;
+ }
+
+ const bool is_aligned = IS_ALIGNED_64(in);
+ while (inlen >= KECCAK_BLOCKLEN) {
+ const uint64_t* aligned_message_block;
+ if (is_aligned) {
+ aligned_message_block = (uint64_t*)in;
+ } else {
+ memcpy(ctx->message, in, KECCAK_BLOCKLEN);
+ aligned_message_block = ctx->message;
+ }
+
+ KECCAK_PROCESS_BLOCK(ctx->hash, aligned_message_block);
+ in += KECCAK_BLOCKLEN;
+ inlen -= KECCAK_BLOCKLEN;
+ }
+ if (inlen) {
+ memcpy(ctx->message, in, inlen);
+ }
+}
+
+void keccak_finish(KECCAK_CTX * ctx, uint8_t *md){
+ if (!(ctx->rest & KECCAK_FINALIZED))
+ {
+ // clear the rest of the data queue
+ memset((char*)ctx->message + ctx->rest, 0, KECCAK_BLOCKLEN - ctx->rest);
+ ((char*)ctx->message)[ctx->rest] |= 0x01;
+ ((char*)ctx->message)[KECCAK_BLOCKLEN - 1] |= 0x80;
+
+ // process final block
+ KECCAK_PROCESS_BLOCK(ctx->hash, ctx->message);
+ ctx->rest = KECCAK_FINALIZED; // mark context as finalized
+ }
+
+ static_assert(KECCAK_BLOCKLEN > KECCAK_DIGESTSIZE, "");
+ if (md) {
+ memcpy(md, ctx->hash, KECCAK_DIGESTSIZE);
+ }
+}
diff --git a/src/crypto/keccak.h b/src/crypto/keccak.h
index fb9d8bd04..9123c7a3b 100644
--- a/src/crypto/keccak.h
+++ b/src/crypto/keccak.h
@@ -15,6 +15,17 @@
#define ROTL64(x, y) (((x) << (y)) | ((x) >> (64 - (y))))
#endif
+// SHA3 Algorithm context.
+typedef struct KECCAK_CTX
+{
+ // 1600 bits algorithm hashing state
+ uint64_t hash[25];
+ // 1088-bit buffer for leftovers, block size = 136 B for 256-bit keccak
+ uint64_t message[17];
+ // count of bytes in the message[] buffer
+ size_t rest;
+} KECCAK_CTX;
+
// compute a keccak hash (md) of given byte length from "in"
void keccak(const uint8_t *in, size_t inlen, uint8_t *md, int mdlen);
@@ -23,4 +34,7 @@ void keccakf(uint64_t st[25], int norounds);
void keccak1600(const uint8_t *in, size_t inlen, uint8_t *md);
+void keccak_init(KECCAK_CTX * ctx);
+void keccak_update(KECCAK_CTX * ctx, const uint8_t *in, size_t inlen);
+void keccak_finish(KECCAK_CTX * ctx, uint8_t *md);
#endif