Fabcoin Core  0.16.2
P2P Digital Currency
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 #include "ECDHE.h"
30 
31 static_assert(CRYPTOPP_VERSION == 570, "Wrong Crypto++ version");
32 
33 using namespace std;
34 using namespace dev;
35 using namespace dev::crypto;
36 using namespace CryptoPP;
37 
38 static_assert(dev::Secret::size == 32, "Secret key must be 32 bytes.");
39 static_assert(dev::Public::size == 64, "Public key must be 64 bytes.");
40 static_assert(dev::Signature::size == 65, "Signature must be 65 bytes.");
41 
42 namespace
43 {
44 class Secp256k1PPCtx
45 {
46 public:
47  OID m_oid;
48 
49  std::mutex x_rng;
50  AutoSeededRandomPool m_rng;
51 
52  std::mutex x_params;
54 
56 
57  Integer m_q;
58  Integer m_qs;
59 
60  static Secp256k1PPCtx& get()
61  {
62  static Secp256k1PPCtx ctx;
63  return ctx;
64  }
65 
66 private:
67  Secp256k1PPCtx():
68  m_oid(ASN1::secp256k1()), m_params(m_oid), m_curve(m_params.GetCurve()),
69  m_q(m_params.GetGroupOrder()), m_qs(m_params.GetSubgroupOrder())
70  {}
71 };
72 
73 inline ECP::Point publicToPoint(Public const& _p) { Integer x(_p.data(), 32); Integer y(_p.data() + 32, 32); return ECP::Point(x,y); }
74 
75 inline Integer secretToExponent(Secret const& _s) { return Integer(_s.data(), Secret::size); }
76 
77 }
78 
79 Secp256k1PP* Secp256k1PP::get()
80 {
81  static Secp256k1PP s_this;
82  return &s_this;
83 }
84 
85 bytes Secp256k1PP::eciesKDF(Secret const& _z, bytes _s1, unsigned kdByteLen)
86 {
87  auto reps = ((kdByteLen + 7) * 8) / (CryptoPP::SHA256::BLOCKSIZE * 8);
88  // SEC/ISO/Shoup specify counter size SHOULD be equivalent
89  // to size of hash output, however, it also notes that
90  // the 4 bytes is okay. NIST specifies 4 bytes.
91  bytes ctr({0, 0, 0, 1});
92  bytes k;
93  CryptoPP::SHA256 ctx;
94  for (unsigned i = 0; i <= reps; i++)
95  {
96  ctx.Update(ctr.data(), ctr.size());
97  ctx.Update(_z.data(), Secret::size);
98  ctx.Update(_s1.data(), _s1.size());
99  // append hash to k
100  bytes digest(32);
101  ctx.Final(digest.data());
102  ctx.Restart();
103 
104  k.reserve(k.size() + h256::size);
105  move(digest.begin(), digest.end(), back_inserter(k));
106 
107  if (++ctr[3] || ++ctr[2] || ++ctr[1] || ++ctr[0])
108  continue;
109  }
110 
111  k.resize(kdByteLen);
112  return k;
113 }
114 
115 void Secp256k1PP::encryptECIES(Public const& _k, bytes& io_cipher)
116 {
117  encryptECIES(_k, bytesConstRef(), io_cipher);
118 }
119 
120 void Secp256k1PP::encryptECIES(Public const& _k, bytesConstRef _sharedMacData, bytes& io_cipher)
121 {
122  // interop w/go ecies implementation
123  auto r = KeyPair::create();
124  Secret z;
125  ecdh::agree(r.secret(), _k, z);
126  auto key = eciesKDF(z, bytes(), 32);
127  bytesConstRef eKey = bytesConstRef(&key).cropped(0, 16);
128  bytesRef mKeyMaterial = bytesRef(&key).cropped(16, 16);
129  CryptoPP::SHA256 ctx;
130  ctx.Update(mKeyMaterial.data(), mKeyMaterial.size());
131  bytes mKey(32);
132  ctx.Final(mKey.data());
133 
134  auto iv = h128::random();
135  bytes cipherText = encryptSymNoAuth(SecureFixedHash<16>(eKey), iv, bytesConstRef(&io_cipher));
136  if (cipherText.empty())
137  return;
138 
139  bytes msg(1 + Public::size + h128::size + cipherText.size() + 32);
140  msg[0] = 0x04;
141  r.pub().ref().copyTo(bytesRef(&msg).cropped(1, Public::size));
142  iv.ref().copyTo(bytesRef(&msg).cropped(1 + Public::size, h128::size));
143  bytesRef msgCipherRef = bytesRef(&msg).cropped(1 + Public::size + h128::size, cipherText.size());
144  bytesConstRef(&cipherText).copyTo(msgCipherRef);
145 
146  // tag message
147  CryptoPP::HMAC<SHA256> hmacctx(mKey.data(), mKey.size());
148  bytesConstRef cipherWithIV = bytesRef(&msg).cropped(1 + Public::size, h128::size + cipherText.size());
149  hmacctx.Update(cipherWithIV.data(), cipherWithIV.size());
150  hmacctx.Update(_sharedMacData.data(), _sharedMacData.size());
151  hmacctx.Final(msg.data() + 1 + Public::size + cipherWithIV.size());
152 
153  io_cipher.resize(msg.size());
154  io_cipher.swap(msg);
155 }
156 
157 bool Secp256k1PP::decryptECIES(Secret const& _k, bytes& io_text)
158 {
159  return decryptECIES(_k, bytesConstRef(), io_text);
160 }
161 
162 bool Secp256k1PP::decryptECIES(Secret const& _k, bytesConstRef _sharedMacData, bytes& io_text)
163 {
164 
165  // interop w/go ecies implementation
166 
167  // io_cipher[0] must be 2, 3, or 4, else invalidpublickey
168  if (io_text.empty() || io_text[0] < 2 || io_text[0] > 4)
169  // invalid message: publickey
170  return false;
171 
172  if (io_text.size() < (1 + Public::size + h128::size + 1 + h256::size))
173  // invalid message: length
174  return false;
175 
176  Secret z;
177  ecdh::agree(_k, *(Public*)(io_text.data() + 1), z);
178  auto key = eciesKDF(z, bytes(), 64);
179  bytesConstRef eKey = bytesConstRef(&key).cropped(0, 16);
180  bytesRef mKeyMaterial = bytesRef(&key).cropped(16, 16);
181  bytes mKey(32);
182  CryptoPP::SHA256 ctx;
183  ctx.Update(mKeyMaterial.data(), mKeyMaterial.size());
184  ctx.Final(mKey.data());
185 
186  bytes plain;
187  size_t cipherLen = io_text.size() - 1 - Public::size - h128::size - h256::size;
188  bytesConstRef cipherWithIV(io_text.data() + 1 + Public::size, h128::size + cipherLen);
189  bytesConstRef cipherIV = cipherWithIV.cropped(0, h128::size);
190  bytesConstRef cipherNoIV = cipherWithIV.cropped(h128::size, cipherLen);
191  bytesConstRef msgMac(cipherNoIV.data() + cipherLen, h256::size);
192  h128 iv(cipherIV.toBytes());
193 
194  // verify tag
195  CryptoPP::HMAC<SHA256> hmacctx(mKey.data(), mKey.size());
196  hmacctx.Update(cipherWithIV.data(), cipherWithIV.size());
197  hmacctx.Update(_sharedMacData.data(), _sharedMacData.size());
198  h256 mac;
199  hmacctx.Final(mac.data());
200  for (unsigned i = 0; i < h256::size; i++)
201  if (mac[i] != msgMac[i])
202  return false;
203 
204  plain = decryptSymNoAuth(SecureFixedHash<16>(eKey), iv, cipherNoIV).makeInsecure();
205  io_text.resize(plain.size());
206  io_text.swap(plain);
207 
208  return true;
209 }
210 
211 void Secp256k1PP::encrypt(Public const& _k, bytes& io_cipher)
212 {
213  auto& ctx = Secp256k1PPCtx::get();
215  {
216  Guard l(ctx.x_params);
217  e.AccessKey().Initialize(ctx.m_params, publicToPoint(_k));
218  }
219 
220  size_t plen = io_cipher.size();
221  bytes ciphertext;
222  ciphertext.resize(e.CiphertextLength(plen));
223 
224  {
225  Guard l(ctx.x_rng);
226  e.Encrypt(ctx.m_rng, io_cipher.data(), plen, ciphertext.data());
227  }
228 
229  memset(io_cipher.data(), 0, io_cipher.size());
230  io_cipher = std::move(ciphertext);
231 }
232 
233 void Secp256k1PP::decrypt(Secret const& _k, bytes& io_text)
234 {
235  auto& ctx = Secp256k1PPCtx::get();
236  CryptoPP::ECIES<CryptoPP::ECP>::Decryptor d;
237  {
238  Guard l(ctx.x_params);
239  d.AccessKey().Initialize(ctx.m_params, secretToExponent(_k));
240  }
241 
242  if (!io_text.size())
243  {
244  io_text.resize(1);
245  io_text[0] = 0;
246  }
247 
248  size_t clen = io_text.size();
249  bytes plain;
250  plain.resize(d.MaxPlaintextLength(io_text.size()));
251 
252  DecodingResult r;
253  {
254  Guard l(ctx.x_rng);
255  r = d.Decrypt(ctx.m_rng, io_text.data(), clen, plain.data());
256  }
257 
258  if (!r.isValidCoding)
259  {
260  io_text.clear();
261  return;
262  }
263 
264  io_text.resize(r.messageLength);
265  io_text = std::move(plain);
266 }
Adapted from code found on http://stackoverflow.com/questions/180947/base64-decode-snippet-in-c Origi...
Definition: Arith256.cpp:15
byte * data()
Definition: FixedHash.h:139
Elliptical Curve Point over GF(p), where p is prime.
Definition: ecpoint.h:21
byte const * data() const
Definition: FixedHash.h:293
CryptoPP secp256k1 algorithms.
Definition: CryptoPP.h:39
Elliptic Curve over GF(p), where p is prime.
Definition: ecp.h:22
bytesSec decryptSymNoAuth(SecureFixedHash< 16 > const &_k, h128 const &_iv, bytesConstRef _cipher)
Decrypts payload with specified IV/ctr using AES128-CTR.
Definition: Common.h:129
bool decryptECIES(Secret const &_k, bytesConstRef _cipher, bytes &o_plaintext)
Decrypt payload using ECIES standard with AES128-CTR.
Definition: Common.cpp:131
std::pair< bytes, h128 > encryptSymNoAuth(SecureFixedHash< 16 > const &_k, bytesConstRef _plain)
Encrypts payload with random IV/ctr using AES128-CTR.
Definition: Common.cpp:157
ASN.1 object identifiers for algorthms and schemes.
std::hash for asio::adress
Definition: Common.h:323
void encryptECIES(Public const &_k, bytesConstRef _plain, bytes &o_cipher)
Encrypt payload using ECIES standard with AES128-CTR.
Definition: Common.cpp:119
size_t messageLength
Recovered message length if isValidCoding is true, undefined otherwise.
Definition: cryptlib.h:261
std::vector< T > const & makeInsecure() const
Definition: Common.h:102
vector_ref< _T > cropped(size_t _begin, size_t _count) const
Definition: vector_ref.h:62
Returns a decoding results.
Definition: cryptlib.h:238
#define x(i)
vector_ref< byte > bytesRef
Definition: Common.h:76
std::lock_guard< std::mutex > Guard
Definition: Guards.h:41
std::vector< byte > bytes
Definition: Common.h:75
Multiple precision integer with arithmetic operations.
Definition: integer.h:43
vector_ref< byte const > bytesConstRef
Definition: Common.h:77
size_t size() const
Definition: vector_ref.h:55
Elliptic Curve Parameters.
Definition: eccrypto.h:32
_T * data() const
Definition: vector_ref.h:51
void encrypt(Public const &_k, bytesConstRef _plain, bytes &o_cipher)
Encrypts plain text using Public key.
Definition: Common.cpp:102
uint8_t const size_t const size
Definition: sha3.h:20
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:69
bool decrypt(Secret const &_k, bytesConstRef _cipher, bytes &o_plaintext)
Decrypts cipher using Secret key.
Definition: Common.cpp:109
void agree(Secret const &_s, Public const &_r, Secret &o_s)
Definition: Common.cpp:348
#define CRYPTOPP_VERSION
Definition: config.h:66
bool isValidCoding
Flag to indicate the decoding is valid.
Definition: cryptlib.h:259
#define e(i)
Definition: sha.cpp:733
Classes and functions for Elliptic Curves over prime and binary fields.
#define d(i)
Definition: sha.cpp:732
#define z(i)
Object Identifier.
Definition: asn.h:166
ECPPoint Point
Definition: ecp.h:27
Classes for access to the operating system&#39;s random number generators.
Template implementing constructors for public key algorithm classes.
Definition: pubkey.h:1989