diff --git a/src/Makefile.am b/src/Makefile.am index 1a7c3c2db..6483cacab 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -422,6 +422,8 @@ libdash_common_a_SOURCES = \ libdash_util_a_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) libdash_util_a_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS) libdash_util_a_SOURCES = \ + crypto/bls_ies.cpp \ + crypto/bls_ies.h \ support/lockedpool.cpp \ chainparamsbase.cpp \ clientversion.cpp \ diff --git a/src/crypto/bls_ies.cpp b/src/crypto/bls_ies.cpp new file mode 100644 index 000000000..7212692ec --- /dev/null +++ b/src/crypto/bls_ies.cpp @@ -0,0 +1,136 @@ +// Copyright (c) 2018 The Dash Core developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#include "bls_ies.h" + +#include "hash.h" +#include "random.h" +#include "streams.h" + +#include "aes.h" + +template +static bool EncryptBlob(const void* in, size_t inSize, Out& out, const void* symKey, const void* iv) +{ + out.resize(inSize); + + AES256CBCEncrypt enc((const unsigned char*)symKey, (const unsigned char*)iv, false); + int w = enc.Encrypt((const unsigned char*)in, (int)inSize, (unsigned char*)out.data()); + return w == (int)inSize; +} + +template +static bool DecryptBlob(const void* in, size_t inSize, Out& out, const void* symKey, const void* iv) +{ + out.resize(inSize); + + AES256CBCDecrypt enc((const unsigned char*)symKey, (const unsigned char*)iv, false); + int w = enc.Decrypt((const unsigned char*)in, (int)inSize, (unsigned char*)out.data()); + return w == (int)inSize; +} + +bool CBLSIESEncryptedBlob::Encrypt(const CBLSPublicKey& peerPubKey, const void* plainTextData, size_t dataSize) +{ + CBLSSecretKey ephemeralSecretKey; + ephemeralSecretKey.MakeNewKey(); + ephemeralPubKey = ephemeralSecretKey.GetPublicKey(); + GetStrongRandBytes(iv, sizeof(iv)); + + CBLSPublicKey pk; + if (!pk.DHKeyExchange(ephemeralSecretKey, peerPubKey)) { + return false; + } + + std::vector symKey; + pk.GetBuf(symKey); + symKey.resize(32); + + return EncryptBlob(plainTextData, dataSize, data, symKey.data(), iv); +} + +bool CBLSIESEncryptedBlob::Decrypt(const CBLSSecretKey& secretKey, CDataStream& decryptedDataRet) const +{ + CBLSPublicKey pk; + if (!pk.DHKeyExchange(secretKey, ephemeralPubKey)) { + return false; + } + + std::vector symKey; + pk.GetBuf(symKey); + symKey.resize(32); + + return DecryptBlob(data.data(), data.size(), decryptedDataRet, symKey.data(), iv); +} + + +bool CBLSIESMultiRecipientBlobs::Encrypt(const std::vector& recipients, const BlobVector& _blobs) +{ + if (recipients.size() != _blobs.size()) { + return false; + } + + InitEncrypt(_blobs.size()); + + for (size_t i = 0; i < _blobs.size(); i++) { + if (!Encrypt(i, recipients[i], _blobs[i])) { + return false; + } + } + + return true; +} + +void CBLSIESMultiRecipientBlobs::InitEncrypt(size_t count) +{ + ephemeralSecretKey.MakeNewKey(); + ephemeralPubKey = ephemeralSecretKey.GetPublicKey(); + GetStrongRandBytes(ivSeed.begin(), ivSeed.size()); + + uint256 iv = ivSeed; + ivVector.resize(count); + blobs.resize(count); + for (size_t i = 0; i < count; i++) { + ivVector[i] = iv; + iv = ::SerializeHash(iv); + } +} + +bool CBLSIESMultiRecipientBlobs::Encrypt(size_t idx, const CBLSPublicKey& recipient, const Blob& blob) +{ + assert(idx < blobs.size()); + + CBLSPublicKey pk; + if (!pk.DHKeyExchange(ephemeralSecretKey, recipient)) { + return false; + } + + std::vector symKey; + pk.GetBuf(symKey); + symKey.resize(32); + + return EncryptBlob(blob.data(), blob.size(), blobs[idx], symKey.data(), ivVector[idx].begin()); +} + +bool CBLSIESMultiRecipientBlobs::Decrypt(size_t idx, const CBLSSecretKey& sk, Blob& blobRet) const +{ + if (idx >= blobs.size()) { + return false; + } + + CBLSPublicKey pk; + if (!pk.DHKeyExchange(sk, ephemeralPubKey)) { + return false; + } + + std::vector symKey; + pk.GetBuf(symKey); + symKey.resize(32); + + uint256 iv = ivSeed; + for (size_t i = 0; i < idx; i++) { + iv = ::SerializeHash(iv); + } + + return DecryptBlob(blobs[idx].data(), blobs[idx].size(), blobRet, symKey.data(), iv.begin()); +} diff --git a/src/crypto/bls_ies.h b/src/crypto/bls_ies.h new file mode 100644 index 000000000..5f28c91aa --- /dev/null +++ b/src/crypto/bls_ies.h @@ -0,0 +1,164 @@ +// Copyright (c) 2018 The Dash Core developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#ifndef DASH_CRYPTO_BLS_IES_H +#define DASH_CRYPTO_BLS_IES_H + +#include "bls.h" +#include "streams.h" + +class CBLSIESEncryptedBlob +{ +public: + CBLSPublicKey ephemeralPubKey; + unsigned char iv[16]; + std::vector data; + + bool valid{false}; + +public: + ADD_SERIALIZE_METHODS + + template + inline void SerializationOp(Stream& s, Operation ser_action) + { + if (!ser_action.ForRead()) { + assert(valid); + } else { + valid = false; + } + READWRITE(ephemeralPubKey); + READWRITE(FLATDATA(iv)); + READWRITE(data); + if (ser_action.ForRead()) { + valid = true; + } + }; + +public: + bool Encrypt(const CBLSPublicKey& peerPubKey, const void* data, size_t dataSize); + bool Decrypt(const CBLSSecretKey& secretKey, CDataStream& decryptedDataRet) const; +}; + +template +class CBLSIESEncryptedObject : public CBLSIESEncryptedBlob +{ +public: + CBLSIESEncryptedObject() + { + } + + bool Encrypt(const CBLSPublicKey& peerPubKey, const Object& obj, int nVersion) + { + try { + CDataStream ds(SER_NETWORK, nVersion); + ds << obj; + return CBLSIESEncryptedBlob::Encrypt(peerPubKey, ds.data(), ds.size()); + } catch (std::exception&) { + return false; + } + } + + bool Decrypt(const CBLSSecretKey& secretKey, Object& objRet, int nVersion) const + { + CDataStream ds(SER_NETWORK, nVersion); + if (!CBLSIESEncryptedBlob::Decrypt(secretKey, ds)) { + return false; + } + try { + ds >> objRet; + } catch (std::exception& e) { + return false; + } + return true; + } +}; + +class CBLSIESMultiRecipientBlobs +{ +public: + typedef std::vector Blob; + typedef std::vector BlobVector; + +public: + CBLSPublicKey ephemeralPubKey; + uint256 ivSeed; + BlobVector blobs; + + // Used while encrypting. Temporary and only in-memory + CBLSSecretKey ephemeralSecretKey; + std::vector ivVector; + +public: + bool Encrypt(const std::vector& recipients, const BlobVector& _blobs); + + void InitEncrypt(size_t count); + bool Encrypt(size_t idx, const CBLSPublicKey& recipient, const Blob& blob); + bool Decrypt(size_t idx, const CBLSSecretKey& sk, Blob& blobRet) const; + +public: + ADD_SERIALIZE_METHODS + + template + inline void SerializationOp(Stream& s, Operation ser_action) + { + READWRITE(ephemeralPubKey); + READWRITE(ivSeed); + READWRITE(blobs); + } +}; + +template +class CBLSIESMultiRecipientObjects : public CBLSIESMultiRecipientBlobs +{ +public: + typedef std::vector ObjectVector; + +public: + bool Encrypt(const std::vector& recipients, const ObjectVector& _objects, int nVersion) + { + BlobVector blobs; + blobs.resize(_objects.size()); + + try { + CDataStream ds(SER_NETWORK, nVersion); + for (size_t i = 0; i < _objects.size(); i++) { + ds.clear(); + + ds << _objects[i]; + blobs[i].assign(ds.begin(), ds.end()); + } + } catch (std::exception&) { + return false; + } + + return CBLSIESMultiRecipientBlobs::Encrypt(recipients, blobs); + } + + bool Encrypt(size_t idx, const CBLSPublicKey& recipient, const Object& obj, int nVersion) + { + CDataStream ds(SER_NETWORK, nVersion); + ds << obj; + Blob blob(ds.begin(), ds.end()); + return CBLSIESMultiRecipientBlobs::Encrypt(idx, recipient, blob); + } + + bool Decrypt(size_t idx, const CBLSSecretKey& sk, Object& objectRet, int nVersion) const + { + Blob blob; + if (!CBLSIESMultiRecipientBlobs::Decrypt(idx, sk, blob)) { + return false; + } + + try { + CDataStream ds(blob, SER_NETWORK, nVersion); + ds >> objectRet; + return true; + } catch (std::exception&) { + return false; + } + } +}; + +#endif // DASH_CRYPTO_BLS_IES_H