blob: 98e117fe393e3c5bef67581aaa13011794d8ae84 [file] [log] [blame]
Yingdi Yu2d9c50f2014-01-21 18:25:00 -08001/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil -*- */
2/**
3 * Copyright (C) 2013 Regents of the University of California.
4 * @author: Xingyu Ma <maxy12@cs.ucla.edu>
5 * Alexander Afanasyev <alexander.afanasyev@ucla.edu>
6 * Yingdi Yu <yingdi@cs.ucla.edu>
7 * See COPYING for copyright and distribution information.
8 */
9
Alexander Afanasyeve2dcdfd2014-02-07 15:53:28 -080010#include "common.hpp"
Yingdi Yu04020922014-01-22 12:46:53 -080011
Alexander Afanasyeve2dcdfd2014-02-07 15:53:28 -080012#include "sec-tpm-file.hpp"
Yingdi Yu2d9c50f2014-01-21 18:25:00 -080013
14#include <boost/filesystem.hpp>
15#include <boost/algorithm/string.hpp>
16
Junxiao Shi482ccc52014-03-31 13:05:24 -070017#include "cryptopp.hpp"
Yingdi Yu2d9c50f2014-01-21 18:25:00 -080018
19#include <sys/types.h>
20#include <sys/stat.h>
21
Yingdi Yu8dceb1d2014-02-18 12:45:10 -080022#include <algorithm>
23
Yingdi Yu2d9c50f2014-01-21 18:25:00 -080024using namespace std;
25
Yingdi Yufc40d872014-02-18 12:56:04 -080026namespace ndn {
Yingdi Yu2d9c50f2014-01-21 18:25:00 -080027
28class SecTpmFile::Impl {
29public:
Yingdi Yu4b752752014-02-18 12:24:03 -080030 Impl(const string& dir)
Yingdi Yu2d9c50f2014-01-21 18:25:00 -080031 {
32 if(dir.empty())
Yingdi Yu37e317f2014-03-19 12:16:23 -070033 m_keystorePath = boost::filesystem::path(getenv("HOME")) / ".ndn" / "ndnsec-tpm-file";
Yingdi Yu2d9c50f2014-01-21 18:25:00 -080034 else
35 m_keystorePath = dir;
36
37 boost::filesystem::create_directories (m_keystorePath);
38 }
39
Yingdi Yu8dceb1d2014-02-18 12:45:10 -080040 boost::filesystem::path
41 nameTransform(const string& keyName, const string& extension)
42 {
43 using namespace CryptoPP;
44 string digest;
45 SHA256 hash;
46 StringSource src(keyName, true, new HashFilter(hash, new Base64Encoder (new CryptoPP::StringSink(digest))));
47
48 boost::algorithm::trim(digest);
49 std::replace(digest.begin(), digest.end(), '/', '%');
50
51 return m_keystorePath / (digest + extension);
52 }
53
54 string
55 maintainMapping(const string& keyName)
56 {
57 string keyFileName = nameTransform(keyName, "").string();
58
59 ofstream outfile;
60 string dirFile = (m_keystorePath / "mapping.txt").string();
61
62 outfile.open(dirFile.c_str(), std::ios_base::app);
63 outfile << keyName << ' ' << keyFileName << '\n';
64 outfile.close();
65
66 return keyFileName;
67 }
68
Yingdi Yu2d9c50f2014-01-21 18:25:00 -080069public:
70 boost::filesystem::path m_keystorePath;
71};
72
Yingdi Yu4b752752014-02-18 12:24:03 -080073
Yingdi Yube4150e2014-02-18 13:02:46 -080074SecTpmFile::SecTpmFile(const string& dir)
Yingdi Yu4b752752014-02-18 12:24:03 -080075 : m_impl(new Impl(dir))
Yingdi Yube4150e2014-02-18 13:02:46 -080076 , m_inTerminal(false)
Yingdi Yu2d9c50f2014-01-21 18:25:00 -080077{}
78
79void
80SecTpmFile::generateKeyPairInTpm(const Name & keyName, KeyType keyType, int keySize)
81{
82 string keyURI = keyName.toUri();
83
84 if(doesKeyExistInTpm(keyName, KEY_CLASS_PUBLIC))
85 throw Error("public key exists");
86 if(doesKeyExistInTpm(keyName, KEY_CLASS_PRIVATE))
87 throw Error("private key exists");
88
Yingdi Yu8dceb1d2014-02-18 12:45:10 -080089 string keyFileName = m_impl->maintainMapping(keyURI);
Yingdi Yu2d9c50f2014-01-21 18:25:00 -080090
91 try{
92 switch(keyType){
93 case KEY_TYPE_RSA:
94 {
Yingdi Yu4b752752014-02-18 12:24:03 -080095 using namespace CryptoPP;
96 AutoSeededRandomPool rng;
97
Yingdi Yu2d9c50f2014-01-21 18:25:00 -080098 InvertibleRSAFunction privateKey;
99 privateKey.Initialize(rng, keySize);
100
101 string privateKeyFileName = keyFileName + ".pri";
102 Base64Encoder privateKeySink(new FileSink(privateKeyFileName.c_str()));
103 privateKey.DEREncode(privateKeySink);
104 privateKeySink.MessageEnd();
105
106 RSAFunction publicKey(privateKey);
107 string publicKeyFileName = keyFileName + ".pub";
108 Base64Encoder publicKeySink(new FileSink(publicKeyFileName.c_str()));
109 publicKey.DEREncode(publicKeySink);
110 publicKeySink.MessageEnd();
111
112 /*set file permission*/
113 chmod(privateKeyFileName.c_str(), 0000400);
114 chmod(publicKeyFileName.c_str(), 0000444);
115 return;
116 }
117 default:
118 throw Error("Unsupported key type!");
119 }
120 }catch(const CryptoPP::Exception& e){
121 throw Error(e.what());
122 }
123}
124
Yingdi Yu28fd32f2014-01-28 19:03:03 -0800125void
126SecTpmFile::deleteKeyPairInTpm(const Name &keyName)
127{
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800128 boost::filesystem::path publicKeyPath(m_impl->nameTransform(keyName.toUri(), ".pub"));
129 boost::filesystem::path privateKeyPath(m_impl->nameTransform(keyName.toUri(), ".pri"));
Yingdi Yu28fd32f2014-01-28 19:03:03 -0800130
131 if(boost::filesystem::exists(publicKeyPath))
132 boost::filesystem::remove(publicKeyPath);
133
134 if(boost::filesystem::exists(privateKeyPath))
135 boost::filesystem::remove(privateKeyPath);
136}
137
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800138shared_ptr<PublicKey>
Yingdi Yu2d9c50f2014-01-21 18:25:00 -0800139SecTpmFile::getPublicKeyFromTpm(const Name & keyName)
140{
141 string keyURI = keyName.toUri();
142
143 if(!doesKeyExistInTpm(keyName, KEY_CLASS_PUBLIC))
Yingdi Yu2e57a582014-02-20 23:34:43 -0800144 throw Error("Public Key already exist");
Yingdi Yu2d9c50f2014-01-21 18:25:00 -0800145
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800146 ostringstream os;
Yingdi Yu2d9c50f2014-01-21 18:25:00 -0800147 try{
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800148 using namespace CryptoPP;
149 FileSource(m_impl->nameTransform(keyURI, ".pub").string().c_str(), true, new Base64Decoder(new FileSink(os)));
Yingdi Yu2d9c50f2014-01-21 18:25:00 -0800150 }catch(const CryptoPP::Exception& e){
Yingdi Yu2e57a582014-02-20 23:34:43 -0800151 throw Error(e.what());
Yingdi Yu2d9c50f2014-01-21 18:25:00 -0800152 }
153
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800154 return make_shared<PublicKey>(reinterpret_cast<const uint8_t*>(os.str().c_str()), os.str().size());
155}
156
157ConstBufferPtr
158SecTpmFile::exportPrivateKeyPkcs1FromTpm(const Name& keyName)
159{
160 OBufferStream privateKeyOs;
161 CryptoPP::FileSource(m_impl->nameTransform(keyName.toUri(), ".pri").string().c_str(), true,
162 new CryptoPP::Base64Decoder(new CryptoPP::FileSink(privateKeyOs)));
163
164 return privateKeyOs.buf();
165}
166
167bool
168SecTpmFile::importPrivateKeyPkcs1IntoTpm(const Name& keyName, const uint8_t* buf, size_t size)
169{
170 try{
171 string keyFileName = m_impl->maintainMapping(keyName.toUri());
172 keyFileName.append(".pri");
173 CryptoPP::StringSource(buf, size, true,
174 new CryptoPP::Base64Encoder(new CryptoPP::FileSink(keyFileName.c_str())));
175 return true;
176 }catch(...){
177 return false;
178 }
179}
180
181bool
182SecTpmFile::importPublicKeyPkcs1IntoTpm(const Name& keyName, const uint8_t* buf, size_t size)
183{
184 try{
185 string keyFileName = m_impl->maintainMapping(keyName.toUri());
186 keyFileName.append(".pub");
187 CryptoPP::StringSource(buf, size, true,
188 new CryptoPP::Base64Encoder(new CryptoPP::FileSink(keyFileName.c_str())));
189 return true;
190 }catch(...){
191 return false;
192 }
Yingdi Yu2d9c50f2014-01-21 18:25:00 -0800193}
194
195Block
196SecTpmFile::signInTpm(const uint8_t *data, size_t dataLength, const Name& keyName, DigestAlgorithm digestAlgorithm)
197{
198 string keyURI = keyName.toUri();
199
200 if(!doesKeyExistInTpm(keyName, KEY_CLASS_PRIVATE))
201 throw Error("private key doesn't exists");
202
203 try{
Yingdi Yu4b752752014-02-18 12:24:03 -0800204 using namespace CryptoPP;
Yingdi Yu2d9c50f2014-01-21 18:25:00 -0800205 AutoSeededRandomPool rng;
Yingdi Yu4b752752014-02-18 12:24:03 -0800206
Yingdi Yu2d9c50f2014-01-21 18:25:00 -0800207 //Read private key
208 ByteQueue bytes;
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800209 FileSource file(m_impl->nameTransform(keyURI, ".pri").string().c_str(), true, new Base64Decoder);
Yingdi Yu2d9c50f2014-01-21 18:25:00 -0800210 file.TransferTo(bytes);
211 bytes.MessageEnd();
212 RSA::PrivateKey privateKey;
213 privateKey.Load(bytes);
214
215 //Sign message
216 switch(digestAlgorithm){
217 case DIGEST_ALGORITHM_SHA256:
218 {
219 RSASS<PKCS1v15, SHA256>::Signer signer(privateKey);
220
221 OBufferStream os;
222 StringSource(data, dataLength, true, new SignerFilter(rng, signer, new FileSink(os)));
223
224 return Block(Tlv::SignatureValue, os.buf());
225 }
226 default:
227 throw Error("Unsupported digest algorithm!");
228 }
229 }catch(const CryptoPP::Exception& e){
230 throw Error(e.what());
231 }
232}
233
234
235ConstBufferPtr
Yingdi Yufc40d872014-02-18 12:56:04 -0800236SecTpmFile::decryptInTpm(const uint8_t* data, size_t dataLength, const Name& keyName, bool isSymmetric)
Yingdi Yu2d9c50f2014-01-21 18:25:00 -0800237{
Yingdi Yu2e57a582014-02-20 23:34:43 -0800238 throw Error("SecTpmFile::decryptInTpm is not supported!");
239 // string keyURI = keyName.toUri();
240 // if (!isSymmetric)
241 // {
242 // if(!doesKeyExistInTpm(keyName, KEY_CLASS_PRIVATE))
243 // throw Error("private key doesn't exist");
Yingdi Yu2d9c50f2014-01-21 18:25:00 -0800244
Yingdi Yu2e57a582014-02-20 23:34:43 -0800245 // try{
246 // using namespace CryptoPP;
247 // AutoSeededRandomPool rng;
Yingdi Yu4b752752014-02-18 12:24:03 -0800248
Yingdi Yu2e57a582014-02-20 23:34:43 -0800249 // //Read private key
250 // ByteQueue bytes;
251 // FileSource file(m_impl->nameTransform(keyURI, ".pri").string().c_str(), true, new Base64Decoder);
252 // file.TransferTo(bytes);
253 // bytes.MessageEnd();
254 // RSA::PrivateKey privateKey;
255 // privateKey.Load(bytes);
256 // RSAES_PKCS1v15_Decryptor decryptor(privateKey);
Yingdi Yu2d9c50f2014-01-21 18:25:00 -0800257
Yingdi Yu2e57a582014-02-20 23:34:43 -0800258 // OBufferStream os;
259 // StringSource(data, dataLength, true, new PK_DecryptorFilter(rng, decryptor, new FileSink(os)));
Yingdi Yu2d9c50f2014-01-21 18:25:00 -0800260
Yingdi Yu2e57a582014-02-20 23:34:43 -0800261 // return os.buf();
262 // }
263 // catch(const CryptoPP::Exception& e){
264 // throw Error(e.what());
265 // }
266 // }
267 // else
268 // {
269 // throw Error("Symmetric encryption is not implemented!");
270 // // if(!doesKeyExistInTpm(keyName, KEY_CLASS_SYMMETRIC))
271 // // throw Error("symmetric key doesn't exist");
Yingdi Yu2d9c50f2014-01-21 18:25:00 -0800272
Yingdi Yu2e57a582014-02-20 23:34:43 -0800273 // // try{
274 // // string keyBits;
275 // // string symKeyFileName = m_impl->nameTransform(keyURI, ".key");
276 // // FileSource(symKeyFileName, true, new HexDecoder(new StringSink(keyBits)));
Yingdi Yu2d9c50f2014-01-21 18:25:00 -0800277
Yingdi Yu2e57a582014-02-20 23:34:43 -0800278 // // using CryptoPP::AES;
279 // // AutoSeededRandomPool rnd;
280 // // byte iv[AES::BLOCKSIZE];
281 // // rnd.GenerateBlock(iv, AES::BLOCKSIZE);
Yingdi Yu2d9c50f2014-01-21 18:25:00 -0800282
Yingdi Yu2e57a582014-02-20 23:34:43 -0800283 // // CFB_Mode<AES>::Decryption decryptor;
284 // // decryptor.SetKeyWithIV(reinterpret_cast<const uint8_t*>(keyBits.c_str()), keyBits.size(), iv);
Yingdi Yu2d9c50f2014-01-21 18:25:00 -0800285
Yingdi Yu2e57a582014-02-20 23:34:43 -0800286 // // OBufferStream os;
287 // // StringSource(data, dataLength, true, new StreamTransformationFilter(decryptor,new FileSink(os)));
288 // // return os.buf();
Yingdi Yu2d9c50f2014-01-21 18:25:00 -0800289
Yingdi Yu2e57a582014-02-20 23:34:43 -0800290 // // }catch(const CryptoPP::Exception& e){
291 // // throw Error(e.what());
292 // // }
293 // }
Yingdi Yu2d9c50f2014-01-21 18:25:00 -0800294}
295
296ConstBufferPtr
Yingdi Yufc40d872014-02-18 12:56:04 -0800297SecTpmFile::encryptInTpm(const uint8_t* data, size_t dataLength, const Name& keyName, bool isSymmetric)
Yingdi Yu2d9c50f2014-01-21 18:25:00 -0800298{
Yingdi Yu2e57a582014-02-20 23:34:43 -0800299 throw Error("SecTpmFile::encryptInTpm is not supported!");
300 // string keyURI = keyName.toUri();
Yingdi Yu2d9c50f2014-01-21 18:25:00 -0800301
Yingdi Yu2e57a582014-02-20 23:34:43 -0800302 // if (!isSymmetric)
303 // {
304 // if(!doesKeyExistInTpm(keyName, KEY_CLASS_PUBLIC))
305 // throw Error("public key doesn't exist");
306 // try
307 // {
308 // using namespace CryptoPP;
309 // AutoSeededRandomPool rng;
Yingdi Yu2d9c50f2014-01-21 18:25:00 -0800310
Yingdi Yu2e57a582014-02-20 23:34:43 -0800311 // //Read private key
312 // ByteQueue bytes;
313 // FileSource file(m_impl->nameTransform(keyURI, ".pub").string().c_str(), true, new Base64Decoder);
314 // file.TransferTo(bytes);
315 // bytes.MessageEnd();
316 // RSA::PublicKey publicKey;
317 // publicKey.Load(bytes);
Yingdi Yu2d9c50f2014-01-21 18:25:00 -0800318
Yingdi Yu2e57a582014-02-20 23:34:43 -0800319 // OBufferStream os;
320 // RSAES_PKCS1v15_Encryptor encryptor(publicKey);
Yingdi Yu2d9c50f2014-01-21 18:25:00 -0800321
Yingdi Yu2e57a582014-02-20 23:34:43 -0800322 // StringSource(data, dataLength, true, new PK_EncryptorFilter(rng, encryptor, new FileSink(os)));
323 // return os.buf();
324 // }
325 // catch(const CryptoPP::Exception& e){
326 // throw Error(e.what());
327 // }
328 // }
329 // else
330 // {
331 // throw Error("Symmetric encryption is not implemented!");
332 // // if(!doesKeyExistInTpm(keyName, KEY_CLASS_SYMMETRIC))
333 // // throw Error("symmetric key doesn't exist");
Yingdi Yu2d9c50f2014-01-21 18:25:00 -0800334
Yingdi Yu2e57a582014-02-20 23:34:43 -0800335 // // try{
336 // // string keyBits;
337 // // string symKeyFileName = m_impl->nameTransform(keyURI, ".key");
338 // // FileSource(symKeyFileName, true, new HexDecoder(new StringSink(keyBits)));
Yingdi Yu2d9c50f2014-01-21 18:25:00 -0800339
Yingdi Yu2e57a582014-02-20 23:34:43 -0800340 // // using CryptoPP::AES;
341 // // AutoSeededRandomPool rnd;
342 // // byte iv[AES::BLOCKSIZE];
343 // // rnd.GenerateBlock(iv, AES::BLOCKSIZE);
Yingdi Yu2d9c50f2014-01-21 18:25:00 -0800344
Yingdi Yu2e57a582014-02-20 23:34:43 -0800345 // // CFB_Mode<AES>::Encryption encryptor;
346 // // encryptor.SetKeyWithIV(reinterpret_cast<const uint8_t*>(keyBits.c_str()), keyBits.size(), iv);
Yingdi Yu2d9c50f2014-01-21 18:25:00 -0800347
Yingdi Yu2e57a582014-02-20 23:34:43 -0800348 // // OBufferStream os;
349 // // StringSource(data, dataLength, true, new StreamTransformationFilter(encryptor, new FileSink(os)));
350 // // return os.buf();
351 // // }catch(const CryptoPP::Exception& e){
352 // // throw Error(e.what());
353 // // }
354 // }
Yingdi Yu2d9c50f2014-01-21 18:25:00 -0800355}
356
357
358void
359SecTpmFile::generateSymmetricKeyInTpm(const Name & keyName, KeyType keyType, int keySize)
360{
Yingdi Yu2e57a582014-02-20 23:34:43 -0800361 throw Error("SecTpmFile::generateSymmetricKeyInTpm is not supported!");
362 // string keyURI = keyName.toUri();
Yingdi Yu2d9c50f2014-01-21 18:25:00 -0800363
Yingdi Yu2e57a582014-02-20 23:34:43 -0800364 // if(doesKeyExistInTpm(keyName, KEY_CLASS_SYMMETRIC))
365 // throw Error("symmetric key exists");
Yingdi Yu2d9c50f2014-01-21 18:25:00 -0800366
Yingdi Yu2e57a582014-02-20 23:34:43 -0800367 // string keyFileName = m_impl->maintainMapping(keyURI);
368 // string symKeyFileName = keyFileName + ".key";
Yingdi Yu2d9c50f2014-01-21 18:25:00 -0800369
Yingdi Yu2e57a582014-02-20 23:34:43 -0800370 // try{
371 // switch(keyType){
372 // case KEY_TYPE_AES:
373 // {
374 // using namespace CryptoPP;
375 // AutoSeededRandomPool rng;
Yingdi Yu4b752752014-02-18 12:24:03 -0800376
Yingdi Yu2e57a582014-02-20 23:34:43 -0800377 // SecByteBlock key(0x00, keySize);
378 // rng.GenerateBlock(key, keySize);
Yingdi Yu2d9c50f2014-01-21 18:25:00 -0800379
Yingdi Yu2e57a582014-02-20 23:34:43 -0800380 // StringSource(key, key.size(), true, new HexEncoder(new FileSink(symKeyFileName.c_str())));
Yingdi Yu2d9c50f2014-01-21 18:25:00 -0800381
Yingdi Yu2e57a582014-02-20 23:34:43 -0800382 // chmod(symKeyFileName.c_str(), 0000400);
383 // return;
384 // }
385 // default:
386 // throw Error("Unsupported symmetric key type!");
387 // }
388 // }catch(const CryptoPP::Exception& e){
389 // throw Error(e.what());
390 // }
Yingdi Yu2d9c50f2014-01-21 18:25:00 -0800391}
392
393bool
394SecTpmFile::doesKeyExistInTpm(const Name & keyName, KeyClass keyClass)
395{
396 string keyURI = keyName.toUri();
397 if (keyClass == KEY_CLASS_PUBLIC)
398 {
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800399 if(boost::filesystem::exists(m_impl->nameTransform(keyURI, ".pub")))
Yingdi Yu2d9c50f2014-01-21 18:25:00 -0800400 return true;
401 else
402 return false;
403 }
404 if (keyClass == KEY_CLASS_PRIVATE)
405 {
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800406 if(boost::filesystem::exists(m_impl->nameTransform(keyURI, ".pri")))
Yingdi Yu2d9c50f2014-01-21 18:25:00 -0800407 return true;
408 else
409 return false;
410 }
411 if (keyClass == KEY_CLASS_SYMMETRIC)
412 {
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800413 if(boost::filesystem::exists(m_impl->nameTransform(keyURI, ".key")))
Yingdi Yu2d9c50f2014-01-21 18:25:00 -0800414 return true;
415 else
416 return false;
417 }
418 return false;
419}
420
Yingdi Yu4b752752014-02-18 12:24:03 -0800421bool
422SecTpmFile::generateRandomBlock(uint8_t* res, size_t size)
423{
424 try{
425 CryptoPP::AutoSeededRandomPool rng;
426 rng.GenerateBlock(res, size);
427 return true;
428 }catch(const CryptoPP::Exception& e){
429 return false;
430 }
431}
432
Yingdi Yufc40d872014-02-18 12:56:04 -0800433} // namespace ndn