[ Web Proxy ]
URL:
Viewing: https://raw.githubusercontent.com/cheny56/cpp-ethereum/develop/libdevcrypto/SecretStore.cpp [Back]  [Original]

/*
	This file is part of cpp-ethereum.

	cpp-ethereum is free software: you can redistribute it and/or modify
	it under the terms of the GNU General Public License as published by
	the Free Software Foundation, either version 3 of the License, or
	(at your option) any later version.

	cpp-ethereum is distributed in the hope that it will be useful,
	but WITHOUT ANY WARRANTY; without even the implied warranty of
	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
	GNU General Public License for more details.

	You should have received a copy of the GNU General Public License
	along with cpp-ethereum.  If not, see .
*/
/** @file SecretStore.cpp
 * @author Gav Wood 
 * @date 2014
 */

#include "SecretStore.h"
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
using namespace std;
using namespace dev;
namespace js = json_spirit;
namespace fs = boost::filesystem;

static const int c_keyFileVersion = 3;

/// Upgrade the json-format to the current version.
static js::mValue upgraded(string const& _s)
{
	js::mValue v;
	js::read_string(_s, v);
	if (v.type() != js::obj_type)
		return js::mValue();
	js::mObject ret = v.get_obj();
	unsigned version = ret.count("Version") ? stoi(ret["Version"].get_str()) : ret.count("version") ? ret["version"].get_int() : 0;
	if (version == 1)
	{
		// upgrade to version 2
		js::mObject old;
		swap(old, ret);

		ret["id"] = old["Id"];
		js::mObject c;
		c["ciphertext"] = old["Crypto"].get_obj()["CipherText"];
		c["cipher"] = "aes-128-cbc";
		{
			js::mObject cp;
			cp["iv"] = old["Crypto"].get_obj()["IV"];
			c["cipherparams"] = cp;
		}
		c["kdf"] = old["Crypto"].get_obj()["KeyHeader"].get_obj()["Kdf"];
		{
			js::mObject kp;
			kp["salt"] = old["Crypto"].get_obj()["Salt"];
			for (auto const& i: old["Crypto"].get_obj()["KeyHeader"].get_obj()["KdfParams"].get_obj())
				if (i.first != "SaltLen")
					kp[boost::to_lower_copy(i.first)] = i.second;
			c["kdfparams"] = kp;
		}
		c["sillymac"] = old["Crypto"].get_obj()["MAC"];
		c["sillymacjson"] = _s;
		ret["crypto"] = c;
		version = 2;
	}
	if (ret.count("Crypto") && !ret.count("crypto"))
	{
		ret["crypto"] = ret["Crypto"];
		ret.erase("Crypto");
	}
	if (version == 2)
	{
		ret["crypto"].get_obj()["cipher"] = "aes-128-ctr";
		ret["crypto"].get_obj()["compat"] = "2";
		version = 3;
	}
	if (version == c_keyFileVersion)
		return ret;
	return js::mValue();
}

SecretStore::SecretStore(fs::path const& _path): m_path(_path)
{
	load();
}

void SecretStore::setPath(fs::path const& _path)
{
	m_path = _path;
	load();
}

bytesSec SecretStore::secret(h128 const& _uuid, function const& _pass, bool _useCache) const
{
    auto rit = m_cached.find(_uuid);
    if (_useCache && rit != m_cached.end())
        return rit->second;
    auto it = m_keys.find(_uuid);
    bytesSec key;
    if (it != m_keys.end())
    {
        key = bytesSec(decrypt(it->second.encryptedKey, _pass()));
        if (!key.empty())
        {
            m_cached[_uuid] = key;
            // TODO: Fix constness.
            const_cast(this)->noteAddress(_uuid, toAddress(Secret{key}));
        }
    }
    return key;
}

bytesSec SecretStore::secret(Address const& _address, function const& _pass) const
{
	bytesSec ret;
	if (auto k = key(_address))
		ret = bytesSec(decrypt(k->second.encryptedKey, _pass()));
	return ret;
}

bytesSec SecretStore::secret(string const& _content, string const& _pass)
{
	try
	{
		js::mValue u = upgraded(_content);
		if (u.type() != js::obj_type)
			return bytesSec();
		return decrypt(js::write_string(u.get_obj()["crypto"], false), _pass);
	}
	catch (...)
	{
		return bytesSec();
	}
}

h128 SecretStore::importSecret(bytesSec const& _s, string const& _pass)
{
	h128 r = h128::random();
	EncryptedKey key{encrypt(_s.ref(), _pass), toUUID(r), KeyPair(Secret(_s)).address()};
	m_cached[r] = _s;
	m_keys[r] = move(key);
	save();
	return r;
}

h128 SecretStore::importSecret(bytesConstRef _s, string const& _pass)
{
	h128 r = h128::random();
	EncryptedKey key{encrypt(_s, _pass), toUUID(r), KeyPair(Secret(_s)).address()};
	m_cached[r] = bytesSec(_s);
	m_keys[r] = move(key);
	save();
	return r;
}

void SecretStore::kill(h128 const& _uuid)
{
	m_cached.erase(_uuid);
	if (m_keys.count(_uuid))
	{
		fs::remove(m_keys[_uuid].filename);
		m_keys.erase(_uuid);
	}
}

void SecretStore::clearCache() const
{
	m_cached.clear();
}

void SecretStore::save(fs::path const& _keysPath)
{
	fs::create_directories(_keysPath);
	DEV_IGNORE_EXCEPTIONS(fs::permissions(_keysPath, fs::owner_all));
	for (auto& k: m_keys)
	{
		string uuid = toUUID(k.first);
		fs::path filename = (_keysPath / uuid).string() + ".json";
		js::mObject v;
		js::mValue crypto;
		js::read_string(k.second.encryptedKey, crypto);
		v["address"] = k.second.address.hex();
		v["crypto"] = crypto;
		v["id"] = uuid;
		v["version"] = c_keyFileVersion;
		writeFile(filename, js::write_string(js::mValue(v), true));
		swap(k.second.filename, filename);
		if (!filename.empty() && !fs::equivalent(filename, k.second.filename))
			fs::remove(filename);
	}
}

bool SecretStore::noteAddress(h128 const& _uuid, Address const& _address)
{
    auto it = m_keys.find(_uuid);
    if (it != m_keys.end() && it->second.address == ZeroAddress)
    {
        it->second.address = _address;
        return true;
    }
    return false;
}

void SecretStore::load(fs::path const& _keysPath)
{
	try
	{
		for (fs::directory_iterator it(_keysPath); it != fs::directory_iterator(); ++it)
			if (fs::is_regular_file(it->path()))
				readKey(it->path().string(), true);
	}
	catch (...) {}
}

h128 SecretStore::readKey(fs::path const& _file, bool _takeFileOwnership)
{
	ctrace 

Web Proxy Viewer  |  New URL  |  Original Page