NS-3 based Named Data Networking (NDN) simulator
ndnSIM 2.3: NDN, CCN, CCNx, content centric networks
API Documentation
sec-tpm.cpp
Go to the documentation of this file.
1 /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
24 #include "sec-tpm.hpp"
25 
26 #include "../encoding/oid.hpp"
27 #include "../encoding/buffer-stream.hpp"
28 #include "v1/cryptopp.hpp"
29 #include <unistd.h>
30 
31 namespace ndn {
32 namespace security {
33 
34 SecTpm::SecTpm(const std::string& location)
35  : m_location(location)
36 {
37 }
38 
40 {
41 }
42 
43 std::string
45 {
46  return this->getScheme() + ":" + m_location;
47 }
48 
50 SecTpm::exportPrivateKeyPkcs5FromTpm(const Name& keyName, const std::string& passwordStr)
51 {
52  using namespace CryptoPP;
53 
54  uint8_t salt[8] = {0};
55  uint8_t iv[8] = {0};
56 
57  // derive key
58  if (!generateRandomBlock(salt, 8) || !generateRandomBlock(iv, 8))
59  BOOST_THROW_EXCEPTION(Error("Cannot generate salt or iv"));
60 
61  uint32_t iterationCount = 2048;
62 
63  PKCS5_PBKDF2_HMAC<SHA1> keyGenerator;
64  size_t derivedLen = 24; // For DES-EDE3-CBC-PAD
65  byte derived[24] = {0};
66  byte purpose = 0;
67 
68  try {
69  keyGenerator.DeriveKey(derived, derivedLen, purpose,
70  reinterpret_cast<const byte*>(passwordStr.c_str()), passwordStr.size(),
71  salt, 8, iterationCount);
72  }
73  catch (const CryptoPP::Exception& e) {
74  BOOST_THROW_EXCEPTION(Error("Cannot derived the encryption key"));
75  }
76 
77  // encrypt
78  CBC_Mode< DES_EDE3 >::Encryption e;
79  e.SetKeyWithIV(derived, derivedLen, iv);
80 
81  ConstBufferPtr pkcs8PrivateKey = exportPrivateKeyPkcs8FromTpm(keyName);
82 
83  if (pkcs8PrivateKey == nullptr)
84  BOOST_THROW_EXCEPTION(Error("Cannot export the private key, #1"));
85 
86  OBufferStream encryptedOs;
87  try {
88  StringSource stringSource(pkcs8PrivateKey->buf(), pkcs8PrivateKey->size(), true,
89  new StreamTransformationFilter(e, new FileSink(encryptedOs)));
90  }
91  catch (const CryptoPP::Exception& e) {
92  BOOST_THROW_EXCEPTION(Error("Cannot export the private key, #2"));
93  }
94 
95  // encode
96  Oid pbes2Id("1.2.840.113549.1.5.13");
97  Oid pbkdf2Id("1.2.840.113549.1.5.12");
98  Oid pbes2encsId("1.2.840.113549.3.7");
99 
100  OBufferStream pkcs8Os;
101  try {
102  FileSink sink(pkcs8Os);
103 
104  // EncryptedPrivateKeyInfo ::= SEQUENCE {
105  // encryptionAlgorithm EncryptionAlgorithmIdentifier,
106  // encryptedData OCTET STRING }
107  DERSequenceEncoder encryptedPrivateKeyInfo(sink);
108  {
109  // EncryptionAlgorithmIdentifier ::= SEQUENCE {
110  // algorithm OBJECT IDENTIFIER {{PBES2-id}},
111  // parameters SEQUENCE {{PBES2-params}} }
112  DERSequenceEncoder encryptionAlgorithm(encryptedPrivateKeyInfo);
113  {
114  pbes2Id.encode(encryptionAlgorithm);
115  // PBES2-params ::= SEQUENCE {
116  // keyDerivationFunc AlgorithmIdentifier {{PBES2-KDFs}},
117  // encryptionScheme AlgorithmIdentifier {{PBES2-Encs}} }
118  DERSequenceEncoder pbes2Params(encryptionAlgorithm);
119  {
120  // AlgorithmIdentifier ::= SEQUENCE {
121  // algorithm OBJECT IDENTIFIER {{PBKDF2-id}},
122  // parameters SEQUENCE {{PBKDF2-params}} }
123  DERSequenceEncoder pbes2KDFs(pbes2Params);
124  {
125  pbkdf2Id.encode(pbes2KDFs);
126  // AlgorithmIdentifier ::= SEQUENCE {
127  // salt OCTET STRING,
128  // iterationCount INTEGER (1..MAX),
129  // keyLength INTEGER (1..MAX) OPTIONAL,
130  // prf AlgorithmIdentifier {{PBKDF2-PRFs}} DEFAULT algid-hmacWithSHA1 }
131  DERSequenceEncoder pbkdf2Params(pbes2KDFs);
132  {
133  DEREncodeOctetString(pbkdf2Params, salt, 8);
134  DEREncodeUnsigned<uint32_t>(pbkdf2Params, iterationCount, INTEGER);
135  }
136  pbkdf2Params.MessageEnd();
137  }
138  pbes2KDFs.MessageEnd();
139 
140  // AlgorithmIdentifier ::= SEQUENCE {
141  // algorithm OBJECT IDENTIFIER {{DES-EDE3-CBC-PAD}},
142  // parameters OCTET STRING} {{iv}} }
143  DERSequenceEncoder pbes2Encs(pbes2Params);
144  {
145  pbes2encsId.encode(pbes2Encs);
146  DEREncodeOctetString(pbes2Encs, iv, 8);
147  }
148  pbes2Encs.MessageEnd();
149  }
150  pbes2Params.MessageEnd();
151  }
152  encryptionAlgorithm.MessageEnd();
153 
154  DEREncodeOctetString(encryptedPrivateKeyInfo,
155  encryptedOs.buf()->buf(), encryptedOs.buf()->size());
156  }
157  encryptedPrivateKeyInfo.MessageEnd();
158 
159  return pkcs8Os.buf();
160  }
161  catch (const CryptoPP::Exception& e) {
162  BOOST_THROW_EXCEPTION(Error("Cannot export the private key, #3"));
163  }
164 }
165 
166 bool
168  const uint8_t* buf, size_t size,
169  const std::string& passwordStr)
170 {
171  using namespace CryptoPP;
172 
173  Oid pbes2Id;
174  Oid pbkdf2Id;
175  SecByteBlock saltBlock;
176  uint32_t iterationCount;
177  Oid pbes2encsId;
178  SecByteBlock ivBlock;
179  SecByteBlock encryptedDataBlock;
180 
181  try {
182  // decode some decoding processes are not necessary for now,
183  // because we assume only one encryption scheme.
184  StringSource source(buf, size, true);
185 
186  // EncryptedPrivateKeyInfo ::= SEQUENCE {
187  // encryptionAlgorithm EncryptionAlgorithmIdentifier,
188  // encryptedData OCTET STRING }
189  BERSequenceDecoder encryptedPrivateKeyInfo(source);
190  {
191  // EncryptionAlgorithmIdentifier ::= SEQUENCE {
192  // algorithm OBJECT IDENTIFIER {{PBES2-id}},
193  // parameters SEQUENCE {{PBES2-params}} }
194  BERSequenceDecoder encryptionAlgorithm(encryptedPrivateKeyInfo);
195  {
196  pbes2Id.decode(encryptionAlgorithm);
197  // PBES2-params ::= SEQUENCE {
198  // keyDerivationFunc AlgorithmIdentifier {{PBES2-KDFs}},
199  // encryptionScheme AlgorithmIdentifier {{PBES2-Encs}} }
200  BERSequenceDecoder pbes2Params(encryptionAlgorithm);
201  {
202  // AlgorithmIdentifier ::= SEQUENCE {
203  // algorithm OBJECT IDENTIFIER {{PBKDF2-id}},
204  // parameters SEQUENCE {{PBKDF2-params}} }
205  BERSequenceDecoder pbes2KDFs(pbes2Params);
206  {
207  pbkdf2Id.decode(pbes2KDFs);
208  // AlgorithmIdentifier ::= SEQUENCE {
209  // salt OCTET STRING,
210  // iterationCount INTEGER (1..MAX),
211  // keyLength INTEGER (1..MAX) OPTIONAL,
212  // prf AlgorithmIdentifier {{PBKDF2-PRFs}} DEFAULT algid-hmacWithSHA1 }
213  BERSequenceDecoder pbkdf2Params(pbes2KDFs);
214  {
215  BERDecodeOctetString(pbkdf2Params, saltBlock);
216  BERDecodeUnsigned<uint32_t>(pbkdf2Params, iterationCount, INTEGER);
217  }
218  pbkdf2Params.MessageEnd();
219  }
220  pbes2KDFs.MessageEnd();
221 
222  // AlgorithmIdentifier ::= SEQUENCE {
223  // algorithm OBJECT IDENTIFIER {{DES-EDE3-CBC-PAD}},
224  // parameters OCTET STRING} {{iv}} }
225  BERSequenceDecoder pbes2Encs(pbes2Params);
226  {
227  pbes2encsId.decode(pbes2Encs);
228  BERDecodeOctetString(pbes2Encs, ivBlock);
229  }
230  pbes2Encs.MessageEnd();
231  }
232  pbes2Params.MessageEnd();
233  }
234  encryptionAlgorithm.MessageEnd();
235 
236  BERDecodeOctetString(encryptedPrivateKeyInfo, encryptedDataBlock);
237  }
238  encryptedPrivateKeyInfo.MessageEnd();
239  }
240  catch (const CryptoPP::Exception& e) {
241  return false;
242  }
243 
244  PKCS5_PBKDF2_HMAC<SHA1> keyGenerator;
245  size_t derivedLen = 24; //For DES-EDE3-CBC-PAD
246  byte derived[24] = {0};
247  byte purpose = 0;
248 
249  try {
250  keyGenerator.DeriveKey(derived, derivedLen,
251  purpose,
252  reinterpret_cast<const byte*>(passwordStr.c_str()), passwordStr.size(),
253  saltBlock.BytePtr(), saltBlock.size(),
254  iterationCount);
255  }
256  catch (const CryptoPP::Exception& e) {
257  return false;
258  }
259 
260  //decrypt
261  CBC_Mode< DES_EDE3 >::Decryption d;
262  d.SetKeyWithIV(derived, derivedLen, ivBlock.BytePtr());
263 
264  OBufferStream privateKeyOs;
265  try {
266  StringSource encryptedSource(encryptedDataBlock.BytePtr(), encryptedDataBlock.size(), true,
267  new StreamTransformationFilter(d, new FileSink(privateKeyOs)));
268  }
269  catch (const CryptoPP::Exception& e) {
270  return false;
271  }
272 
273  if (!importPrivateKeyPkcs8IntoTpm(keyName,
274  privateKeyOs.buf()->buf(), privateKeyOs.buf()->size()))
275  return false;
276 
277  // determine key type
278  StringSource privateKeySource(privateKeyOs.buf()->buf(), privateKeyOs.buf()->size(), true);
279 
280  KeyType publicKeyType = KeyType::NONE;
281  SecByteBlock rawKeyBits;
282  // PrivateKeyInfo ::= SEQUENCE {
283  // INTEGER,
284  // SEQUENCE,
285  // OCTECT STRING}
286  BERSequenceDecoder privateKeyInfo(privateKeySource);
287  {
288  uint32_t versionNum;
289  BERDecodeUnsigned<uint32_t>(privateKeyInfo, versionNum, INTEGER);
290  BERSequenceDecoder sequenceDecoder(privateKeyInfo);
291  {
292  Oid keyTypeOid;
293  keyTypeOid.decode(sequenceDecoder);
294  if (keyTypeOid == oid::RSA)
295  publicKeyType = KeyType::RSA;
296  else if (keyTypeOid == oid::ECDSA)
297  publicKeyType = KeyType::EC;
298  else
299  return false; // Unsupported key type;
300  }
301  }
302 
303 
304  // derive public key
305  OBufferStream publicKeyOs;
306 
307  try {
308  switch (publicKeyType) {
309  case KeyType::RSA: {
310  RSA::PrivateKey privateKey;
311  privateKey.Load(StringStore(privateKeyOs.buf()->buf(), privateKeyOs.buf()->size()).Ref());
312  RSAFunction publicKey(privateKey);
313 
314  FileSink publicKeySink(publicKeyOs);
315  publicKey.DEREncode(publicKeySink);
316  publicKeySink.MessageEnd();
317  break;
318  }
319 
320  case KeyType::EC: {
321  ECDSA<ECP, SHA256>::PrivateKey privateKey;
322  privateKey.Load(StringStore(privateKeyOs.buf()->buf(), privateKeyOs.buf()->size()).Ref());
323 
324  ECDSA<ECP, SHA256>::PublicKey publicKey;
325  privateKey.MakePublicKey(publicKey);
326  publicKey.AccessGroupParameters().SetEncodeAsOID(true);
327 
328  FileSink publicKeySink(publicKeyOs);
329  publicKey.DEREncode(publicKeySink);
330  publicKeySink.MessageEnd();
331  break;
332  }
333 
334  default:
335  return false;
336  }
337  }
338  catch (const CryptoPP::Exception& e) {
339  return false;
340  }
341 
342  if (!importPublicKeyPkcs1IntoTpm(keyName, publicKeyOs.buf()->buf(), publicKeyOs.buf()->size()))
343  return false;
344 
345  return true;
346 }
347 
348 bool
349 SecTpm::getImpExpPassWord(std::string& password, const std::string& prompt)
350 {
351  bool isInitialized = false;
352 
353 #ifdef NDN_CXX_HAVE_GETPASS
354  char* pw0 = nullptr;
355 
356  pw0 = getpass(prompt.c_str());
357  if (pw0 == nullptr)
358  return false;
359  std::string password1 = pw0;
360  memset(pw0, 0, strlen(pw0));
361 
362  pw0 = getpass("Confirm:");
363  if (pw0 == nullptr) {
364  std::fill(password1.begin(), password1.end(), 0);
365  return false;
366  }
367 
368  if (password1.compare(pw0) == 0) {
369  isInitialized = true;
370  password.swap(password1);
371  }
372 
373  std::fill(password1.begin(), password1.end(), 0);
374  memset(pw0, 0, strlen(pw0));
375 
376  if (password.empty())
377  return false;
378 
379 #endif // NDN_CXX_HAVE_GETPASS
380 
381  return isInitialized;
382 }
383 
384 } // namespace security
385 } // namespace ndn
void encode(CryptoPP::BufferedTransformation &out) const
Definition: oid.cpp:118
void decode(CryptoPP::BufferedTransformation &in)
Definition: oid.cpp:135
const Oid ECDSA("1.2.840.10045.2.1")
Definition: oid.hpp:102
Copyright (c) 2011-2015 Regents of the University of California.
Copyright (c) 2013-2016 Regents of the University of California.
Definition: oid.hpp:29
std::string m_location
Definition: sec-tpm.hpp:301
ConstBufferPtr exportPrivateKeyPkcs5FromTpm(const Name &keyName, const std::string &password)
Export a private key in PKCS#5 format.
Definition: sec-tpm.cpp:50
SecTpm(const std::string &location)
Definition: sec-tpm.cpp:34
std::string getTpmLocator()
Definition: sec-tpm.cpp:44
virtual bool importPublicKeyPkcs1IntoTpm(const Name &keyName, const uint8_t *buffer, size_t bufferSize)=0
Import a public key in PKCS#1 formatted buffer of size bufferSize.
virtual bool generateRandomBlock(uint8_t *res, size_t size)=0
Generate a random block.
const Oid RSA("1.2.840.113549.1.1.1")
Definition: oid.hpp:101
Definition: oid.hpp:35
virtual bool importPrivateKeyPkcs8IntoTpm(const Name &keyName, const uint8_t *buffer, size_t bufferSize)=0
Import a private key from PKCS#8 formatted buffer of size bufferSize.
Name abstraction to represent an absolute name.
Definition: name.hpp:46
shared_ptr< Buffer > buf()
Flush written data to the stream and return shared pointer to the underlying buffer.
virtual ConstBufferPtr exportPrivateKeyPkcs8FromTpm(const Name &keyName)=0
Export a private key in PKCS#8 format.
bool importPrivateKeyPkcs5IntoTpm(const Name &keyName, const uint8_t *buffer, size_t bufferSize, const std::string &password)
Import a private key in PKCS#5 formatted buffer of size bufferSize.
Definition: sec-tpm.cpp:167
implements an output stream that constructs ndn::Buffer
virtual std::string getScheme()=0
virtual bool getImpExpPassWord(std::string &password, const std::string &prompt)
Get import/export password.
Definition: sec-tpm.cpp:349
shared_ptr< const Buffer > ConstBufferPtr
Definition: buffer.hpp:33