Browse Source

Secure datatypes now copyable only to similar datatypes.

More restrictions on usage to prevent accidental data leakage.
cl-refactor
Gav Wood 10 years ago
parent
commit
591b4c8c64
  1. 5
      alethzero/DappLoader.cpp
  2. 22
      alethzero/MainWin.cpp
  3. 18
      eth/main.cpp
  4. 24
      ethkey/KeyAux.h
  5. 29
      libdevcore/Common.h
  6. 11
      libdevcore/CommonJS.h
  7. 79
      libdevcore/FixedHash.h
  8. 9
      libdevcore/SHA3.cpp
  9. 19
      libdevcore/SHA3.h
  10. 12
      libdevcore/vector_ref.h
  11. 32
      libdevcrypto/Common.cpp
  12. 32
      libdevcrypto/Common.h
  13. 16
      libdevcrypto/CryptoPP.cpp
  14. 4
      libdevcrypto/CryptoPP.h
  15. 2
      libdevcrypto/ECDHE.cpp
  16. 2
      libdevcrypto/ECDHE.h
  17. 59
      libdevcrypto/SecretStore.cpp
  18. 7
      libdevcrypto/SecretStore.h
  19. 2
      libethcore/BasicAuthority.cpp
  20. 2
      libethcore/CommonJS.h
  21. 16
      libethcore/KeyManager.cpp
  22. 6
      libethcore/KeyManager.h
  23. 2
      libp2p/Host.cpp
  24. 4
      libp2p/RLPxHandshake.cpp
  25. 10
      libwhisper/Message.cpp
  26. 2
      libwhisper/Message.h
  27. 2
      mix/FileIo.cpp
  28. 6
      test/libdevcrypto/AES.cpp
  29. 32
      test/libdevcrypto/SecretStore.cpp
  30. 39
      test/libdevcrypto/crypto.cpp
  31. 14
      test/libethcore/commonjs.cpp

5
alethzero/DappLoader.cpp

@ -130,14 +130,14 @@ void DappLoader::downloadComplete(QNetworkReply* _reply)
h256 expected = m_uriHashes[requestUrl]; h256 expected = m_uriHashes[requestUrl];
bytes package(reinterpret_cast<unsigned char const*>(data.constData()), reinterpret_cast<unsigned char const*>(data.constData() + data.size())); bytes package(reinterpret_cast<unsigned char const*>(data.constData()), reinterpret_cast<unsigned char const*>(data.constData() + data.size()));
Secp256k1PP dec; Secp256k1PP dec;
dec.decrypt(expected, package); dec.decrypt(Secret(expected), package);
h256 got = sha3(package); h256 got = sha3(package);
if (got != expected) if (got != expected)
{ {
//try base64 //try base64
data = QByteArray::fromBase64(data); data = QByteArray::fromBase64(data);
package = bytes(reinterpret_cast<unsigned char const*>(data.constData()), reinterpret_cast<unsigned char const*>(data.constData() + data.size())); package = bytes(reinterpret_cast<unsigned char const*>(data.constData()), reinterpret_cast<unsigned char const*>(data.constData() + data.size()));
dec.decrypt(expected, package); dec.decrypt(Secret(expected), package);
got = sha3(package); got = sha3(package);
if (got != expected) if (got != expected)
throw dev::Exception() << errinfo_comment("Dapp content hash does not match"); throw dev::Exception() << errinfo_comment("Dapp content hash does not match");
@ -145,6 +145,7 @@ void DappLoader::downloadComplete(QNetworkReply* _reply)
RLP rlp(package); RLP rlp(package);
loadDapp(rlp); loadDapp(rlp);
bytesRef(&package).cleanse(); // TODO: replace with bytesSec once the crypto API is up to it.
} }
catch (...) catch (...)
{ {

22
alethzero/MainWin.cpp

@ -845,29 +845,15 @@ void Main::readSettings(bool _skipGeometry)
restoreGeometry(s.value("geometry").toByteArray()); restoreGeometry(s.value("geometry").toByteArray());
restoreState(s.value("windowState").toByteArray()); restoreState(s.value("windowState").toByteArray());
{
QByteArray b = s.value("address").toByteArray();
if (!b.isEmpty())
{
h256 k;
for (unsigned i = 0; i < b.size() / sizeof(Secret); ++i)
{
memcpy(&k, b.data() + i * sizeof(Secret), sizeof(Secret));
if (!m_keyManager.hasAccount(KeyPair(k).address()))
m_keyManager.import(k, "Imported (UNSAFE) key.");
}
}
}
{ {
m_myIdentities.clear(); m_myIdentities.clear();
QByteArray b = s.value("identities").toByteArray(); QByteArray b = s.value("identities").toByteArray();
if (!b.isEmpty()) if (!b.isEmpty())
{ {
h256 k; Secret k;
for (unsigned i = 0; i < b.size() / sizeof(Secret); ++i) for (unsigned i = 0; i < b.size() / sizeof(Secret); ++i)
{ {
memcpy(&k, b.data() + i * sizeof(Secret), sizeof(Secret)); memcpy(k.writable().data(), b.data() + i * sizeof(Secret), sizeof(Secret));
if (!count(m_myIdentities.begin(), m_myIdentities.end(), KeyPair(k))) if (!count(m_myIdentities.begin(), m_myIdentities.end(), KeyPair(k)))
m_myIdentities.append(KeyPair(k)); m_myIdentities.append(KeyPair(k));
} }
@ -960,7 +946,7 @@ void Main::on_importKey_triggered()
bytes b = fromHex(s.toStdString()); bytes b = fromHex(s.toStdString());
if (b.size() == 32) if (b.size() == 32)
{ {
auto k = KeyPair(h256(b)); auto k = KeyPair(Secret(bytesConstRef(&b)));
if (!m_keyManager.hasAccount(k.address())) if (!m_keyManager.hasAccount(k.address()))
{ {
QString s = QInputDialog::getText(this, "Import Account Key", "Enter this account's name"); QString s = QInputDialog::getText(this, "Import Account Key", "Enter this account's name");
@ -1067,7 +1053,7 @@ void Main::on_exportKey_triggered()
auto hba = ui->ourAccounts->currentItem()->data(Qt::UserRole).toByteArray(); auto hba = ui->ourAccounts->currentItem()->data(Qt::UserRole).toByteArray();
Address h((byte const*)hba.data(), Address::ConstructFromPointer); Address h((byte const*)hba.data(), Address::ConstructFromPointer);
Secret s = retrieveSecret(h); Secret s = retrieveSecret(h);
QMessageBox::information(this, "Export Account Key", "Secret key to account " + QString::fromStdString(render(h) + " is:\n" + s.hex())); QMessageBox::information(this, "Export Account Key", "Secret key to account " + QString::fromStdString(render(h) + " is:\n" + s.makeInsecure().hex()));
} }
} }

18
eth/main.cpp

@ -526,7 +526,7 @@ void interactiveMode(eth::Client* c, std::shared_ptr<eth::TrivialGasPricer> gasP
{ {
try try
{ {
Secret secret = h256(fromHex(sechex)); Secret secret(fromHex(sechex));
Address dest = h160(fromHex(hexAddr)); Address dest = h160(fromHex(hexAddr));
c->submitTransaction(secret, amount, dest, data, gas, gasPrice); c->submitTransaction(secret, amount, dest, data, gas, gasPrice);
} }
@ -594,7 +594,7 @@ void interactiveMode(eth::Client* c, std::shared_ptr<eth::TrivialGasPricer> gasP
{ {
try try
{ {
Secret secret = h256(fromHex(sechex)); Secret secret(fromHex(sechex));
Address dest = h160(fromHex(hexAddr)); Address dest = h160(fromHex(hexAddr));
c->submitTransaction(secret, amount, dest, data, gas, gasPrice, nonce); c->submitTransaction(secret, amount, dest, data, gas, gasPrice, nonce);
} }
@ -654,7 +654,7 @@ void interactiveMode(eth::Client* c, std::shared_ptr<eth::TrivialGasPricer> gasP
{ {
try try
{ {
Secret secret = h256(fromHex(sechex)); Secret secret(fromHex(sechex));
cout << " new contract address : " << c->submitTransaction(secret, amount, data, gas, gasPrice) << endl; cout << " new contract address : " << c->submitTransaction(secret, amount, data, gas, gasPrice) << endl;
} }
catch (BadHexCharacter& _e) catch (BadHexCharacter& _e)
@ -1147,13 +1147,7 @@ int main(int argc, char** argv)
if (b.size()) if (b.size())
{ {
RLP config(b); RLP config(b);
if (config[0].size() == 32) // secret key - import and forget. signingKey = config[0].toHash<Address>();
{
Secret s = config[0].toHash<Secret>();
toImport.push_back(s);
}
else // new format - just use it as an address.
signingKey = config[0].toHash<Address>();
beneficiary = config[1].toHash<Address>(); beneficiary = config[1].toHash<Address>();
} }
@ -1300,13 +1294,13 @@ int main(int argc, char** argv)
else if ((arg == "-s" || arg == "--import-secret") && i + 1 < argc) else if ((arg == "-s" || arg == "--import-secret") && i + 1 < argc)
{ {
Secret s(fromHex(argv[++i])); Secret s(fromHex(argv[++i]));
toImport.push_back(s); toImport.emplace_back(s);
signingKey = toAddress(s); signingKey = toAddress(s);
} }
else if ((arg == "-S" || arg == "--import-session-secret") && i + 1 < argc) else if ((arg == "-S" || arg == "--import-session-secret") && i + 1 < argc)
{ {
Secret s(fromHex(argv[++i])); Secret s(fromHex(argv[++i]));
toImport.push_back(s); toImport.emplace_back(s);
sessionKey = toAddress(s); sessionKey = toAddress(s);
} }
else if ((arg == "--sign-key") && i + 1 < argc) else if ((arg == "--sign-key") && i + 1 < argc)

24
ethkey/KeyAux.h

@ -192,7 +192,7 @@ public:
{ {
KeyPair k(Secret::random()); KeyPair k(Secret::random());
while (m_icap && k.address()[0]) while (m_icap && k.address()[0])
k = KeyPair(sha3(k.secret())); k = KeyPair(Secret(sha3(k.secret().ref())));
return k; return k;
} }
@ -352,7 +352,7 @@ public:
if (m_lock.empty()) if (m_lock.empty())
m_lock = createPassword("Enter a password with which to secure this account: "); m_lock = createPassword("Enter a password with which to secure this account: ");
auto k = makeKey(); auto k = makeKey();
h128 u = store.importSecret(k.secret().asBytes(), m_lock); h128 u = store.importSecret(k.secret().ref(), m_lock);
cout << "Created key " << toUUID(u) << endl; cout << "Created key " << toUUID(u) << endl;
cout << " Address: " << k.address().hex() << endl; cout << " Address: " << k.address().hex() << endl;
cout << " ICAP: " << ICAP(k.address()).encoded() << endl; cout << " ICAP: " << ICAP(k.address()).encoded() << endl;
@ -362,12 +362,12 @@ public:
for (string const& input: m_inputs) for (string const& input: m_inputs)
{ {
h128 u; h128 u;
bytes b; bytesSec b;
b = fromHex(input); b.writable() = fromHex(input);
if (b.size() != 32) if (b.size() != 32)
{ {
std::string s = contentsString(input); std::string s = contentsString(input);
b = fromHex(s); b.writable() = fromHex(s);
if (b.size() != 32) if (b.size() != 32)
u = store.importKey(input); u = store.importKey(input);
} }
@ -386,18 +386,18 @@ public:
if (!contents(i).empty()) if (!contents(i).empty())
{ {
h128 u = store.readKey(i, false); h128 u = store.readKey(i, false);
bytes s = store.secret(u, [&](){ return getPassword("Enter password for key " + i + ": "); }); bytesSec s = store.secret(u, [&](){ return getPassword("Enter password for key " + i + ": "); });
cout << "Key " << i << ":" << endl; cout << "Key " << i << ":" << endl;
cout << " UUID: " << toUUID(u) << ":" << endl; cout << " UUID: " << toUUID(u) << ":" << endl;
cout << " Address: " << toAddress(Secret(s)).hex() << endl; cout << " Address: " << toAddress(Secret(s)).hex() << endl;
cout << " Secret: " << Secret(s).abridged() << endl; cout << " Secret: " << toHex(s.ref().cropped(0, 8)) << "..." << endl;
} }
else if (h128 u = fromUUID(i)) else if (h128 u = fromUUID(i))
{ {
bytes s = store.secret(u, [&](){ return getPassword("Enter password for key " + toUUID(u) + ": "); }); bytesSec s = store.secret(u, [&](){ return getPassword("Enter password for key " + toUUID(u) + ": "); });
cout << "Key " << i << ":" << endl; cout << "Key " << i << ":" << endl;
cout << " Address: " << toAddress(Secret(s)).hex() << endl; cout << " Address: " << toAddress(Secret(s)).hex() << endl;
cout << " Secret: " << Secret(s).abridged() << endl; cout << " Secret: " << toHex(s.ref().cropped(0, 8)) << "..." << endl;
} }
else else
cerr << "Couldn't inspect " << i << "; not found." << endl; cerr << "Couldn't inspect " << i << "; not found." << endl;
@ -454,12 +454,12 @@ public:
{ {
string const& i = m_inputs[0]; string const& i = m_inputs[0];
h128 u; h128 u;
bytes b; bytesSec b;
b = fromHex(i); b.writable() = fromHex(i);
if (b.size() != 32) if (b.size() != 32)
{ {
std::string s = contentsString(i); std::string s = contentsString(i);
b = fromHex(s); b.writable() = fromHex(s);
if (b.size() != 32) if (b.size() != 32)
u = wallet.store().importKey(i); u = wallet.store().importKey(i);
} }

29
libdevcore/Common.h

@ -80,11 +80,34 @@ using bytesRef = vector_ref<byte>;
using bytesConstRef = vector_ref<byte const>; using bytesConstRef = vector_ref<byte const>;
template <class T> template <class T>
class secure_vector: public std::vector<T> class secure_vector
{ {
public: public:
template <class ... Args> secure_vector(Args&& ... _args): std::vector<T>(_args ...) {} secure_vector() {}
~secure_vector() { vector_ref<T>(this).cleanse(); } secure_vector(secure_vector<T> const& _c) = default;
explicit secure_vector(unsigned _size): m_data(_size) {}
explicit secure_vector(unsigned _size, T _item): m_data(_size, _item) {}
explicit secure_vector(std::vector<T> const& _c): m_data(_c) {}
explicit secure_vector(vector_ref<T> _c): m_data(_c.data(), _c.data() + _c.size()) {}
explicit secure_vector(vector_ref<const T> _c): m_data(_c.data(), _c.data() + _c.size()) {}
~secure_vector() { ref().cleanse(); }
secure_vector<T>& operator=(secure_vector<T> const& _c) { ref().cleanse(); m_data = _c.m_data; return *this; }
std::vector<T>& writable() { clear(); return m_data; }
std::vector<T> const& makeInsecure() const { return m_data; }
void clear() { ref().cleanse(); }
vector_ref<T> ref() { return vector_ref<T>(&m_data); }
vector_ref<T const> ref() const { return vector_ref<T const>(&m_data); }
size_t size() const { return m_data.size(); }
bool empty() const { return m_data.empty(); }
void swap(secure_vector<T>& io_other) { m_data.swap(io_other.m_data); }
private:
std::vector<T> m_data;
}; };
using bytesSec = secure_vector<byte>; using bytesSec = secure_vector<byte>;

11
libdevcore/CommonJS.h

@ -51,10 +51,17 @@ inline std::string toJS(bytes const& _n, std::size_t _padding = 0)
return "0x" + toHex(n); return "0x" + toHex(n);
} }
template< typename T >std::string toJS( T const& i ) template<unsigned T> std::string toJS(SecureFixedHash<T> const& _i)
{ {
std::stringstream stream; std::stringstream stream;
stream << "0x" << std::hex << i; stream << "0x" << _i.makeInsecure().hex();
return stream.str();
}
template<typename T> std::string toJS(T const& _i)
{
std::stringstream stream;
stream << "0x" << std::hex << _i;
return stream.str(); return stream.str();
} }

79
libdevcore/FixedHash.h

@ -220,6 +220,77 @@ private:
std::array<byte, N> m_data; ///< The binary data. std::array<byte, N> m_data; ///< The binary data.
}; };
template <unsigned T>
class SecureFixedHash: private FixedHash<T>
{
public:
using ConstructFromHashType = typename FixedHash<T>::ConstructFromHashType;
using ConstructFromStringType = typename FixedHash<T>::ConstructFromStringType;
using ConstructFromPointerType = typename FixedHash<T>::ConstructFromPointerType;
SecureFixedHash() = default;
explicit SecureFixedHash(bytes const& _b, ConstructFromHashType _t = FixedHash<T>::FailIfDifferent): FixedHash<T>(_b, _t) {}
explicit SecureFixedHash(bytesConstRef _b, ConstructFromHashType _t = FixedHash<T>::FailIfDifferent): FixedHash<T>(_b, _t) {}
explicit SecureFixedHash(bytesSec const& _b, ConstructFromHashType _t = FixedHash<T>::FailIfDifferent): FixedHash<T>(_b.ref(), _t) {}
template <unsigned M> explicit SecureFixedHash(FixedHash<M> const& _h, ConstructFromHashType _t = FixedHash<T>::AlignLeft): FixedHash<T>(_h, _t) {}
template <unsigned M> explicit SecureFixedHash(SecureFixedHash<M> const& _h, ConstructFromHashType _t = FixedHash<T>::AlignLeft): FixedHash<T>(_h.makeInsecure(), _t) {}
explicit SecureFixedHash(std::string const& _s, ConstructFromStringType _t = FixedHash<T>::FromHex, ConstructFromHashType _ht = FixedHash<T>::FailIfDifferent): FixedHash<T>(_s, _t, _ht) {}
explicit SecureFixedHash(bytes const* _d, ConstructFromPointerType _t): FixedHash<T>(_d, _t) {}
~SecureFixedHash() { ref().cleanse(); }
SecureFixedHash<T>& operator=(SecureFixedHash<T> const& _c) { ref().cleanse(); FixedHash<T>::operator=(static_cast<FixedHash<T> const&>(_c)); return *this; }
using FixedHash<T>::size;
bytesSec asBytesSec() const { return bytesSec(ref()); }
FixedHash<T> const& makeInsecure() const { return static_cast<FixedHash<T> const&>(*this); }
FixedHash<T>& writable() { clear(); return static_cast<FixedHash<T>&>(*this); }
using FixedHash<T>::operator bool;
// The obvious comparison operators.
bool operator==(SecureFixedHash const& _c) const { return static_cast<FixedHash<T> const&>(*this).operator==(static_cast<FixedHash<T> const&>(_c)); }
bool operator!=(SecureFixedHash const& _c) const { return static_cast<FixedHash<T> const&>(*this).operator!=(static_cast<FixedHash<T> const&>(_c)); }
bool operator<(SecureFixedHash const& _c) const { return static_cast<FixedHash<T> const&>(*this).operator<(static_cast<FixedHash<T> const&>(_c)); }
bool operator>=(SecureFixedHash const& _c) const { return static_cast<FixedHash<T> const&>(*this).operator>=(static_cast<FixedHash<T> const&>(_c)); }
bool operator<=(SecureFixedHash const& _c) const { return static_cast<FixedHash<T> const&>(*this).operator<=(static_cast<FixedHash<T> const&>(_c)); }
bool operator>(SecureFixedHash const& _c) const { return static_cast<FixedHash<T> const&>(*this).operator>(static_cast<FixedHash<T> const&>(_c)); }
using FixedHash<T>::operator==;
using FixedHash<T>::operator!=;
using FixedHash<T>::operator<;
using FixedHash<T>::operator>=;
using FixedHash<T>::operator<=;
using FixedHash<T>::operator>;
// The obvious binary operators.
SecureFixedHash& operator^=(FixedHash<T> const& _c) { static_cast<FixedHash<T>&>(*this).operator^=(_c); return *this; }
SecureFixedHash operator^(FixedHash<T> const& _c) const { return SecureFixedHash(*this) ^= _c; }
SecureFixedHash& operator|=(FixedHash<T> const& _c) { static_cast<FixedHash<T>&>(*this).operator^=(_c); return *this; }
SecureFixedHash operator|(FixedHash<T> const& _c) const { return SecureFixedHash(*this) |= _c; }
SecureFixedHash& operator&=(FixedHash<T> const& _c) { static_cast<FixedHash<T>&>(*this).operator^=(_c); return *this; }
SecureFixedHash operator&(FixedHash<T> const& _c) const { return SecureFixedHash(*this) &= _c; }
SecureFixedHash& operator^=(SecureFixedHash const& _c) { static_cast<FixedHash<T>&>(*this).operator^=(static_cast<FixedHash<T> const&>(_c)); return *this; }
SecureFixedHash operator^(SecureFixedHash const& _c) const { return SecureFixedHash(*this) ^= _c; }
SecureFixedHash& operator|=(SecureFixedHash const& _c) { static_cast<FixedHash<T>&>(*this).operator^=(static_cast<FixedHash<T> const&>(_c)); return *this; }
SecureFixedHash operator|(SecureFixedHash const& _c) const { return SecureFixedHash(*this) |= _c; }
SecureFixedHash& operator&=(SecureFixedHash const& _c) { static_cast<FixedHash<T>&>(*this).operator^=(static_cast<FixedHash<T> const&>(_c)); return *this; }
SecureFixedHash operator&(SecureFixedHash const& _c) const { return SecureFixedHash(*this) &= _c; }
SecureFixedHash operator~() const { ~static_cast<FixedHash<T>&>(*this); return *this; }
using FixedHash<T>::abridged;
using FixedHash<T>::abridgedMiddle;
bytesConstRef ref() const { return FixedHash<T>::ref(); }
byte const* data() const { return FixedHash<T>::data(); }
static SecureFixedHash<T> random() { SecureFixedHash<T> ret; ret.FixedHash<T>::ref().randomize(); return ret; }
using FixedHash<T>::firstBitSet;
void clear() { ref().cleanse(); }
};
/// Fast equality operator for h256. /// Fast equality operator for h256.
template<> inline bool FixedHash<32>::operator==(FixedHash<32> const& _other) const template<> inline bool FixedHash<32>::operator==(FixedHash<32> const& _other) const
{ {
@ -246,6 +317,14 @@ inline std::ostream& operator<<(std::ostream& _out, FixedHash<N> const& _h)
return _out; return _out;
} }
/// Stream I/O for the SecureFixedHash class.
template <unsigned N>
inline std::ostream& operator<<(std::ostream& _out, SecureFixedHash<N> const& _h)
{
_out << "SecureFixedHash#" << std::hex << typename FixedHash<N>::hash()(_h.makeInsecure()) << std::dec;
return _out;
}
// Common types of FixedHash. // Common types of FixedHash.
using h2048 = FixedHash<256>; using h2048 = FixedHash<256>;
using h1024 = FixedHash<128>; using h1024 = FixedHash<128>;

9
libdevcore/SHA3.cpp

@ -211,13 +211,14 @@ defsha3(512)
} }
h256 sha3(bytesConstRef _input) bool sha3(bytesConstRef _input, bytesRef o_output)
{ {
// FIXME: What with unaligned memory? // FIXME: What with unaligned memory?
h256 ret; if (o_output.size() != 32)
keccak::sha3_256(ret.data(), 32, _input.data(), _input.size()); return false;
keccak::sha3_256(o_output.data(), 32, _input.data(), _input.size());
// keccak::keccak(ret.data(), 32, (uint64_t const*)_input.data(), _input.size()); // keccak::keccak(ret.data(), 32, (uint64_t const*)_input.data(), _input.size());
return ret; return true;
} }
} }

19
libdevcore/SHA3.h

@ -32,20 +32,31 @@ namespace dev
// SHA-3 convenience routines. // SHA-3 convenience routines.
/// Calculate SHA3-256 hash of the given input, returning as a 256-bit hash.
h256 sha3(bytesConstRef _input);
/// Calculate SHA3-256 hash of the given input and load it into the given output. /// Calculate SHA3-256 hash of the given input and load it into the given output.
inline void sha3(bytesConstRef _input, bytesRef _output) { sha3(_input).ref().populate(_output); } /// @returns false if o_output.size() != 32.
bool sha3(bytesConstRef _input, bytesRef o_output);
/// Calculate SHA3-256 hash of the given input, returning as a 256-bit hash.
inline h256 sha3(bytesConstRef _input) { h256 ret; sha3(_input, ret.ref()); return ret; }
inline SecureFixedHash<32> sha3Secure(bytesConstRef _input) { SecureFixedHash<32> ret; sha3(_input, ret.writable().ref()); return ret; }
/// Calculate SHA3-256 hash of the given input, returning as a 256-bit hash. /// Calculate SHA3-256 hash of the given input, returning as a 256-bit hash.
inline h256 sha3(bytes const& _input) { return sha3(bytesConstRef(&_input)); } inline h256 sha3(bytes const& _input) { return sha3(bytesConstRef(&_input)); }
inline SecureFixedHash<32> sha3Secure(bytes const& _input) { return sha3Secure(bytesConstRef(&_input)); }
/// Calculate SHA3-256 hash of the given input (presented as a binary-filled string), returning as a 256-bit hash. /// Calculate SHA3-256 hash of the given input (presented as a binary-filled string), returning as a 256-bit hash.
inline h256 sha3(std::string const& _input) { return sha3(bytesConstRef(_input)); } inline h256 sha3(std::string const& _input) { return sha3(bytesConstRef(_input)); }
inline SecureFixedHash<32> sha3Secure(std::string const& _input) { return sha3Secure(bytesConstRef(_input)); }
/// Calculate SHA3-256 hash of the given input (presented as a FixedHash), returns a 256-bit hash. /// Calculate SHA3-256 hash of the given input (presented as a FixedHash), returns a 256-bit hash.
template<unsigned N> inline h256 sha3(FixedHash<N> const& _input) { return sha3(_input.ref()); } template<unsigned N> inline h256 sha3(FixedHash<N> const& _input) { return sha3(_input.ref()); }
template<unsigned N> inline SecureFixedHash<32> sha3Secure(FixedHash<N> const& _input) { return sha3Secure(_input.ref()); }
/// Fully secure variants are equivalent for sha3 and sha3Secure.
inline SecureFixedHash<32> sha3(bytesSec const& _input) { return sha3Secure(_input.ref()); }
inline SecureFixedHash<32> sha3Secure(bytesSec const& _input) { return sha3Secure(_input.ref()); }
template<unsigned N> inline SecureFixedHash<32> sha3(SecureFixedHash<N> const& _input) { return sha3Secure(_input.ref()); }
template<unsigned N> inline SecureFixedHash<32> sha3Secure(SecureFixedHash<N> const& _input) { return sha3Secure(_input.ref()); }
/// Calculate SHA3-256 hash of the given input, possibly interpreting it as nibbles, and return the hash as a string filled with binary data. /// Calculate SHA3-256 hash of the given input, possibly interpreting it as nibbles, and return the hash as a string filled with binary data.
inline std::string sha3(std::string const& _input, bool _isNibbles) { return asString((_isNibbles ? sha3(fromHex(_input)) : sha3(bytesConstRef(&_input))).asBytes()); } inline std::string sha3(std::string const& _input, bool _isNibbles) { return asString((_isNibbles ? sha3(fromHex(_input)) : sha3(bytesConstRef(&_input))).asBytes()); }

12
libdevcore/vector_ref.h

@ -5,11 +5,13 @@
#include <type_traits> #include <type_traits>
#include <vector> #include <vector>
#include <string> #include <string>
#include <random>
namespace dev namespace dev
{ {
static unsigned char s_cleanseCounter = 0; static unsigned char s_cleanseCounter = 0;
static std::random_device s_vectorRefEngine;
/** /**
* A modifiable reference to an existing object or vector in memory. * A modifiable reference to an existing object or vector in memory.
@ -67,6 +69,16 @@ public:
void copyTo(vector_ref<typename std::remove_const<_T>::type> _t) const { if (overlapsWith(_t)) memmove(_t.data(), m_data, std::min(_t.size(), m_count) * sizeof(_T)); else memcpy(_t.data(), m_data, std::min(_t.size(), m_count) * sizeof(_T)); } void copyTo(vector_ref<typename std::remove_const<_T>::type> _t) const { if (overlapsWith(_t)) memmove(_t.data(), m_data, std::min(_t.size(), m_count) * sizeof(_T)); else memcpy(_t.data(), m_data, std::min(_t.size(), m_count) * sizeof(_T)); }
/// Copies the contents of this vector_ref to the contents of @a _t, and zeros further trailing elements in @a _t. /// Copies the contents of this vector_ref to the contents of @a _t, and zeros further trailing elements in @a _t.
void populate(vector_ref<typename std::remove_const<_T>::type> _t) const { copyTo(_t); memset(_t.data() + m_count, 0, std::max(_t.size(), m_count) - m_count); } void populate(vector_ref<typename std::remove_const<_T>::type> _t) const { copyTo(_t); memset(_t.data() + m_count, 0, std::max(_t.size(), m_count) - m_count); }
/// Populate with random data.
template <class Engine>
void randomize(Engine& _eng)
{
uint8_t* e = (uint8_t*)end();
for (uint8_t* i = (uint8_t*)begin(); i != e; ++i)
*i = (uint8_t)std::uniform_int_distribution<uint16_t>(0, 255)(_eng);
}
/// @returns a random valued object.
void randomize() { randomize(s_vectorRefEngine); }
/// Securely overwrite the memory. /// Securely overwrite the memory.
/// @note adapted from OpenSSL's implementation. /// @note adapted from OpenSSL's implementation.
void cleanse() void cleanse()

32
libdevcrypto/Common.cpp

@ -149,7 +149,7 @@ bool dev::decryptSym(Secret const& _k, bytesConstRef _cipher, bytes& o_plain)
return decrypt(_k, _cipher, o_plain); return decrypt(_k, _cipher, o_plain);
} }
std::pair<bytes, h128> dev::encryptSymNoAuth(h128 const& _k, bytesConstRef _plain) std::pair<bytes, h128> dev::encryptSymNoAuth(SecureFixedHash<16> const& _k, bytesConstRef _plain)
{ {
h128 iv(Nonce::get()); h128 iv(Nonce::get());
return make_pair(encryptSymNoAuth(_k, iv, _plain), iv); return make_pair(encryptSymNoAuth(_k, iv, _plain), iv);
@ -175,23 +175,23 @@ bytes dev::encryptAES128CTR(bytesConstRef _k, h128 const& _iv, bytesConstRef _pl
} }
} }
bytes dev::decryptAES128CTR(bytesConstRef _k, h128 const& _iv, bytesConstRef _cipher) bytesSec dev::decryptAES128CTR(bytesConstRef _k, h128 const& _iv, bytesConstRef _cipher)
{ {
if (_k.size() != 16 && _k.size() != 24 && _k.size() != 32) if (_k.size() != 16 && _k.size() != 24 && _k.size() != 32)
return bytes(); return bytesSec();
SecByteBlock key(_k.data(), _k.size()); SecByteBlock key(_k.data(), _k.size());
try try
{ {
CTR_Mode<AES>::Decryption d; CTR_Mode<AES>::Decryption d;
d.SetKeyWithIV(key, key.size(), _iv.data()); d.SetKeyWithIV(key, key.size(), _iv.data());
bytes ret(_cipher.size()); bytesSec ret(_cipher.size());
d.ProcessData(ret.data(), _cipher.data(), _cipher.size()); d.ProcessData(ret.writable().data(), _cipher.data(), _cipher.size());
return ret; return ret;
} }
catch (CryptoPP::Exception& _e) catch (CryptoPP::Exception& _e)
{ {
cerr << _e.what() << endl; cerr << _e.what() << endl;
return bytes(); return bytesSec();
} }
} }
@ -239,12 +239,12 @@ bool dev::verify(Public const& _p, Signature const& _s, h256 const& _hash)
#endif #endif
} }
bytes dev::pbkdf2(string const& _pass, bytes const& _salt, unsigned _iterations, unsigned _dkLen) bytesSec dev::pbkdf2(string const& _pass, bytes const& _salt, unsigned _iterations, unsigned _dkLen)
{ {
bytes ret(_dkLen); bytesSec ret(_dkLen);
if (PKCS5_PBKDF2_HMAC<SHA256>().DeriveKey( if (PKCS5_PBKDF2_HMAC<SHA256>().DeriveKey(
ret.data(), ret.writable().data(),
ret.size(), _dkLen,
0, 0,
reinterpret_cast<byte const*>(_pass.data()), reinterpret_cast<byte const*>(_pass.data()),
_pass.size(), _pass.size(),
@ -256,9 +256,9 @@ bytes dev::pbkdf2(string const& _pass, bytes const& _salt, unsigned _iterations,
return ret; return ret;
} }
bytes dev::scrypt(std::string const& _pass, bytes const& _salt, uint64_t _n, uint32_t _r, uint32_t _p, unsigned _dkLen) bytesSec dev::scrypt(std::string const& _pass, bytes const& _salt, uint64_t _n, uint32_t _r, uint32_t _p, unsigned _dkLen)
{ {
bytes ret(_dkLen); bytesSec ret(_dkLen);
if (libscrypt_scrypt( if (libscrypt_scrypt(
reinterpret_cast<uint8_t const*>(_pass.data()), reinterpret_cast<uint8_t const*>(_pass.data()),
_pass.size(), _pass.size(),
@ -267,8 +267,8 @@ bytes dev::scrypt(std::string const& _pass, bytes const& _salt, uint64_t _n, uin
_n, _n,
_r, _r,
_p, _p,
ret.data(), ret.writable().data(),
ret.size() _dkLen
) != 0) ) != 0)
BOOST_THROW_EXCEPTION(CryptoException() << errinfo_comment("Key derivation failed.")); BOOST_THROW_EXCEPTION(CryptoException() << errinfo_comment("Key derivation failed."));
return ret; return ret;
@ -285,7 +285,7 @@ KeyPair KeyPair::create()
{ {
for (int i = 0; i < 100; ++i) for (int i = 0; i < 100; ++i)
{ {
KeyPair ret(FixedHash<32>::random()); KeyPair ret(Secret::random());
if (ret.address()) if (ret.address())
return ret; return ret;
} }
@ -294,7 +294,7 @@ KeyPair KeyPair::create()
KeyPair KeyPair::fromEncryptedSeed(bytesConstRef _seed, std::string const& _password) KeyPair KeyPair::fromEncryptedSeed(bytesConstRef _seed, std::string const& _password)
{ {
return KeyPair(sha3(aesDecrypt(_seed, _password))); return KeyPair(Secret(sha3(aesDecrypt(_seed, _password))));
} }
h256 crypto::kdf(Secret const& _priv, h256 const& _hash) h256 crypto::kdf(Secret const& _priv, h256 const& _hash)

32
libdevcrypto/Common.h

@ -32,15 +32,7 @@
namespace dev namespace dev
{ {
/// A secret key: 32 bytes. using Secret = SecureFixedHash<32>;
/// @NOTE This is not endian-specific; it's just a bunch of bytes.
class Secret: public h256
{
public:
template <class ... Args> Secret(Args&& ... _args): h256(_args ...) {}
Secret(bytesSec const& _b): h256(bytesConstRef(&_b)) {}
~Secret() { ref().cleanse(); }
};
/// A public key: 64 bytes. /// A public key: 64 bytes.
/// @NOTE This is not endian-specific; it's just a bunch of bytes. /// @NOTE This is not endian-specific; it's just a bunch of bytes.
@ -82,7 +74,7 @@ using Addresses = h160s;
using AddressHash = std::unordered_set<h160>; using AddressHash = std::unordered_set<h160>;
/// A vector of secrets. /// A vector of secrets.
using Secrets = h256s; using Secrets = std::vector<Secret>;
/// Convert a secret key into the public key equivalent. /// Convert a secret key into the public key equivalent.
Public toPublic(Secret const& _secret); Public toPublic(Secret const& _secret);
@ -116,21 +108,21 @@ void encryptECIES(Public const& _k, bytesConstRef _plain, bytes& o_cipher);
bool decryptECIES(Secret const& _k, bytesConstRef _cipher, bytes& o_plaintext); bool decryptECIES(Secret const& _k, bytesConstRef _cipher, bytes& o_plaintext);
/// Encrypts payload with random IV/ctr using AES128-CTR. /// Encrypts payload with random IV/ctr using AES128-CTR.
std::pair<bytes, h128> encryptSymNoAuth(h128 const& _k, bytesConstRef _plain); std::pair<bytes, h128> encryptSymNoAuth(SecureFixedHash<16> const& _k, bytesConstRef _plain);
/// Encrypts payload with specified IV/ctr using AES128-CTR. /// Encrypts payload with specified IV/ctr using AES128-CTR.
bytes encryptAES128CTR(bytesConstRef _k, h128 const& _iv, bytesConstRef _plain); bytes encryptAES128CTR(bytesConstRef _k, h128 const& _iv, bytesConstRef _plain);
/// Decrypts payload with specified IV/ctr using AES128-CTR. /// Decrypts payload with specified IV/ctr using AES128-CTR.
bytes decryptAES128CTR(bytesConstRef _k, h128 const& _iv, bytesConstRef _cipher); bytesSec decryptAES128CTR(bytesConstRef _k, h128 const& _iv, bytesConstRef _cipher);
/// Encrypts payload with specified IV/ctr using AES128-CTR. /// Encrypts payload with specified IV/ctr using AES128-CTR.
inline bytes encryptSymNoAuth(h128 const& _k, h128 const& _iv, bytesConstRef _plain) { return encryptAES128CTR(_k.ref(), _iv, _plain); } inline bytes encryptSymNoAuth(SecureFixedHash<16> const& _k, h128 const& _iv, bytesConstRef _plain) { return encryptAES128CTR(_k.ref(), _iv, _plain); }
inline bytes encryptSymNoAuth(h256 const& _k, h128 const& _iv, bytesConstRef _plain) { return encryptAES128CTR(_k.ref(), _iv, _plain); } inline bytes encryptSymNoAuth(SecureFixedHash<32> const& _k, h128 const& _iv, bytesConstRef _plain) { return encryptAES128CTR(_k.ref(), _iv, _plain); }
/// Decrypts payload with specified IV/ctr using AES128-CTR. /// Decrypts payload with specified IV/ctr using AES128-CTR.
inline bytes decryptSymNoAuth(h128 const& _k, h128 const& _iv, bytesConstRef _cipher) { return decryptAES128CTR(_k.ref(), _iv, _cipher); } inline bytesSec decryptSymNoAuth(SecureFixedHash<16> const& _k, h128 const& _iv, bytesConstRef _cipher) { return decryptAES128CTR(_k.ref(), _iv, _cipher); }
inline bytes decryptSymNoAuth(h256 const& _k, h128 const& _iv, bytesConstRef _cipher) { return decryptAES128CTR(_k.ref(), _iv, _cipher); } inline bytesSec decryptSymNoAuth(SecureFixedHash<32> const& _k, h128 const& _iv, bytesConstRef _cipher) { return decryptAES128CTR(_k.ref(), _iv, _cipher); }
/// Recovers Public key from signed message hash. /// Recovers Public key from signed message hash.
Public recover(Signature const& _sig, h256 const& _hash); Public recover(Signature const& _sig, h256 const& _hash);
@ -142,10 +134,10 @@ Signature sign(Secret const& _k, h256 const& _hash);
bool verify(Public const& _k, Signature const& _s, h256 const& _hash); bool verify(Public const& _k, Signature const& _s, h256 const& _hash);
/// Derive key via PBKDF2. /// Derive key via PBKDF2.
bytes pbkdf2(std::string const& _pass, bytes const& _salt, unsigned _iterations, unsigned _dkLen = 32); bytesSec pbkdf2(std::string const& _pass, bytes const& _salt, unsigned _iterations, unsigned _dkLen = 32);
/// Derive key via Scrypt. /// Derive key via Scrypt.
bytes scrypt(std::string const& _pass, bytes const& _salt, uint64_t _n, uint32_t _r, uint32_t _p, unsigned _dkLen); bytesSec scrypt(std::string const& _pass, bytes const& _salt, uint64_t _n, uint32_t _r, uint32_t _p, unsigned _dkLen);
/// Simple class that represents a "key pair". /// Simple class that represents a "key pair".
/// All of the data of the class can be regenerated from the secret key (m_secret) alone. /// All of the data of the class can be regenerated from the secret key (m_secret) alone.
@ -176,8 +168,8 @@ public:
/// Retrieve the associated address of the public key. /// Retrieve the associated address of the public key.
Address const& address() const { return m_address; } Address const& address() const { return m_address; }
bool operator==(KeyPair const& _c) const { return m_secret == _c.m_secret; } bool operator==(KeyPair const& _c) const { return m_public == _c.m_public; }
bool operator!=(KeyPair const& _c) const { return m_secret != _c.m_secret; } bool operator!=(KeyPair const& _c) const { return m_public != _c.m_public; }
private: private:
void populateFromSecret(Secret const& _k); void populateFromSecret(Secret const& _k);

16
libdevcrypto/CryptoPP.cpp

@ -67,7 +67,7 @@ void Secp256k1PP::encryptECIES(Public const& _k, bytes& io_cipher)
{ {
// interop w/go ecies implementation // interop w/go ecies implementation
auto r = KeyPair::create(); auto r = KeyPair::create();
h256 z; Secret z;
ecdh::agree(r.sec(), _k, z); ecdh::agree(r.sec(), _k, z);
auto key = eciesKDF(z, bytes(), 32); auto key = eciesKDF(z, bytes(), 32);
bytesConstRef eKey = bytesConstRef(&key).cropped(0, 16); bytesConstRef eKey = bytesConstRef(&key).cropped(0, 16);
@ -77,7 +77,7 @@ void Secp256k1PP::encryptECIES(Public const& _k, bytes& io_cipher)
bytes mKey(32); bytes mKey(32);
ctx.Final(mKey.data()); ctx.Final(mKey.data());
bytes cipherText = encryptSymNoAuth(h128(eKey), h128(), bytesConstRef(&io_cipher)); bytes cipherText = encryptSymNoAuth(SecureFixedHash<16>(eKey), h128(), bytesConstRef(&io_cipher));
if (cipherText.empty()) if (cipherText.empty())
return; return;
@ -110,8 +110,8 @@ bool Secp256k1PP::decryptECIES(Secret const& _k, bytes& io_text)
// invalid message: length // invalid message: length
return false; return false;
h256 z; Secret z;
ecdh::agree(_k, *(Public*)(io_text.data()+1), z); ecdh::agree(_k, *(Public*)(io_text.data() + 1), z);
auto key = eciesKDF(z, bytes(), 64); auto key = eciesKDF(z, bytes(), 64);
bytesConstRef eKey = bytesConstRef(&key).cropped(0, 16); bytesConstRef eKey = bytesConstRef(&key).cropped(0, 16);
bytesRef mKeyMaterial = bytesRef(&key).cropped(16, 16); bytesRef mKeyMaterial = bytesRef(&key).cropped(16, 16);
@ -137,7 +137,7 @@ bool Secp256k1PP::decryptECIES(Secret const& _k, bytes& io_text)
if (mac[i] != msgMac[i]) if (mac[i] != msgMac[i])
return false; return false;
plain = decryptSymNoAuth(h128(eKey), iv, cipherNoIV); plain = decryptSymNoAuth(SecureFixedHash<16>(eKey), iv, cipherNoIV).makeInsecure();
io_text.resize(plain.size()); io_text.resize(plain.size());
io_text.swap(plain); io_text.swap(plain);
@ -222,7 +222,7 @@ Signature Secp256k1PP::sign(Secret const& _key, h256 const& _hash)
Integer kInv = k.InverseMod(m_q); Integer kInv = k.InverseMod(m_q);
Integer z(_hash.asBytes().data(), 32); Integer z(_hash.asBytes().data(), 32);
Integer s = (kInv * (Integer(_key.asBytes().data(), 32) * r + z)) % m_q; Integer s = (kInv * (Integer(_key.data(), 32) * r + z)) % m_q;
if (r == 0 || s == 0) if (r == 0 || s == 0)
BOOST_THROW_EXCEPTION(InvalidState()); BOOST_THROW_EXCEPTION(InvalidState());
@ -310,7 +310,7 @@ bool Secp256k1PP::verifySecret(Secret const& _s, Public& _p)
return true; return true;
} }
void Secp256k1PP::agree(Secret const& _s, Public const& _r, h256& o_s) void Secp256k1PP::agree(Secret const& _s, Public const& _r, Secret& o_s)
{ {
// TODO: mutex ASN1::secp256k1() singleton // TODO: mutex ASN1::secp256k1() singleton
// Creating Domain is non-const for m_oid and m_oid is not thread-safe // Creating Domain is non-const for m_oid and m_oid is not thread-safe
@ -318,7 +318,7 @@ void Secp256k1PP::agree(Secret const& _s, Public const& _r, h256& o_s)
assert(d.AgreedValueLength() == sizeof(o_s)); assert(d.AgreedValueLength() == sizeof(o_s));
byte remote[65] = {0x04}; byte remote[65] = {0x04};
memcpy(&remote[1], _r.data(), 64); memcpy(&remote[1], _r.data(), 64);
d.Agree(o_s.data(), _s.data(), remote); d.Agree(o_s.writable().data(), _s.data(), remote);
} }
void Secp256k1PP::exportPublicKey(CryptoPP::DL_PublicKey_EC<CryptoPP::ECP> const& _k, Public& o_p) void Secp256k1PP::exportPublicKey(CryptoPP::DL_PublicKey_EC<CryptoPP::ECP> const& _k, Public& o_p)

4
libdevcrypto/CryptoPP.h

@ -107,10 +107,10 @@ public:
/// Verifies _s is a valid secret key and returns corresponding public key in o_p. /// Verifies _s is a valid secret key and returns corresponding public key in o_p.
bool verifySecret(Secret const& _s, Public& o_p); bool verifySecret(Secret const& _s, Public& o_p);
void agree(Secret const& _s, Public const& _r, h256& o_s); void agree(Secret const& _s, Public const& _r, Secret& o_s);
protected: protected:
void exportPrivateKey(DL_PrivateKey_EC<ECP> const& _k, Secret& o_s) { _k.GetPrivateExponent().Encode(o_s.data(), Secret::size); } void exportPrivateKey(DL_PrivateKey_EC<ECP> const& _k, Secret& o_s) { _k.GetPrivateExponent().Encode(o_s.writable().data(), Secret::size); }
void exportPublicKey(DL_PublicKey_EC<ECP> const& _k, Public& o_p); void exportPublicKey(DL_PublicKey_EC<ECP> const& _k, Public& o_p);

2
libdevcrypto/ECDHE.cpp

@ -29,7 +29,7 @@ using namespace dev::crypto;
static Secp256k1PP s_secp256k1; static Secp256k1PP s_secp256k1;
void dev::crypto::ecdh::agree(Secret const& _s, Public const& _r, h256& o_s) void dev::crypto::ecdh::agree(Secret const& _s, Public const& _r, Secret& o_s)
{ {
s_secp256k1.agree(_s, _r, o_s); s_secp256k1.agree(_s, _r, o_s);
} }

2
libdevcrypto/ECDHE.h

@ -50,7 +50,7 @@ private:
namespace ecdh namespace ecdh
{ {
void agree(Secret const& _s, Public const& _r, h256& o_s); void agree(Secret const& _s, Public const& _r, Secret& o_s);
} }
/** /**

59
libdevcrypto/SecretStore.cpp

@ -100,17 +100,17 @@ bytesSec SecretStore::secret(h128 const& _uuid, function<string()> const& _pass,
bytesSec key; bytesSec key;
if (it != m_keys.end()) if (it != m_keys.end())
{ {
key = decrypt(it->second.encryptedKey, _pass()); key = bytesSec(decrypt(it->second.encryptedKey, _pass()));
if (!key.empty()) if (!key.empty())
m_cached[_uuid] = key; m_cached[_uuid] = key;
} }
return key; return key;
} }
h128 SecretStore::importSecret(bytes const& _s, string const& _pass) h128 SecretStore::importSecret(bytesSec const& _s, string const& _pass)
{ {
h128 r; h128 r;
EncryptedKey key{encrypt(_s, _pass), string()}; EncryptedKey key{encrypt(_s.ref(), _pass), string()};
r = h128::random(); r = h128::random();
m_cached[r] = _s; m_cached[r] = _s;
m_keys[r] = move(key); m_keys[r] = move(key);
@ -118,6 +118,17 @@ h128 SecretStore::importSecret(bytes const& _s, string const& _pass)
return r; return r;
} }
h128 SecretStore::importSecret(bytesConstRef _s, string const& _pass)
{
h128 r;
EncryptedKey key{encrypt(_s, _pass), string()};
r = h128::random();
m_cached[r] = bytesSec(_s);
m_keys[r] = move(key);
save();
return r;
}
void SecretStore::kill(h128 const& _uuid) void SecretStore::kill(h128 const& _uuid)
{ {
m_cached.erase(_uuid); m_cached.erase(_uuid);
@ -188,16 +199,16 @@ h128 SecretStore::readKeyContent(string const& _content, string const& _file)
bool SecretStore::recode(h128 const& _uuid, string const& _newPass, function<string()> const& _pass, KDF _kdf) bool SecretStore::recode(h128 const& _uuid, string const& _newPass, function<string()> const& _pass, KDF _kdf)
{ {
bytes s = secret(_uuid, _pass, true); bytesSec s = secret(_uuid, _pass, true);
if (s.empty()) if (s.empty())
return false; return false;
m_cached.erase(_uuid); m_cached.erase(_uuid);
m_keys[_uuid].encryptedKey = encrypt(s, _newPass, _kdf); m_keys[_uuid].encryptedKey = encrypt(s.ref(), _newPass, _kdf);
save(); save();
return true; return true;
} }
static bytes deriveNewKey(string const& _pass, KDF _kdf, js::mObject& o_ret) static bytesSec deriveNewKey(string const& _pass, KDF _kdf, js::mObject& o_ret)
{ {
unsigned dklen = 32; unsigned dklen = 32;
unsigned iterations = 1 << 18; unsigned iterations = 1 << 18;
@ -233,16 +244,16 @@ static bytes deriveNewKey(string const& _pass, KDF _kdf, js::mObject& o_ret)
} }
} }
string SecretStore::encrypt(bytes const& _v, string const& _pass, KDF _kdf) string SecretStore::encrypt(bytesConstRef _v, string const& _pass, KDF _kdf)
{ {
js::mObject ret; js::mObject ret;
bytes derivedKey = deriveNewKey(_pass, _kdf, ret); bytesSec derivedKey = deriveNewKey(_pass, _kdf, ret);
if (derivedKey.empty()) if (derivedKey.empty())
BOOST_THROW_EXCEPTION(crypto::CryptoException() << errinfo_comment("Key derivation failed.")); BOOST_THROW_EXCEPTION(crypto::CryptoException() << errinfo_comment("Key derivation failed."));
ret["cipher"] = "aes-128-ctr"; ret["cipher"] = "aes-128-ctr";
h128 key(derivedKey, h128::AlignLeft); SecureFixedHash<16> key(derivedKey, h128::AlignLeft);
h128 iv = h128::random(); h128 iv = h128::random();
{ {
js::mObject params; js::mObject params;
@ -251,19 +262,19 @@ string SecretStore::encrypt(bytes const& _v, string const& _pass, KDF _kdf)
} }
// cipher text // cipher text
bytes cipherText = encryptSymNoAuth(key, iv, &_v); bytes cipherText = encryptSymNoAuth(key, iv, _v);
if (cipherText.empty()) if (cipherText.empty())
BOOST_THROW_EXCEPTION(crypto::CryptoException() << errinfo_comment("Key encryption failed.")); BOOST_THROW_EXCEPTION(crypto::CryptoException() << errinfo_comment("Key encryption failed."));
ret["ciphertext"] = toHex(cipherText); ret["ciphertext"] = toHex(cipherText);
// and mac. // and mac.
h256 mac = sha3(ref(derivedKey).cropped(16, 16).toBytes() + cipherText); h256 mac = sha3(derivedKey.ref().cropped(16, 16).toBytes() + cipherText);
ret["mac"] = toHex(mac.ref()); ret["mac"] = toHex(mac.ref());
return js::write_string(js::mValue(ret), true); return js::write_string(js::mValue(ret), true);
} }
bytes SecretStore::decrypt(string const& _v, string const& _pass) bytesSec SecretStore::decrypt(string const& _v, string const& _pass)
{ {
js::mObject o; js::mObject o;
{ {
@ -273,14 +284,14 @@ bytes SecretStore::decrypt(string const& _v, string const& _pass)
} }
// derive key // derive key
bytes derivedKey; bytesSec derivedKey;
if (o["kdf"].get_str() == "pbkdf2") if (o["kdf"].get_str() == "pbkdf2")
{ {
auto params = o["kdfparams"].get_obj(); auto params = o["kdfparams"].get_obj();
if (params["prf"].get_str() != "hmac-sha256") if (params["prf"].get_str() != "hmac-sha256")
{ {
cwarn << "Unknown PRF for PBKDF2" << params["prf"].get_str() << "not supported."; cwarn << "Unknown PRF for PBKDF2" << params["prf"].get_str() << "not supported.";
return bytes(); return bytesSec();
} }
unsigned iterations = params["c"].get_int(); unsigned iterations = params["c"].get_int();
bytes salt = fromHex(params["salt"].get_str()); bytes salt = fromHex(params["salt"].get_str());
@ -294,13 +305,13 @@ bytes SecretStore::decrypt(string const& _v, string const& _pass)
else else
{ {
cwarn << "Unknown KDF" << o["kdf"].get_str() << "not supported."; cwarn << "Unknown KDF" << o["kdf"].get_str() << "not supported.";
return bytes(); return bytesSec();
} }
if (derivedKey.size() < 32 && !(o.count("compat") && o["compat"].get_str() == "2")) if (derivedKey.size() < 32 && !(o.count("compat") && o["compat"].get_str() == "2"))
{ {
cwarn << "Derived key's length too short (<32 bytes)"; cwarn << "Derived key's length too short (<32 bytes)";
return bytes(); return bytesSec();
} }
bytes cipherText = fromHex(o["ciphertext"].get_str()); bytes cipherText = fromHex(o["ciphertext"].get_str());
@ -311,23 +322,23 @@ bytes SecretStore::decrypt(string const& _v, string const& _pass)
h256 mac(o["mac"].get_str()); h256 mac(o["mac"].get_str());
h256 macExp; h256 macExp;
if (o.count("compat") && o["compat"].get_str() == "2") if (o.count("compat") && o["compat"].get_str() == "2")
macExp = sha3(bytesConstRef(&derivedKey).cropped(derivedKey.size() - 16).toBytes() + cipherText); macExp = sha3(derivedKey.ref().cropped(derivedKey.size() - 16).toBytes() + cipherText);
else else
macExp = sha3(bytesConstRef(&derivedKey).cropped(16, 16).toBytes() + cipherText); macExp = sha3(derivedKey.ref().cropped(16, 16).toBytes() + cipherText);
if (mac != macExp) if (mac != macExp)
{ {
cwarn << "Invalid key - MAC mismatch; expected" << toString(macExp) << ", got" << toString(mac); cwarn << "Invalid key - MAC mismatch; expected" << toString(macExp) << ", got" << toString(mac);
return bytes(); return bytesSec();
} }
} }
else if (o.count("sillymac")) else if (o.count("sillymac"))
{ {
h256 mac(o["sillymac"].get_str()); h256 mac(o["sillymac"].get_str());
h256 macExp = sha3(asBytes(o["sillymacjson"].get_str()) + bytesConstRef(&derivedKey).cropped(derivedKey.size() - 16).toBytes() + cipherText); h256 macExp = sha3(asBytes(o["sillymacjson"].get_str()) + derivedKey.ref().cropped(derivedKey.size() - 16).toBytes() + cipherText);
if (mac != macExp) if (mac != macExp)
{ {
cwarn << "Invalid key - MAC mismatch; expected" << toString(macExp) << ", got" << toString(mac); cwarn << "Invalid key - MAC mismatch; expected" << toString(macExp) << ", got" << toString(mac);
return bytes(); return bytesSec();
} }
} }
else else
@ -340,15 +351,15 @@ bytes SecretStore::decrypt(string const& _v, string const& _pass)
h128 iv(params["iv"].get_str()); h128 iv(params["iv"].get_str());
if (o.count("compat") && o["compat"].get_str() == "2") if (o.count("compat") && o["compat"].get_str() == "2")
{ {
h128 key(sha3(h128(derivedKey, h128::AlignRight)), h128::AlignRight); SecureFixedHash<16> key(sha3Secure(derivedKey.ref().cropped(derivedKey.size() - 16)), h128::AlignRight);
return decryptSymNoAuth(key, iv, &cipherText); return decryptSymNoAuth(key, iv, &cipherText);
} }
else else
return decryptSymNoAuth(h128(derivedKey, h128::AlignLeft), iv, &cipherText); return decryptSymNoAuth(SecureFixedHash<16>(derivedKey, h128::AlignLeft), iv, &cipherText);
} }
else else
{ {
cwarn << "Unknown cipher" << o["cipher"].get_str() << "not supported."; cwarn << "Unknown cipher" << o["cipher"].get_str() << "not supported.";
return bytes(); return bytesSec();
} }
} }

7
libdevcrypto/SecretStore.h

@ -60,7 +60,8 @@ public:
h128 importKeyContent(std::string const& _content) { auto ret = readKeyContent(_content, std::string()); if (ret) save(); return ret; } h128 importKeyContent(std::string const& _content) { auto ret = readKeyContent(_content, std::string()); if (ret) save(); return ret; }
/// Imports the decrypted key given by @a _s and stores it, encrypted with /// Imports the decrypted key given by @a _s and stores it, encrypted with
/// (a key derived from) the password @a _pass. /// (a key derived from) the password @a _pass.
h128 importSecret(bytes const& _s, std::string const& _pass); h128 importSecret(bytesSec const& _s, std::string const& _pass);
h128 importSecret(bytesConstRef _s, std::string const& _pass);
/// Decrypts and re-encrypts the key identified by @a _uuid. /// Decrypts and re-encrypts the key identified by @a _uuid.
bool recode(h128 const& _uuid, std::string const& _newPass, std::function<std::string()> const& _pass, KDF _kdf = KDF::Scrypt); bool recode(h128 const& _uuid, std::string const& _newPass, std::function<std::string()> const& _pass, KDF _kdf = KDF::Scrypt);
/// Removes the key specified by @a _uuid from both memory and disk. /// Removes the key specified by @a _uuid from both memory and disk.
@ -102,9 +103,9 @@ private:
void load(std::string const& _keysPath); void load(std::string const& _keysPath);
void load() { load(m_path); } void load() { load(m_path); }
/// Encrypts @a _v with a key derived from @a _pass or the empty string on error. /// Encrypts @a _v with a key derived from @a _pass or the empty string on error.
static std::string encrypt(bytes const& _v, std::string const& _pass, KDF _kdf = KDF::Scrypt); static std::string encrypt(bytesConstRef _v, std::string const& _pass, KDF _kdf = KDF::Scrypt);
/// Decrypts @a _v with a key derived from @a _pass or the empty byte array on error. /// Decrypts @a _v with a key derived from @a _pass or the empty byte array on error.
static bytes decrypt(std::string const& _v, std::string const& _pass); static bytesSec decrypt(std::string const& _v, std::string const& _pass);
/// Stores decrypted keys by uuid. /// Stores decrypted keys by uuid.
mutable std::unordered_map<h128, bytesSec> m_cached; mutable std::unordered_map<h128, bytesSec> m_cached;

2
libethcore/BasicAuthority.cpp

@ -101,7 +101,7 @@ private:
if (_name == "authorities") if (_name == "authorities")
BasicAuthority::s_authorities = rlp.toUnorderedSet<Address>(); BasicAuthority::s_authorities = rlp.toUnorderedSet<Address>();
else if (_name == "authority") else if (_name == "authority")
m_secret = rlp.toHash<Secret>(); m_secret = Secret(rlp.toHash<h256>());
else else
return false; return false;
return true; return true;

2
libethcore/CommonJS.h

@ -40,7 +40,7 @@ Address toAddress(std::string const& _a);
inline Public jsToPublic(std::string const& _s) { return jsToFixed<sizeof(dev::Public)>(_s); } inline Public jsToPublic(std::string const& _s) { return jsToFixed<sizeof(dev::Public)>(_s); }
/// Leniently convert string to Secret (h256). Accepts integers, "0x" prefixing, non-exact length. /// Leniently convert string to Secret (h256). Accepts integers, "0x" prefixing, non-exact length.
inline Secret jsToSecret(std::string const& _s) { return jsToFixed<sizeof(dev::Secret)>(_s); } inline Secret jsToSecret(std::string const& _s) { h256 d = jsToFixed<sizeof(dev::Secret)>(_s); Secret ret(d); d.ref().cleanse(); return ret; }
/// Leniently convert string to Address (h160). Accepts integers, "0x" prefixing, non-exact length. /// Leniently convert string to Address (h160). Accepts integers, "0x" prefixing, non-exact length.
inline Address jsToAddress(std::string const& _s) { return jsToFixed<sizeof(dev::Address)>(_s); } inline Address jsToAddress(std::string const& _s) { return jsToFixed<sizeof(dev::Address)>(_s); }

16
libethcore/KeyManager.cpp

@ -81,9 +81,9 @@ bool KeyManager::load(string const& _pass)
{ {
bytes salt = contents(m_keysFile + ".salt"); bytes salt = contents(m_keysFile + ".salt");
bytes encKeys = contents(m_keysFile); bytes encKeys = contents(m_keysFile);
m_keysFileKey = h128(pbkdf2(_pass, salt, 262144, 16)); m_keysFileKey = SecureFixedHash<16>(pbkdf2(_pass, salt, 262144, 16));
bytes bs = decryptSymNoAuth(m_keysFileKey, h128(), &encKeys); bytesSec bs = decryptSymNoAuth(m_keysFileKey, h128(), &encKeys);
RLP s(bs); RLP s(bs.ref());
unsigned version = unsigned(s[0]); unsigned version = unsigned(s[0]);
if (version == 1) if (version == 1)
{ {
@ -178,7 +178,7 @@ h128 KeyManager::import(Secret const& _s, string const& _accountName, string con
auto passHash = hashPassword(_pass); auto passHash = hashPassword(_pass);
cachePassword(_pass); cachePassword(_pass);
m_passwordHint[passHash] = _passwordHint; m_passwordHint[passHash] = _passwordHint;
auto uuid = m_store.importSecret(_s.asBytes(), _pass); auto uuid = m_store.importSecret(_s.asBytesSec(), _pass);
m_keyInfo[uuid] = KeyInfo{passHash, _accountName}; m_keyInfo[uuid] = KeyInfo{passHash, _accountName};
m_addrLookup[addr] = uuid; m_addrLookup[addr] = uuid;
write(m_keysFile); write(m_keysFile);
@ -187,7 +187,7 @@ h128 KeyManager::import(Secret const& _s, string const& _accountName, string con
void KeyManager::importExisting(h128 const& _uuid, string const& _info, string const& _pass, string const& _passwordHint) void KeyManager::importExisting(h128 const& _uuid, string const& _info, string const& _pass, string const& _passwordHint)
{ {
bytes key = m_store.secret(_uuid, [&](){ return _pass; }); bytesSec key = m_store.secret(_uuid, [&](){ return _pass; });
if (key.empty()) if (key.empty())
return; return;
Address a = KeyPair(Secret(key)).address(); Address a = KeyPair(Secret(key)).address();
@ -258,7 +258,7 @@ string const& KeyManager::passwordHint(Address const& _address) const
h256 KeyManager::hashPassword(string const& _pass) const h256 KeyManager::hashPassword(string const& _pass) const
{ {
// TODO SECURITY: store this a bit more securely; Scrypt perhaps? // TODO SECURITY: store this a bit more securely; Scrypt perhaps?
return h256(pbkdf2(_pass, asBytes(m_defaultPasswordDeprecated), 262144, 32)); return h256(pbkdf2(_pass, asBytes(m_defaultPasswordDeprecated), 262144, 32).makeInsecure());
} }
void KeyManager::cachePassword(string const& _password) const void KeyManager::cachePassword(string const& _password) const
@ -278,14 +278,14 @@ void KeyManager::write(string const& _pass, string const& _keysFile) const
{ {
bytes salt = h256::random().asBytes(); bytes salt = h256::random().asBytes();
writeFile(_keysFile + ".salt", salt); writeFile(_keysFile + ".salt", salt);
auto key = h128(pbkdf2(_pass, salt, 262144, 16)); auto key = SecureFixedHash<16>(pbkdf2(_pass, salt, 262144, 16));
cachePassword(_pass); cachePassword(_pass);
m_master = hashPassword(_pass); m_master = hashPassword(_pass);
write(key, _keysFile); write(key, _keysFile);
} }
void KeyManager::write(h128 const& _key, string const& _keysFile) const void KeyManager::write(SecureFixedHash<16> const& _key, string const& _keysFile) const
{ {
RLPStream s(4); RLPStream s(4);
s << 1; // version s << 1; // version

6
libethcore/KeyManager.h

@ -136,8 +136,8 @@ private:
// @returns false if wasn't previously loaded ok. // @returns false if wasn't previously loaded ok.
bool write() const { return write(m_keysFile); } bool write() const { return write(m_keysFile); }
bool write(std::string const& _keysFile) const; bool write(std::string const& _keysFile) const;
void write(std::string const& _pass, std::string const& _keysFile) const; void write(std::string const& _pass, std::string const& _keysFile) const; // TODO: all passwords should be a secure string.
void write(h128 const& _key, std::string const& _keysFile) const; void write(SecureFixedHash<16> const& _key, std::string const& _keysFile) const;
// Ethereum keys. // Ethereum keys.
@ -159,7 +159,7 @@ private:
std::string m_defaultPasswordDeprecated; std::string m_defaultPasswordDeprecated;
mutable std::string m_keysFile; mutable std::string m_keysFile;
mutable h128 m_keysFileKey; mutable SecureFixedHash<16> m_keysFileKey;
mutable h256 m_master; mutable h256 m_master;
SecretStore m_store; SecretStore m_store;
}; };

2
libp2p/Host.cpp

@ -809,7 +809,7 @@ bytes Host::saveNetwork() const
// else: TODO: use previous configuration if available // else: TODO: use previous configuration if available
RLPStream ret(3); RLPStream ret(3);
ret << dev::p2p::c_protocolVersion << m_alias.secret(); ret << dev::p2p::c_protocolVersion << m_alias.secret().ref();
ret.appendList(count); ret.appendList(count);
if (!!count) if (!!count)
ret.appendRaw(network.out(), count); ret.appendRaw(network.out(), count);

4
libp2p/RLPxHandshake.cpp

@ -40,7 +40,7 @@ void RLPXHandshake::writeAuth()
// E(remote-pubk, S(ecdhe-random, ecdh-shared-secret^nonce) || H(ecdhe-random-pubk) || pubk || nonce || 0x0) // E(remote-pubk, S(ecdhe-random, ecdh-shared-secret^nonce) || H(ecdhe-random-pubk) || pubk || nonce || 0x0)
Secret staticShared; Secret staticShared;
crypto::ecdh::agree(m_host->m_alias.sec(), m_remote, staticShared); crypto::ecdh::agree(m_host->m_alias.sec(), m_remote, staticShared);
sign(m_ecdhe.seckey(), staticShared ^ m_nonce).ref().copyTo(sig); sign(m_ecdhe.seckey(), staticShared.makeInsecure() ^ m_nonce).ref().copyTo(sig);
sha3(m_ecdhe.pubkey().ref(), hepubk); sha3(m_ecdhe.pubkey().ref(), hepubk);
m_host->m_alias.pub().ref().copyTo(pubk); m_host->m_alias.pub().ref().copyTo(pubk);
m_nonce.ref().copyTo(nonce); m_nonce.ref().copyTo(nonce);
@ -92,7 +92,7 @@ void RLPXHandshake::readAuth()
Secret sharedSecret; Secret sharedSecret;
crypto::ecdh::agree(m_host->m_alias.sec(), m_remote, sharedSecret); crypto::ecdh::agree(m_host->m_alias.sec(), m_remote, sharedSecret);
m_remoteEphemeral = recover(*(Signature*)sig.data(), sharedSecret ^ m_remoteNonce); m_remoteEphemeral = recover(*(Signature*)sig.data(), sharedSecret.makeInsecure() ^ m_remoteNonce);
if (sha3(m_remoteEphemeral) != *(h256*)hepubk.data()) if (sha3(m_remoteEphemeral) != *(h256*)hepubk.data())
clog(NetP2PConnect) << "p2p.connect.ingress auth failed (invalid: hash mismatch) for" << m_socket->remoteEndpoint(); clog(NetP2PConnect) << "p2p.connect.ingress auth failed (invalid: hash mismatch) for" << m_socket->remoteEndpoint();

10
libwhisper/Message.cpp

@ -60,7 +60,7 @@ bool Message::openBroadcastEnvelope(Envelope const& _e, Topics const& _fk, bytes
for (unsigned i = 0; i < _e.topic().size(); ++i) for (unsigned i = 0; i < _e.topic().size(); ++i)
if (_e.topic()[i] == knownTopic[ti]) if (_e.topic()[i] == knownTopic[ti])
{ {
topicSecret = _fk[ti]; topicSecret = Secret(_fk[ti]);
topicIndex = i; topicIndex = i;
break; break;
} }
@ -69,9 +69,9 @@ bool Message::openBroadcastEnvelope(Envelope const& _e, Topics const& _fk, bytes
return false; return false;
unsigned index = topicIndex * 2; unsigned index = topicIndex * 2;
h256 encryptedKey = h256(bytesConstRef(&(_e.data())).cropped(h256::size * index, h256::size)); Secret encryptedKey(bytesConstRef(&(_e.data())).cropped(h256::size * index, h256::size));
h256 salt = h256(bytesConstRef(&(_e.data())).cropped(h256::size * ++index, h256::size)); h256 salt = h256(bytesConstRef(&(_e.data())).cropped(h256::size * ++index, h256::size));
h256 key = generateGamma(topicSecret, salt) ^ encryptedKey; Secret key = Secret(generateGamma(topicSecret, salt).makeInsecure() ^ encryptedKey.makeInsecure());
bytesConstRef cipherText = bytesConstRef(&(_e.data())).cropped(h256::size * 2 * _e.topic().size()); bytesConstRef cipherText = bytesConstRef(&(_e.data())).cropped(h256::size * 2 * _e.topic().size());
return decryptSym(key, cipherText, o_b); return decryptSym(key, cipherText, o_b);
} }
@ -122,10 +122,10 @@ Envelope Message::seal(Secret const& _from, Topics const& _fullTopics, unsigned
// this message is for broadcast (could be read by anyone who knows at least one of the topics) // this message is for broadcast (could be read by anyone who knows at least one of the topics)
// create the shared secret for encrypting the payload, then encrypt the shared secret with each topic // create the shared secret for encrypting the payload, then encrypt the shared secret with each topic
Secret s = Secret::random(); Secret s = Secret::random();
for (h256 const& t : _fullTopics) for (h256 const& t: _fullTopics)
{ {
h256 salt = h256::random(); h256 salt = h256::random();
ret.m_data += (generateGamma(t, salt) ^ s).asBytes(); ret.m_data += (generateGamma(Secret(t), salt).makeInsecure() ^ s.makeInsecure()).ref().toBytes();
ret.m_data += salt.asBytes(); ret.m_data += salt.asBytes();
} }

2
libwhisper/Message.h

@ -127,7 +127,7 @@ public:
private: private:
bool populate(bytes const& _data); bool populate(bytes const& _data);
bool openBroadcastEnvelope(Envelope const& _e, Topics const& _t, bytes& o_b); bool openBroadcastEnvelope(Envelope const& _e, Topics const& _t, bytes& o_b);
h256 generateGamma(h256 const& _key, h256 const& _salt) const { return sha3(_key ^ _salt); } Secret generateGamma(Secret const& _key, h256 const& _salt) const { return sha3(_key ^ _salt); }
Public m_from; Public m_from;
Public m_to; Public m_to;

2
mix/FileIo.cpp

@ -187,7 +187,7 @@ QStringList FileIo::makePackage(QString const& _deploymentFolder)
bytes dapp = rlpStr.out(); bytes dapp = rlpStr.out();
dev::h256 dappHash = dev::sha3(dapp); dev::h256 dappHash = dev::sha3(dapp);
//encrypt //encrypt
KeyPair key(dappHash); KeyPair key((Secret(dappHash)));
Secp256k1PP enc; Secp256k1PP enc;
enc.encrypt(key.pub(), dapp); enc.encrypt(key.pub(), dapp);

6
test/libdevcrypto/AES.cpp

@ -35,7 +35,7 @@ BOOST_AUTO_TEST_CASE(AesDecrypt)
{ {
cout << "AesDecrypt" << endl; cout << "AesDecrypt" << endl;
bytes seed = fromHex("2dbaead416c20cfd00c2fc9f1788ff9f965a2000799c96a624767cb0e1e90d2d7191efdd92349226742fdc73d1d87e2d597536c4641098b9a89836c94f58a2ab4c525c27c4cb848b3e22ea245b2bc5c8c7beaa900b0c479253fc96fce7ffc621"); bytes seed = fromHex("2dbaead416c20cfd00c2fc9f1788ff9f965a2000799c96a624767cb0e1e90d2d7191efdd92349226742fdc73d1d87e2d597536c4641098b9a89836c94f58a2ab4c525c27c4cb848b3e22ea245b2bc5c8c7beaa900b0c479253fc96fce7ffc621");
KeyPair kp(sha3(aesDecrypt(&seed, "test"))); KeyPair kp(sha3Secure(aesDecrypt(&seed, "test")));
BOOST_CHECK(Address("07746f871de684297923f933279555dda418f8a2") == kp.address()); BOOST_CHECK(Address("07746f871de684297923f933279555dda418f8a2") == kp.address());
} }
@ -43,7 +43,7 @@ BOOST_AUTO_TEST_CASE(AesDecryptWrongSeed)
{ {
cout << "AesDecryptWrongSeed" << endl; cout << "AesDecryptWrongSeed" << endl;
bytes seed = fromHex("badaead416c20cfd00c2fc9f1788ff9f965a2000799c96a624767cb0e1e90d2d7191efdd92349226742fdc73d1d87e2d597536c4641098b9a89836c94f58a2ab4c525c27c4cb848b3e22ea245b2bc5c8c7beaa900b0c479253fc96fce7ffc621"); bytes seed = fromHex("badaead416c20cfd00c2fc9f1788ff9f965a2000799c96a624767cb0e1e90d2d7191efdd92349226742fdc73d1d87e2d597536c4641098b9a89836c94f58a2ab4c525c27c4cb848b3e22ea245b2bc5c8c7beaa900b0c479253fc96fce7ffc621");
KeyPair kp(sha3(aesDecrypt(&seed, "test"))); KeyPair kp(sha3Secure(aesDecrypt(&seed, "test")));
BOOST_CHECK(Address("07746f871de684297923f933279555dda418f8a2") != kp.address()); BOOST_CHECK(Address("07746f871de684297923f933279555dda418f8a2") != kp.address());
} }
@ -51,7 +51,7 @@ BOOST_AUTO_TEST_CASE(AesDecryptWrongPassword)
{ {
cout << "AesDecryptWrongPassword" << endl; cout << "AesDecryptWrongPassword" << endl;
bytes seed = fromHex("2dbaead416c20cfd00c2fc9f1788ff9f965a2000799c96a624767cb0e1e90d2d7191efdd92349226742fdc73d1d87e2d597536c4641098b9a89836c94f58a2ab4c525c27c4cb848b3e22ea245b2bc5c8c7beaa900b0c479253fc96fce7ffc621"); bytes seed = fromHex("2dbaead416c20cfd00c2fc9f1788ff9f965a2000799c96a624767cb0e1e90d2d7191efdd92349226742fdc73d1d87e2d597536c4641098b9a89836c94f58a2ab4c525c27c4cb848b3e22ea245b2bc5c8c7beaa900b0c479253fc96fce7ffc621");
KeyPair kp(sha3(aesDecrypt(&seed, "badtest"))); KeyPair kp(sha3Secure(aesDecrypt(&seed, "badtest")));
BOOST_CHECK(Address("07746f871de684297923f933279555dda418f8a2") != kp.address()); BOOST_CHECK(Address("07746f871de684297923f933279555dda418f8a2") != kp.address());
} }

32
test/libdevcrypto/SecretStore.cpp

@ -61,9 +61,9 @@ BOOST_AUTO_TEST_CASE(basic_tests)
SecretStore store(tmpDir.path()); SecretStore store(tmpDir.path());
h128 u = store.readKeyContent(js::write_string(o["json"], false)); h128 u = store.readKeyContent(js::write_string(o["json"], false));
cdebug << "read uuid" << u; cdebug << "read uuid" << u;
bytes s = store.secret(u, [&](){ return o["password"].get_str(); }); bytesSec s = store.secret(u, [&](){ return o["password"].get_str(); });
cdebug << "got secret" << toHex(s); cdebug << "got secret" << toHex(s.makeInsecure());
BOOST_REQUIRE_EQUAL(toHex(s), o["priv"].get_str()); BOOST_REQUIRE_EQUAL(toHex(s.makeInsecure()), o["priv"].get_str());
} }
} }
@ -98,7 +98,7 @@ BOOST_AUTO_TEST_CASE(import_key_from_file)
uuid = store.importKey(importFile); uuid = store.importKey(importFile);
BOOST_CHECK(!!uuid); BOOST_CHECK(!!uuid);
BOOST_CHECK(contentsString(importFile) == keyData); BOOST_CHECK(contentsString(importFile) == keyData);
BOOST_CHECK_EQUAL(priv, toHex(store.secret(uuid, [&](){ return password; }))); BOOST_CHECK_EQUAL(priv, toHex(store.secret(uuid, [&](){ return password; }).makeInsecure()));
BOOST_CHECK_EQUAL(store.keys().size(), 1); BOOST_CHECK_EQUAL(store.keys().size(), 1);
} }
fs::remove(importFile); fs::remove(importFile);
@ -106,7 +106,7 @@ BOOST_AUTO_TEST_CASE(import_key_from_file)
{ {
SecretStore store(storeDir.path()); SecretStore store(storeDir.path());
BOOST_CHECK_EQUAL(store.keys().size(), 1); BOOST_CHECK_EQUAL(store.keys().size(), 1);
BOOST_CHECK_EQUAL(priv, toHex(store.secret(uuid, [&](){ return password; }))); BOOST_CHECK_EQUAL(priv, toHex(store.secret(uuid, [&](){ return password; }).makeInsecure()));
} }
} }
@ -121,15 +121,15 @@ BOOST_AUTO_TEST_CASE(import_secret)
{ {
SecretStore store(storeDir.path()); SecretStore store(storeDir.path());
BOOST_CHECK_EQUAL(store.keys().size(), 0); BOOST_CHECK_EQUAL(store.keys().size(), 0);
uuid = store.importSecret(fromHex(priv), password); uuid = store.importSecret(bytesSec(fromHex(priv)), password);
BOOST_CHECK(!!uuid); BOOST_CHECK(!!uuid);
BOOST_CHECK_EQUAL(priv, toHex(store.secret(uuid, [&](){ return password; }))); BOOST_CHECK_EQUAL(priv, toHex(store.secret(uuid, [&](){ return password; }).makeInsecure()));
BOOST_CHECK_EQUAL(store.keys().size(), 1); BOOST_CHECK_EQUAL(store.keys().size(), 1);
} }
{ {
SecretStore store(storeDir.path()); SecretStore store(storeDir.path());
BOOST_CHECK_EQUAL(store.keys().size(), 1); BOOST_CHECK_EQUAL(store.keys().size(), 1);
BOOST_CHECK_EQUAL(priv, toHex(store.secret(uuid, [&](){ return password; }))); BOOST_CHECK_EQUAL(priv, toHex(store.secret(uuid, [&](){ return password; }).makeInsecure()));
} }
} }
} }
@ -145,12 +145,12 @@ BOOST_AUTO_TEST_CASE(wrong_password)
{ {
SecretStore store(storeDir.path()); SecretStore store(storeDir.path());
BOOST_CHECK_EQUAL(store.keys().size(), 0); BOOST_CHECK_EQUAL(store.keys().size(), 0);
uuid = store.importSecret(fromHex(priv), password); uuid = store.importSecret(bytesSec(fromHex(priv)), password);
BOOST_CHECK(!!uuid); BOOST_CHECK(!!uuid);
BOOST_CHECK_EQUAL(priv, toHex(store.secret(uuid, [&](){ return password; }))); BOOST_CHECK_EQUAL(priv, toHex(store.secret(uuid, [&](){ return password; }).makeInsecure()));
BOOST_CHECK_EQUAL(store.keys().size(), 1); BOOST_CHECK_EQUAL(store.keys().size(), 1);
// password will not be queried // password will not be queried
BOOST_CHECK_EQUAL(priv, toHex(store.secret(uuid, [&](){ return "abcdefg"; }))); BOOST_CHECK_EQUAL(priv, toHex(store.secret(uuid, [&](){ return "abcdefg"; }).makeInsecure()));
} }
{ {
SecretStore store(storeDir.path()); SecretStore store(storeDir.path());
@ -171,9 +171,9 @@ BOOST_AUTO_TEST_CASE(recode)
{ {
SecretStore store(storeDir.path()); SecretStore store(storeDir.path());
BOOST_CHECK_EQUAL(store.keys().size(), 0); BOOST_CHECK_EQUAL(store.keys().size(), 0);
uuid = store.importSecret(fromHex(priv), password); uuid = store.importSecret(bytesSec(fromHex(priv)), password);
BOOST_CHECK(!!uuid); BOOST_CHECK(!!uuid);
BOOST_CHECK_EQUAL(priv, toHex(store.secret(uuid, [&](){ return password; }))); BOOST_CHECK_EQUAL(priv, toHex(store.secret(uuid, [&](){ return password; }).makeInsecure()));
BOOST_CHECK_EQUAL(store.keys().size(), 1); BOOST_CHECK_EQUAL(store.keys().size(), 1);
} }
{ {
@ -182,16 +182,16 @@ BOOST_AUTO_TEST_CASE(recode)
BOOST_CHECK(store.secret(uuid, [&](){ return "abcdefg"; }).empty()); BOOST_CHECK(store.secret(uuid, [&](){ return "abcdefg"; }).empty());
BOOST_CHECK(store.recode(uuid, changedPassword, [&](){ return password; })); BOOST_CHECK(store.recode(uuid, changedPassword, [&](){ return password; }));
BOOST_CHECK_EQUAL(store.keys().size(), 1); BOOST_CHECK_EQUAL(store.keys().size(), 1);
BOOST_CHECK_EQUAL(priv, toHex(store.secret(uuid, [&](){ return changedPassword; }))); BOOST_CHECK_EQUAL(priv, toHex(store.secret(uuid, [&](){ return changedPassword; }).makeInsecure()));
store.clearCache(); store.clearCache();
BOOST_CHECK(store.secret(uuid, [&](){ return password; }).empty()); BOOST_CHECK(store.secret(uuid, [&](){ return password; }).empty());
BOOST_CHECK_EQUAL(priv, toHex(store.secret(uuid, [&](){ return changedPassword; }))); BOOST_CHECK_EQUAL(priv, toHex(store.secret(uuid, [&](){ return changedPassword; }).makeInsecure()));
} }
{ {
SecretStore store(storeDir.path()); SecretStore store(storeDir.path());
BOOST_CHECK_EQUAL(store.keys().size(), 1); BOOST_CHECK_EQUAL(store.keys().size(), 1);
BOOST_CHECK(store.secret(uuid, [&](){ return password; }).empty()); BOOST_CHECK(store.secret(uuid, [&](){ return password; }).empty());
BOOST_CHECK_EQUAL(priv, toHex(store.secret(uuid, [&](){ return changedPassword; }))); BOOST_CHECK_EQUAL(priv, toHex(store.secret(uuid, [&](){ return changedPassword; }).makeInsecure()));
} }
} }

39
test/libdevcrypto/crypto.cpp

@ -87,7 +87,7 @@ BOOST_AUTO_TEST_CASE(cryptopp_patch)
BOOST_AUTO_TEST_CASE(verify_secert) BOOST_AUTO_TEST_CASE(verify_secert)
{ {
h256 empty; Secret empty;
KeyPair kNot(empty); KeyPair kNot(empty);
BOOST_REQUIRE(!kNot.address()); BOOST_REQUIRE(!kNot.address());
KeyPair k(sha3(empty)); KeyPair k(sha3(empty));
@ -128,7 +128,7 @@ BOOST_AUTO_TEST_CASE(cryptopp_cryptopp_secp256k1libport)
bytes e(fromHex("0x01")); bytes e(fromHex("0x01"));
e.resize(32); e.resize(32);
int tests = 2; int tests = 2;
while (sha3(&e, &e), secret = sha3(secret.asBytes()), tests--) while (sha3(&e, &e), secret = sha3(secret), tests--)
{ {
KeyPair key(secret); KeyPair key(secret);
Public pkey = key.pub(); Public pkey = key.pub();
@ -145,7 +145,7 @@ BOOST_AUTO_TEST_CASE(cryptopp_cryptopp_secp256k1libport)
Integer r = s_params.ConvertElementToInteger(rp); Integer r = s_params.ConvertElementToInteger(rp);
Integer kInv = kInt.InverseMod(q); Integer kInv = kInt.InverseMod(q);
Integer s = (kInv * (Integer(secret.asBytes().data(), 32)*r + heInt)) % q; Integer s = (kInv * (Integer(secret.data(), 32) * r + heInt)) % q;
BOOST_REQUIRE(!!r && !!s); BOOST_REQUIRE(!!r && !!s);
Signature sig; Signature sig;
@ -311,7 +311,7 @@ BOOST_AUTO_TEST_CASE(ecies_kdf)
BOOST_REQUIRE(eKey1.toBytes() == eKey2.toBytes()); BOOST_REQUIRE(eKey1.toBytes() == eKey2.toBytes());
BOOST_REQUIRE(mKey1.toBytes() == mKey2.toBytes()); BOOST_REQUIRE(mKey1.toBytes() == mKey2.toBytes());
BOOST_REQUIRE((u256)h256(z1) > 0); BOOST_REQUIRE(!!z1);
BOOST_REQUIRE(z1 == z2); BOOST_REQUIRE(z1 == z2);
BOOST_REQUIRE(key1.size() > 0 && ((u512)h512(key1)) > 0); BOOST_REQUIRE(key1.size() > 0 && ((u512)h512(key1)) > 0);
@ -395,7 +395,7 @@ BOOST_AUTO_TEST_CASE(ecdh)
ECDH<ECP>::Domain dhA(s_curveOID); ECDH<ECP>::Domain dhA(s_curveOID);
Secret shared; Secret shared;
BOOST_REQUIRE(dhA.Agree(shared.data(), a.sec().data(), pubb)); BOOST_REQUIRE(dhA.Agree(shared.writable().data(), a.sec().data(), pubb));
BOOST_REQUIRE(shared); BOOST_REQUIRE(shared);
} }
@ -453,7 +453,7 @@ BOOST_AUTO_TEST_CASE(handshakeNew)
bytesRef nonce(&auth[Signature::size + h256::size + Public::size], h256::size); bytesRef nonce(&auth[Signature::size + h256::size + Public::size], h256::size);
crypto::ecdh::agree(nodeA.sec(), nodeB.pub(), ssA); crypto::ecdh::agree(nodeA.sec(), nodeB.pub(), ssA);
sign(eA.seckey(), ssA ^ nonceA).ref().copyTo(sig); sign(eA.seckey(), (ssA ^ nonceA).makeInsecure()).ref().copyTo(sig);
sha3(eA.pubkey().ref(), hepubk); sha3(eA.pubkey().ref(), hepubk);
nodeA.pub().ref().copyTo(pubk); nodeA.pub().ref().copyTo(pubk);
nonceA.ref().copyTo(nonce); nonceA.ref().copyTo(nonce);
@ -520,21 +520,21 @@ BOOST_AUTO_TEST_CASE(handshakeNew)
ess.ref().copyTo(keyMaterial.cropped(0, h256::size)); ess.ref().copyTo(keyMaterial.cropped(0, h256::size));
ssA.ref().copyTo(keyMaterial.cropped(h256::size, h256::size)); ssA.ref().copyTo(keyMaterial.cropped(h256::size, h256::size));
// auto token = sha3(ssA); // auto token = sha3(ssA);
aEncryptK = sha3(keyMaterial); aEncryptK = sha3Secure(keyMaterial);
aEncryptK.ref().copyTo(keyMaterial.cropped(h256::size, h256::size)); aEncryptK.ref().copyTo(keyMaterial.cropped(h256::size, h256::size));
aMacK = sha3(keyMaterial); aMacK = sha3Secure(keyMaterial);
keyMaterialBytes.resize(h256::size + authcipher.size()); keyMaterialBytes.resize(h256::size + authcipher.size());
keyMaterial.retarget(keyMaterialBytes.data(), keyMaterialBytes.size()); keyMaterial.retarget(keyMaterialBytes.data(), keyMaterialBytes.size());
(aMacK ^ nonceBAck).ref().copyTo(keyMaterial); (aMacK ^ nonceBAck).ref().copyTo(keyMaterial);
bytesConstRef(&authcipher).copyTo(keyMaterial.cropped(h256::size, authcipher.size())); bytesConstRef(&authcipher).copyTo(keyMaterial.cropped(h256::size, authcipher.size()));
aEgressMac = sha3(keyMaterial); aEgressMac = sha3Secure(keyMaterial);
keyMaterialBytes.resize(h256::size + ackcipher.size()); keyMaterialBytes.resize(h256::size + ackcipher.size());
keyMaterial.retarget(keyMaterialBytes.data(), keyMaterialBytes.size()); keyMaterial.retarget(keyMaterialBytes.data(), keyMaterialBytes.size());
(aMacK ^ nonceA).ref().copyTo(keyMaterial); (aMacK ^ nonceA).ref().copyTo(keyMaterial);
bytesConstRef(&ackcipher).copyTo(keyMaterial.cropped(h256::size, ackcipher.size())); bytesConstRef(&ackcipher).copyTo(keyMaterial.cropped(h256::size, ackcipher.size()));
aIngressMac = sha3(keyMaterial); aIngressMac = sha3Secure(keyMaterial);
} }
@ -573,7 +573,7 @@ BOOST_AUTO_TEST_CASE(handshakeNew)
Secret ss; Secret ss;
s_secp256k1.agree(nodeB.sec(), nodeAAuth, ss); s_secp256k1.agree(nodeB.sec(), nodeAAuth, ss);
eAAuth = recover(sigAuth, ss ^ nonceAAuth); eAAuth = recover(sigAuth, (ss ^ nonceAAuth).makeInsecure());
// todo: test when this fails; means remote is bad or packet bits were flipped // todo: test when this fails; means remote is bad or packet bits were flipped
BOOST_REQUIRE_EQUAL(heA, sha3(eAAuth)); BOOST_REQUIRE_EQUAL(heA, sha3(eAAuth));
BOOST_REQUIRE_EQUAL(eAAuth, eA.pubkey()); BOOST_REQUIRE_EQUAL(eAAuth, eA.pubkey());
@ -588,22 +588,22 @@ BOOST_AUTO_TEST_CASE(handshakeNew)
ess.ref().copyTo(keyMaterial.cropped(0, h256::size)); ess.ref().copyTo(keyMaterial.cropped(0, h256::size));
ssB.ref().copyTo(keyMaterial.cropped(h256::size, h256::size)); ssB.ref().copyTo(keyMaterial.cropped(h256::size, h256::size));
// auto token = sha3(ssA); // auto token = sha3(ssA);
bEncryptK = sha3(keyMaterial); bEncryptK = sha3Secure(keyMaterial);
bEncryptK.ref().copyTo(keyMaterial.cropped(h256::size, h256::size)); bEncryptK.ref().copyTo(keyMaterial.cropped(h256::size, h256::size));
bMacK = sha3(keyMaterial); bMacK = sha3Secure(keyMaterial);
// todo: replace nonceB with decrypted nonceB // todo: replace nonceB with decrypted nonceB
keyMaterialBytes.resize(h256::size + ackcipher.size()); keyMaterialBytes.resize(h256::size + ackcipher.size());
keyMaterial.retarget(keyMaterialBytes.data(), keyMaterialBytes.size()); keyMaterial.retarget(keyMaterialBytes.data(), keyMaterialBytes.size());
(bMacK ^ nonceAAuth).ref().copyTo(keyMaterial); (bMacK ^ nonceAAuth).ref().copyTo(keyMaterial);
bytesConstRef(&ackcipher).copyTo(keyMaterial.cropped(h256::size, ackcipher.size())); bytesConstRef(&ackcipher).copyTo(keyMaterial.cropped(h256::size, ackcipher.size()));
bEgressMac = sha3(keyMaterial); bEgressMac = sha3Secure(keyMaterial);
keyMaterialBytes.resize(h256::size + authcipher.size()); keyMaterialBytes.resize(h256::size + authcipher.size());
keyMaterial.retarget(keyMaterialBytes.data(), keyMaterialBytes.size()); keyMaterial.retarget(keyMaterialBytes.data(), keyMaterialBytes.size());
(bMacK ^ nonceB).ref().copyTo(keyMaterial); (bMacK ^ nonceB).ref().copyTo(keyMaterial);
bytesConstRef(&authcipher).copyTo(keyMaterial.cropped(h256::size, authcipher.size())); bytesConstRef(&authcipher).copyTo(keyMaterial.cropped(h256::size, authcipher.size()));
bIngressMac = sha3(keyMaterial); bIngressMac = sha3Secure(keyMaterial);
} }
BOOST_REQUIRE_EQUAL(aEncryptK, bEncryptK); BOOST_REQUIRE_EQUAL(aEncryptK, bEncryptK);
@ -617,7 +617,7 @@ BOOST_AUTO_TEST_CASE(handshakeNew)
BOOST_AUTO_TEST_CASE(ecies_aes128_ctr_unaligned) BOOST_AUTO_TEST_CASE(ecies_aes128_ctr_unaligned)
{ {
h128 encryptK(sha3("..."), h128::AlignLeft); SecureFixedHash<16> encryptK(sha3("..."), h128::AlignLeft);
h256 egressMac(sha3("+++")); h256 egressMac(sha3("+++"));
// TESTING: send encrypt magic sequence // TESTING: send encrypt magic sequence
bytes magic {0x22,0x40,0x08,0x91}; bytes magic {0x22,0x40,0x08,0x91};
@ -629,16 +629,17 @@ BOOST_AUTO_TEST_CASE(ecies_aes128_ctr_unaligned)
egressMac.ref().copyTo(bytesRef(&magicCipherAndMac).cropped(magicCipherAndMac.size() - 32, 32)); egressMac.ref().copyTo(bytesRef(&magicCipherAndMac).cropped(magicCipherAndMac.size() - 32, 32));
bytesConstRef cipher(&magicCipherAndMac[0], magicCipherAndMac.size() - 32); bytesConstRef cipher(&magicCipherAndMac[0], magicCipherAndMac.size() - 32);
bytes plaintext = decryptSymNoAuth(encryptK, h128(), cipher); bytes plaintext = decryptSymNoAuth(encryptK, h128(), cipher).makeInsecure();
plaintext.resize(magic.size()); plaintext.resize(magic.size());
// @alex @subtly TODO: FIX: this check is pointless with the above line.
BOOST_REQUIRE(plaintext.size() > 0); BOOST_REQUIRE(plaintext.size() > 0);
BOOST_REQUIRE(magic == plaintext); BOOST_REQUIRE(magic == plaintext);
} }
BOOST_AUTO_TEST_CASE(ecies_aes128_ctr) BOOST_AUTO_TEST_CASE(ecies_aes128_ctr)
{ {
h128 k(sha3("0xAAAA"), h128::AlignLeft); SecureFixedHash<16> k(sha3("0xAAAA"), h128::AlignLeft);
string m = "AAAAAAAAAAAAAAAA"; string m = "AAAAAAAAAAAAAAAA";
bytesConstRef msg((byte*)m.data(), m.size()); bytesConstRef msg((byte*)m.data(), m.size());
@ -646,7 +647,7 @@ BOOST_AUTO_TEST_CASE(ecies_aes128_ctr)
h128 iv; h128 iv;
tie(ciphertext, iv) = encryptSymNoAuth(k, msg); tie(ciphertext, iv) = encryptSymNoAuth(k, msg);
bytes plaintext = decryptSymNoAuth(k, iv, &ciphertext); bytes plaintext = decryptSymNoAuth(k, iv, &ciphertext).makeInsecure();
BOOST_REQUIRE_EQUAL(asString(plaintext), m); BOOST_REQUIRE_EQUAL(asString(plaintext), m);
} }

14
test/libethcore/commonjs.cpp

@ -32,8 +32,8 @@ BOOST_AUTO_TEST_CASE(jsToPublic)
{ {
cnote << "Testing jsToPublic..."; cnote << "Testing jsToPublic...";
KeyPair kp = KeyPair::create(); KeyPair kp = KeyPair::create();
string string = toJS(kp.pub()); string s = toJS(kp.pub());
Public pub = dev::jsToPublic(string); Public pub = dev::jsToPublic(s);
BOOST_CHECK_EQUAL(kp.pub(), pub); BOOST_CHECK_EQUAL(kp.pub(), pub);
} }
@ -41,8 +41,8 @@ BOOST_AUTO_TEST_CASE(jsToAddress)
{ {
cnote << "Testing jsToPublic..."; cnote << "Testing jsToPublic...";
KeyPair kp = KeyPair::create(); KeyPair kp = KeyPair::create();
string string = toJS(kp.address()); string s = toJS(kp.address());
Address address = dev::jsToAddress(string); Address address = dev::jsToAddress(s);
BOOST_CHECK_EQUAL(kp.address(), address); BOOST_CHECK_EQUAL(kp.address(), address);
} }
@ -50,9 +50,9 @@ BOOST_AUTO_TEST_CASE(jsToSecret)
{ {
cnote << "Testing jsToPublic..."; cnote << "Testing jsToPublic...";
KeyPair kp = KeyPair::create(); KeyPair kp = KeyPair::create();
string string = toJS(kp.secret()); string s = toJS(kp.secret().makeInsecure());
Secret secret = dev::jsToSecret(string); Secret secret = dev::jsToSecret(s);
BOOST_CHECK_EQUAL(kp.secret(), secret); BOOST_CHECK_EQUAL(kp.secret().makeInsecure(), secret.makeInsecure());
} }
BOOST_AUTO_TEST_SUITE_END() BOOST_AUTO_TEST_SUITE_END()

Loading…
Cancel
Save