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