NS-3 based Named Data Networking (NDN) simulator
ndnSIM 2.0: NDN, CCN, CCNx, content centric networks
API Documentation
sec-tpm-file.cpp
Go to the documentation of this file.
1 /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
26 #include "sec-tpm-file.hpp"
27 
28 #include "../encoding/buffer-stream.hpp"
29 
30 #include <boost/filesystem.hpp>
31 #include <boost/algorithm/string.hpp>
32 
33 #include "cryptopp.hpp"
34 
35 #include <sys/types.h>
36 #include <sys/stat.h>
37 
38 #include <algorithm>
39 
40 namespace ndn {
41 
42 using std::string;
43 using std::ostringstream;
44 using std::ofstream;
45 
46 const std::string SecTpmFile::SCHEME("tpm-file");
47 
49 {
50 public:
51  explicit
52  Impl(const string& dir)
53  {
54  if (dir.empty())
55  m_keystorePath = boost::filesystem::path(getenv("HOME")) / ".ndn" / "ndnsec-tpm-file";
56  else
57  m_keystorePath = boost::filesystem::path(dir) / ".ndn" / "ndnsec-tpm-file";
58 
59  boost::filesystem::create_directories(m_keystorePath);
60  }
61 
62  boost::filesystem::path
63  transformName(const string& keyName, const string& extension)
64  {
65  using namespace CryptoPP;
66  string digest;
67  SHA256 hash;
68  StringSource src(keyName,
69  true,
70  new HashFilter(hash,
71  new Base64Encoder(new CryptoPP::StringSink(digest))));
72 
73  boost::algorithm::trim(digest);
74  std::replace(digest.begin(), digest.end(), '/', '%');
75 
76  return m_keystorePath / (digest + extension);
77  }
78 
79  string
80  maintainMapping(const string& keyName)
81  {
82  string keyFileName = transformName(keyName, "").string();
83 
84  ofstream outfile;
85  string dirFile = (m_keystorePath / "mapping.txt").string();
86 
87  outfile.open(dirFile.c_str(), std::ios_base::app);
88  outfile << keyName << ' ' << keyFileName << '\n';
89  outfile.close();
90 
91  return keyFileName;
92  }
93 
94 public:
95  boost::filesystem::path m_keystorePath;
96 };
97 
98 
99 SecTpmFile::SecTpmFile(const string& location)
100  : SecTpm(location)
101  , m_impl(new Impl(location))
102  , m_inTerminal(false)
103 {
104 }
105 
107 {
108 }
109 
110 void
111 SecTpmFile::generateKeyPairInTpm(const Name& keyName, const KeyParams& params)
112 {
113  string keyURI = keyName.toUri();
114 
115  if (doesKeyExistInTpm(keyName, KEY_CLASS_PUBLIC))
116  BOOST_THROW_EXCEPTION(Error("public key exists"));
117  if (doesKeyExistInTpm(keyName, KEY_CLASS_PRIVATE))
118  BOOST_THROW_EXCEPTION(Error("private key exists"));
119 
120  string keyFileName = m_impl->maintainMapping(keyURI);
121 
122  try
123  {
124  switch (params.getKeyType())
125  {
126  case KEY_TYPE_RSA:
127  {
128  using namespace CryptoPP;
129 
130  const RsaKeyParams& rsaParams = static_cast<const RsaKeyParams&>(params);
131  AutoSeededRandomPool rng;
132  InvertibleRSAFunction privateKey;
133  privateKey.Initialize(rng, rsaParams.getKeySize());
134 
135  string privateKeyFileName = keyFileName + ".pri";
136  Base64Encoder privateKeySink(new FileSink(privateKeyFileName.c_str()));
137  privateKey.DEREncode(privateKeySink);
138  privateKeySink.MessageEnd();
139 
140  RSAFunction publicKey(privateKey);
141  string publicKeyFileName = keyFileName + ".pub";
142  Base64Encoder publicKeySink(new FileSink(publicKeyFileName.c_str()));
143  publicKey.DEREncode(publicKeySink);
144  publicKeySink.MessageEnd();
145 
146  /*set file permission*/
147  chmod(privateKeyFileName.c_str(), 0000400);
148  chmod(publicKeyFileName.c_str(), 0000444);
149  return;
150  }
151  case KEY_TYPE_ECDSA:
152  {
153  using namespace CryptoPP;
154 
155  const EcdsaKeyParams& ecdsaParams = static_cast<const EcdsaKeyParams&>(params);
156 
157  CryptoPP::OID curveName;
158  switch (ecdsaParams.getKeySize())
159  {
160  case 256:
161  curveName = ASN1::secp256r1();
162  break;
163  case 384:
164  curveName = ASN1::secp384r1();
165  break;
166  default:
167  curveName = ASN1::secp256r1();
168  }
169 
170  AutoSeededRandomPool rng;
171 
172  ECDSA<ECP, SHA256>::PrivateKey privateKey;
173  DL_GroupParameters_EC<ECP> cryptoParams(curveName);
174  cryptoParams.SetEncodeAsOID(true);
175  privateKey.Initialize(rng, cryptoParams);
176 
177  ECDSA<ECP, SHA256>::PublicKey publicKey;
178  privateKey.MakePublicKey(publicKey);
179  publicKey.AccessGroupParameters().SetEncodeAsOID(true);
180 
181  string privateKeyFileName = keyFileName + ".pri";
182  Base64Encoder privateKeySink(new FileSink(privateKeyFileName.c_str()));
183  privateKey.DEREncode(privateKeySink);
184  privateKeySink.MessageEnd();
185 
186  string publicKeyFileName = keyFileName + ".pub";
187  Base64Encoder publicKeySink(new FileSink(publicKeyFileName.c_str()));
188  publicKey.Save(publicKeySink);
189  publicKeySink.MessageEnd();
190 
191  /*set file permission*/
192  chmod(privateKeyFileName.c_str(), 0000400);
193  chmod(publicKeyFileName.c_str(), 0000444);
194  return;
195  }
196  default:
197  BOOST_THROW_EXCEPTION(Error("Unsupported key type"));
198  }
199  }
200  catch (KeyParams::Error& e)
201  {
202  BOOST_THROW_EXCEPTION(Error(e.what()));
203  }
204  catch (CryptoPP::Exception& e)
205  {
206  BOOST_THROW_EXCEPTION(Error(e.what()));
207  }
208 }
209 
210 void
212 {
213  boost::filesystem::path publicKeyPath(m_impl->transformName(keyName.toUri(), ".pub"));
214  boost::filesystem::path privateKeyPath(m_impl->transformName(keyName.toUri(), ".pri"));
215 
216  if (boost::filesystem::exists(publicKeyPath))
217  boost::filesystem::remove(publicKeyPath);
218 
219  if (boost::filesystem::exists(privateKeyPath))
220  boost::filesystem::remove(privateKeyPath);
221 }
222 
223 shared_ptr<PublicKey>
225 {
226  string keyURI = keyName.toUri();
227 
228  if (!doesKeyExistInTpm(keyName, KEY_CLASS_PUBLIC))
229  BOOST_THROW_EXCEPTION(Error("Public Key does not exist"));
230 
231  ostringstream os;
232  try
233  {
234  using namespace CryptoPP;
235  FileSource(m_impl->transformName(keyURI, ".pub").string().c_str(),
236  true,
237  new Base64Decoder(new FileSink(os)));
238  }
239  catch (CryptoPP::Exception& e)
240  {
241  BOOST_THROW_EXCEPTION(Error(e.what()));
242  }
243 
244  return make_shared<PublicKey>(reinterpret_cast<const uint8_t*>(os.str().c_str()),
245  os.str().size());
246 }
247 
248 std::string
250 {
251  return SCHEME;
252 }
253 
256 {
257  OBufferStream privateKeyOs;
258  CryptoPP::FileSource(m_impl->transformName(keyName.toUri(), ".pri").string().c_str(), true,
259  new CryptoPP::Base64Decoder(new CryptoPP::FileSink(privateKeyOs)));
260 
261  return privateKeyOs.buf();
262 }
263 
264 bool
265 SecTpmFile::importPrivateKeyPkcs8IntoTpm(const Name& keyName, const uint8_t* buf, size_t size)
266 {
267  try
268  {
269  using namespace CryptoPP;
270 
271  string keyFileName = m_impl->maintainMapping(keyName.toUri());
272  keyFileName.append(".pri");
273  StringSource(buf, size,
274  true,
275  new Base64Encoder(new FileSink(keyFileName.c_str())));
276  return true;
277  }
278  catch (CryptoPP::Exception& e)
279  {
280  return false;
281  }
282 }
283 
284 bool
285 SecTpmFile::importPublicKeyPkcs1IntoTpm(const Name& keyName, const uint8_t* buf, size_t size)
286 {
287  try
288  {
289  using namespace CryptoPP;
290 
291  string keyFileName = m_impl->maintainMapping(keyName.toUri());
292  keyFileName.append(".pub");
293  StringSource(buf, size,
294  true,
295  new Base64Encoder(new FileSink(keyFileName.c_str())));
296  return true;
297  }
298  catch (CryptoPP::Exception& e)
299  {
300  return false;
301  }
302 }
303 
304 Block
305 SecTpmFile::signInTpm(const uint8_t* data, size_t dataLength,
306  const Name& keyName, DigestAlgorithm digestAlgorithm)
307 {
308  string keyURI = keyName.toUri();
309 
310  if (!doesKeyExistInTpm(keyName, KEY_CLASS_PRIVATE))
311  BOOST_THROW_EXCEPTION(Error("private key doesn't exist"));
312 
313  try
314  {
315  using namespace CryptoPP;
316  AutoSeededRandomPool rng;
317 
318  //Read public key
319  shared_ptr<PublicKey> pubkeyPtr;
320  pubkeyPtr = getPublicKeyFromTpm(keyName);
321 
322  switch (pubkeyPtr->getKeyType())
323  {
324  case KEY_TYPE_RSA:
325  {
326  //Read private key
327  ByteQueue bytes;
328  FileSource file(m_impl->transformName(keyURI, ".pri").string().c_str(),
329  true, new Base64Decoder);
330  file.TransferTo(bytes);
331  bytes.MessageEnd();
332  RSA::PrivateKey privateKey;
333  privateKey.Load(bytes);
334 
335  //Sign message
336  switch (digestAlgorithm)
337  {
339  {
340  RSASS<PKCS1v15, SHA256>::Signer signer(privateKey);
341 
342  OBufferStream os;
343  StringSource(data, dataLength,
344  true,
345  new SignerFilter(rng, signer, new FileSink(os)));
346 
347  return Block(tlv::SignatureValue, os.buf());
348  }
349  default:
350  BOOST_THROW_EXCEPTION(Error("Unsupported digest algorithm"));
351  }
352  }
353  case KEY_TYPE_ECDSA:
354  {
355  //Read private key
356  ByteQueue bytes;
357  FileSource file(m_impl->transformName(keyURI, ".pri").string().c_str(),
358  true, new Base64Decoder);
359  file.TransferTo(bytes);
360  bytes.MessageEnd();
361 
362  //Sign message
363  switch (digestAlgorithm)
364  {
366  {
367  ECDSA<ECP, SHA256>::PrivateKey privateKey;
368  privateKey.Load(bytes);
369  ECDSA<ECP, SHA256>::Signer signer(privateKey);
370 
371  OBufferStream os;
372  StringSource(data, dataLength,
373  true,
374  new SignerFilter(rng, signer, new FileSink(os)));
375 
376  uint8_t buf[200];
377  size_t bufSize = DSAConvertSignatureFormat(buf, 200, DSA_DER,
378  os.buf()->buf(), os.buf()->size(),
379  DSA_P1363);
380 
381  shared_ptr<Buffer> sigBuffer = make_shared<Buffer>(buf, bufSize);
382 
383  return Block(tlv::SignatureValue, sigBuffer);
384  }
385  default:
386  BOOST_THROW_EXCEPTION(Error("Unsupported digest algorithm"));
387  }
388  }
389  default:
390  BOOST_THROW_EXCEPTION(Error("Unsupported key type"));
391  }
392  }
393  catch (CryptoPP::Exception& e)
394  {
395  BOOST_THROW_EXCEPTION(Error(e.what()));
396  }
397 }
398 
399 
401 SecTpmFile::decryptInTpm(const uint8_t* data, size_t dataLength,
402  const Name& keyName, bool isSymmetric)
403 {
404  BOOST_THROW_EXCEPTION(Error("SecTpmFile::decryptInTpm is not supported"));
405  // string keyURI = keyName.toUri();
406  // if (!isSymmetric)
407  // {
408  // if (!doesKeyExistInTpm(keyName, KEY_CLASS_PRIVATE))
409  // throw Error("private key doesn't exist");
410 
411  // try{
412  // using namespace CryptoPP;
413  // AutoSeededRandomPool rng;
414 
415  // //Read private key
416  // ByteQueue bytes;
417  // FileSource file(m_impl->transformName(keyURI, ".pri").string().c_str(), true, new Base64Decoder);
418  // file.TransferTo(bytes);
419  // bytes.MessageEnd();
420  // RSA::PrivateKey privateKey;
421  // privateKey.Load(bytes);
422  // RSAES_PKCS1v15_Decryptor decryptor(privateKey);
423 
424  // OBufferStream os;
425  // StringSource(data, dataLength, true, new PK_DecryptorFilter(rng, decryptor, new FileSink(os)));
426 
427  // return os.buf();
428  // }
429  // catch (CryptoPP::Exception& e){
430  // throw Error(e.what());
431  // }
432  // }
433  // else
434  // {
435  // throw Error("Symmetric encryption is not implemented!");
436  // // if (!doesKeyExistInTpm(keyName, KEY_CLASS_SYMMETRIC))
437  // // throw Error("symmetric key doesn't exist");
438 
439  // // try{
440  // // string keyBits;
441  // // string symKeyFileName = m_impl->transformName(keyURI, ".key");
442  // // FileSource(symKeyFileName, true, new HexDecoder(new StringSink(keyBits)));
443 
444  // // using CryptoPP::AES;
445  // // AutoSeededRandomPool rnd;
446  // // byte iv[AES::BLOCKSIZE];
447  // // rnd.GenerateBlock(iv, AES::BLOCKSIZE);
448 
449  // // CFB_Mode<AES>::Decryption decryptor;
450  // // decryptor.SetKeyWithIV(reinterpret_cast<const uint8_t*>(keyBits.c_str()), keyBits.size(), iv);
451 
452  // // OBufferStream os;
453  // // StringSource(data, dataLength, true, new StreamTransformationFilter(decryptor,new FileSink(os)));
454  // // return os.buf();
455 
456  // // }catch (CryptoPP::Exception& e){
457  // // throw Error(e.what());
458  // // }
459  // }
460 }
461 
463 SecTpmFile::encryptInTpm(const uint8_t* data, size_t dataLength,
464  const Name& keyName, bool isSymmetric)
465 {
466  BOOST_THROW_EXCEPTION(Error("SecTpmFile::encryptInTpm is not supported"));
467  // string keyURI = keyName.toUri();
468 
469  // if (!isSymmetric)
470  // {
471  // if (!doesKeyExistInTpm(keyName, KEY_CLASS_PUBLIC))
472  // throw Error("public key doesn't exist");
473  // try
474  // {
475  // using namespace CryptoPP;
476  // AutoSeededRandomPool rng;
477 
478  // //Read private key
479  // ByteQueue bytes;
480  // FileSource file(m_impl->transformName(keyURI, ".pub").string().c_str(), true, new Base64Decoder);
481  // file.TransferTo(bytes);
482  // bytes.MessageEnd();
483  // RSA::PublicKey publicKey;
484  // publicKey.Load(bytes);
485 
486  // OBufferStream os;
487  // RSAES_PKCS1v15_Encryptor encryptor(publicKey);
488 
489  // StringSource(data, dataLength, true, new PK_EncryptorFilter(rng, encryptor, new FileSink(os)));
490  // return os.buf();
491  // }
492  // catch (CryptoPP::Exception& e){
493  // throw Error(e.what());
494  // }
495  // }
496  // else
497  // {
498  // throw Error("Symmetric encryption is not implemented!");
499  // // if (!doesKeyExistInTpm(keyName, KEY_CLASS_SYMMETRIC))
500  // // throw Error("symmetric key doesn't exist");
501 
502  // // try{
503  // // string keyBits;
504  // // string symKeyFileName = m_impl->transformName(keyURI, ".key");
505  // // FileSource(symKeyFileName, true, new HexDecoder(new StringSink(keyBits)));
506 
507  // // using CryptoPP::AES;
508  // // AutoSeededRandomPool rnd;
509  // // byte iv[AES::BLOCKSIZE];
510  // // rnd.GenerateBlock(iv, AES::BLOCKSIZE);
511 
512  // // CFB_Mode<AES>::Encryption encryptor;
513  // // encryptor.SetKeyWithIV(reinterpret_cast<const uint8_t*>(keyBits.c_str()), keyBits.size(), iv);
514 
515  // // OBufferStream os;
516  // // StringSource(data, dataLength, true, new StreamTransformationFilter(encryptor, new FileSink(os)));
517  // // return os.buf();
518  // // }catch (CryptoPP::Exception& e){
519  // // throw Error(e.what());
520  // // }
521  // }
522 }
523 
524 void
526 {
527  BOOST_THROW_EXCEPTION(Error("SecTpmFile::generateSymmetricKeyInTpm is not supported"));
528  // string keyURI = keyName.toUri();
529 
530  // if (doesKeyExistInTpm(keyName, KEY_CLASS_SYMMETRIC))
531  // throw Error("symmetric key exists");
532 
533  // string keyFileName = m_impl->maintainMapping(keyURI);
534  // string symKeyFileName = keyFileName + ".key";
535 
536  // try{
537  // switch (keyType){
538  // case KEY_TYPE_AES:
539  // {
540  // using namespace CryptoPP;
541  // AutoSeededRandomPool rng;
542 
543  // SecByteBlock key(0x00, keySize);
544  // rng.GenerateBlock(key, keySize);
545 
546  // StringSource(key, key.size(), true, new HexEncoder(new FileSink(symKeyFileName.c_str())));
547 
548  // chmod(symKeyFileName.c_str(), 0000400);
549  // return;
550  // }
551  // default:
552  // throw Error("Unsupported symmetric key type!");
553  // }
554  // }catch (CryptoPP::Exception& e){
555  // throw Error(e.what());
556  // }
557 }
558 
559 bool
560 SecTpmFile::doesKeyExistInTpm(const Name& keyName, KeyClass keyClass)
561 {
562  string keyURI = keyName.toUri();
563  if (keyClass == KEY_CLASS_PUBLIC)
564  {
565  if (boost::filesystem::exists(m_impl->transformName(keyURI, ".pub")))
566  return true;
567  else
568  return false;
569  }
570  if (keyClass == KEY_CLASS_PRIVATE)
571  {
572  if (boost::filesystem::exists(m_impl->transformName(keyURI, ".pri")))
573  return true;
574  else
575  return false;
576  }
577  if (keyClass == KEY_CLASS_SYMMETRIC)
578  {
579  if (boost::filesystem::exists(m_impl->transformName(keyURI, ".key")))
580  return true;
581  else
582  return false;
583  }
584  return false;
585 }
586 
587 bool
588 SecTpmFile::generateRandomBlock(uint8_t* res, size_t size)
589 {
590  try
591  {
592  CryptoPP::AutoSeededRandomPool rng;
593  rng.GenerateBlock(res, size);
594  return true;
595  }
596  catch (CryptoPP::Exception& e)
597  {
598  return false;
599  }
600 }
601 
602 } // namespace ndn
boost::filesystem::path m_keystorePath
Copyright (c) 2011-2015 Regents of the University of California.
Copyright (c) 2013-2014 Regents of the University of California.
Definition: oid.hpp:29
KeyType getKeyType() const
Definition: key-params.hpp:54
virtual bool doesKeyExistInTpm(const Name &keyName, KeyClass keyClass)
Check if a particular key exists.
uint32_t getKeySize() const
Definition: key-params.hpp:135
Class representing a wire element of NDN-TLV packet format.
Definition: block.hpp:43
SecTpmFile(const std::string &dir="")
static const std::string SCHEME
virtual void generateKeyPairInTpm(const Name &keyName, const KeyParams &params)
Generate a pair of asymmetric keys.
shared_ptr< Buffer > buf()
Flush written data to the stream and return shared pointer to the underlying buffer.
std::string toUri() const
Encode this name as a URI.
Definition: name.cpp:183
virtual void deleteKeyPairInTpm(const Name &keyName)
Delete a key pair of asymmetric keys.
virtual shared_ptr< PublicKey > getPublicKeyFromTpm(const Name &keyName)
Get a public key.
virtual ConstBufferPtr decryptInTpm(const uint8_t *data, size_t dataLength, const Name &keyName, bool isSymmetric)
Decrypt data.
boost::filesystem::path transformName(const string &keyName, const string &extension)
SecTpm is the base class of the TPM classes.
Definition: sec-tpm.hpp:41
virtual bool generateRandomBlock(uint8_t *res, size_t size)
Generate a random block.
Name abstraction to represent an absolute name.
Definition: name.hpp:46
virtual ConstBufferPtr exportPrivateKeyPkcs8FromTpm(const Name &keyName)
Export a private key in PKCS#8 format.
string maintainMapping(const string &keyName)
virtual Block signInTpm(const uint8_t *data, size_t dataLength, const Name &keyName, DigestAlgorithm digestAlgorithm)
Sign data.
virtual bool importPublicKeyPkcs1IntoTpm(const Name &keyName, const uint8_t *buf, size_t size)
Import a public key in PKCS#1 formatted.
virtual ConstBufferPtr encryptInTpm(const uint8_t *data, size_t dataLength, const Name &keyName, bool isSymmetric)
Encrypt data.
virtual void generateSymmetricKeyInTpm(const Name &keyName, const KeyParams &params)
Generate a symmetric key.
Base class of key parameters.
Definition: key-params.hpp:35
void trim(std::string &str)
Modify str in place to erase whitespace on the left and right.
Class implementing interface similar to ostringstream, but to construct ndn::Buffer.
virtual bool importPrivateKeyPkcs8IntoTpm(const Name &keyName, const uint8_t *buf, size_t size)
Import a private key from PKCS#8 formatted.
shared_ptr< const Buffer > ConstBufferPtr
Definition: buffer.hpp:33
SimplePublicKeyParams is a template for public keys with only one parameter: size.
Definition: key-params.hpp:110
Impl(const string &dir)
virtual ~SecTpmFile()
virtual std::string getScheme()