diff --git a/exp/main.cpp b/exp/main.cpp index 4fff5b63a..5a57c091e 100644 --- a/exp/main.cpp +++ b/exp/main.cpp @@ -65,6 +65,7 @@ namespace fs = boost::filesystem; #if 1 inline h128 fromUUID(std::string const& _uuid) { return h128(boost::replace_all_copy(_uuid, "-", "")); } +inline std::string toUUID(h128 const& _uuid) { std::string ret = toHex(_uuid.ref()); for (unsigned i: {20, 16, 12, 8}) ret.insert(ret.begin() + i, '-'); return ret; } class KeyManager: public Worker { @@ -74,31 +75,48 @@ public: Secret secret(h128 const& _uuid, function const& _pass) { - auto rit = m_ready.find(_uuid); - if (rit != m_ready.end()) + auto rit = m_cached.find(_uuid); + if (rit != m_cached.end()) return rit->second; auto it = m_keys.find(_uuid); if (it == m_keys.end()) return Secret(); Secret ret(decrypt(it->second, _pass())); if (ret) - m_ready[_uuid] = ret; + m_cached[_uuid] = ret; return ret; } - h128 create(std::string const& _pass) + h128 import(Secret const& _s, std::string const& _pass) { - auto s = Secret::random(); - h128 r(sha3(s)); - m_ready[r] = s; - m_keys[r] = encrypt(s.asBytes(), _pass); + h128 r(sha3(_s)); + m_cached[r] = _s; + m_keys[r] = encrypt(_s.asBytes(), _pass); + writeKeys(); return r; } + h128 create(std::string const& _pass) + { + return import(Secret::random(), _pass); + } + + void clearCache() const { m_cached.clear(); } + private: void writeKeys(std::string const& _keysPath = getDataDir("web3") + "/keys") { - (void)_keysPath; + fs::path p(_keysPath); + boost::filesystem::create_directories(p); + for (auto const& k: m_keys) + { + std::string uuid = toUUID(k.first); + js::mObject v; + v["crypto"] = k.second; + v["id"] = uuid; + v["version"] = 2; + writeFile((p / uuid).string() + ".json", js::write_string(js::mValue(v), true)); + } } void readKeys(std::string const& _keysPath = getDataDir("web3") + "/keys") @@ -126,9 +144,42 @@ private: static js::mValue encrypt(bytes const& _v, std::string const& _pass) { - (void)_v; - (void)_pass; - return js::mValue(); + js::mObject ret; + + // KDF info + unsigned dklen = 16; + unsigned iterations = 262144; + bytes salt = h256::random().asBytes(); + ret["kdf"] = "pbkdf2"; + { + js::mObject params; + params["prf"] = "hmac-sha256"; + params["c"] = (int)iterations; + params["salt"] = toHex(salt); + params["dklen"] = (int)dklen; + ret["kdfparams"] = params; + } + bytes derivedKey = pbkdf2(_pass, salt, iterations, dklen); + + // cipher info + ret["cipher"] = "aes-128-cbc"; + h128 key(sha3(h128(derivedKey, h128::AlignRight)), h128::AlignRight); + h128 iv = h128::random(); + { + js::mObject params; + params["iv"] = toHex(iv.ref()); + ret["cipherparams"] = params; + } + + // cipher text + bytes cipherText = encryptSymNoAuth(key, iv, &_v); + ret["ciphertext"] = toHex(cipherText); + + // and mac. + h256 mac = sha3(bytesConstRef(&derivedKey).cropped(derivedKey.size() - 16).toBytes() + cipherText); + ret["mac"] = toHex(mac.ref()); + + return ret; } static bytes decrypt(js::mValue const& _v, std::string const& _pass) @@ -167,32 +218,29 @@ private: } // decrypt - bytes ret; if (o["cipher"].get_str() == "aes-128-cbc") { auto params = o["cipherparams"].get_obj(); h128 key(sha3(h128(derivedKey, h128::AlignRight)), h128::AlignRight); h128 iv(params["iv"].get_str()); - decryptSymNoAuth(key, iv, &cipherText, ret); + return decryptSymNoAuth(key, iv, &cipherText); } else { cwarn << "Unknown cipher" << o["cipher"].get_str() << "not supported."; return bytes(); } - - return ret; } - mutable std::map m_ready; + mutable std::map m_cached; std::map m_keys; }; int main() { - cdebug << toHex(pbkdf2("password", asBytes("salt"), 1, 20)); KeyManager keyman; - cdebug << "Secret key for 0498f19a-59db-4d54-ac95-33901b4f1870 is " << keyman.secret(fromUUID("0498f19a-59db-4d54-ac95-33901b4f1870"), [](){ return "foo"; }); + auto id = fromUUID("441193ae-a767-f1c3-48ba-dd6610db5ed0"); + cdebug << "Secret key for " << toUUID(id) << "is" << keyman.secret(id, [](){ return "bar"; }); } #elif 0 diff --git a/libdevcore/FixedHash.h b/libdevcore/FixedHash.h index 2cf81cb77..3d7a830e6 100644 --- a/libdevcore/FixedHash.h +++ b/libdevcore/FixedHash.h @@ -113,6 +113,9 @@ public: /// @returns an abridged version of the hash as a user-readable hex string. std::string abridged() const { return toHex(ref().cropped(0, 4)) + "\342\200\246"; } + /// @returns an abridged version of the hash as a user-readable hex string. + std::string hex() const { return toHex(ref()); } + /// @returns a mutable byte vector_ref to the object's data. bytesRef ref() { return bytesRef(m_data.data(), N); } diff --git a/libdevcrypto/Common.cpp b/libdevcrypto/Common.cpp index c3133cca7..e4f383a38 100644 --- a/libdevcrypto/Common.cpp +++ b/libdevcrypto/Common.cpp @@ -112,51 +112,47 @@ bool dev::decryptSym(Secret const& _k, bytesConstRef _cipher, bytes& o_plain) return decrypt(_k, _cipher, o_plain); } -h128 dev::encryptSymNoAuth(h128 const& _k, bytesConstRef _plain, bytes& o_cipher) +std::pair dev::encryptSymNoAuth(h128 const& _k, bytesConstRef _plain) { h128 iv(Nonce::get()); - return encryptSymNoAuth(_k, _plain, o_cipher, iv); + return make_pair(encryptSymNoAuth(_k, iv, _plain), iv); } -h128 dev::encryptSymNoAuth(h128 const& _k, bytesConstRef _plain, bytes& o_cipher, h128 const& _iv) +bytes dev::encryptSymNoAuth(h128 const& _k, h128 const& _iv, bytesConstRef _plain) { - o_cipher.resize(_plain.size()); - const int c_aesKeyLen = 16; SecByteBlock key(_k.data(), c_aesKeyLen); try { CTR_Mode::Encryption e; e.SetKeyWithIV(key, key.size(), _iv.data()); - e.ProcessData(o_cipher.data(), _plain.data(), _plain.size()); - return _iv; + bytes ret(_plain.size()); + e.ProcessData(ret.data(), _plain.data(), _plain.size()); + return ret; } catch (CryptoPP::Exception& _e) { cerr << _e.what() << endl; - o_cipher.resize(0); - return h128(); + return bytes(); } } -bool dev::decryptSymNoAuth(h128 const& _k, h128 const& _iv, bytesConstRef _cipher, bytes& o_plaintext) +bytes dev::decryptSymNoAuth(h128 const& _k, h128 const& _iv, bytesConstRef _cipher) { - o_plaintext.resize(_cipher.size()); - const size_t c_aesKeyLen = 16; SecByteBlock key(_k.data(), c_aesKeyLen); try { CTR_Mode::Decryption d; d.SetKeyWithIV(key, key.size(), _iv.data()); - d.ProcessData(o_plaintext.data(), _cipher.data(), _cipher.size()); - return true; + bytes ret(_cipher.size()); + d.ProcessData(ret.data(), _cipher.data(), _cipher.size()); + return ret; } catch (CryptoPP::Exception& _e) { cerr << _e.what() << endl; - o_plaintext.resize(0); - return false; + return bytes(); } } diff --git a/libdevcrypto/Common.h b/libdevcrypto/Common.h index 3b243d319..48660bb96 100644 --- a/libdevcrypto/Common.h +++ b/libdevcrypto/Common.h @@ -103,13 +103,13 @@ void encryptECIES(Public const& _k, bytesConstRef _plain, bytes& o_cipher); bool decryptECIES(Secret const& _k, bytesConstRef _cipher, bytes& o_plaintext); /// Encrypts payload with random IV/ctr using AES128-CTR. -h128 encryptSymNoAuth(h128 const& _k, bytesConstRef _plain, bytes& o_cipher); +std::pair encryptSymNoAuth(h128 const& _k, bytesConstRef _plain); /// Encrypts payload with specified IV/ctr using AES128-CTR. -h128 encryptSymNoAuth(h128 const& _k, bytesConstRef _plain, bytes& o_cipher, h128 const& _iv); - +bytes encryptSymNoAuth(h128 const& _k, h128 const& _iv, bytesConstRef _plain); + /// Decrypts payload with specified IV/ctr using AES128-CTR. -bool decryptSymNoAuth(h128 const& _k, h128 const& _iv, bytesConstRef _cipher, bytes& o_plaintext); +bytes decryptSymNoAuth(h128 const& _k, h128 const& _iv, bytesConstRef _cipher); /// Recovers Public key from signed message hash. Public recover(Signature const& _sig, h256 const& _hash); diff --git a/libdevcrypto/CryptoPP.cpp b/libdevcrypto/CryptoPP.cpp index e89857502..b701fed8d 100644 --- a/libdevcrypto/CryptoPP.cpp +++ b/libdevcrypto/CryptoPP.cpp @@ -78,8 +78,7 @@ void Secp256k1::encryptECIES(Public const& _k, bytes& io_cipher) bytes mKey(32); ctx.Final(mKey.data()); - bytes cipherText; - encryptSymNoAuth(h128(eKey), bytesConstRef(&io_cipher), cipherText, h128()); + bytes cipherText = encryptSymNoAuth(h128(eKey), h128(), bytesConstRef(&io_cipher)); if (cipherText.empty()) return; @@ -139,7 +138,7 @@ bool Secp256k1::decryptECIES(Secret const& _k, bytes& io_text) if (mac[i] != msgMac[i]) return false; - decryptSymNoAuth(h128(eKey), iv, cipherNoIV, plain); + plain = decryptSymNoAuth(h128(eKey), iv, cipherNoIV); io_text.resize(plain.size()); io_text.swap(plain); diff --git a/test/libdevcrypto/crypto.cpp b/test/libdevcrypto/crypto.cpp index 96826bdf9..88ff98965 100644 --- a/test/libdevcrypto/crypto.cpp +++ b/test/libdevcrypto/crypto.cpp @@ -593,15 +593,14 @@ BOOST_AUTO_TEST_CASE(ecies_aes128_ctr_unaligned) // TESTING: send encrypt magic sequence bytes magic {0x22,0x40,0x08,0x91}; bytes magicCipherAndMac; - encryptSymNoAuth(encryptK, &magic, magicCipherAndMac, h128()); + magicCipherAndMac = encryptSymNoAuth(encryptK, h128(), &magic); magicCipherAndMac.resize(magicCipherAndMac.size() + 32); sha3mac(egressMac.ref(), &magic, egressMac.ref()); egressMac.ref().copyTo(bytesRef(&magicCipherAndMac).cropped(magicCipherAndMac.size() - 32, 32)); - bytes plaintext; bytesConstRef cipher(&magicCipherAndMac[0], magicCipherAndMac.size() - 32); - decryptSymNoAuth(encryptK, h128(), cipher, plaintext); + bytes plaintext = decryptSymNoAuth(encryptK, h128(), cipher); plaintext.resize(magic.size()); BOOST_REQUIRE(plaintext.size() > 0); @@ -615,10 +614,10 @@ BOOST_AUTO_TEST_CASE(ecies_aes128_ctr) bytesConstRef msg((byte*)m.data(), m.size()); bytes ciphertext; - auto iv = encryptSymNoAuth(k, msg, ciphertext); + h128 iv; + tie(ciphertext, iv) = encryptSymNoAuth(k, msg); - bytes plaintext; - decryptSymNoAuth(k, iv, &ciphertext, plaintext); + bytes plaintext = decryptSymNoAuth(k, iv, &ciphertext); BOOST_REQUIRE_EQUAL(asString(plaintext), m); }