Ethereum  PoC-8
The C++ Implementation of Ethereum
CryptoPP.cpp
Go to the documentation of this file.
1 /*
2  This file is part of cpp-ethereum.
3 
4  cpp-ethereum is free software: you can redistribute it and/or modify
5  it under the terms of the GNU General Public License as published by
6  the Free Software Foundation, either version 3 of the License, or
7  (at your option) any later version.
8 
9  cpp-ethereum is distributed in the hope that it will be useful,
10  but WITHOUT ANY WARRANTY; without even the implied warranty of
11  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12  GNU General Public License for more details.
13 
14  You should have received a copy of the GNU General Public License
15  along with cpp-ethereum. If not, see <http://www.gnu.org/licenses/>.
16  */
22 #include <libdevcore/Guards.h> // <boost/thread> conflicts with <thread>
23 #include "CryptoPP.h"
24 #include <cryptopp/eccrypto.h>
25 #include <cryptopp/osrng.h>
26 #include <cryptopp/oids.h>
27 #include <libdevcore/Assertions.h>
28 #include <libdevcore/SHA3.h>
29 
30 using namespace dev;
31 using namespace dev::crypto;
32 
33 static_assert(dev::Secret::size == 32, "Secret key must be 32 bytes.");
34 static_assert(dev::Public::size == 64, "Public key must be 64 bytes.");
35 static_assert(dev::Signature::size == 65, "Signature must be 65 bytes.");
36 
37 namespace
38 {
39 class Secp256k1PPCtx
40 {
41 public:
42  CryptoPP::OID m_oid;
43 
44  std::mutex x_rng;
45  CryptoPP::AutoSeededRandomPool m_rng;
46 
47  std::mutex x_params;
48  CryptoPP::DL_GroupParameters_EC<CryptoPP::ECP> m_params;
49 
50  CryptoPP::DL_GroupParameters_EC<CryptoPP::ECP>::EllipticCurve m_curve;
51 
52  CryptoPP::Integer m_q;
53  CryptoPP::Integer m_qs;
54 
55  static Secp256k1PPCtx& get()
56  {
57  static Secp256k1PPCtx ctx;
58  return ctx;
59  }
60 
61 private:
62  Secp256k1PPCtx():
63  m_oid(CryptoPP::ASN1::secp256k1()), m_params(m_oid), m_curve(m_params.GetCurve()),
64  m_q(m_params.GetGroupOrder()), m_qs(m_params.GetSubgroupOrder())
65  {}
66 };
67 
68 inline CryptoPP::ECP::Point publicToPoint(Public const& _p) { CryptoPP::Integer x(_p.data(), 32); CryptoPP::Integer y(_p.data() + 32, 32); return CryptoPP::ECP::Point(x,y); }
69 
70 inline CryptoPP::Integer secretToExponent(Secret const& _s) { return CryptoPP::Integer(_s.data(), Secret::size); }
71 
72 }
73 
75 {
76  static Secp256k1PP s_this;
77  return &s_this;
78 }
79 
80 void Secp256k1PP::encryptECIES(Public const& _k, bytes& io_cipher)
81 {
82  encryptECIES(_k, bytesConstRef(), io_cipher);
83 }
84 
85 void Secp256k1PP::encryptECIES(Public const& _k, bytesConstRef _sharedMacData, bytes& io_cipher)
86 {
87  // interop w/go ecies implementation
88  auto r = KeyPair::create();
89  Secret z;
90  ecdh::agree(r.secret(), _k, z);
91  auto key = ecies::kdf(z, bytes(), 32);
92  bytesConstRef eKey = bytesConstRef(&key).cropped(0, 16);
93  bytesRef mKeyMaterial = bytesRef(&key).cropped(16, 16);
94  CryptoPP::SHA256 ctx;
95  ctx.Update(mKeyMaterial.data(), mKeyMaterial.size());
96  bytes mKey(32);
97  ctx.Final(mKey.data());
98 
99  auto iv = h128::random();
100  bytes cipherText = encryptSymNoAuth(SecureFixedHash<16>(eKey), iv, bytesConstRef(&io_cipher));
101  if (cipherText.empty())
102  return;
103 
104  bytes msg(1 + Public::size + h128::size + cipherText.size() + 32);
105  msg[0] = 0x04;
106  r.pub().ref().copyTo(bytesRef(&msg).cropped(1, Public::size));
107  iv.ref().copyTo(bytesRef(&msg).cropped(1 + Public::size, h128::size));
108  bytesRef msgCipherRef = bytesRef(&msg).cropped(1 + Public::size + h128::size, cipherText.size());
109  bytesConstRef(&cipherText).copyTo(msgCipherRef);
110 
111  // tag message
112  CryptoPP::HMAC<CryptoPP::SHA256> hmacctx(mKey.data(), mKey.size());
113  bytesConstRef cipherWithIV = bytesRef(&msg).cropped(1 + Public::size, h128::size + cipherText.size());
114  hmacctx.Update(cipherWithIV.data(), cipherWithIV.size());
115  hmacctx.Update(_sharedMacData.data(), _sharedMacData.size());
116  hmacctx.Final(msg.data() + 1 + Public::size + cipherWithIV.size());
117 
118  io_cipher.resize(msg.size());
119  io_cipher.swap(msg);
120 }
121 
122 bool Secp256k1PP::decryptECIES(Secret const& _k, bytes& io_text)
123 {
124  return decryptECIES(_k, bytesConstRef(), io_text);
125 }
126 
127 bool Secp256k1PP::decryptECIES(Secret const& _k, bytesConstRef _sharedMacData, bytes& io_text)
128 {
129 
130  // interop w/go ecies implementation
131 
132  // io_cipher[0] must be 2, 3, or 4, else invalidpublickey
133  if (io_text.empty() || io_text[0] < 2 || io_text[0] > 4)
134  // invalid message: publickey
135  return false;
136 
137  if (io_text.size() < (1 + Public::size + h128::size + 1 + h256::size))
138  // invalid message: length
139  return false;
140 
141  Secret z;
142  if (!ecdh::agree(_k, *(Public*)(io_text.data() + 1), z))
143  return false; // Invalid pubkey or seckey.
144  auto key = ecies::kdf(z, bytes(), 64);
145  bytesConstRef eKey = bytesConstRef(&key).cropped(0, 16);
146  bytesRef mKeyMaterial = bytesRef(&key).cropped(16, 16);
147  bytes mKey(32);
148  CryptoPP::SHA256 ctx;
149  ctx.Update(mKeyMaterial.data(), mKeyMaterial.size());
150  ctx.Final(mKey.data());
151 
152  bytes plain;
153  size_t cipherLen = io_text.size() - 1 - Public::size - h128::size - h256::size;
154  bytesConstRef cipherWithIV(io_text.data() + 1 + Public::size, h128::size + cipherLen);
155  bytesConstRef cipherIV = cipherWithIV.cropped(0, h128::size);
156  bytesConstRef cipherNoIV = cipherWithIV.cropped(h128::size, cipherLen);
157  bytesConstRef msgMac(cipherNoIV.data() + cipherLen, h256::size);
158  h128 iv(cipherIV.toBytes());
159 
160  // verify tag
161  CryptoPP::HMAC<CryptoPP::SHA256> hmacctx(mKey.data(), mKey.size());
162  hmacctx.Update(cipherWithIV.data(), cipherWithIV.size());
163  hmacctx.Update(_sharedMacData.data(), _sharedMacData.size());
164  h256 mac;
165  hmacctx.Final(mac.data());
166  for (unsigned i = 0; i < h256::size; i++)
167  if (mac[i] != msgMac[i])
168  return false;
169 
170  plain = decryptSymNoAuth(SecureFixedHash<16>(eKey), iv, cipherNoIV).makeInsecure();
171  io_text.resize(plain.size());
172  io_text.swap(plain);
173 
174  return true;
175 }
176 
177 void Secp256k1PP::encrypt(Public const& _k, bytes& io_cipher)
178 {
179  auto& ctx = Secp256k1PPCtx::get();
180 
181 #pragma GCC diagnostic push
182 #pragma GCC diagnostic ignored "-Wdeprecated-declarations"
183 #pragma clang diagnostic push
184 #pragma clang diagnostic ignored "-Wdeprecated-declarations"
185  CryptoPP::ECIES<CryptoPP::ECP>::Encryptor e;
186 #pragma GCC diagnostic pop
187 #pragma clang diagnostic pop
188 
189  {
190  Guard l(ctx.x_params);
191  e.AccessKey().Initialize(ctx.m_params, publicToPoint(_k));
192  }
193 
194 
195  size_t plen = io_cipher.size();
196  bytes ciphertext;
197  ciphertext.resize(e.CiphertextLength(plen));
198 
199  {
200  Guard l(ctx.x_rng);
201  e.Encrypt(ctx.m_rng, io_cipher.data(), plen, ciphertext.data());
202  }
203 
204  memset(io_cipher.data(), 0, io_cipher.size());
205  io_cipher = std::move(ciphertext);
206 }
207 
208 void Secp256k1PP::decrypt(Secret const& _k, bytes& io_text)
209 {
210  auto& ctx = Secp256k1PPCtx::get();
211 
212 #pragma GCC diagnostic push
213 #pragma GCC diagnostic ignored "-Wdeprecated-declarations"
214 #pragma clang diagnostic push
215 #pragma clang diagnostic ignored "-Wdeprecated-declarations"
216  CryptoPP::ECIES<CryptoPP::ECP>::Decryptor d;
217 #pragma GCC diagnostic pop
218 #pragma clang diagnostic pop
219 
220  {
221  Guard l(ctx.x_params);
222  d.AccessKey().Initialize(ctx.m_params, secretToExponent(_k));
223  }
224 
225  if (!io_text.size())
226  {
227  io_text.resize(1);
228  io_text[0] = 0;
229  }
230 
231  size_t clen = io_text.size();
232  bytes plain;
233  plain.resize(d.MaxPlaintextLength(io_text.size()));
234 
235  CryptoPP::DecodingResult r;
236  {
237  Guard l(ctx.x_rng);
238  r = d.Decrypt(ctx.m_rng, io_text.data(), clen, plain.data());
239  }
240 
241  if (!r.isValidCoding)
242  {
243  io_text.clear();
244  return;
245  }
246 
247  io_text.resize(r.messageLength);
248  io_text = std::move(plain);
249 }
dev::encryptSymNoAuth
std::pair< bytes, h128 > encryptSymNoAuth(SecureFixedHash< 16 > const &_k, bytesConstRef _plain)
Encrypts payload with random IV/ctr using AES128-CTR.
Definition: Common.cpp:175
dev::SecureFixedHash::data
byte const * data() const
Definition: FixedHash.h:303
dev::vector_ref< byte const >
dev::crypto::Secp256k1PP::encrypt
void encrypt(Public const &_k, bytes &io_cipher)
Encrypts text (replace input). (ECIES w/XOR-SHA1)
Definition: CryptoPP.cpp:177
dev::decryptSymNoAuth
bytesSec decryptSymNoAuth(SecureFixedHash< 16 > const &_k, h128 const &_iv, bytesConstRef _cipher)
Decrypts payload with specified IV/ctr using AES128-CTR.
Definition: Common.h:124
dev::FixedHash::data
byte * data()
Definition: FixedHash.h:138
dev::SecureFixedHash< 32 >
dev::Guard
std::lock_guard< std::mutex > Guard
Definition: Guards.h:41
dev::vector_ref::copyTo
void copyTo(vector_ref< typename std::remove_const< _T >::type > _t) const
Copies the contents of this vector_ref to the contents of _t, up to the max size of _t.
Definition: vector_ref.h:67
CryptoPP.h
dev::FixedHash< 64 >
dev::crypto::Secp256k1PP::decryptECIES
bool decryptECIES(Secret const &_k, bytes &io_text)
Decrypts text (replace input). (ECIES w/AES128-CTR-SHA256)
Definition: CryptoPP.cpp:122
dev::crypto::Secp256k1PP::decrypt
void decrypt(Secret const &_k, bytes &io_text)
Decrypts text (replace input). (ECIES w/XOR-SHA1)
Definition: CryptoPP.cpp:208
dev::KeyPair::create
static KeyPair create()
Create a new, randomly generated object.
Definition: Common.cpp:340
dev::crypto
Definition: Common.h:180
dev::vector_ref::cropped
vector_ref< _T > cropped(size_t _begin, size_t _count) const
Definition: vector_ref.h:60
dev::bytes
std::vector< byte > bytes
Definition: Common.h:72
SHA3.h
dev::vector_ref::data
_T * data() const
Definition: vector_ref.h:49
dev::bytesConstRef
vector_ref< byte const > bytesConstRef
Definition: Common.h:74
dev::secure_vector::makeInsecure
std::vector< T > const & makeInsecure() const
Definition: Common.h:99
dev::FixedHash::random
static FixedHash random()
Definition: FixedHash.h:167
dev::vector_ref::size
size_t size() const
Definition: vector_ref.h:53
dev::crypto::Secp256k1PP::get
static Secp256k1PP * get()
Definition: CryptoPP.cpp:74
dev::bytesRef
vector_ref< byte > bytesRef
Definition: Common.h:73
dev::crypto::ecdh::agree
bool agree(Secret const &_s, Public const &_r, Secret &o_s) noexcept
Definition: Common.cpp:388
dev::crypto::Secp256k1PP::encryptECIES
void encryptECIES(Public const &_k, bytes &io_cipher)
Encrypts text (replace input). (ECIES w/AES128-CTR-SHA256)
Definition: CryptoPP.cpp:80
dev::crypto::ecies::kdf
bytes kdf(Secret const &_z, bytes const &_s1, unsigned kdByteLen)
Definition: Common.cpp:406
Assertions.h
dev::FixedHash< T >::size
@ size
Definition: FixedHash.h:53
dev::vector_ref::toBytes
std::vector< unsigned char > toBytes() const
Definition: vector_ref.h:43
dev
Definition: Address.cpp:21
dev::crypto::Secp256k1PP
Definition: CryptoPP.h:40
Guards.h