blob: d25c593e95c4c5aaf5f565a5352685b52fc5d35e [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
17#include <cryptopp/rsa.h>
18#include <cryptopp/files.h>
19#include <cryptopp/base64.h>
20#include <cryptopp/hex.h>
21#include <cryptopp/osrng.h>
22#include <cryptopp/sha.h>
23#include <cryptopp/pssr.h>
24#include <cryptopp/modes.h>
Yingdi Yu8dceb1d2014-02-18 12:45:10 -080025#include <cryptopp/pwdbased.h>
26#include <cryptopp/sha.h>
27#include <cryptopp/des.h>
Yingdi Yu2d9c50f2014-01-21 18:25:00 -080028
29#include <sys/types.h>
30#include <sys/stat.h>
31
Yingdi Yu8dceb1d2014-02-18 12:45:10 -080032#include <algorithm>
33
Yingdi Yu2d9c50f2014-01-21 18:25:00 -080034using namespace std;
35
Yingdi Yufc40d872014-02-18 12:56:04 -080036namespace ndn {
Yingdi Yu2d9c50f2014-01-21 18:25:00 -080037
38class SecTpmFile::Impl {
39public:
Yingdi Yu4b752752014-02-18 12:24:03 -080040 Impl(const string& dir)
Yingdi Yu2d9c50f2014-01-21 18:25:00 -080041 {
42 if(dir.empty())
Yingdi Yu04020922014-01-22 12:46:53 -080043 m_keystorePath = boost::filesystem::path(getenv("HOME")) / ".ndnx" / "ndnsec-tpm-file";
Yingdi Yu2d9c50f2014-01-21 18:25:00 -080044 else
45 m_keystorePath = dir;
46
47 boost::filesystem::create_directories (m_keystorePath);
48 }
49
Yingdi Yu8dceb1d2014-02-18 12:45:10 -080050 boost::filesystem::path
51 nameTransform(const string& keyName, const string& extension)
52 {
53 using namespace CryptoPP;
54 string digest;
55 SHA256 hash;
56 StringSource src(keyName, true, new HashFilter(hash, new Base64Encoder (new CryptoPP::StringSink(digest))));
57
58 boost::algorithm::trim(digest);
59 std::replace(digest.begin(), digest.end(), '/', '%');
60
61 return m_keystorePath / (digest + extension);
62 }
63
64 string
65 maintainMapping(const string& keyName)
66 {
67 string keyFileName = nameTransform(keyName, "").string();
68
69 ofstream outfile;
70 string dirFile = (m_keystorePath / "mapping.txt").string();
71
72 outfile.open(dirFile.c_str(), std::ios_base::app);
73 outfile << keyName << ' ' << keyFileName << '\n';
74 outfile.close();
75
76 return keyFileName;
77 }
78
Yingdi Yu2d9c50f2014-01-21 18:25:00 -080079public:
80 boost::filesystem::path m_keystorePath;
81};
82
Yingdi Yu4b752752014-02-18 12:24:03 -080083
Yingdi Yube4150e2014-02-18 13:02:46 -080084SecTpmFile::SecTpmFile(const string& dir)
Yingdi Yu4b752752014-02-18 12:24:03 -080085 : m_impl(new Impl(dir))
Yingdi Yube4150e2014-02-18 13:02:46 -080086 , m_inTerminal(false)
Yingdi Yu2d9c50f2014-01-21 18:25:00 -080087{}
88
89void
90SecTpmFile::generateKeyPairInTpm(const Name & keyName, KeyType keyType, int keySize)
91{
92 string keyURI = keyName.toUri();
93
94 if(doesKeyExistInTpm(keyName, KEY_CLASS_PUBLIC))
95 throw Error("public key exists");
96 if(doesKeyExistInTpm(keyName, KEY_CLASS_PRIVATE))
97 throw Error("private key exists");
98
Yingdi Yu8dceb1d2014-02-18 12:45:10 -080099 string keyFileName = m_impl->maintainMapping(keyURI);
Yingdi Yu2d9c50f2014-01-21 18:25:00 -0800100
101 try{
102 switch(keyType){
103 case KEY_TYPE_RSA:
104 {
Yingdi Yu4b752752014-02-18 12:24:03 -0800105 using namespace CryptoPP;
106 AutoSeededRandomPool rng;
107
Yingdi Yu2d9c50f2014-01-21 18:25:00 -0800108 InvertibleRSAFunction privateKey;
109 privateKey.Initialize(rng, keySize);
110
111 string privateKeyFileName = keyFileName + ".pri";
112 Base64Encoder privateKeySink(new FileSink(privateKeyFileName.c_str()));
113 privateKey.DEREncode(privateKeySink);
114 privateKeySink.MessageEnd();
115
116 RSAFunction publicKey(privateKey);
117 string publicKeyFileName = keyFileName + ".pub";
118 Base64Encoder publicKeySink(new FileSink(publicKeyFileName.c_str()));
119 publicKey.DEREncode(publicKeySink);
120 publicKeySink.MessageEnd();
121
122 /*set file permission*/
123 chmod(privateKeyFileName.c_str(), 0000400);
124 chmod(publicKeyFileName.c_str(), 0000444);
125 return;
126 }
127 default:
128 throw Error("Unsupported key type!");
129 }
130 }catch(const CryptoPP::Exception& e){
131 throw Error(e.what());
132 }
133}
134
Yingdi Yu28fd32f2014-01-28 19:03:03 -0800135void
136SecTpmFile::deleteKeyPairInTpm(const Name &keyName)
137{
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800138 boost::filesystem::path publicKeyPath(m_impl->nameTransform(keyName.toUri(), ".pub"));
139 boost::filesystem::path privateKeyPath(m_impl->nameTransform(keyName.toUri(), ".pri"));
Yingdi Yu28fd32f2014-01-28 19:03:03 -0800140
141 if(boost::filesystem::exists(publicKeyPath))
142 boost::filesystem::remove(publicKeyPath);
143
144 if(boost::filesystem::exists(privateKeyPath))
145 boost::filesystem::remove(privateKeyPath);
146}
147
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800148shared_ptr<PublicKey>
Yingdi Yu2d9c50f2014-01-21 18:25:00 -0800149SecTpmFile::getPublicKeyFromTpm(const Name & keyName)
150{
151 string keyURI = keyName.toUri();
152
153 if(!doesKeyExistInTpm(keyName, KEY_CLASS_PUBLIC))
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800154 return shared_ptr<PublicKey>();
Yingdi Yu2d9c50f2014-01-21 18:25:00 -0800155
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800156 ostringstream os;
Yingdi Yu2d9c50f2014-01-21 18:25:00 -0800157 try{
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800158 using namespace CryptoPP;
159 FileSource(m_impl->nameTransform(keyURI, ".pub").string().c_str(), true, new Base64Decoder(new FileSink(os)));
Yingdi Yu2d9c50f2014-01-21 18:25:00 -0800160 }catch(const CryptoPP::Exception& e){
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800161 return shared_ptr<PublicKey>();
Yingdi Yu2d9c50f2014-01-21 18:25:00 -0800162 }
163
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800164 return make_shared<PublicKey>(reinterpret_cast<const uint8_t*>(os.str().c_str()), os.str().size());
165}
166
167ConstBufferPtr
168SecTpmFile::exportPrivateKeyPkcs1FromTpm(const Name& keyName)
169{
170 OBufferStream privateKeyOs;
171 CryptoPP::FileSource(m_impl->nameTransform(keyName.toUri(), ".pri").string().c_str(), true,
172 new CryptoPP::Base64Decoder(new CryptoPP::FileSink(privateKeyOs)));
173
174 return privateKeyOs.buf();
175}
176
177bool
178SecTpmFile::importPrivateKeyPkcs1IntoTpm(const Name& keyName, const uint8_t* buf, size_t size)
179{
180 try{
181 string keyFileName = m_impl->maintainMapping(keyName.toUri());
182 keyFileName.append(".pri");
183 CryptoPP::StringSource(buf, size, true,
184 new CryptoPP::Base64Encoder(new CryptoPP::FileSink(keyFileName.c_str())));
185 return true;
186 }catch(...){
187 return false;
188 }
189}
190
191bool
192SecTpmFile::importPublicKeyPkcs1IntoTpm(const Name& keyName, const uint8_t* buf, size_t size)
193{
194 try{
195 string keyFileName = m_impl->maintainMapping(keyName.toUri());
196 keyFileName.append(".pub");
197 CryptoPP::StringSource(buf, size, true,
198 new CryptoPP::Base64Encoder(new CryptoPP::FileSink(keyFileName.c_str())));
199 return true;
200 }catch(...){
201 return false;
202 }
Yingdi Yu2d9c50f2014-01-21 18:25:00 -0800203}
204
205Block
206SecTpmFile::signInTpm(const uint8_t *data, size_t dataLength, const Name& keyName, DigestAlgorithm digestAlgorithm)
207{
208 string keyURI = keyName.toUri();
209
210 if(!doesKeyExistInTpm(keyName, KEY_CLASS_PRIVATE))
211 throw Error("private key doesn't exists");
212
213 try{
Yingdi Yu4b752752014-02-18 12:24:03 -0800214 using namespace CryptoPP;
Yingdi Yu2d9c50f2014-01-21 18:25:00 -0800215 AutoSeededRandomPool rng;
Yingdi Yu4b752752014-02-18 12:24:03 -0800216
Yingdi Yu2d9c50f2014-01-21 18:25:00 -0800217 //Read private key
218 ByteQueue bytes;
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800219 FileSource file(m_impl->nameTransform(keyURI, ".pri").string().c_str(), true, new Base64Decoder);
Yingdi Yu2d9c50f2014-01-21 18:25:00 -0800220 file.TransferTo(bytes);
221 bytes.MessageEnd();
222 RSA::PrivateKey privateKey;
223 privateKey.Load(bytes);
224
225 //Sign message
226 switch(digestAlgorithm){
227 case DIGEST_ALGORITHM_SHA256:
228 {
229 RSASS<PKCS1v15, SHA256>::Signer signer(privateKey);
230
231 OBufferStream os;
232 StringSource(data, dataLength, true, new SignerFilter(rng, signer, new FileSink(os)));
233
234 return Block(Tlv::SignatureValue, os.buf());
235 }
236 default:
237 throw Error("Unsupported digest algorithm!");
238 }
239 }catch(const CryptoPP::Exception& e){
240 throw Error(e.what());
241 }
242}
243
244
245ConstBufferPtr
Yingdi Yufc40d872014-02-18 12:56:04 -0800246SecTpmFile::decryptInTpm(const uint8_t* data, size_t dataLength, const Name& keyName, bool isSymmetric)
Yingdi Yu2d9c50f2014-01-21 18:25:00 -0800247{
248 string keyURI = keyName.toUri();
249 if (!isSymmetric)
250 {
251 if(!doesKeyExistInTpm(keyName, KEY_CLASS_PRIVATE))
252 throw Error("private key doesn't exist");
253
254 try{
Yingdi Yu4b752752014-02-18 12:24:03 -0800255 using namespace CryptoPP;
256 AutoSeededRandomPool rng;
257
Yingdi Yu2d9c50f2014-01-21 18:25:00 -0800258 //Read private key
259 ByteQueue bytes;
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800260 FileSource file(m_impl->nameTransform(keyURI, ".pri").string().c_str(), true, new Base64Decoder);
Yingdi Yu2d9c50f2014-01-21 18:25:00 -0800261 file.TransferTo(bytes);
262 bytes.MessageEnd();
263 RSA::PrivateKey privateKey;
264 privateKey.Load(bytes);
265 RSAES_PKCS1v15_Decryptor decryptor(privateKey);
266
267 OBufferStream os;
268 StringSource(data, dataLength, true, new PK_DecryptorFilter(rng, decryptor, new FileSink(os)));
269
270 return os.buf();
271 }
272 catch(const CryptoPP::Exception& e){
273 throw Error(e.what());
274 }
275 }
276 else
277 {
278 throw Error("Symmetric encryption is not implemented!");
279 // if(!doesKeyExistInTpm(keyName, KEY_CLASS_SYMMETRIC))
280 // throw Error("symmetric key doesn't exist");
281
282 // try{
283 // string keyBits;
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800284 // string symKeyFileName = m_impl->nameTransform(keyURI, ".key");
Yingdi Yu2d9c50f2014-01-21 18:25:00 -0800285 // FileSource(symKeyFileName, true, new HexDecoder(new StringSink(keyBits)));
286
287 // using CryptoPP::AES;
288 // AutoSeededRandomPool rnd;
289 // byte iv[AES::BLOCKSIZE];
290 // rnd.GenerateBlock(iv, AES::BLOCKSIZE);
291
292 // CFB_Mode<AES>::Decryption decryptor;
293 // decryptor.SetKeyWithIV(reinterpret_cast<const uint8_t*>(keyBits.c_str()), keyBits.size(), iv);
294
295 // OBufferStream os;
296 // StringSource(data, dataLength, true, new StreamTransformationFilter(decryptor,new FileSink(os)));
297 // return os.buf();
298
299 // }catch(const CryptoPP::Exception& e){
300 // throw Error(e.what());
301 // }
302 }
303}
304
305ConstBufferPtr
Yingdi Yufc40d872014-02-18 12:56:04 -0800306SecTpmFile::encryptInTpm(const uint8_t* data, size_t dataLength, const Name& keyName, bool isSymmetric)
Yingdi Yu2d9c50f2014-01-21 18:25:00 -0800307{
308 string keyURI = keyName.toUri();
309
310 if (!isSymmetric)
311 {
312 if(!doesKeyExistInTpm(keyName, KEY_CLASS_PUBLIC))
313 throw Error("public key doesn't exist");
314 try
315 {
Yingdi Yu4b752752014-02-18 12:24:03 -0800316 using namespace CryptoPP;
317 AutoSeededRandomPool rng;
Yingdi Yu2d9c50f2014-01-21 18:25:00 -0800318
319 //Read private key
320 ByteQueue bytes;
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800321 FileSource file(m_impl->nameTransform(keyURI, ".pub").string().c_str(), true, new Base64Decoder);
Yingdi Yu2d9c50f2014-01-21 18:25:00 -0800322 file.TransferTo(bytes);
323 bytes.MessageEnd();
324 RSA::PublicKey publicKey;
325 publicKey.Load(bytes);
326
327 OBufferStream os;
328 RSAES_PKCS1v15_Encryptor encryptor(publicKey);
329
330 StringSource(data, dataLength, true, new PK_EncryptorFilter(rng, encryptor, new FileSink(os)));
331 return os.buf();
332 }
333 catch(const CryptoPP::Exception& e){
334 throw Error(e.what());
335 }
336 }
337 else
338 {
339 throw Error("Symmetric encryption is not implemented!");
340 // if(!doesKeyExistInTpm(keyName, KEY_CLASS_SYMMETRIC))
341 // throw Error("symmetric key doesn't exist");
342
343 // try{
344 // string keyBits;
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800345 // string symKeyFileName = m_impl->nameTransform(keyURI, ".key");
Yingdi Yu2d9c50f2014-01-21 18:25:00 -0800346 // FileSource(symKeyFileName, true, new HexDecoder(new StringSink(keyBits)));
347
348 // using CryptoPP::AES;
349 // AutoSeededRandomPool rnd;
350 // byte iv[AES::BLOCKSIZE];
351 // rnd.GenerateBlock(iv, AES::BLOCKSIZE);
352
353 // CFB_Mode<AES>::Encryption encryptor;
354 // encryptor.SetKeyWithIV(reinterpret_cast<const uint8_t*>(keyBits.c_str()), keyBits.size(), iv);
355
356 // OBufferStream os;
357 // StringSource(data, dataLength, true, new StreamTransformationFilter(encryptor, new FileSink(os)));
358 // return os.buf();
359 // }catch(const CryptoPP::Exception& e){
360 // throw Error(e.what());
361 // }
362 }
363}
364
365
366void
367SecTpmFile::generateSymmetricKeyInTpm(const Name & keyName, KeyType keyType, int keySize)
368{
369 string keyURI = keyName.toUri();
370
371 if(doesKeyExistInTpm(keyName, KEY_CLASS_SYMMETRIC))
372 throw Error("symmetric key exists");
373
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800374 string keyFileName = m_impl->maintainMapping(keyURI);
Yingdi Yu2d9c50f2014-01-21 18:25:00 -0800375 string symKeyFileName = keyFileName + ".key";
376
377 try{
378 switch(keyType){
379 case KEY_TYPE_AES:
380 {
Yingdi Yu4b752752014-02-18 12:24:03 -0800381 using namespace CryptoPP;
382 AutoSeededRandomPool rng;
383
Yingdi Yu2d9c50f2014-01-21 18:25:00 -0800384 SecByteBlock key(0x00, keySize);
Yingdi Yu4b752752014-02-18 12:24:03 -0800385 rng.GenerateBlock(key, keySize);
Yingdi Yu2d9c50f2014-01-21 18:25:00 -0800386
387 StringSource(key, key.size(), true, new HexEncoder(new FileSink(symKeyFileName.c_str())));
388
389 chmod(symKeyFileName.c_str(), 0000400);
390 return;
391 }
392 default:
393 throw Error("Unsupported symmetric key type!");
394 }
395 }catch(const CryptoPP::Exception& e){
396 throw Error(e.what());
397 }
398}
399
400bool
401SecTpmFile::doesKeyExistInTpm(const Name & keyName, KeyClass keyClass)
402{
403 string keyURI = keyName.toUri();
404 if (keyClass == KEY_CLASS_PUBLIC)
405 {
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800406 if(boost::filesystem::exists(m_impl->nameTransform(keyURI, ".pub")))
Yingdi Yu2d9c50f2014-01-21 18:25:00 -0800407 return true;
408 else
409 return false;
410 }
411 if (keyClass == KEY_CLASS_PRIVATE)
412 {
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800413 if(boost::filesystem::exists(m_impl->nameTransform(keyURI, ".pri")))
Yingdi Yu2d9c50f2014-01-21 18:25:00 -0800414 return true;
415 else
416 return false;
417 }
418 if (keyClass == KEY_CLASS_SYMMETRIC)
419 {
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800420 if(boost::filesystem::exists(m_impl->nameTransform(keyURI, ".key")))
Yingdi Yu2d9c50f2014-01-21 18:25:00 -0800421 return true;
422 else
423 return false;
424 }
425 return false;
426}
427
Yingdi Yu4b752752014-02-18 12:24:03 -0800428bool
429SecTpmFile::generateRandomBlock(uint8_t* res, size_t size)
430{
431 try{
432 CryptoPP::AutoSeededRandomPool rng;
433 rng.GenerateBlock(res, size);
434 return true;
435 }catch(const CryptoPP::Exception& e){
436 return false;
437 }
438}
439
Yingdi Yufc40d872014-02-18 12:56:04 -0800440} // namespace ndn