Electroneum
account.cpp
Go to the documentation of this file.
1 // Copyrights(c) 2017-2021, The Electroneum Project
2 // Copyrights(c) 2014-2019, The Monero Project
3 //
4 // All rights reserved.
5 //
6 // Redistribution and use in source and binary forms, with or without modification, are
7 // permitted provided that the following conditions are met:
8 //
9 // 1. Redistributions of source code must retain the above copyright notice, this list of
10 // conditions and the following disclaimer.
11 //
12 // 2. Redistributions in binary form must reproduce the above copyright notice, this list
13 // of conditions and the following disclaimer in the documentation and/or other
14 // materials provided with the distribution.
15 //
16 // 3. Neither the name of the copyright holder nor the names of its contributors may be
17 // used to endorse or promote products derived from this software without specific
18 // prior written permission.
19 //
20 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
21 // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
22 // MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
23 // THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
25 // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26 // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
27 // STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
28 // THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 //
30 // Parts of this file are originally copyright (c) 2012-2013 The Cryptonote developers
31 
32 #include <fstream>
33 
34 #include "include_base_utils.h"
35 #include "account.h"
36 #include "warnings.h"
37 #include "crypto/crypto.h"
38 extern "C"
39 {
40 #include "crypto/keccak.h"
41 }
42 #include "cryptonote_basic_impl.h"
44 
45 #undef ELECTRONEUM_DEFAULT_LOG_CATEGORY
46 #define ELECTRONEUM_DEFAULT_LOG_CATEGORY "account"
47 
48 #define KEYS_ENCRYPTION_SALT 'k'
49 
50 
51 using namespace std;
52 
53 DISABLE_VS_WARNINGS(4244 4345)
54 
55  namespace cryptonote
56 {
57 
58  //-----------------------------------------------------------------
60  return *m_device;
61  }
62  //-----------------------------------------------------------------
63  void account_keys::set_device( hw::device &hwdev) {
64  m_device = &hwdev;
65  MCDEBUG("device", "account_keys::set_device device type: "<<typeid(hwdev).name());
66  }
67  //-----------------------------------------------------------------
68  static void derive_key(const crypto::chacha_key &base_key, crypto::chacha_key &key)
69  {
70  static_assert(sizeof(base_key) == sizeof(crypto::hash), "chacha key and hash should be the same size");
72  memcpy(data.data(), &base_key, sizeof(base_key));
73  data[sizeof(base_key)] = KEYS_ENCRYPTION_SALT;
74  crypto::generate_chacha_key(data.data(), sizeof(data), key, 1);
75  }
76  //-----------------------------------------------------------------
77  static epee::wipeable_string get_key_stream(const crypto::chacha_key &base_key, const crypto::chacha_iv &iv, size_t bytes)
78  {
79  // derive a new key
80  crypto::chacha_key key;
81  derive_key(base_key, key);
82 
83  // chacha
84  epee::wipeable_string buffer0(std::string(bytes, '\0'));
85  epee::wipeable_string buffer1 = buffer0;
86  crypto::chacha20(buffer0.data(), buffer0.size(), key, iv, buffer1.data());
87  return buffer1;
88  }
89  //-----------------------------------------------------------------
90  void account_keys::xor_with_key_stream(const crypto::chacha_key &key)
91  {
92  // encrypt a large enough byte stream with chacha20
93  epee::wipeable_string key_stream = get_key_stream(key, m_encryption_iv, sizeof(crypto::secret_key) * (2 + m_multisig_keys.size()));
94  const char *ptr = key_stream.data();
95  for (size_t i = 0; i < sizeof(crypto::secret_key); ++i)
96  m_spend_secret_key.data[i] ^= *ptr++;
97  for (size_t i = 0; i < sizeof(crypto::secret_key); ++i)
98  m_view_secret_key.data[i] ^= *ptr++;
99  for (crypto::secret_key &k: m_multisig_keys)
100  {
101  for (size_t i = 0; i < sizeof(crypto::secret_key); ++i)
102  k.data[i] ^= *ptr++;
103  }
104  }
105  //-----------------------------------------------------------------
106  void account_keys::encrypt(const crypto::chacha_key &key)
107  {
108  m_encryption_iv = crypto::rand<crypto::chacha_iv>();
109  xor_with_key_stream(key);
110  }
111  //-----------------------------------------------------------------
112  void account_keys::decrypt(const crypto::chacha_key &key)
113  {
114  xor_with_key_stream(key);
115  }
116  //-----------------------------------------------------------------
117  void account_keys::encrypt_viewkey(const crypto::chacha_key &key)
118  {
119  // encrypt a large enough byte stream with chacha20
120  epee::wipeable_string key_stream = get_key_stream(key, m_encryption_iv, sizeof(crypto::secret_key) * 2);
121  const char *ptr = key_stream.data();
122  ptr += sizeof(crypto::secret_key);
123  for (size_t i = 0; i < sizeof(crypto::secret_key); ++i)
124  m_view_secret_key.data[i] ^= *ptr++;
125  }
126  //-----------------------------------------------------------------
127  void account_keys::decrypt_viewkey(const crypto::chacha_key &key)
128  {
129  encrypt_viewkey(key);
130  }
131  //-----------------------------------------------------------------
132  account_base::account_base()
133  {
134  set_null();
135  }
136  //-----------------------------------------------------------------
137  void account_base::set_null()
138  {
139  m_keys = account_keys();
140  m_creation_timestamp = 0;
141  }
142  //-----------------------------------------------------------------
144  {
145  try{
146  m_keys.get_device().disconnect();
147  } catch (const std::exception &e){
148  MERROR("Device disconnect exception: " << e.what());
149  }
150  }
151  //-----------------------------------------------------------------
152  void account_base::forget_spend_key()
153  {
154  m_keys.m_spend_secret_key = crypto::secret_key();
155  m_keys.m_multisig_keys.clear();
156  }
157  //-----------------------------------------------------------------
158  crypto::secret_key account_base::generate(const crypto::secret_key& recovery_key, bool recover, bool two_random)
159  {
160  crypto::secret_key first = generate_keys(m_keys.m_account_address.m_spend_public_key, m_keys.m_spend_secret_key, recovery_key, recover);
161 
162  // rng for generating second set of keys is hash of first rng. means only one set of electrum-style words needed for recovery
163  crypto::secret_key second;
164  keccak((uint8_t *)&m_keys.m_spend_secret_key, sizeof(crypto::secret_key), (uint8_t *)&second, sizeof(crypto::secret_key));
165 
166  generate_keys(m_keys.m_account_address.m_view_public_key, m_keys.m_view_secret_key, second, two_random ? false : true);
167 
168  struct tm timestamp = {0};
169  timestamp.tm_year = 2014 - 1900; // year 2014
170  timestamp.tm_mon = 6 - 1; // month june
171  timestamp.tm_mday = 8; // 8th of june
172  timestamp.tm_hour = 0;
173  timestamp.tm_min = 0;
174  timestamp.tm_sec = 0;
175 
176  if (recover)
177  {
178  m_creation_timestamp = mktime(&timestamp);
179  if (m_creation_timestamp == (uint64_t)-1) // failure
180  m_creation_timestamp = 0; // lowest value
181  }
182  else
183  {
184  m_creation_timestamp = time(NULL);
185  }
186  return first;
187  }
188  //-----------------------------------------------------------------
189  void account_base::create_from_keys(const cryptonote::account_public_address& address, const crypto::secret_key& spendkey, const crypto::secret_key& viewkey)
190  {
191  m_keys.m_account_address = address;
192  m_keys.m_spend_secret_key = spendkey;
193  m_keys.m_view_secret_key = viewkey;
194 
195  struct tm timestamp = {0};
196  timestamp.tm_year = 2014 - 1900; // year 2014
197  timestamp.tm_mon = 4 - 1; // month april
198  timestamp.tm_mday = 15; // 15th of april
199  timestamp.tm_hour = 0;
200  timestamp.tm_min = 0;
201  timestamp.tm_sec = 0;
202 
203  m_creation_timestamp = mktime(&timestamp);
204  if (m_creation_timestamp == (uint64_t)-1) // failure
205  m_creation_timestamp = 0; // lowest value
206  }
207 
208  //-----------------------------------------------------------------
209  void account_base::create_from_device(const std::string &device_name)
210  {
211  hw::device &hwdev = hw::get_device(device_name);
212  hwdev.set_name(device_name);
213  create_from_device(hwdev);
214  }
215 
216  void account_base::create_from_device(hw::device &hwdev)
217  {
218  m_keys.set_device(hwdev);
219  MCDEBUG("device", "device type: "<<typeid(hwdev).name());
220  CHECK_AND_ASSERT_THROW_MES(hwdev.init(), "Device init failed");
221  CHECK_AND_ASSERT_THROW_MES(hwdev.connect(), "Device connect failed");
222  try {
223  CHECK_AND_ASSERT_THROW_MES(hwdev.get_public_address(m_keys.m_account_address), "Cannot get a device address");
224  CHECK_AND_ASSERT_THROW_MES(hwdev.get_secret_keys(m_keys.m_view_secret_key, m_keys.m_spend_secret_key), "Cannot get device secret");
225  } catch (const std::exception &e){
226  hwdev.disconnect();
227  throw;
228  }
229  struct tm timestamp = {0};
230  timestamp.tm_year = 2014 - 1900; // year 2014
231  timestamp.tm_mon = 4 - 1; // month april
232  timestamp.tm_mday = 15; // 15th of april
233  timestamp.tm_hour = 0;
234  timestamp.tm_min = 0;
235  timestamp.tm_sec = 0;
236 
237  m_creation_timestamp = mktime(&timestamp);
238  if (m_creation_timestamp == (uint64_t)-1) // failure
239  m_creation_timestamp = 0; // lowest value
240  }
241 
242  //-----------------------------------------------------------------
243  void account_base::create_from_viewkey(const cryptonote::account_public_address& address, const crypto::secret_key& viewkey)
244  {
245  crypto::secret_key fake;
246  memset(&unwrap(unwrap(fake)), 0, sizeof(fake));
247  create_from_keys(address, fake, viewkey);
248  }
249  //-----------------------------------------------------------------
250  bool account_base::make_multisig(const crypto::secret_key &view_secret_key, const crypto::secret_key &spend_secret_key, const crypto::public_key &spend_public_key, const std::vector<crypto::secret_key> &multisig_keys)
251  {
252  m_keys.m_account_address.m_spend_public_key = spend_public_key;
253  m_keys.m_view_secret_key = view_secret_key;
254  m_keys.m_spend_secret_key = spend_secret_key;
255  m_keys.m_multisig_keys = multisig_keys;
256  return crypto::secret_key_to_public_key(view_secret_key, m_keys.m_account_address.m_view_public_key);
257  }
258  //-----------------------------------------------------------------
259  void account_base::finalize_multisig(const crypto::public_key &spend_public_key)
260  {
261  m_keys.m_account_address.m_spend_public_key = spend_public_key;
262  }
263  //-----------------------------------------------------------------
264  const account_keys& account_base::get_keys() const
265  {
266  return m_keys;
267  }
268  //-----------------------------------------------------------------
269  std::string account_base::get_public_address_str(network_type nettype) const
270  {
271  //TODO: change this code into base 58
272  return get_account_address_as_str(nettype, false, m_keys.m_account_address);
273  }
274  //-----------------------------------------------------------------
275  std::string account_base::get_public_integrated_address_str(const crypto::hash8 &payment_id, network_type nettype) const
276  {
277  //TODO: change this code into base 58
278  return get_account_integrated_address_as_str(nettype, m_keys.m_account_address, payment_id);
279  }
280  //-----------------------------------------------------------------
281 }
#define MERROR(x)
Definition: misc_log_ex.h:73
#define CHECK_AND_ASSERT_THROW_MES(expr, message)
Definition: misc_log_ex.h:173
std::string get_account_address_as_str(network_type nettype, bool subaddress, account_public_address const &adr)
::std::string string
Definition: gtest-port.h:1097
#define KEYS_ENCRYPTION_SALT
Definition: account.cpp:48
void chacha20(const void *data, size_t length, const uint8_t *key, const uint8_t *iv, char *cipher)
const char * key
Definition: hmac_keccak.cpp:39
epee::mlocked< tools::scrubbed< ec_scalar > > secret_key
Definition: crypto.h:82
STL namespace.
unsigned char uint8_t
Definition: stdint.h:124
const char * name
virtual bool set_name(const std::string &name)=0
virtual bool disconnect(void)=0
for(i=1;i< 1;++i) fe_sq(t0
Holds cryptonote related classes and helpers.
Definition: ban.cpp:40
time_t time
Definition: blockchain.cpp:93
std::string get_account_integrated_address_as_str(network_type nettype, account_public_address const &adr, crypto::hash8 const &payment_id)
virtual bool get_public_address(cryptonote::account_public_address &pubkey)=0
device & get_device(const std::string &device_descriptor)
Definition: device.cpp:95
unsigned __int64 uint64_t
Definition: stdint.h:136
secret_key generate_keys(public_key &pub, secret_key &sec, const secret_key &recovery_key=secret_key(), bool recover=false)
Definition: crypto.h:250
POD_CLASS public_key
Definition: crypto.h:76
void decrypt(const void *ciphertext, size_t length, const uint8_t *key, const uint8_t *iv, char *plaintext, size_t *plaintext_len)
Definition: protocol.cpp:120
POD_CLASS hash8
Definition: hash.h:53
virtual bool get_secret_keys(crypto::secret_key &viewkey, crypto::secret_key &spendkey)=0
void * memcpy(void *a, const void *b, size_t c)
T & unwrap(mlocked< T > &src)
Definition: mlocker.h:80
void keccak(const uint8_t *in, size_t inlen, uint8_t *md, int mdlen)
DISABLE_VS_WARNINGS(4244 4345 4503) using namespace crypto
POD_CLASS hash
Definition: hash.h:50
#define MCDEBUG(cat, x)
Definition: misc_log_ex.h:54
const char * address
Definition: multisig.cpp:37
bool secret_key_to_public_key(const secret_key &sec, public_key &pub)
Definition: crypto.h:262
const char * spendkey
Definition: multisig.cpp:38
virtual bool connect(void)=0
const char * data() const noexcept
virtual bool init(void)=0