From 1e5491e942d0a372ebebe9ef3d40941fc4a4fbb6 Mon Sep 17 00:00:00 2001 From: moneromooo-monero Date: Thu, 7 Dec 2017 13:27:11 +0000 Subject: Add a chacha20 variant to go with chacha8 --- src/crypto/CMakeLists.txt | 4 +- src/crypto/chacha.c | 180 +++++++++++++++++++++++++++++++++++++++++++++ src/crypto/chacha.h | 84 +++++++++++++++++++++ src/crypto/chacha8.c | 170 ------------------------------------------ src/crypto/chacha8.h | 79 -------------------- src/serialization/crypto.h | 4 +- src/wallet/wallet2.cpp | 42 +++++------ src/wallet/wallet2.h | 8 +- 8 files changed, 293 insertions(+), 278 deletions(-) create mode 100644 src/crypto/chacha.c create mode 100644 src/crypto/chacha.h delete mode 100644 src/crypto/chacha8.c delete mode 100644 src/crypto/chacha8.h (limited to 'src') diff --git a/src/crypto/CMakeLists.txt b/src/crypto/CMakeLists.txt index 1e06a0dfd..fd71a87e7 100644 --- a/src/crypto/CMakeLists.txt +++ b/src/crypto/CMakeLists.txt @@ -29,7 +29,7 @@ set(crypto_sources aesb.c blake256.c - chacha8.c + chacha.c crypto-ops-data.c crypto-ops.c crypto.cpp @@ -51,7 +51,7 @@ set(crypto_headers) set(crypto_private_headers blake256.h - chacha8.h + chacha.h crypto-ops.h crypto.h generic-ops.h diff --git a/src/crypto/chacha.c b/src/crypto/chacha.c new file mode 100644 index 000000000..f573083be --- /dev/null +++ b/src/crypto/chacha.c @@ -0,0 +1,180 @@ +/* +chacha-merged.c version 20080118 +D. J. Bernstein +Public domain. +*/ + +#include +#include +#include + +#include "chacha.h" +#include "common/int-util.h" +#include "warnings.h" + +/* + * The following macros are used to obtain exact-width results. + */ +#define U8V(v) ((uint8_t)(v) & UINT8_C(0xFF)) +#define U32V(v) ((uint32_t)(v) & UINT32_C(0xFFFFFFFF)) + +/* + * The following macros load words from an array of bytes with + * different types of endianness, and vice versa. + */ +#define U8TO32_LITTLE(p) SWAP32LE(((uint32_t*)(p))[0]) +#define U32TO8_LITTLE(p, v) (((uint32_t*)(p))[0] = SWAP32LE(v)) + +#define ROTATE(v,c) (rol32(v,c)) +#define XOR(v,w) ((v) ^ (w)) +#define PLUS(v,w) (U32V((v) + (w))) +#define PLUSONE(v) (PLUS((v),1)) + +#define QUARTERROUND(a,b,c,d) \ + a = PLUS(a,b); d = ROTATE(XOR(d,a),16); \ + c = PLUS(c,d); b = ROTATE(XOR(b,c),12); \ + a = PLUS(a,b); d = ROTATE(XOR(d,a), 8); \ + c = PLUS(c,d); b = ROTATE(XOR(b,c), 7); + +static const char sigma[] = "expand 32-byte k"; + +DISABLE_GCC_AND_CLANG_WARNING(strict-aliasing) + +static void chacha(unsigned rounds, const void* data, size_t length, const uint8_t* key, const uint8_t* iv, char* cipher) { + uint32_t x0, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12, x13, x14, x15; + uint32_t j0, j1, j2, j3, j4, j5, j6, j7, j8, j9, j10, j11, j12, j13, j14, j15; + char* ctarget = 0; + char tmp[64]; + int i; + + if (!length) return; + + j0 = U8TO32_LITTLE(sigma + 0); + j1 = U8TO32_LITTLE(sigma + 4); + j2 = U8TO32_LITTLE(sigma + 8); + j3 = U8TO32_LITTLE(sigma + 12); + j4 = U8TO32_LITTLE(key + 0); + j5 = U8TO32_LITTLE(key + 4); + j6 = U8TO32_LITTLE(key + 8); + j7 = U8TO32_LITTLE(key + 12); + j8 = U8TO32_LITTLE(key + 16); + j9 = U8TO32_LITTLE(key + 20); + j10 = U8TO32_LITTLE(key + 24); + j11 = U8TO32_LITTLE(key + 28); + j12 = 0; + j13 = 0; + j14 = U8TO32_LITTLE(iv + 0); + j15 = U8TO32_LITTLE(iv + 4); + + for (;;) { + if (length < 64) { + memcpy(tmp, data, length); + data = tmp; + ctarget = cipher; + cipher = tmp; + } + x0 = j0; + x1 = j1; + x2 = j2; + x3 = j3; + x4 = j4; + x5 = j5; + x6 = j6; + x7 = j7; + x8 = j8; + x9 = j9; + x10 = j10; + x11 = j11; + x12 = j12; + x13 = j13; + x14 = j14; + x15 = j15; + for (i = rounds;i > 0;i -= 2) { + QUARTERROUND( x0, x4, x8,x12) + QUARTERROUND( x1, x5, x9,x13) + QUARTERROUND( x2, x6,x10,x14) + QUARTERROUND( x3, x7,x11,x15) + QUARTERROUND( x0, x5,x10,x15) + QUARTERROUND( x1, x6,x11,x12) + QUARTERROUND( x2, x7, x8,x13) + QUARTERROUND( x3, x4, x9,x14) + } + x0 = PLUS( x0, j0); + x1 = PLUS( x1, j1); + x2 = PLUS( x2, j2); + x3 = PLUS( x3, j3); + x4 = PLUS( x4, j4); + x5 = PLUS( x5, j5); + x6 = PLUS( x6, j6); + x7 = PLUS( x7, j7); + x8 = PLUS( x8, j8); + x9 = PLUS( x9, j9); + x10 = PLUS(x10,j10); + x11 = PLUS(x11,j11); + x12 = PLUS(x12,j12); + x13 = PLUS(x13,j13); + x14 = PLUS(x14,j14); + x15 = PLUS(x15,j15); + + x0 = XOR( x0,U8TO32_LITTLE((uint8_t*)data + 0)); + x1 = XOR( x1,U8TO32_LITTLE((uint8_t*)data + 4)); + x2 = XOR( x2,U8TO32_LITTLE((uint8_t*)data + 8)); + x3 = XOR( x3,U8TO32_LITTLE((uint8_t*)data + 12)); + x4 = XOR( x4,U8TO32_LITTLE((uint8_t*)data + 16)); + x5 = XOR( x5,U8TO32_LITTLE((uint8_t*)data + 20)); + x6 = XOR( x6,U8TO32_LITTLE((uint8_t*)data + 24)); + x7 = XOR( x7,U8TO32_LITTLE((uint8_t*)data + 28)); + x8 = XOR( x8,U8TO32_LITTLE((uint8_t*)data + 32)); + x9 = XOR( x9,U8TO32_LITTLE((uint8_t*)data + 36)); + x10 = XOR(x10,U8TO32_LITTLE((uint8_t*)data + 40)); + x11 = XOR(x11,U8TO32_LITTLE((uint8_t*)data + 44)); + x12 = XOR(x12,U8TO32_LITTLE((uint8_t*)data + 48)); + x13 = XOR(x13,U8TO32_LITTLE((uint8_t*)data + 52)); + x14 = XOR(x14,U8TO32_LITTLE((uint8_t*)data + 56)); + x15 = XOR(x15,U8TO32_LITTLE((uint8_t*)data + 60)); + + j12 = PLUSONE(j12); + if (!j12) + { + j13 = PLUSONE(j13); + /* stopping at 2^70 bytes per iv is user's responsibility */ + } + + U32TO8_LITTLE(cipher + 0,x0); + U32TO8_LITTLE(cipher + 4,x1); + U32TO8_LITTLE(cipher + 8,x2); + U32TO8_LITTLE(cipher + 12,x3); + U32TO8_LITTLE(cipher + 16,x4); + U32TO8_LITTLE(cipher + 20,x5); + U32TO8_LITTLE(cipher + 24,x6); + U32TO8_LITTLE(cipher + 28,x7); + U32TO8_LITTLE(cipher + 32,x8); + U32TO8_LITTLE(cipher + 36,x9); + U32TO8_LITTLE(cipher + 40,x10); + U32TO8_LITTLE(cipher + 44,x11); + U32TO8_LITTLE(cipher + 48,x12); + U32TO8_LITTLE(cipher + 52,x13); + U32TO8_LITTLE(cipher + 56,x14); + U32TO8_LITTLE(cipher + 60,x15); + + if (length <= 64) { + if (length < 64) { + memcpy(ctarget, cipher, length); + } + return; + } + length -= 64; + cipher += 64; + data = (uint8_t*)data + 64; + } +} + +void chacha8(const void* data, size_t length, const uint8_t* key, const uint8_t* iv, char* cipher) +{ + chacha(8, data, length, key, iv, cipher); +} + +void chacha20(const void* data, size_t length, const uint8_t* key, const uint8_t* iv, char* cipher) +{ + chacha(20, data, length, key, iv, cipher); +} diff --git a/src/crypto/chacha.h b/src/crypto/chacha.h new file mode 100644 index 000000000..a9665030d --- /dev/null +++ b/src/crypto/chacha.h @@ -0,0 +1,84 @@ +// Copyright (c) 2014-2017, The Monero Project +// +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without modification, are +// permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright notice, this list of +// conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright notice, this list +// of conditions and the following disclaimer in the documentation and/or other +// materials provided with the distribution. +// +// 3. Neither the name of the copyright holder nor the names of its contributors may be +// used to endorse or promote products derived from this software without specific +// prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY +// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL +// THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, +// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF +// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Parts of this file are originally copyright (c) 2012-2013 The Cryptonote developers + +#pragma once + +#include +#include + +#define CHACHA_KEY_SIZE 32 +#define CHACHA_IV_SIZE 8 + +#if defined(__cplusplus) +#include + +#include "common/memwipe.h" +#include "hash.h" + +namespace crypto { + extern "C" { +#endif + void chacha8(const void* data, size_t length, const uint8_t* key, const uint8_t* iv, char* cipher); + void chacha20(const void* data, size_t length, const uint8_t* key, const uint8_t* iv, char* cipher); +#if defined(__cplusplus) + } + + using chacha_key = tools::scrubbed_arr; + +#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 + struct chacha_iv { + uint8_t data[CHACHA_IV_SIZE]; + }; +#pragma pack(pop) + + static_assert(sizeof(chacha_key) == CHACHA_KEY_SIZE && sizeof(chacha_iv) == CHACHA_IV_SIZE, "Invalid structure size"); + + inline void chacha8(const void* data, std::size_t length, const chacha_key& key, const chacha_iv& iv, char* cipher) { + chacha8(data, length, key.data(), reinterpret_cast(&iv), cipher); + } + + inline void chacha20(const void* data, std::size_t length, const chacha_key& key, const chacha_iv& iv, char* cipher) { + chacha20(data, length, key.data(), reinterpret_cast(&iv), cipher); + } + + inline void generate_chacha_key(const void *data, size_t size, chacha_key& key) { + static_assert(sizeof(chacha_key) <= sizeof(hash), "Size of hash must be at least that of chacha_key"); + tools::scrubbed_arr pwd_hash; + crypto::cn_slow_hash(data, size, pwd_hash.data()); + memcpy(&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); + } +} + +#endif diff --git a/src/crypto/chacha8.c b/src/crypto/chacha8.c deleted file mode 100644 index df135af59..000000000 --- a/src/crypto/chacha8.c +++ /dev/null @@ -1,170 +0,0 @@ -/* -chacha-merged.c version 20080118 -D. J. Bernstein -Public domain. -*/ - -#include -#include -#include - -#include "chacha8.h" -#include "common/int-util.h" -#include "warnings.h" - -/* - * The following macros are used to obtain exact-width results. - */ -#define U8V(v) ((uint8_t)(v) & UINT8_C(0xFF)) -#define U32V(v) ((uint32_t)(v) & UINT32_C(0xFFFFFFFF)) - -/* - * The following macros load words from an array of bytes with - * different types of endianness, and vice versa. - */ -#define U8TO32_LITTLE(p) SWAP32LE(((uint32_t*)(p))[0]) -#define U32TO8_LITTLE(p, v) (((uint32_t*)(p))[0] = SWAP32LE(v)) - -#define ROTATE(v,c) (rol32(v,c)) -#define XOR(v,w) ((v) ^ (w)) -#define PLUS(v,w) (U32V((v) + (w))) -#define PLUSONE(v) (PLUS((v),1)) - -#define QUARTERROUND(a,b,c,d) \ - a = PLUS(a,b); d = ROTATE(XOR(d,a),16); \ - c = PLUS(c,d); b = ROTATE(XOR(b,c),12); \ - a = PLUS(a,b); d = ROTATE(XOR(d,a), 8); \ - c = PLUS(c,d); b = ROTATE(XOR(b,c), 7); - -static const char sigma[] = "expand 32-byte k"; - -DISABLE_GCC_AND_CLANG_WARNING(strict-aliasing) - -void chacha8(const void* data, size_t length, const uint8_t* key, const uint8_t* iv, char* cipher) { - uint32_t x0, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12, x13, x14, x15; - uint32_t j0, j1, j2, j3, j4, j5, j6, j7, j8, j9, j10, j11, j12, j13, j14, j15; - char* ctarget = 0; - char tmp[64]; - int i; - - if (!length) return; - - j0 = U8TO32_LITTLE(sigma + 0); - j1 = U8TO32_LITTLE(sigma + 4); - j2 = U8TO32_LITTLE(sigma + 8); - j3 = U8TO32_LITTLE(sigma + 12); - j4 = U8TO32_LITTLE(key + 0); - j5 = U8TO32_LITTLE(key + 4); - j6 = U8TO32_LITTLE(key + 8); - j7 = U8TO32_LITTLE(key + 12); - j8 = U8TO32_LITTLE(key + 16); - j9 = U8TO32_LITTLE(key + 20); - j10 = U8TO32_LITTLE(key + 24); - j11 = U8TO32_LITTLE(key + 28); - j12 = 0; - j13 = 0; - j14 = U8TO32_LITTLE(iv + 0); - j15 = U8TO32_LITTLE(iv + 4); - - for (;;) { - if (length < 64) { - memcpy(tmp, data, length); - data = tmp; - ctarget = cipher; - cipher = tmp; - } - x0 = j0; - x1 = j1; - x2 = j2; - x3 = j3; - x4 = j4; - x5 = j5; - x6 = j6; - x7 = j7; - x8 = j8; - x9 = j9; - x10 = j10; - x11 = j11; - x12 = j12; - x13 = j13; - x14 = j14; - x15 = j15; - for (i = 8;i > 0;i -= 2) { - QUARTERROUND( x0, x4, x8,x12) - QUARTERROUND( x1, x5, x9,x13) - QUARTERROUND( x2, x6,x10,x14) - QUARTERROUND( x3, x7,x11,x15) - QUARTERROUND( x0, x5,x10,x15) - QUARTERROUND( x1, x6,x11,x12) - QUARTERROUND( x2, x7, x8,x13) - QUARTERROUND( x3, x4, x9,x14) - } - x0 = PLUS( x0, j0); - x1 = PLUS( x1, j1); - x2 = PLUS( x2, j2); - x3 = PLUS( x3, j3); - x4 = PLUS( x4, j4); - x5 = PLUS( x5, j5); - x6 = PLUS( x6, j6); - x7 = PLUS( x7, j7); - x8 = PLUS( x8, j8); - x9 = PLUS( x9, j9); - x10 = PLUS(x10,j10); - x11 = PLUS(x11,j11); - x12 = PLUS(x12,j12); - x13 = PLUS(x13,j13); - x14 = PLUS(x14,j14); - x15 = PLUS(x15,j15); - - x0 = XOR( x0,U8TO32_LITTLE((uint8_t*)data + 0)); - x1 = XOR( x1,U8TO32_LITTLE((uint8_t*)data + 4)); - x2 = XOR( x2,U8TO32_LITTLE((uint8_t*)data + 8)); - x3 = XOR( x3,U8TO32_LITTLE((uint8_t*)data + 12)); - x4 = XOR( x4,U8TO32_LITTLE((uint8_t*)data + 16)); - x5 = XOR( x5,U8TO32_LITTLE((uint8_t*)data + 20)); - x6 = XOR( x6,U8TO32_LITTLE((uint8_t*)data + 24)); - x7 = XOR( x7,U8TO32_LITTLE((uint8_t*)data + 28)); - x8 = XOR( x8,U8TO32_LITTLE((uint8_t*)data + 32)); - x9 = XOR( x9,U8TO32_LITTLE((uint8_t*)data + 36)); - x10 = XOR(x10,U8TO32_LITTLE((uint8_t*)data + 40)); - x11 = XOR(x11,U8TO32_LITTLE((uint8_t*)data + 44)); - x12 = XOR(x12,U8TO32_LITTLE((uint8_t*)data + 48)); - x13 = XOR(x13,U8TO32_LITTLE((uint8_t*)data + 52)); - x14 = XOR(x14,U8TO32_LITTLE((uint8_t*)data + 56)); - x15 = XOR(x15,U8TO32_LITTLE((uint8_t*)data + 60)); - - j12 = PLUSONE(j12); - if (!j12) - { - j13 = PLUSONE(j13); - /* stopping at 2^70 bytes per iv is user's responsibility */ - } - - U32TO8_LITTLE(cipher + 0,x0); - U32TO8_LITTLE(cipher + 4,x1); - U32TO8_LITTLE(cipher + 8,x2); - U32TO8_LITTLE(cipher + 12,x3); - U32TO8_LITTLE(cipher + 16,x4); - U32TO8_LITTLE(cipher + 20,x5); - U32TO8_LITTLE(cipher + 24,x6); - U32TO8_LITTLE(cipher + 28,x7); - U32TO8_LITTLE(cipher + 32,x8); - U32TO8_LITTLE(cipher + 36,x9); - U32TO8_LITTLE(cipher + 40,x10); - U32TO8_LITTLE(cipher + 44,x11); - U32TO8_LITTLE(cipher + 48,x12); - U32TO8_LITTLE(cipher + 52,x13); - U32TO8_LITTLE(cipher + 56,x14); - U32TO8_LITTLE(cipher + 60,x15); - - if (length <= 64) { - if (length < 64) { - memcpy(ctarget, cipher, length); - } - return; - } - length -= 64; - cipher += 64; - data = (uint8_t*)data + 64; - } -} diff --git a/src/crypto/chacha8.h b/src/crypto/chacha8.h deleted file mode 100644 index dcbe6a933..000000000 --- a/src/crypto/chacha8.h +++ /dev/null @@ -1,79 +0,0 @@ -// Copyright (c) 2014-2017, The Monero Project -// -// All rights reserved. -// -// Redistribution and use in source and binary forms, with or without modification, are -// permitted provided that the following conditions are met: -// -// 1. Redistributions of source code must retain the above copyright notice, this list of -// conditions and the following disclaimer. -// -// 2. Redistributions in binary form must reproduce the above copyright notice, this list -// of conditions and the following disclaimer in the documentation and/or other -// materials provided with the distribution. -// -// 3. Neither the name of the copyright holder nor the names of its contributors may be -// used to endorse or promote products derived from this software without specific -// prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY -// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF -// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL -// THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, -// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS -// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, -// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF -// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -// -// Parts of this file are originally copyright (c) 2012-2013 The Cryptonote developers - -#pragma once - -#include -#include - -#define CHACHA8_KEY_SIZE 32 -#define CHACHA8_IV_SIZE 8 - -#if defined(__cplusplus) -#include - -#include "common/memwipe.h" -#include "hash.h" - -namespace crypto { - extern "C" { -#endif - void chacha8(const void* data, size_t length, const uint8_t* key, const uint8_t* iv, char* cipher); -#if defined(__cplusplus) - } - - using chacha8_key = tools::scrubbed_arr; - -#pragma pack(push, 1) - // MS VC 2012 doesn't interpret `class chacha8_iv` as POD in spite of [9.0.10], so it is a struct - struct chacha8_iv { - uint8_t data[CHACHA8_IV_SIZE]; - }; -#pragma pack(pop) - - static_assert(sizeof(chacha8_key) == CHACHA8_KEY_SIZE && sizeof(chacha8_iv) == CHACHA8_IV_SIZE, "Invalid structure size"); - - inline void chacha8(const void* data, std::size_t length, const chacha8_key& key, const chacha8_iv& iv, char* cipher) { - chacha8(data, length, key.data(), reinterpret_cast(&iv), cipher); - } - - inline void generate_chacha8_key(const void *data, size_t size, chacha8_key& key) { - static_assert(sizeof(chacha8_key) <= sizeof(hash), "Size of hash must be at least that of chacha8_key"); - tools::scrubbed_arr pwd_hash; - crypto::cn_slow_hash(data, size, pwd_hash.data()); - memcpy(&key, pwd_hash.data(), sizeof(key)); - } - - inline void generate_chacha8_key(std::string password, chacha8_key& key) { - return generate_chacha8_key(password.data(), password.size(), key); - } -} - -#endif diff --git a/src/serialization/crypto.h b/src/serialization/crypto.h index 4213f2e58..8083bdeb1 100644 --- a/src/serialization/crypto.h +++ b/src/serialization/crypto.h @@ -34,7 +34,7 @@ #include "serialization.h" #include "debug_archive.h" -#include "crypto/chacha8.h" +#include "crypto/chacha.h" #include "crypto/crypto.h" #include "crypto/hash.h" @@ -77,7 +77,7 @@ bool do_serialize(Archive &ar, std::vector &v) return true; } -BLOB_SERIALIZER(crypto::chacha8_iv); +BLOB_SERIALIZER(crypto::chacha_iv); BLOB_SERIALIZER(crypto::hash); BLOB_SERIALIZER(crypto::hash8); BLOB_SERIALIZER(crypto::public_key); diff --git a/src/wallet/wallet2.cpp b/src/wallet/wallet2.cpp index 8f5f15f9c..14e7368a0 100644 --- a/src/wallet/wallet2.cpp +++ b/src/wallet/wallet2.cpp @@ -2373,11 +2373,11 @@ bool wallet2::store_keys(const std::string& keys_file_name, const epee::wipeable account_data = buffer.GetString(); // Encrypt the entire JSON object. - crypto::chacha8_key key; - crypto::generate_chacha8_key(password.data(), password.size(), key); + crypto::chacha_key key; + crypto::generate_chacha_key(password.data(), password.size(), key); std::string cipher; cipher.resize(account_data.size()); - keys_file_data.iv = crypto::rand(); + keys_file_data.iv = crypto::rand(); crypto::chacha8(account_data.data(), account_data.size(), key, keys_file_data.iv, &cipher[0]); keys_file_data.account_data = cipher; @@ -2414,8 +2414,8 @@ bool wallet2::load_keys(const std::string& keys_file_name, const epee::wipeable_ // Decrypt the contents r = ::serialization::parse_binary(buf, keys_file_data); THROW_WALLET_EXCEPTION_IF(!r, error::wallet_internal_error, "internal error: failed to deserialize \"" + keys_file_name + '\"'); - crypto::chacha8_key key; - crypto::generate_chacha8_key(password.data(), password.size(), key); + crypto::chacha_key key; + crypto::generate_chacha_key(password.data(), password.size(), key); std::string account_data; account_data.resize(keys_file_data.account_data.size()); crypto::chacha8(keys_file_data.account_data.data(), keys_file_data.account_data.size(), key, keys_file_data.iv, &account_data[0]); @@ -2599,8 +2599,8 @@ bool wallet2::verify_password(const std::string& keys_file_name, const epee::wip // Decrypt the contents r = ::serialization::parse_binary(buf, keys_file_data); THROW_WALLET_EXCEPTION_IF(!r, error::wallet_internal_error, "internal error: failed to deserialize \"" + keys_file_name + '\"'); - crypto::chacha8_key key; - crypto::generate_chacha8_key(password.data(), password.size(), key); + crypto::chacha_key key; + crypto::generate_chacha_key(password.data(), password.size(), key); std::string account_data; account_data.resize(keys_file_data.account_data.size()); crypto::chacha8(keys_file_data.account_data.data(), keys_file_data.account_data.size(), key, keys_file_data.iv, &account_data[0]); @@ -3292,7 +3292,7 @@ bool wallet2::check_connection(uint32_t *version, uint32_t timeout) return true; } //---------------------------------------------------------------------------------------------------- -bool wallet2::generate_chacha8_key_from_secret_keys(crypto::chacha8_key &key) const +bool wallet2::generate_chacha_key_from_secret_keys(crypto::chacha_key &key) const { const account_keys &keys = m_account.get_keys(); const crypto::secret_key &view_key = keys.m_view_secret_key; @@ -3301,7 +3301,7 @@ bool wallet2::generate_chacha8_key_from_secret_keys(crypto::chacha8_key &key) co memcpy(data.data(), &view_key, sizeof(view_key)); memcpy(data.data() + sizeof(view_key), &spend_key, sizeof(spend_key)); data[sizeof(data) - 1] = CHACHA8_KEY_TAIL; - crypto::generate_chacha8_key(data.data(), sizeof(data), key); + crypto::generate_chacha_key(data.data(), sizeof(data), key); return true; } //---------------------------------------------------------------------------------------------------- @@ -3341,8 +3341,8 @@ void wallet2::load(const std::string& wallet_, const epee::wipeable_string& pass r = ::serialization::parse_binary(buf, cache_file_data); THROW_WALLET_EXCEPTION_IF(!r, error::wallet_internal_error, "internal error: failed to deserialize \"" + m_wallet_file + '\"'); - crypto::chacha8_key key; - generate_chacha8_key_from_secret_keys(key); + crypto::chacha_key key; + generate_chacha_key_from_secret_keys(key); std::string cache_data; cache_data.resize(cache_file_data.cache_data.size()); crypto::chacha8(cache_file_data.cache_data.data(), cache_file_data.cache_data.size(), key, cache_file_data.iv, &cache_data[0]); @@ -3500,11 +3500,11 @@ void wallet2::store_to(const std::string &path, const epee::wipeable_string &pas wallet2::cache_file_data cache_file_data = boost::value_initialized(); cache_file_data.cache_data = oss.str(); - crypto::chacha8_key key; - generate_chacha8_key_from_secret_keys(key); + crypto::chacha_key key; + generate_chacha_key_from_secret_keys(key); std::string cipher; cipher.resize(cache_file_data.cache_data.size()); - cache_file_data.iv = crypto::rand(); + cache_file_data.iv = crypto::rand(); crypto::chacha8(cache_file_data.cache_data.data(), cache_file_data.cache_data.size(), key, cache_file_data.iv, &cipher[0]); cache_file_data.cache_data = cipher; @@ -8720,10 +8720,10 @@ size_t wallet2::import_multisig(std::vector blobs) //---------------------------------------------------------------------------------------------------- std::string wallet2::encrypt(const std::string &plaintext, const crypto::secret_key &skey, bool authenticated) const { - crypto::chacha8_key key; - crypto::generate_chacha8_key(&skey, sizeof(skey), key); + crypto::chacha_key key; + crypto::generate_chacha_key(&skey, sizeof(skey), key); std::string ciphertext; - crypto::chacha8_iv iv = crypto::rand(); + crypto::chacha_iv iv = crypto::rand(); ciphertext.resize(plaintext.size() + sizeof(iv) + (authenticated ? sizeof(crypto::signature) : 0)); crypto::chacha8(plaintext.data(), plaintext.size(), key, iv, &ciphertext[sizeof(iv)]); memcpy(&ciphertext[0], &iv, sizeof(iv)); @@ -8746,13 +8746,13 @@ std::string wallet2::encrypt_with_view_secret_key(const std::string &plaintext, //---------------------------------------------------------------------------------------------------- std::string wallet2::decrypt(const std::string &ciphertext, const crypto::secret_key &skey, bool authenticated) const { - const size_t prefix_size = sizeof(chacha8_iv) + (authenticated ? sizeof(crypto::signature) : 0); + const size_t prefix_size = sizeof(chacha_iv) + (authenticated ? sizeof(crypto::signature) : 0); THROW_WALLET_EXCEPTION_IF(ciphertext.size() < prefix_size, error::wallet_internal_error, "Unexpected ciphertext size"); - crypto::chacha8_key key; - crypto::generate_chacha8_key(&skey, sizeof(skey), key); - const crypto::chacha8_iv &iv = *(const crypto::chacha8_iv*)&ciphertext[0]; + crypto::chacha_key key; + crypto::generate_chacha_key(&skey, sizeof(skey), key); + const crypto::chacha_iv &iv = *(const crypto::chacha_iv*)&ciphertext[0]; std::string plaintext; plaintext.resize(ciphertext.size() - prefix_size); if (authenticated) diff --git a/src/wallet/wallet2.h b/src/wallet/wallet2.h index 2b46359bf..b1115f67b 100644 --- a/src/wallet/wallet2.h +++ b/src/wallet/wallet2.h @@ -49,7 +49,7 @@ #include "cryptonote_basic/cryptonote_format_utils.h" #include "cryptonote_core/cryptonote_tx_utils.h" #include "common/unordered_containers_boost_serialization.h" -#include "crypto/chacha8.h" +#include "crypto/chacha.h" #include "crypto/hash.h" #include "ringct/rctTypes.h" #include "ringct/rctOps.h" @@ -404,7 +404,7 @@ namespace tools struct keys_file_data { - crypto::chacha8_iv iv; + crypto::chacha_iv iv; std::string account_data; BEGIN_SERIALIZE_OBJECT() @@ -415,7 +415,7 @@ namespace tools struct cache_file_data { - crypto::chacha8_iv iv; + crypto::chacha_iv iv; std::string cache_data; BEGIN_SERIALIZE_OBJECT() @@ -996,7 +996,7 @@ namespace tools void add_unconfirmed_tx(const cryptonote::transaction& tx, uint64_t amount_in, const std::vector &dests, const crypto::hash &payment_id, uint64_t change_amount, uint32_t subaddr_account, const std::set& subaddr_indices); void generate_genesis(cryptonote::block& b); void check_genesis(const crypto::hash& genesis_hash) const; //throws - bool generate_chacha8_key_from_secret_keys(crypto::chacha8_key &key) const; + bool generate_chacha_key_from_secret_keys(crypto::chacha_key &key) const; crypto::hash get_payment_id(const pending_tx &ptx) const; void check_acc_out_precomp(const cryptonote::tx_out &o, const crypto::key_derivation &derivation, const std::vector &additional_derivations, size_t i, tx_scan_info_t &tx_scan_info) const; void parse_block_round(const cryptonote::blobdata &blob, cryptonote::block &bl, crypto::hash &bl_id, bool &error) const; -- cgit v1.2.3 From 5ad312a1c3c0491444338758119f332030b8fa2c Mon Sep 17 00:00:00 2001 From: moneromooo-monero Date: Thu, 7 Dec 2017 19:17:32 +0000 Subject: wallet2: switch to chacha20 instead of chacha8 Wallet caches and keys files are loaded with chacha8 as needed, but only saved with chacha20. Other data (eg, cold wallet data files, etc) will be incompatible. --- src/wallet/wallet2.cpp | 55 +++++++++++++++++++++++++++++++++----------------- 1 file changed, 36 insertions(+), 19 deletions(-) (limited to 'src') diff --git a/src/wallet/wallet2.cpp b/src/wallet/wallet2.cpp index 14e7368a0..2d88ef06a 100644 --- a/src/wallet/wallet2.cpp +++ b/src/wallet/wallet2.cpp @@ -2378,7 +2378,7 @@ bool wallet2::store_keys(const std::string& keys_file_name, const epee::wipeable std::string cipher; cipher.resize(account_data.size()); keys_file_data.iv = crypto::rand(); - crypto::chacha8(account_data.data(), account_data.size(), key, keys_file_data.iv, &cipher[0]); + crypto::chacha20(account_data.data(), account_data.size(), key, keys_file_data.iv, &cipher[0]); keys_file_data.account_data = cipher; std::string buf; @@ -2406,6 +2406,7 @@ namespace */ bool wallet2::load_keys(const std::string& keys_file_name, const epee::wipeable_string& password) { + rapidjson::Document json; wallet2::keys_file_data keys_file_data; std::string buf; bool r = epee::file_io_utils::load_file_to_string(keys_file_name, buf); @@ -2418,10 +2419,11 @@ bool wallet2::load_keys(const std::string& keys_file_name, const epee::wipeable_ crypto::generate_chacha_key(password.data(), password.size(), key); std::string account_data; account_data.resize(keys_file_data.account_data.size()); - crypto::chacha8(keys_file_data.account_data.data(), keys_file_data.account_data.size(), key, keys_file_data.iv, &account_data[0]); + crypto::chacha20(keys_file_data.account_data.data(), keys_file_data.account_data.size(), key, keys_file_data.iv, &account_data[0]); + if (json.Parse(account_data.c_str()).HasParseError() || !json.IsObject()) + crypto::chacha8(keys_file_data.account_data.data(), keys_file_data.account_data.size(), key, keys_file_data.iv, &account_data[0]); // The contents should be JSON if the wallet follows the new format. - rapidjson::Document json; if (json.Parse(account_data.c_str()).HasParseError()) { is_old_file_format = true; @@ -2591,6 +2593,7 @@ bool wallet2::verify_password(const epee::wipeable_string& password) const */ bool wallet2::verify_password(const std::string& keys_file_name, const epee::wipeable_string& password, bool no_spend_key) { + rapidjson::Document json; wallet2::keys_file_data keys_file_data; std::string buf; bool r = epee::file_io_utils::load_file_to_string(keys_file_name, buf); @@ -2603,10 +2606,11 @@ bool wallet2::verify_password(const std::string& keys_file_name, const epee::wip crypto::generate_chacha_key(password.data(), password.size(), key); std::string account_data; account_data.resize(keys_file_data.account_data.size()); - crypto::chacha8(keys_file_data.account_data.data(), keys_file_data.account_data.size(), key, keys_file_data.iv, &account_data[0]); + crypto::chacha20(keys_file_data.account_data.data(), keys_file_data.account_data.size(), key, keys_file_data.iv, &account_data[0]); + if (json.Parse(account_data.c_str()).HasParseError() || !json.IsObject()) + crypto::chacha8(keys_file_data.account_data.data(), keys_file_data.account_data.size(), key, keys_file_data.iv, &account_data[0]); // The contents should be JSON if the wallet follows the new format. - rapidjson::Document json; if (json.Parse(account_data.c_str()).HasParseError()) { // old format before JSON wallet key file format @@ -3345,30 +3349,42 @@ void wallet2::load(const std::string& wallet_, const epee::wipeable_string& pass generate_chacha_key_from_secret_keys(key); std::string cache_data; cache_data.resize(cache_file_data.cache_data.size()); - crypto::chacha8(cache_file_data.cache_data.data(), cache_file_data.cache_data.size(), key, cache_file_data.iv, &cache_data[0]); + crypto::chacha20(cache_file_data.cache_data.data(), cache_file_data.cache_data.size(), key, cache_file_data.iv, &cache_data[0]); - std::stringstream iss; - iss << cache_data; try { + std::stringstream iss; + iss << cache_data; boost::archive::portable_binary_iarchive ar(iss); ar >> *this; } catch (...) { - LOG_PRINT_L0("Failed to open portable binary, trying unportable"); - boost::filesystem::copy_file(m_wallet_file, m_wallet_file + ".unportable", boost::filesystem::copy_option::overwrite_if_exists); - iss.str(""); - iss << cache_data; - boost::archive::binary_iarchive ar(iss); - ar >> *this; + crypto::chacha8(cache_file_data.cache_data.data(), cache_file_data.cache_data.size(), key, cache_file_data.iv, &cache_data[0]); + try + { + std::stringstream iss; + iss << cache_data; + boost::archive::portable_binary_iarchive ar(iss); + ar >> *this; + } + catch (...) + { + LOG_PRINT_L0("Failed to open portable binary, trying unportable"); + boost::filesystem::copy_file(m_wallet_file, m_wallet_file + ".unportable", boost::filesystem::copy_option::overwrite_if_exists); + std::stringstream iss; + iss.str(""); + iss << cache_data; + boost::archive::binary_iarchive ar(iss); + ar >> *this; + } } } catch (...) { LOG_PRINT_L1("Failed to load encrypted cache, trying unencrypted"); - std::stringstream iss; - iss << buf; try { + std::stringstream iss; + iss << buf; boost::archive::portable_binary_iarchive ar(iss); ar >> *this; } @@ -3376,6 +3392,7 @@ void wallet2::load(const std::string& wallet_, const epee::wipeable_string& pass { LOG_PRINT_L0("Failed to open portable binary, trying unportable"); boost::filesystem::copy_file(m_wallet_file, m_wallet_file + ".unportable", boost::filesystem::copy_option::overwrite_if_exists); + std::stringstream iss; iss.str(""); iss << buf; boost::archive::binary_iarchive ar(iss); @@ -3505,7 +3522,7 @@ void wallet2::store_to(const std::string &path, const epee::wipeable_string &pas std::string cipher; cipher.resize(cache_file_data.cache_data.size()); cache_file_data.iv = crypto::rand(); - crypto::chacha8(cache_file_data.cache_data.data(), cache_file_data.cache_data.size(), key, cache_file_data.iv, &cipher[0]); + crypto::chacha20(cache_file_data.cache_data.data(), cache_file_data.cache_data.size(), key, cache_file_data.iv, &cipher[0]); cache_file_data.cache_data = cipher; const std::string new_file = same_file ? m_wallet_file + ".new" : path; @@ -8725,7 +8742,7 @@ std::string wallet2::encrypt(const std::string &plaintext, const crypto::secret_ std::string ciphertext; crypto::chacha_iv iv = crypto::rand(); ciphertext.resize(plaintext.size() + sizeof(iv) + (authenticated ? sizeof(crypto::signature) : 0)); - crypto::chacha8(plaintext.data(), plaintext.size(), key, iv, &ciphertext[sizeof(iv)]); + crypto::chacha20(plaintext.data(), plaintext.size(), key, iv, &ciphertext[sizeof(iv)]); memcpy(&ciphertext[0], &iv, sizeof(iv)); if (authenticated) { @@ -8765,7 +8782,7 @@ std::string wallet2::decrypt(const std::string &ciphertext, const crypto::secret THROW_WALLET_EXCEPTION_IF(!crypto::check_signature(hash, pkey, signature), error::wallet_internal_error, "Failed to authenticate ciphertext"); } - crypto::chacha8(ciphertext.data() + sizeof(iv), ciphertext.size() - prefix_size, key, iv, &plaintext[0]); + crypto::chacha20(ciphertext.data() + sizeof(iv), ciphertext.size() - prefix_size, key, iv, &plaintext[0]); return plaintext; } //---------------------------------------------------------------------------------------------------- -- cgit v1.2.3