예제 #1
0
void ECDHEKeyExchange::exchange(bytes& o_exchange)
{
	if (!m_ephemeralSecret)
		// didn't agree on public remote
		BOOST_THROW_EXCEPTION(InvalidState());

	// The key exchange payload is in two parts and is encrypted
	// using ephemeral keypair.
	//
	// The first part is the 'prefix' which is a zero-knowledge proof
	// allowing the remote to resume or emplace a previous session.
	// If a session previously exists:
	//	prefix is sha3(token) // todo: ephemeral entropy from both sides
	// If a session doesn't exist:
	//	prefix is sha3(m_ephemeralSecret)
	//
	// The second part is encrypted using the public key which relates to the prefix.
	
	Public encpk = m_known.first ? m_known.first : m_remoteEphemeral;
	bytes exchange(encpk.asBytes());
	
	// This is the public key which we would like the remote to use,
	// which maybe different than the previously-known public key.
	//
	// Here we should pick an appropriate alias or generate a new one,
	// but for now, we use static alias passed to constructor.
	//
	Public p = toPublic(m_alias.m_secret);
	exchange.resize(exchange.size() + sizeof(p));
	memcpy(&exchange[exchange.size() - sizeof(p)], p.data(), sizeof(p));
	
	// protocol parameters; should be fixed size
	bytes v(1, 0x80);
	exchange.resize(exchange.size() + v.size());
	memcpy(&exchange[exchange.size() - v.size()], v.data(), v.size());
	
	h256 auth;
	sha3mac(m_alias.m_secret.ref(), m_ephemeralSecret.ref(), auth.ref());
	Signature sig = s_secp256k1.sign(m_alias.m_secret, auth);
	exchange.resize(exchange.size() + sizeof(sig));
	memcpy(&exchange[exchange.size() - sizeof(sig)], sig.data(), sizeof(sig));
	
	aes::AuthenticatedStream aes(aes::Encrypt, m_ephemeralSecret, 0);
	h256 prefix(sha3(m_known.second ? m_known.second : (h256)m_remoteEphemeral));
	aes.update(prefix.ref());
	
	s_secp256k1.encrypt(encpk, exchange);
	aes.update(&exchange);

	aes.streamOut(o_exchange);
}
예제 #2
0
bool ecdh::agree(Secret const& _s, Public const& _r, Secret& o_s) noexcept
{
    auto* ctx = getCtx();
    static_assert(sizeof(Secret) == 32, "Invalid Secret type size");
    secp256k1_pubkey rawPubkey;
    std::array<byte, 65> serializedPubKey{{0x04}};
    std::copy(_r.asArray().begin(), _r.asArray().end(), serializedPubKey.begin() + 1);
    if (!secp256k1_ec_pubkey_parse(ctx, &rawPubkey, serializedPubKey.data(), serializedPubKey.size()))
        return false;  // Invalid public key.
    // FIXME: We should verify the public key when constructed, maybe even keep
    //        secp256k1_pubkey as the internal data of Public.
    std::array<byte, 33> compressedPoint;
    if (!secp256k1_ecdh_raw(ctx, compressedPoint.data(), &rawPubkey, _s.data()))
        return false;  // Invalid secret key.
    std::copy(compressedPoint.begin() + 1, compressedPoint.end(), o_s.writable().data());
    return true;
}
예제 #3
0
void Secp256k1PP::agree(Secret const& _s, Public const& _r, Secret& o_s)
{
	// TODO: mutex ASN1::secp256k1() singleton
	// Creating Domain is non-const for m_oid and m_oid is not thread-safe
	ECDH<ECP>::Domain d(ASN1::secp256k1());
	assert(d.AgreedValueLength() == sizeof(o_s));
	byte remote[65] = {0x04};
	memcpy(&remote[1], _r.data(), 64);
	d.Agree(o_s.writable().data(), _s.data(), remote);
}
예제 #4
0
Public Secp256k1PP::recover(Signature _signature, bytesConstRef _message)
{
	Public recovered;
	
	Integer r(_signature.data(), 32);
	Integer s(_signature.data()+32, 32);
	// cryptopp encodes sign of y as 0x02/0x03 instead of 0/1 or 27/28
	byte encodedpoint[33];
	encodedpoint[0] = _signature[64] | 2;
	memcpy(&encodedpoint[1], _signature.data(), 32);
	
	ECP::Element x;
	{
		m_curve.DecodePoint(x, encodedpoint, 33);
		if (!m_curve.VerifyPoint(x))
			return recovered;
	}
	
//	if (_signature[64] & 2)
//	{
//		r += m_q;
//		Guard l(x_params);
//		if (r >= m_params.GetMaxExponent())
//			return recovered;
//	}
	
	Integer z(_message.data(), 32);
	Integer rn = r.InverseMod(m_q);
	Integer u1 = m_q - (rn.Times(z)).Modulo(m_q);
	Integer u2 = (rn.Times(s)).Modulo(m_q);
	
	ECP::Point p;
	byte recoveredbytes[65];
	{
		// todo: make generator member
		p = m_curve.CascadeMultiply(u2, x, u1, m_params.GetSubgroupGenerator());
		if (p.identity)
			return Public();
		m_curve.EncodePoint(recoveredbytes, p, false);
	}
	memcpy(recovered.data(), &recoveredbytes[1], 64);
	return recovered;
}
예제 #5
0
void Secp256k1PP::exportPublicKey(CryptoPP::DL_PublicKey_EC<CryptoPP::ECP> const& _k, Public& o_p)
{
	bytes prefixedKey(_k.GetGroupParameters().GetEncodedElementSize(true));
	
	{
		Guard l(x_params);
		m_params.GetCurve().EncodePoint(prefixedKey.data(), _k.GetPublicElement(), false);
		assert(Public::size + 1 == _k.GetGroupParameters().GetEncodedElementSize(true));
	}

	memcpy(o_p.data(), &prefixedKey[1], Public::size);
}
예제 #6
0
void NodeTable::noteActiveNode(Public const& _pubk, bi::udp::endpoint const& _endpoint)
{
	if (_pubk == m_node.address())
		return;
	
	clog(NodeTableNote) << "Noting active node:" << _pubk.abridged() << _endpoint.address().to_string() << ":" << _endpoint.port();

	shared_ptr<NodeEntry> node(addNode(_pubk, _endpoint, bi::tcp::endpoint(_endpoint.address(), _endpoint.port())));

	// TODO p2p: old bug (maybe gone now) sometimes node is nullptr here
	if (!!node)
	{
		shared_ptr<NodeEntry> contested;
		{
			Guard l(x_state);
			NodeBucket& s = bucket_UNSAFE(node.get());
			s.nodes.remove_if([&node](weak_ptr<NodeEntry> n)
			{
				if (n.lock() == node)
					return true;
				return false;
			});
			
			if (s.nodes.size() >= s_bucketSize)
			{
				// It's only contested iff nodeentry exists
				contested = s.nodes.front().lock();
				if (!contested)
				{
					s.nodes.pop_front();
					s.nodes.push_back(node);
					s.touch();
				}
			}
			else
			{
				s.nodes.push_back(node);
				s.touch();
			}
		}
		
		if (contested)
			evict(contested, node);
	}
}
예제 #7
0
Address dev::toAddress(Public const& _public)
{
	return right160(sha3(_public.ref()));
}