From: CryptoManiac Date: Tue, 29 Mar 2016 01:22:25 +0000 (+0300) Subject: Move signature verification functions to CPubKey. X-Git-Tag: nvc-v0.5.8~26 X-Git-Url: https://git.novaco.in/?p=novacoin.git;a=commitdiff_plain;h=9e58e0a8ca28b15a4bfa677f5b23891972db40fd Move signature verification functions to CPubKey. --- diff --git a/src/alert.cpp b/src/alert.cpp index 121bd1e..65927ed 100644 --- a/src/alert.cpp +++ b/src/alert.cpp @@ -149,9 +149,8 @@ bool CAlert::RelayTo(CNode* pnode) const bool CAlert::CheckSignature() const { - CKey key; - if (!key.SetPubKey(ParseHex(fTestNet ? pszTestKey : pszMainKey))) - return error("CAlert::CheckSignature() : SetPubKey failed"); + CPubKey key; + key.Set(ParseHex(fTestNet ? pszTestKey : pszMainKey)); if (!key.Verify(Hash(vchMsg.begin(), vchMsg.end()), vchSig)) return error("CAlert::CheckSignature() : verify signature failed"); diff --git a/src/bitcoinrpc.cpp b/src/bitcoinrpc.cpp index b555f0b..bd1c1f4 100644 --- a/src/bitcoinrpc.cpp +++ b/src/bitcoinrpc.cpp @@ -297,6 +297,7 @@ static const CRPCCommand vRPCCommands[] = { "submitblock", &submitblock, false, false }, { "listsinceblock", &listsinceblock, false, false }, { "dumpprivkey", &dumpprivkey, false, false }, + { "dumppem", &dumppem, true, false }, { "dumpwallet", &dumpwallet, true, false }, { "importwallet", &importwallet, false, false }, { "importprivkey", &importprivkey, false, false }, diff --git a/src/bitcoinrpc.h b/src/bitcoinrpc.h index 5befb76..3c9106b 100644 --- a/src/bitcoinrpc.h +++ b/src/bitcoinrpc.h @@ -212,6 +212,7 @@ extern json_spirit::Value adjustmalleablepubkey(const json_spirit::Array& params extern json_spirit::Value listmalleableviews(const json_spirit::Array& params, bool fHelp); extern json_spirit::Value dumpmalleablekey(const json_spirit::Array& params, bool fHelp); extern json_spirit::Value importmalleablekey(const json_spirit::Array& params, bool fHelp); +extern json_spirit::Value dumppem(const json_spirit::Array& params, bool fHelp); extern json_spirit::Value encryptdata(const json_spirit::Array& params, bool fHelp); // in rpccrypt.cpp extern json_spirit::Value decryptdata(const json_spirit::Array& params, bool fHelp); diff --git a/src/checkpoints.cpp b/src/checkpoints.cpp index 54f5790..c6fb487 100644 --- a/src/checkpoints.cpp +++ b/src/checkpoints.cpp @@ -396,9 +396,7 @@ std::string CSyncCheckpoint::strMasterPrivKey = ""; // ppcoin: verify signature of sync-checkpoint message bool CSyncCheckpoint::CheckSignature() { - CKey key; - if (!key.SetPubKey(ParseHex(CSyncCheckpoint::strMasterPubKey))) - return error("CSyncCheckpoint::CheckSignature() : SetPubKey failed"); + CPubKey key(ParseHex(CSyncCheckpoint::strMasterPubKey)); if (!key.Verify(Hash(vchMsg.begin(), vchMsg.end()), vchSig)) return error("CSyncCheckpoint::CheckSignature() : verify signature failed"); diff --git a/src/key.cpp b/src/key.cpp index 546d95f..20ea691 100644 --- a/src/key.cpp +++ b/src/key.cpp @@ -5,6 +5,7 @@ #include #include +#include #include #include "key.h" @@ -164,8 +165,6 @@ const unsigned char vchMaxModHalfOrder[32] = { const unsigned char *vchZero = NULL; - - void CKey::SetCompressedPubKey() { EC_KEY_set_conv_form(pkey, POINT_CONVERSION_COMPRESSED); @@ -174,13 +173,12 @@ void CKey::SetCompressedPubKey() void CKey::Reset() { - fCompressedPubKey = false; + fCompressedPubKey = fSet = false; if (pkey != NULL) EC_KEY_free(pkey); pkey = EC_KEY_new_by_curve_name(NID_secp256k1); if (pkey == NULL) throw key_error("CKey::CKey() : EC_KEY_new_by_curve_name failed"); - fSet = false; } CKey::CKey() @@ -217,7 +215,8 @@ CKey& CKey::operator=(const CKey& b) CKey::~CKey() { - EC_KEY_free(pkey); + if (pkey != NULL) + EC_KEY_free(pkey); } bool CKey::IsNull() const @@ -235,7 +234,7 @@ bool CKey::CheckSignatureElement(const unsigned char *vch, int len, bool half) { CompareBigEndian(vch, len, half ? vchMaxModHalfOrder : vchMaxModOrder, 32) <= 0; } -bool CKey::ReserealizeSignature(std::vector& vchSig) +bool CPubKey::ReserealizeSignature(std::vector& vchSig) { if (vchSig.empty()) return false; @@ -299,6 +298,7 @@ bool CKey::SetSecret(const CSecret& vchSecret, bool fCompressed) pkey = EC_KEY_new_by_curve_name(NID_secp256k1); if (pkey == NULL) throw key_error("CKey::SetSecret() : EC_KEY_new_by_curve_name failed"); + if (vchSecret.size() != 32) throw key_error("CKey::SetSecret() : secret must be 32 bytes"); BIGNUM *bn = BN_bin2bn(&vchSecret[0],32,BN_new()); @@ -331,6 +331,37 @@ CSecret CKey::GetSecret(bool &fCompressed) const return vchRet; } +bool CKey::WritePEM(BIO *streamObj, const SecureString &strPassKey) const // dumppem 4KJLA99FyqMMhjjDe7KnRXK4sjtv9cCtNS /tmp/test.pem 123 +{ + EVP_PKEY *evpKey = EVP_PKEY_new(); + bool result = true; + + do + { + if (!EVP_PKEY_assign_EC_KEY(evpKey, pkey)) + { + result = error("CKey::WritePEM() : Error initializing EVP_PKEY instance."); + break; + } + + if(!PEM_write_bio_PKCS8PrivateKey(streamObj, evpKey, EVP_aes_256_cbc(), (char *)&strPassKey[0], strPassKey.size(), NULL, NULL)) + { + result = error("CKey::WritePEM() : Error writing private key data to stream object"); + break; + } + + if(!PEM_write_bio_PUBKEY(streamObj, evpKey)) + { + result = error("CKey::WritePEM() : Error writing public key data to stream object"); + break; + } + } + while(false); + + EVP_PKEY_free(evpKey); + return result; +} + CSecret CKey::GetSecret() const { bool fCompressed; @@ -349,21 +380,6 @@ CPrivKey CKey::GetPrivKey() const return vchPrivKey; } -bool CKey::SetPubKey(const CPubKey& vchPubKey) -{ - const unsigned char* pbegin = &vchPubKey.vchPubKey[0]; - if (o2i_ECPublicKey(&pkey, &pbegin, vchPubKey.vchPubKey.size())) - { - fSet = true; - if (vchPubKey.vchPubKey.size() == 33) - SetCompressedPubKey(); - return true; - } - pkey = NULL; - Reset(); - return false; -} - CPubKey CKey::GetPubKey() const { int nSize = i2o_ECPublicKey(pkey, NULL); @@ -462,7 +478,7 @@ bool CKey::SignCompact(uint256 hash, std::vector& vchSig) // This is only slightly more CPU intensive than just verifying it. // If this function succeeds, the recovered public key is guaranteed to be valid // (the signature is a valid signature of the given data for that key) -bool CKey::SetCompactSignature(uint256 hash, const std::vector& vchSig) +bool CPubKey::SetCompactSignature(uint256 hash, const std::vector& vchSig) { if (vchSig.size() != 65) return false; @@ -473,28 +489,46 @@ bool CKey::SetCompactSignature(uint256 hash, const std::vector& v BN_bin2bn(&vchSig[1],32,sig->r); BN_bin2bn(&vchSig[33],32,sig->s); - EC_KEY_free(pkey); - pkey = EC_KEY_new_by_curve_name(NID_secp256k1); + EC_KEY* pkey = EC_KEY_new_by_curve_name(NID_secp256k1); if (nV >= 31) { - SetCompressedPubKey(); nV -= 4; + EC_KEY_set_conv_form(pkey, POINT_CONVERSION_COMPRESSED); } - if (ECDSA_SIG_recover_key_GFp(pkey, sig, (unsigned char*)&hash, sizeof(hash), nV - 27, 0) == 1) + + do { - fSet = true; + if (ECDSA_SIG_recover_key_GFp(pkey, sig, (unsigned char*)&hash, sizeof(hash), nV - 27, 0) != 1) + break; ECDSA_SIG_free(sig); - return true; - } + + int nSize = i2o_ECPublicKey(pkey, NULL); + if (!nSize) + break; + std::vector vchPubKey(nSize, 0); + unsigned char* pbegin = &vchPubKey[0]; + if (i2o_ECPublicKey(pkey, &pbegin) != nSize) + break; + Set(vchPubKey.begin(), vchPubKey.end()); + return IsValid(); + + } while (false); + ECDSA_SIG_free(sig); + Invalidate(); return false; } -bool CKey::Verify(uint256 hash, const std::vector& vchSig) +bool CPubKey::Verify(const uint256 &hash, const std::vector& vchSig) const { - if (vchSig.empty()) + if (vchSig.empty() || !IsValid()) return false; + const unsigned char* pbegin = &vbytes[0]; + EC_KEY *pkey = EC_KEY_new_by_curve_name(NID_secp256k1); + if (!o2i_ECPublicKey(&pkey, &pbegin, size())) + return false; // Unable to parse public key + // New versions of OpenSSL will reject non-canonical DER signatures. de/re-serialize first. unsigned char *norm_der = NULL; ECDSA_SIG *norm_sig = ECDSA_SIG_new(); @@ -522,14 +556,13 @@ bool CKey::Verify(uint256 hash, const std::vector& vchSig) return ret; } -bool CKey::VerifyCompact(uint256 hash, const std::vector& vchSig) +bool CPubKey::VerifyCompact(uint256 hash, const std::vector& vchSig) { - CKey key; + CPubKey key; if (!key.SetCompactSignature(hash, vchSig)) return false; - if (GetPubKey() != key.GetPubKey()) + if ((*this) != key) return false; - return true; } @@ -545,6 +578,7 @@ bool CKey::IsValid() CSecret secret = GetSecret(fCompr); CKey key2; key2.SetSecret(secret, fCompr); + return GetPubKey() == key2.GetPubKey(); } @@ -604,9 +638,10 @@ bool CPoint::setBytes(const std::vector &vchBytes) } // Initialize from octets stream -bool CPoint::setPubKey(const CPubKey &vchPubKey) +bool CPoint::setPubKey(const CPubKey &key) { - return setBytes(vchPubKey.Raw()); + std::vector vchPubKey(key.begin(), key.end()); + return setBytes(vchPubKey); } // Serialize to octets stream @@ -824,7 +859,7 @@ bool CMalleableKey::SetSecrets(const CSecret &pvchSecretL, const CSecret &pvchSe CMalleablePubKey CMalleableKey::GetMalleablePubKey() const { CKey L(vchSecretL), H(vchSecretH); - return CMalleablePubKey(L.GetPubKey().Raw(), H.GetPubKey().Raw()); + return CMalleablePubKey(L.GetPubKey(), H.GetPubKey()); } // Check ownership @@ -851,7 +886,7 @@ bool CMalleableKey::CheckKeyVariant(const CPubKey &R, const CPubKey &vchPubKeyVa } CKey H(vchSecretH); - std::vector vchPubKeyH = H.GetPubKey().Raw(); + CPubKey vchPubKeyH = H.GetPubKey(); CPoint point_H; if (!point_H.setPubKey(vchPubKeyH)) { @@ -928,7 +963,7 @@ bool CMalleableKey::CheckKeyVariant(const CPubKey &R, const CPubKey &vchPubKeyVa } CKey H(vchSecretH); - std::vector vchPubKeyH = H.GetPubKey().Raw(); + CPubKey vchPubKeyH = H.GetPubKey(); CPoint point_H; if (!point_H.setPubKey(vchPubKeyH)) { @@ -1040,7 +1075,7 @@ CMalleableKeyView::CMalleableKeyView(const CMalleableKey &b) vchSecretL = b.vchSecretL; CKey H(b.vchSecretH); - vchPubKeyH = H.GetPubKey().Raw(); + vchPubKeyH = H.GetPubKey(); } CMalleableKeyView::CMalleableKeyView(const CMalleableKeyView &b) @@ -1054,7 +1089,7 @@ CMalleableKeyView& CMalleableKeyView::operator=(const CMalleableKey &b) vchSecretL = b.vchSecretL; CKey H(b.vchSecretH); - vchPubKeyH = H.GetPubKey().Raw(); + vchPubKeyH = H.GetPubKey(); return (*this); } @@ -1184,18 +1219,15 @@ bool CMalleableKeyView::IsValid() const void CPubKey::EncryptData(const std::vector& data, std::vector& encrypted) { - CKey key; - key.SetPubKey(*this); - - key.EncryptData(data, encrypted); -} - -void CKey::EncryptData(const std::vector& data, std::vector& encrypted) -{ ies_ctx_t *ctx; char error[1024] = "Unknown error"; cryptogram_t *cryptogram; + const unsigned char* pbegin = &vbytes[0]; + EC_KEY *pkey = EC_KEY_new_by_curve_name(NID_secp256k1); + if (!o2i_ECPublicKey(&pkey, &pbegin, size())) + throw key_error("Unable to parse EC key"); + ctx = create_context(pkey); if (!EC_KEY_get0_public_key(ctx->user_key)) throw key_error("Given EC key is not public key"); diff --git a/src/key.h b/src/key.h index 2d8e618..2489dfc 100644 --- a/src/key.h +++ b/src/key.h @@ -62,55 +62,162 @@ public: CScriptID(const uint160 &in) : uint160(in) { } }; -/** An encapsulated public key. */ -class CPubKey { +/** An encapsulated OpenSSL Elliptic Curve key (public) */ +class CPubKey +{ private: - std::vector vchPubKey; - friend class CKey; + + /** + * Just store the serialized data. + * Its length can very cheaply be computed from the first byte. + */ + unsigned char vbytes[65]; + + //! Compute the length of a pubkey with a given first byte. + unsigned int static GetLen(unsigned char chHeader) + { + if (chHeader == 2 || chHeader == 3) + return 33; + if (chHeader == 4 || chHeader == 6 || chHeader == 7) + return 65; + return 0; + } + + // Set this key data to be invalid + void Invalidate() + { + vbytes[0] = 0xFF; + } public: - CPubKey() { } - CPubKey(const std::vector &vchPubKeyIn) : vchPubKey(vchPubKeyIn) { } - friend bool operator==(const CPubKey &a, const CPubKey &b) { return a.vchPubKey == b.vchPubKey; } - friend bool operator!=(const CPubKey &a, const CPubKey &b) { return a.vchPubKey != b.vchPubKey; } - friend bool operator<(const CPubKey &a, const CPubKey &b) { return a.vchPubKey < b.vchPubKey; } + // Construct an invalid public key. + CPubKey() + { + Invalidate(); + } - IMPLEMENT_SERIALIZE( - READWRITE(vchPubKey); - ) + // Initialize a public key using begin/end iterators to byte data. + template + void Set(const T pbegin, const T pend) + { + int len = pend == pbegin ? 0 : GetLen(pbegin[0]); + if (len && len == (pend - pbegin)) + memcpy(vbytes, (unsigned char*)&pbegin[0], len); + else + Invalidate(); + } - CKeyID GetID() const { - return CKeyID(Hash160(vchPubKey)); + void Set(const std::vector& vch) + { + Set(vch.begin(), vch.end()); } - uint256 GetHash() const { - return Hash(vchPubKey.begin(), vchPubKey.end()); + template + CPubKey(const T pbegin, const T pend) + { + Set(pbegin, pend); } - bool IsValid() const { - return vchPubKey.size() == 33 || vchPubKey.size() == 65; + CPubKey(const std::vector& vch) + { + Set(vch.begin(), vch.end()); } - bool IsCompressed() const { - return vchPubKey.size() == 33; + // Read-only vector-like interface to the data. + unsigned int size() const { return GetLen(vbytes[0]); } + const unsigned char* begin() const { return vbytes; } + const unsigned char* end() const { return vbytes + size(); } + const unsigned char& operator[](unsigned int pos) const { return vbytes[pos]; } + + friend bool operator==(const CPubKey& a, const CPubKey& b) { return a.vbytes[0] == b.vbytes[0] && memcmp(a.vbytes, b.vbytes, a.size()) == 0; } + friend bool operator!=(const CPubKey& a, const CPubKey& b) { return !(a == b); } + friend bool operator<(const CPubKey& a, const CPubKey& b) { return a.vbytes[0] < b.vbytes[0] || (a.vbytes[0] == b.vbytes[0] && memcmp(a.vbytes, b.vbytes, a.size()) < 0); } + + //! Implement serialization, as if this was a byte vector. + unsigned int GetSerializeSize(int nType, int nVersion) const + { + return size() + 1; + } + template + void Serialize(Stream& s, int nType, int nVersion) const + { + unsigned int len = size(); + ::WriteCompactSize(s, len); + s.write((char*)vbytes, len); + } + template + void Unserialize(Stream& s, int nType, int nVersion) + { + unsigned int len = ::ReadCompactSize(s); + if (len <= 65) { + s.read((char*)vbytes, len); + } else { + // invalid pubkey, skip available data + char dummy; + while (len--) + s.read(&dummy, 1); + Invalidate(); + } } - std::vector Raw() const { - return vchPubKey; + CKeyID GetID() const + { + return CKeyID(Hash160(vbytes, vbytes + size())); } + uint256 GetHash() const + { + return Hash(vbytes, vbytes + size()); + } + + /* + * Check syntactic correctness. + * + * Note that this is consensus critical as CheckSig() calls it! + */ + bool IsValid() const + { + return size() > 0; + } + + //! fully validate whether this is a valid public key (more expensive than IsValid()) + bool IsFullyValid() const + { + const unsigned char* pbegin = &vbytes[0]; + EC_KEY *pkey = EC_KEY_new_by_curve_name(NID_secp256k1); + if (o2i_ECPublicKey(&pkey, &pbegin, size())) + { + EC_KEY_free(pkey); + return true; + } + return false; + } + + //! Check whether this is a compressed public key. + bool IsCompressed() const + { + return size() == 33; + } + + bool Verify(const uint256& hash, const std::vector& vchSig) const; + bool VerifyCompact(uint256 hash, const std::vector& vchSig); + + bool SetCompactSignature(uint256 hash, const std::vector& vchSig); + + // Reserialize to DER + static bool ReserealizeSignature(std::vector& vchSig); + // Encrypt data void EncryptData(const std::vector& data, std::vector& encrypted); }; - // secure_allocator is defined in allocators.h // CPrivKey is a serialized private key, with all parameters included (279 bytes) typedef std::vector > CPrivKey; // CSecret is a serialization of just the secret parameter (32 bytes) typedef std::vector > CSecret; -/** An encapsulated OpenSSL Elliptic Curve key (public and/or private) */ +/** An encapsulated OpenSSL Elliptic Curve key (private) */ class CKey { protected: @@ -118,8 +225,6 @@ protected: bool fSet; bool fCompressedPubKey; - void SetCompressedPubKey(); - public: void Reset(); @@ -135,14 +240,15 @@ public: bool IsNull() const; bool IsCompressed() const; + void SetCompressedPubKey(); void MakeNewKey(bool fCompressed=true); bool SetPrivKey(const CPrivKey& vchPrivKey); bool SetSecret(const CSecret& vchSecret, bool fCompressed = true); CSecret GetSecret(bool &fCompressed) const; CSecret GetSecret() const; CPrivKey GetPrivKey() const; - bool SetPubKey(const CPubKey& vchPubKey); CPubKey GetPubKey() const; + bool WritePEM(BIO *streamObj, const SecureString &strPassKey) const; bool Sign(uint256 hash, std::vector& vchSig); @@ -152,28 +258,11 @@ public: // 0x1D = second key with even y, 0x1E = second key with odd y bool SignCompact(uint256 hash, std::vector& vchSig); - // reconstruct public key from a compact signature - // This is only slightly more CPU intensive than just verifying it. - // If this function succeeds, the recovered public key is guaranteed to be valid - // (the signature is a valid signature of the given data for that key) - bool SetCompactSignature(uint256 hash, const std::vector& vchSig); - - bool Verify(uint256 hash, const std::vector& vchSig); - - // Verify a compact signature - bool VerifyCompact(uint256 hash, const std::vector& vchSig); - bool IsValid(); // Check whether an element of a signature (r or s) is valid. static bool CheckSignatureElement(const unsigned char *vch, int len, bool half); - // Reserialize to DER - static bool ReserealizeSignature(std::vector& vchSig); - - // Encrypt data - void EncryptData(const std::vector& data, std::vector& encrypted); - // Decrypt data void DecryptData(const std::vector& encrypted, std::vector& data); }; diff --git a/src/keystore.cpp b/src/keystore.cpp index 215590e..33b8eb1 100644 --- a/src/keystore.cpp +++ b/src/keystore.cpp @@ -157,8 +157,9 @@ bool CCryptoKeyStore::Unlock(const CKeyingMaterial& vMasterKeyIn) if (vchSecret.size() != 32) return false; CKey key; - key.SetPubKey(vchPubKey); key.SetSecret(vchSecret); + if (vchPubKey.size() == 33) + key.SetCompressedPubKey(); if (key.GetPubKey() == vchPubKey) break; return false; @@ -316,8 +317,9 @@ bool CCryptoKeyStore::GetKey(const CKeyID &address, CKey& keyOut) const return false; if (vchSecret.size() != 32) return false; - keyOut.SetPubKey(vchPubKey); keyOut.SetSecret(vchSecret); + if (vchPubKey.size() == 33) + keyOut.SetCompressedPubKey(); return true; } } @@ -396,8 +398,9 @@ bool CCryptoKeyStore::DecryptKeys(const CKeyingMaterial& vMasterKeyIn) if (vchSecret.size() != 32) return false; CKey key; - key.SetPubKey(vchPubKey); key.SetSecret(vchSecret); + if (vchPubKey.size() == 33) + key.SetCompressedPubKey(); if (!CBasicKeyStore::AddKey(key)) return false; } diff --git a/src/keystore.h b/src/keystore.h index f4d0ad3..36149ba 100644 --- a/src/keystore.h +++ b/src/keystore.h @@ -132,7 +132,6 @@ public: KeyMap::const_iterator mi = mapKeys.find(address); if (mi != mapKeys.end()) { - keyOut.Reset(); keyOut.SetSecret((*mi).second.first, (*mi).second.second); return true; } diff --git a/src/main.cpp b/src/main.cpp index 0a6fda1..65001a3 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -2508,7 +2508,7 @@ bool static ReserealizeBlockSignature(CBlock* pblock) return true; } - return CKey::ReserealizeSignature(pblock->vchBlockSig); + return CPubKey::ReserealizeSignature(pblock->vchBlockSig); } bool static IsCanonicalBlockSignature(CBlock* pblock) @@ -2667,8 +2667,8 @@ bool CBlock::CheckBlockSignature() const if (whichType == TX_PUBKEY) { valtype& vchPubKey = vSolutions[0]; - CKey key; - if (!key.SetPubKey(vchPubKey)) + CPubKey key(vchPubKey); + if (!key.IsValid()) return false; return key.Verify(GetHash(), vchBlockSig); } diff --git a/src/qt/multisigaddressentry.cpp b/src/qt/multisigaddressentry.cpp index 166b9ed..4b07e11 100644 --- a/src/qt/multisigaddressentry.cpp +++ b/src/qt/multisigaddressentry.cpp @@ -108,7 +108,7 @@ void MultisigAddressEntry::on_address_textChanged(const QString &address) { CPubKey vchPubKey; model->getPubKey(keyID, vchPubKey); - std::string pubkey = HexStr(vchPubKey.Raw()); + std::string pubkey = HexStr(vchPubKey.begin(), vchPubKey.end()); if(!pubkey.empty()) ui->pubkey->setText(pubkey.c_str()); } diff --git a/src/qt/multisigdialog.cpp b/src/qt/multisigdialog.cpp index a82f76e..97e49cf 100644 --- a/src/qt/multisigdialog.cpp +++ b/src/qt/multisigdialog.cpp @@ -149,7 +149,7 @@ void MultisigDialog::on_createAddressButton_clicked() if(!model) return; - std::vector pubkeys; + std::vector pubkeys; pubkeys.resize(ui->pubkeyEntries->count()); unsigned int required = ui->requiredSignatures->text().toUInt(); @@ -162,7 +162,7 @@ void MultisigDialog::on_createAddressButton_clicked() CPubKey vchPubKey(ParseHex(str.toStdString().c_str())); if(!vchPubKey.IsValid()) return; - pubkeys[i].SetPubKey(vchPubKey); + pubkeys[i] = vchPubKey; } if(pubkeys.size() > 16) diff --git a/src/qt/signverifymessagedialog.cpp b/src/qt/signverifymessagedialog.cpp index 8d011ab..0782a46 100644 --- a/src/qt/signverifymessagedialog.cpp +++ b/src/qt/signverifymessagedialog.cpp @@ -220,7 +220,7 @@ void SignVerifyMessageDialog::on_verifyMessageButton_VM_clicked() ss << strMessageMagic; ss << ui->messageIn_VM->document()->toPlainText().toStdString(); - CKey key; + CPubKey key; if (!key.SetCompactSignature(Hash(ss.begin(), ss.end()), vchSig)) { ui->signatureIn_VM->setValid(false); @@ -229,7 +229,7 @@ void SignVerifyMessageDialog::on_verifyMessageButton_VM_clicked() return; } - if (!(CBitcoinAddress(key.GetPubKey().GetID()) == addr)) + if (!(CBitcoinAddress(key.GetID()) == addr)) { ui->statusLabel_VM->setStyleSheet("QLabel { color: red; }"); ui->statusLabel_VM->setText(QString("") + tr("Message verification failed.") + QString("")); diff --git a/src/rpcdump.cpp b/src/rpcdump.cpp index 48112a5..bb877bf 100644 --- a/src/rpcdump.cpp +++ b/src/rpcdump.cpp @@ -217,7 +217,7 @@ Value dumpprivkey(const Array& params, bool fHelp) CBitcoinAddress address; if (!address.SetString(strAddress)) throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid NovaCoin address"); - if (fWalletUnlockMintOnly) // ppcoin: no dumpprivkey in mint-only mode + if (fWalletUnlockMintOnly) throw JSONRPCError(RPC_WALLET_UNLOCK_NEEDED, "Wallet is unlocked for minting only."); CKeyID keyID; if (!address.GetKeyID(keyID)) @@ -229,6 +229,35 @@ Value dumpprivkey(const Array& params, bool fHelp) return CBitcoinSecret(vchSecret, fCompressed).ToString(); } +Value dumppem(const Array& params, bool fHelp) +{ + if (fHelp || params.size() != 3) + throw runtime_error( + "dumppem \n" + "Dump the key pair corresponding to and store it as encrypted PEM file." + + HelpRequiringPassphrase()); + + EnsureWalletIsUnlocked(); + + string strAddress = params[0].get_str(); + SecureString strPassKey; + strPassKey.reserve(100); + strPassKey = params[2].get_str().c_str(); + + CBitcoinAddress address; + if (!address.SetString(strAddress)) + throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid NovaCoin address"); + if (fWalletUnlockMintOnly) + throw JSONRPCError(RPC_WALLET_UNLOCK_NEEDED, "Wallet is unlocked for minting only."); + CKeyID keyID; + if (!address.GetKeyID(keyID)) + throw JSONRPCError(RPC_TYPE_ERROR, "Address does not refer to a key"); + if (!pwalletMain->GetPEM(keyID, params[1].get_str(), strPassKey)) + throw JSONRPCError(RPC_WALLET_ERROR, "Error dumping key pair to file"); + + return Value::null; +} + Value dumpwallet(const Array& params, bool fHelp) { if (fHelp || params.size() != 1) diff --git a/src/rpcrawtransaction.cpp b/src/rpcrawtransaction.cpp index c2a10f3..b8365c6 100644 --- a/src/rpcrawtransaction.cpp +++ b/src/rpcrawtransaction.cpp @@ -652,7 +652,7 @@ Value createmultisig(const Array& params, bool fHelp) "(got %" PRIszu " keys, but need at least %d to redeem)", keys.size(), nRequired)); if (keys.size() > 16) throw runtime_error("Number of addresses involved in the multisignature address creation > 16\nReduce the number"); - std::vector pubkeys; + std::vector pubkeys; pubkeys.resize(keys.size()); for (unsigned int i = 0; i < keys.size(); i++) { @@ -670,16 +670,18 @@ Value createmultisig(const Array& params, bool fHelp) if (!pwalletMain->GetPubKey(keyID, vchPubKey)) throw runtime_error( strprintf("no full public key for address %s",ks.c_str())); - if (!vchPubKey.IsValid() || !pubkeys[i].SetPubKey(vchPubKey)) + if (!vchPubKey.IsFullyValid()) throw runtime_error(" Invalid public key: "+ks); + pubkeys[i] = vchPubKey; } // Case 2: hex public key else if (IsHex(ks)) { CPubKey vchPubKey(ParseHex(ks)); - if (!vchPubKey.IsValid() || !pubkeys[i].SetPubKey(vchPubKey)) + if (!vchPubKey.IsFullyValid()) throw runtime_error(" Invalid public key: "+ks); + pubkeys[i] = vchPubKey; } else { diff --git a/src/rpcwallet.cpp b/src/rpcwallet.cpp index b96f5c1..09bacfc 100644 --- a/src/rpcwallet.cpp +++ b/src/rpcwallet.cpp @@ -451,11 +451,11 @@ Value verifymessage(const Array& params, bool fHelp) ss << strMessageMagic; ss << strMessage; - CKey key; + CPubKey key; if (!key.SetCompactSignature(Hash(ss.begin(), ss.end()), vchSig)) return false; - return (key.GetPubKey().GetID() == keyID); + return (key.GetID() == keyID); } @@ -843,7 +843,7 @@ Value addmultisigaddress(const Array& params, bool fHelp) "(got %" PRIszu " keys, but need at least %d to redeem)", keys.size(), nRequired)); if (keys.size() > 16) throw runtime_error("Number of addresses involved in the multisignature address creation > 16\nReduce the number"); - std::vector pubkeys; + std::vector pubkeys; pubkeys.resize(keys.size()); for (unsigned int i = 0; i < keys.size(); i++) { @@ -861,16 +861,18 @@ Value addmultisigaddress(const Array& params, bool fHelp) if (!pwalletMain->GetPubKey(keyID, vchPubKey)) throw runtime_error( strprintf("no full public key for address %s",ks.c_str())); - if (!vchPubKey.IsValid() || !pubkeys[i].SetPubKey(vchPubKey)) + if (!vchPubKey.IsValid()) throw runtime_error(" Invalid public key: "+ks); + pubkeys[i] = vchPubKey; } // Case 2: hex public key else if (IsHex(ks)) { CPubKey vchPubKey(ParseHex(ks)); - if (!vchPubKey.IsValid() || !pubkeys[i].SetPubKey(vchPubKey)) + if (!vchPubKey.IsValid()) throw runtime_error(" Invalid public key: "+ks); + pubkeys[i] = vchPubKey; } else { @@ -1690,7 +1692,7 @@ public: obj.push_back(Pair("isscript", false)); if (mine == MINE_SPENDABLE) { pwalletMain->GetPubKey(keyID, vchPubKey); - obj.push_back(Pair("pubkey", HexStr(vchPubKey.Raw()))); + obj.push_back(Pair("pubkey", HexStr(vchPubKey.begin(), vchPubKey.end()))); obj.push_back(Pair("iscompressed", vchPubKey.IsCompressed())); } return obj; @@ -1886,8 +1888,9 @@ Value makekeypair(const Array& params, bool fHelp) bool fCompressed; CSecret vchSecret = key.GetSecret(fCompressed); + CPubKey vchPubKey = key.GetPubKey(); result.push_back(Pair("Secret", HexStr(vchSecret.begin(), vchSecret.end()))); - result.push_back(Pair("PublicKey", HexStr(key.GetPubKey().Raw()))); + result.push_back(Pair("PublicKey", HexStr(vchPubKey.begin(), vchPubKey.end()))); return result; } @@ -1970,8 +1973,8 @@ Value adjustmalleablepubkey(const Array& params, bool fHelp) malleablePubKey.GetVariant(R, vchPubKeyVariant); Object result; - result.push_back(Pair("R", HexStr(R.Raw()))); - result.push_back(Pair("PubkeyVariant", HexStr(vchPubKeyVariant.Raw()))); + result.push_back(Pair("R", HexStr(R.begin(), R.end()))); + result.push_back(Pair("PubkeyVariant", HexStr(vchPubKeyVariant.begin(), vchPubKeyVariant.end()))); result.push_back(Pair("KeyVariantID", CBitcoinAddress(vchPubKeyVariant.GetID()).ToString())); return result; diff --git a/src/script.cpp b/src/script.cpp index 0f31de1..ad31b76 100644 --- a/src/script.cpp +++ b/src/script.cpp @@ -1284,10 +1284,7 @@ bool CheckSig(vector vchSig, const vector &vchPubK { static CSignatureCache signatureCache; - CKey key; - if (!key.SetPubKey(vchPubKey)) - return false; - CPubKey pubkey = key.GetPubKey(); + CPubKey pubkey(vchPubKey); if (!pubkey.IsValid()) return false; @@ -1305,7 +1302,7 @@ bool CheckSig(vector vchSig, const vector &vchPubK if (signatureCache.Get(sighash, vchSig, pubkey)) return true; - if (!key.Verify(sighash, vchSig)) + if (!pubkey.Verify(sighash, vchSig)) return false; if (!(flags & SCRIPT_VERIFY_NOCACHE)) @@ -1315,12 +1312,6 @@ bool CheckSig(vector vchSig, const vector &vchPubK } - - - - - - // // Return public keys or hashes from scriptPubKey, for 'standard' transaction types. // @@ -2196,12 +2187,12 @@ void CScript::SetAddress(const CBitcoinAddress& dest) } } -void CScript::SetMultisig(int nRequired, const std::vector& keys) +void CScript::SetMultisig(int nRequired, const std::vector& keys) { this->clear(); *this << EncodeOP_N(nRequired); - BOOST_FOREACH(const CKey& key, keys) - *this << key.GetPubKey(); + BOOST_FOREACH(const CPubKey& key, keys) + *this << key; *this << EncodeOP_N((int)(keys.size())) << OP_CHECKMULTISIG; } diff --git a/src/script.h b/src/script.h index c24ab9c..8dd7ce9 100644 --- a/src/script.h +++ b/src/script.h @@ -380,7 +380,7 @@ public: CScript& operator<<(const CPubKey& key) { - std::vector vchKey = key.Raw(); + std::vector vchKey(key.begin(), key.end()); return (*this) << vchKey; } @@ -586,7 +586,7 @@ public: void SetDestination(const CTxDestination& address); void SetAddress(const CBitcoinAddress& dest); - void SetMultisig(int nRequired, const std::vector& keys); + void SetMultisig(int nRequired, const std::vector& keys); void PrintHex() const diff --git a/src/wallet.cpp b/src/wallet.cpp index 87ffe93..a1fe81d 100644 --- a/src/wallet.cpp +++ b/src/wallet.cpp @@ -12,6 +12,7 @@ #include "kernel.h" #include "coincontrol.h" #include +#include #include "main.h" @@ -516,6 +517,19 @@ bool CWallet::DecryptWallet(const SecureString& strWalletPassphrase) return true; } +bool CWallet::GetPEM(const CKeyID &keyID, const std::string &fileName, const SecureString &strPassKey) const +{ + BIO *pemOut = BIO_new_file(fileName.c_str(), "w"); + if (pemOut == NULL) + return error("GetPEM() : failed to create file %s\n", fileName.c_str()); + CKey key; + if (!GetKey(keyID, key)) + return error("GetPEM() : failed to get key for address=%s\n", CBitcoinAddress(keyID).ToString().c_str()); + bool result = key.WritePEM(pemOut, strPassKey); + BIO_free(pemOut); + return result; +} + int64_t CWallet::IncOrderPosNext(CWalletDB *pwalletdb) { int64_t nRet = nOrderPosNext++; diff --git a/src/wallet.h b/src/wallet.h index fb02d02..4db32e5 100644 --- a/src/wallet.h +++ b/src/wallet.h @@ -191,6 +191,7 @@ public: bool DecryptWallet(const SecureString& strWalletPassphrase); void GetAddresses(std::map &mapAddresses) const; + bool GetPEM(const CKeyID &keyID, const std::string &fileName, const SecureString &strPassPhrase) const; /** Increment the next transaction order id diff --git a/src/walletdb.cpp b/src/walletdb.cpp index cd90f97..ab85b07 100644 --- a/src/walletdb.cpp +++ b/src/walletdb.cpp @@ -334,15 +334,14 @@ ReadKeyValue(CWallet* pwallet, CDataStream& ssKey, CDataStream& ssValue, } else if (strType == "key" || strType == "wkey") { - vector vchPubKey; - ssKey >> vchPubKey; CKey key; + CPubKey vchPubKey; + ssKey >> vchPubKey; if (strType == "key") { wss.nKeys++; CPrivKey pkey; ssValue >> pkey; - key.SetPubKey(vchPubKey); if (!key.SetPrivKey(pkey)) { strErr = "Error reading wallet database: CPrivKey corrupt"; @@ -353,6 +352,9 @@ ReadKeyValue(CWallet* pwallet, CDataStream& ssKey, CDataStream& ssValue, strErr = "Error reading wallet database: CPrivKey pubkey inconsistency"; return false; } + if (vchPubKey.size() == 33) { + key.SetCompressedPubKey(); + } if (!key.IsValid()) { strErr = "Error reading wallet database: invalid CPrivKey"; @@ -363,7 +365,6 @@ ReadKeyValue(CWallet* pwallet, CDataStream& ssKey, CDataStream& ssValue, { CWalletKey wkey; ssValue >> wkey; - key.SetPubKey(vchPubKey); if (!key.SetPrivKey(wkey.vchPrivKey)) { strErr = "Error reading wallet database: CPrivKey corrupt"; @@ -374,6 +375,9 @@ ReadKeyValue(CWallet* pwallet, CDataStream& ssKey, CDataStream& ssValue, strErr = "Error reading wallet database: CWalletKey pubkey inconsistency"; return false; } + if (vchPubKey.size() == 33) { + key.SetCompressedPubKey(); + } if (!key.IsValid()) { strErr = "Error reading wallet database: invalid CWalletKey"; @@ -405,7 +409,7 @@ ReadKeyValue(CWallet* pwallet, CDataStream& ssKey, CDataStream& ssValue, else if (strType == "ckey") { wss.nCKeys++; - vector vchPubKey; + CPubKey vchPubKey; ssKey >> vchPubKey; vector vchPrivKey; ssValue >> vchPrivKey; diff --git a/src/walletdb.h b/src/walletdb.h index 94b355f..714b3cc 100644 --- a/src/walletdb.h +++ b/src/walletdb.h @@ -83,13 +83,13 @@ public: return Erase(std::make_pair(std::string("tx"), hash)); } - bool WriteKey(const CPubKey& vchPubKey, const CPrivKey& vchPrivKey, const CKeyMetadata &keyMeta) + bool WriteKey(const CPubKey& key, const CPrivKey& vchPrivKey, const CKeyMetadata &keyMeta) { nWalletDBUpdated++; - if(!Write(std::make_pair(std::string("keymeta"), vchPubKey), keyMeta)) + if(!Write(std::make_pair(std::string("keymeta"), key), keyMeta)) return false; - if(!Write(std::make_pair(std::string("key"), vchPubKey.Raw()), vchPrivKey, false)) + if(!Write(std::make_pair(std::string("key"), key), vchPrivKey, false)) return false; return true; @@ -122,20 +122,20 @@ public: } - bool WriteCryptedKey(const CPubKey& vchPubKey, const std::vector& vchCryptedSecret, const CKeyMetadata &keyMeta) + bool WriteCryptedKey(const CPubKey& key, const std::vector& vchCryptedSecret, const CKeyMetadata &keyMeta) { nWalletDBUpdated++; bool fEraseUnencryptedKey = true; - if(!Write(std::make_pair(std::string("keymeta"), vchPubKey), keyMeta)) + if(!Write(std::make_pair(std::string("keymeta"), key), keyMeta)) return false; - if (!Write(std::make_pair(std::string("ckey"), vchPubKey.Raw()), vchCryptedSecret, false)) + if (!Write(std::make_pair(std::string("ckey"), key), vchCryptedSecret, false)) return false; if (fEraseUnencryptedKey) { - Erase(std::make_pair(std::string("key"), vchPubKey.Raw())); - Erase(std::make_pair(std::string("wkey"), vchPubKey.Raw())); + Erase(std::make_pair(std::string("key"), key)); + Erase(std::make_pair(std::string("wkey"), key)); } return true; } @@ -152,9 +152,9 @@ public: return Erase(std::make_pair(std::string("mkey"), nID)); } - bool EraseCryptedKey(const CPubKey& vchPubKey) + bool EraseCryptedKey(const CPubKey& key) { - return Erase(std::make_pair(std::string("ckey"), vchPubKey.Raw())); + return Erase(std::make_pair(std::string("ckey"), key)); } bool EraseCryptedMalleableKey(const CMalleableKeyView& keyView) @@ -197,10 +197,10 @@ public: return Write(std::string("orderposnext"), nOrderPosNext); } - bool WriteDefaultKey(const CPubKey& vchPubKey) + bool WriteDefaultKey(const CPubKey& key) { nWalletDBUpdated++; - return Write(std::string("defaultkey"), vchPubKey.Raw()); + return Write(std::string("defaultkey"), key); } bool ReadPool(int64_t nPool, CKeyPool& keypool)