|
|
@ -18,7 +18,7 @@ |
|
|
|
* @author Alex Leverington <nessence@gmail.com> |
|
|
|
* @date 2014 |
|
|
|
* |
|
|
|
* Shared EC classes and functions. |
|
|
|
* ECDSA, ECIES |
|
|
|
*/ |
|
|
|
|
|
|
|
#pragma warning(push) |
|
|
@ -32,25 +32,44 @@ |
|
|
|
#include <files.h> |
|
|
|
#pragma warning(pop) |
|
|
|
#pragma GCC diagnostic pop |
|
|
|
#include <secp256k1/secp256k1.h> |
|
|
|
#include "CryptoPP.h" |
|
|
|
#include "SHA3.h" |
|
|
|
#include "SHA3MAC.h" |
|
|
|
#include "EC.h" |
|
|
|
|
|
|
|
// CryptoPP and dev conflict so dev and pp namespace are used explicitly
|
|
|
|
static_assert(dev::Secret::size == 32, "Secret key must be 32 bytes."); |
|
|
|
static_assert(dev::Public::size == 64, "Public key must be 64 bytes."); |
|
|
|
static_assert(dev::Signature::size == 65, "Signature must be 65 bytes."); |
|
|
|
|
|
|
|
using namespace std; |
|
|
|
using namespace dev; |
|
|
|
using namespace dev::crypto; |
|
|
|
using namespace CryptoPP; |
|
|
|
using namespace pp; |
|
|
|
|
|
|
|
void crypto::toPublic(Secret const& _s, Public& o_public) |
|
|
|
{ |
|
|
|
exponentToPublic(Integer(_s.data(),sizeof(_s)), o_public); |
|
|
|
} |
|
|
|
|
|
|
|
void crypto::encrypt(Public const& _key, bytes& io_cipher) |
|
|
|
h256 crypto::kdf(Secret const& _priv, h256 const& _hash) |
|
|
|
{ |
|
|
|
h256 s; |
|
|
|
sha3mac(Sec::getNonce().ref(), _priv.ref(), s.ref()); |
|
|
|
assert(s); |
|
|
|
return sha3((_hash ^ s).asBytes()); |
|
|
|
} |
|
|
|
|
|
|
|
void crypto::encrypt(Public const& _k, bytes& io_cipher) |
|
|
|
{ |
|
|
|
ECIES<ECP>::Encryptor e; |
|
|
|
pp::initializeEncryptor(_key, e); |
|
|
|
initializeDLScheme(_k, e); |
|
|
|
size_t plen = io_cipher.size(); |
|
|
|
bytes c; |
|
|
|
c.resize(e.CiphertextLength(plen)); |
|
|
|
// todo: use StringSource with io_cipher as input and output.
|
|
|
|
e.Encrypt(pp::PRNG, io_cipher.data(), plen, c.data()); |
|
|
|
e.Encrypt(PRNG, io_cipher.data(), plen, c.data()); |
|
|
|
memset(io_cipher.data(), 0, io_cipher.size()); |
|
|
|
io_cipher = std::move(c); |
|
|
|
} |
|
|
@ -58,12 +77,12 @@ void crypto::encrypt(Public const& _key, bytes& io_cipher) |
|
|
|
void crypto::decrypt(Secret const& _k, bytes& io_text) |
|
|
|
{ |
|
|
|
CryptoPP::ECIES<CryptoPP::ECP>::Decryptor d; |
|
|
|
pp::initializeDecryptor(_k, d); |
|
|
|
initializeDLScheme(_k, d); |
|
|
|
size_t clen = io_text.size(); |
|
|
|
bytes p; |
|
|
|
p.resize(d.MaxPlaintextLength(io_text.size())); |
|
|
|
// todo: use StringSource with io_text as input and output.
|
|
|
|
DecodingResult r = d.Decrypt(pp::PRNG, io_text.data(), clen, p.data()); |
|
|
|
DecodingResult r = d.Decrypt(PRNG, io_text.data(), clen, p.data()); |
|
|
|
if (!r.isValidCoding) |
|
|
|
{ |
|
|
|
io_text.clear(); |
|
|
@ -75,19 +94,51 @@ void crypto::decrypt(Secret const& _k, bytes& io_text) |
|
|
|
|
|
|
|
Signature crypto::sign(Secret const& _k, bytesConstRef _message) |
|
|
|
{ |
|
|
|
ECDSA<ECP, SHA3_256>::Signer signer; |
|
|
|
pp::initializeSigner(_k, signer); |
|
|
|
return crypto::sign(_k, sha3(_message)); |
|
|
|
} |
|
|
|
|
|
|
|
Signature crypto::sign(Secret const& _key, h256 const& _hash) |
|
|
|
{ |
|
|
|
ECDSA<ECP,SHA3_256>::Signer signer; |
|
|
|
initializeDLScheme(_key, signer); |
|
|
|
|
|
|
|
Integer const& q = secp256k1Params.GetGroupOrder(); |
|
|
|
Integer e(_hash.asBytes().data(), 32); |
|
|
|
|
|
|
|
Integer k(kdf(_key, _hash).data(), 32); |
|
|
|
k %= secp256k1Params.GetSubgroupOrder()-1; |
|
|
|
|
|
|
|
ECP::Point rp = secp256k1Params.ExponentiateBase(k); |
|
|
|
Integer r = secp256k1Params.ConvertElementToInteger(rp); |
|
|
|
int recid = ((r >= q) ? 2 : 0) | (rp.y.IsOdd() ? 1 : 0); |
|
|
|
|
|
|
|
Integer kInv = k.InverseMod(q); |
|
|
|
Integer s = (kInv * (Integer(_key.asBytes().data(), 32)*r + e)) % q; |
|
|
|
assert(!!r && !!s); |
|
|
|
|
|
|
|
if (s > secp256k1Params.GetSubgroupOrder()) |
|
|
|
{ |
|
|
|
s = q - s; |
|
|
|
if (recid) |
|
|
|
recid ^= 1; |
|
|
|
} |
|
|
|
|
|
|
|
Signature sig; |
|
|
|
r.Encode(sig.data(), 32); |
|
|
|
s.Encode(sig.data()+32, 32); |
|
|
|
sig[64] = recid; |
|
|
|
return sig; |
|
|
|
} |
|
|
|
|
|
|
|
string sigstr; |
|
|
|
StringSource s(_message.toString(), true, new SignerFilter(pp::PRNG, signer, new StringSink(sigstr))); |
|
|
|
FixedHash<sizeof(Signature)> retsig((byte const*)sigstr.data(), Signature::ConstructFromPointer); |
|
|
|
return std::move(retsig); |
|
|
|
bool crypto::verify(Signature const& _signature, bytesConstRef _message) |
|
|
|
{ |
|
|
|
return crypto::verify(crypto::recover(_signature, _message), _signature, _message); |
|
|
|
} |
|
|
|
|
|
|
|
bool crypto::verify(Public _p, Signature _sig, bytesConstRef _message, bool _raw) |
|
|
|
bool crypto::verify(Public const& _p, Signature const& _sig, bytesConstRef _message, bool _hashed) |
|
|
|
{ |
|
|
|
static size_t derMaxEncodingLength = 72; |
|
|
|
if (_raw) |
|
|
|
if (_hashed) |
|
|
|
{ |
|
|
|
assert(_message.size() == 32); |
|
|
|
byte encpub[65] = {0x04}; |
|
|
@ -99,10 +150,53 @@ bool crypto::verify(Public _p, Signature _sig, bytesConstRef _message, bool _raw |
|
|
|
} |
|
|
|
|
|
|
|
ECDSA<ECP, SHA3_256>::Verifier verifier; |
|
|
|
pp::initializeVerifier(_p, verifier); |
|
|
|
// cryptopp signatures are 64 bytes
|
|
|
|
static_assert(sizeof(Signature) == 65, "Expected 65-byte signature."); |
|
|
|
initializeDLScheme(_p, verifier); |
|
|
|
return verifier.VerifyMessage(_message.data(), _message.size(), _sig.data(), sizeof(Signature) - 1); |
|
|
|
} |
|
|
|
|
|
|
|
Public crypto::recover(Signature _signature, bytesConstRef _message) |
|
|
|
{ |
|
|
|
secp256k1_start(); |
|
|
|
|
|
|
|
byte pubkey[65]; |
|
|
|
int pubkeylen = 65; |
|
|
|
if (!secp256k1_ecdsa_recover_compact(_message.data(), 32, _signature.data(), pubkey, &pubkeylen, 0, (int)_signature[64])) |
|
|
|
return Public(); |
|
|
|
|
|
|
|
#if ETH_CRYPTO_TRACE |
|
|
|
h256* sig = (h256 const*)_signature.data(); |
|
|
|
cout << "---- RECOVER -------------------------------" << endl; |
|
|
|
cout << "MSG: " << _message << endl; |
|
|
|
cout << "R S V: " << sig[0] << " " << sig[1] << " " << (int)(_signature[64] - 27) << "+27" << endl; |
|
|
|
cout << "PUB: " << toHex(bytesConstRef(&(pubkey[1]), 64)) << endl; |
|
|
|
#endif |
|
|
|
|
|
|
|
Public ret; |
|
|
|
memcpy(&ret, &(pubkey[1]), sizeof(Public)); |
|
|
|
return ret; |
|
|
|
} |
|
|
|
|
|
|
|
bool crypto::verifySecret(Secret const& _s, Public const& _p) |
|
|
|
{ |
|
|
|
secp256k1_start(); |
|
|
|
int ok = secp256k1_ecdsa_seckey_verify(_s.data()); |
|
|
|
if (!ok) |
|
|
|
return false; |
|
|
|
|
|
|
|
byte pubkey[65]; |
|
|
|
int pubkeylen = 65; |
|
|
|
ok = secp256k1_ecdsa_pubkey_create(pubkey, &pubkeylen, _s.data(), 0); |
|
|
|
if (!ok || pubkeylen != 65) |
|
|
|
return false; |
|
|
|
|
|
|
|
ok = secp256k1_ecdsa_pubkey_verify(pubkey, 65); |
|
|
|
if (!ok) |
|
|
|
return false; |
|
|
|
|
|
|
|
for (int i = 0; i < 32; i++) |
|
|
|
if (pubkey[i+1]!=_p[i]) |
|
|
|
return false; |
|
|
|
|
|
|
|
return true; |
|
|
|
} |
|
|
|
|
|
|
|