blob: 78d7ef752de337fe4daa445906ef44b1535bb6e1 [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
36namespace ndn
37{
38
39class SecTpmFile::Impl {
40public:
Yingdi Yu4b752752014-02-18 12:24:03 -080041 Impl(const string& dir)
Yingdi Yu2d9c50f2014-01-21 18:25:00 -080042 {
43 if(dir.empty())
Yingdi Yu04020922014-01-22 12:46:53 -080044 m_keystorePath = boost::filesystem::path(getenv("HOME")) / ".ndnx" / "ndnsec-tpm-file";
Yingdi Yu2d9c50f2014-01-21 18:25:00 -080045 else
46 m_keystorePath = dir;
47
48 boost::filesystem::create_directories (m_keystorePath);
49 }
50
Yingdi Yu8dceb1d2014-02-18 12:45:10 -080051 boost::filesystem::path
52 nameTransform(const string& keyName, const string& extension)
53 {
54 using namespace CryptoPP;
55 string digest;
56 SHA256 hash;
57 StringSource src(keyName, true, new HashFilter(hash, new Base64Encoder (new CryptoPP::StringSink(digest))));
58
59 boost::algorithm::trim(digest);
60 std::replace(digest.begin(), digest.end(), '/', '%');
61
62 return m_keystorePath / (digest + extension);
63 }
64
65 string
66 maintainMapping(const string& keyName)
67 {
68 string keyFileName = nameTransform(keyName, "").string();
69
70 ofstream outfile;
71 string dirFile = (m_keystorePath / "mapping.txt").string();
72
73 outfile.open(dirFile.c_str(), std::ios_base::app);
74 outfile << keyName << ' ' << keyFileName << '\n';
75 outfile.close();
76
77 return keyFileName;
78 }
79
Yingdi Yu2d9c50f2014-01-21 18:25:00 -080080public:
81 boost::filesystem::path m_keystorePath;
82};
83
Yingdi Yu4b752752014-02-18 12:24:03 -080084
Yingdi Yu2d9c50f2014-01-21 18:25:00 -080085SecTpmFile::SecTpmFile(const string & dir)
Yingdi Yu4b752752014-02-18 12:24:03 -080086 : m_impl(new Impl(dir))
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
246SecTpmFile::decryptInTpm(const Name& keyName, const uint8_t* data, size_t dataLength, bool isSymmetric)
247{
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
306SecTpmFile::encryptInTpm(const Name& keyName, const uint8_t* data, size_t dataLength, bool isSymmetric)
307{
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 Yu2d9c50f2014-01-21 18:25:00 -0800440} //ndn