blob: ecb823753c36485149189ec358cfd1ac710b6b8b [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 Yu2d9c50f2014-01-21 18:25:00 -080084SecTpmFile::SecTpmFile(const string & dir)
Yingdi Yu4b752752014-02-18 12:24:03 -080085 : m_impl(new Impl(dir))
Yingdi Yu2d9c50f2014-01-21 18:25:00 -080086{}
87
88void
89SecTpmFile::generateKeyPairInTpm(const Name & keyName, KeyType keyType, int keySize)
90{
91 string keyURI = keyName.toUri();
92
93 if(doesKeyExistInTpm(keyName, KEY_CLASS_PUBLIC))
94 throw Error("public key exists");
95 if(doesKeyExistInTpm(keyName, KEY_CLASS_PRIVATE))
96 throw Error("private key exists");
97
Yingdi Yu8dceb1d2014-02-18 12:45:10 -080098 string keyFileName = m_impl->maintainMapping(keyURI);
Yingdi Yu2d9c50f2014-01-21 18:25:00 -080099
100 try{
101 switch(keyType){
102 case KEY_TYPE_RSA:
103 {
Yingdi Yu4b752752014-02-18 12:24:03 -0800104 using namespace CryptoPP;
105 AutoSeededRandomPool rng;
106
Yingdi Yu2d9c50f2014-01-21 18:25:00 -0800107 InvertibleRSAFunction privateKey;
108 privateKey.Initialize(rng, keySize);
109
110 string privateKeyFileName = keyFileName + ".pri";
111 Base64Encoder privateKeySink(new FileSink(privateKeyFileName.c_str()));
112 privateKey.DEREncode(privateKeySink);
113 privateKeySink.MessageEnd();
114
115 RSAFunction publicKey(privateKey);
116 string publicKeyFileName = keyFileName + ".pub";
117 Base64Encoder publicKeySink(new FileSink(publicKeyFileName.c_str()));
118 publicKey.DEREncode(publicKeySink);
119 publicKeySink.MessageEnd();
120
121 /*set file permission*/
122 chmod(privateKeyFileName.c_str(), 0000400);
123 chmod(publicKeyFileName.c_str(), 0000444);
124 return;
125 }
126 default:
127 throw Error("Unsupported key type!");
128 }
129 }catch(const CryptoPP::Exception& e){
130 throw Error(e.what());
131 }
132}
133
Yingdi Yu28fd32f2014-01-28 19:03:03 -0800134void
135SecTpmFile::deleteKeyPairInTpm(const Name &keyName)
136{
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800137 boost::filesystem::path publicKeyPath(m_impl->nameTransform(keyName.toUri(), ".pub"));
138 boost::filesystem::path privateKeyPath(m_impl->nameTransform(keyName.toUri(), ".pri"));
Yingdi Yu28fd32f2014-01-28 19:03:03 -0800139
140 if(boost::filesystem::exists(publicKeyPath))
141 boost::filesystem::remove(publicKeyPath);
142
143 if(boost::filesystem::exists(privateKeyPath))
144 boost::filesystem::remove(privateKeyPath);
145}
146
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800147shared_ptr<PublicKey>
Yingdi Yu2d9c50f2014-01-21 18:25:00 -0800148SecTpmFile::getPublicKeyFromTpm(const Name & keyName)
149{
150 string keyURI = keyName.toUri();
151
152 if(!doesKeyExistInTpm(keyName, KEY_CLASS_PUBLIC))
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800153 return shared_ptr<PublicKey>();
Yingdi Yu2d9c50f2014-01-21 18:25:00 -0800154
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800155 ostringstream os;
Yingdi Yu2d9c50f2014-01-21 18:25:00 -0800156 try{
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800157 using namespace CryptoPP;
158 FileSource(m_impl->nameTransform(keyURI, ".pub").string().c_str(), true, new Base64Decoder(new FileSink(os)));
Yingdi Yu2d9c50f2014-01-21 18:25:00 -0800159 }catch(const CryptoPP::Exception& e){
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800160 return shared_ptr<PublicKey>();
Yingdi Yu2d9c50f2014-01-21 18:25:00 -0800161 }
162
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800163 return make_shared<PublicKey>(reinterpret_cast<const uint8_t*>(os.str().c_str()), os.str().size());
164}
165
166ConstBufferPtr
167SecTpmFile::exportPrivateKeyPkcs1FromTpm(const Name& keyName)
168{
169 OBufferStream privateKeyOs;
170 CryptoPP::FileSource(m_impl->nameTransform(keyName.toUri(), ".pri").string().c_str(), true,
171 new CryptoPP::Base64Decoder(new CryptoPP::FileSink(privateKeyOs)));
172
173 return privateKeyOs.buf();
174}
175
176bool
177SecTpmFile::importPrivateKeyPkcs1IntoTpm(const Name& keyName, const uint8_t* buf, size_t size)
178{
179 try{
180 string keyFileName = m_impl->maintainMapping(keyName.toUri());
181 keyFileName.append(".pri");
182 CryptoPP::StringSource(buf, size, true,
183 new CryptoPP::Base64Encoder(new CryptoPP::FileSink(keyFileName.c_str())));
184 return true;
185 }catch(...){
186 return false;
187 }
188}
189
190bool
191SecTpmFile::importPublicKeyPkcs1IntoTpm(const Name& keyName, const uint8_t* buf, size_t size)
192{
193 try{
194 string keyFileName = m_impl->maintainMapping(keyName.toUri());
195 keyFileName.append(".pub");
196 CryptoPP::StringSource(buf, size, true,
197 new CryptoPP::Base64Encoder(new CryptoPP::FileSink(keyFileName.c_str())));
198 return true;
199 }catch(...){
200 return false;
201 }
Yingdi Yu2d9c50f2014-01-21 18:25:00 -0800202}
203
204Block
205SecTpmFile::signInTpm(const uint8_t *data, size_t dataLength, const Name& keyName, DigestAlgorithm digestAlgorithm)
206{
207 string keyURI = keyName.toUri();
208
209 if(!doesKeyExistInTpm(keyName, KEY_CLASS_PRIVATE))
210 throw Error("private key doesn't exists");
211
212 try{
Yingdi Yu4b752752014-02-18 12:24:03 -0800213 using namespace CryptoPP;
Yingdi Yu2d9c50f2014-01-21 18:25:00 -0800214 AutoSeededRandomPool rng;
Yingdi Yu4b752752014-02-18 12:24:03 -0800215
Yingdi Yu2d9c50f2014-01-21 18:25:00 -0800216 //Read private key
217 ByteQueue bytes;
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800218 FileSource file(m_impl->nameTransform(keyURI, ".pri").string().c_str(), true, new Base64Decoder);
Yingdi Yu2d9c50f2014-01-21 18:25:00 -0800219 file.TransferTo(bytes);
220 bytes.MessageEnd();
221 RSA::PrivateKey privateKey;
222 privateKey.Load(bytes);
223
224 //Sign message
225 switch(digestAlgorithm){
226 case DIGEST_ALGORITHM_SHA256:
227 {
228 RSASS<PKCS1v15, SHA256>::Signer signer(privateKey);
229
230 OBufferStream os;
231 StringSource(data, dataLength, true, new SignerFilter(rng, signer, new FileSink(os)));
232
233 return Block(Tlv::SignatureValue, os.buf());
234 }
235 default:
236 throw Error("Unsupported digest algorithm!");
237 }
238 }catch(const CryptoPP::Exception& e){
239 throw Error(e.what());
240 }
241}
242
243
244ConstBufferPtr
Yingdi Yufc40d872014-02-18 12:56:04 -0800245SecTpmFile::decryptInTpm(const uint8_t* data, size_t dataLength, const Name& keyName, bool isSymmetric)
Yingdi Yu2d9c50f2014-01-21 18:25:00 -0800246{
247 string keyURI = keyName.toUri();
248 if (!isSymmetric)
249 {
250 if(!doesKeyExistInTpm(keyName, KEY_CLASS_PRIVATE))
251 throw Error("private key doesn't exist");
252
253 try{
Yingdi Yu4b752752014-02-18 12:24:03 -0800254 using namespace CryptoPP;
255 AutoSeededRandomPool rng;
256
Yingdi Yu2d9c50f2014-01-21 18:25:00 -0800257 //Read private key
258 ByteQueue bytes;
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800259 FileSource file(m_impl->nameTransform(keyURI, ".pri").string().c_str(), true, new Base64Decoder);
Yingdi Yu2d9c50f2014-01-21 18:25:00 -0800260 file.TransferTo(bytes);
261 bytes.MessageEnd();
262 RSA::PrivateKey privateKey;
263 privateKey.Load(bytes);
264 RSAES_PKCS1v15_Decryptor decryptor(privateKey);
265
266 OBufferStream os;
267 StringSource(data, dataLength, true, new PK_DecryptorFilter(rng, decryptor, new FileSink(os)));
268
269 return os.buf();
270 }
271 catch(const CryptoPP::Exception& e){
272 throw Error(e.what());
273 }
274 }
275 else
276 {
277 throw Error("Symmetric encryption is not implemented!");
278 // if(!doesKeyExistInTpm(keyName, KEY_CLASS_SYMMETRIC))
279 // throw Error("symmetric key doesn't exist");
280
281 // try{
282 // string keyBits;
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800283 // string symKeyFileName = m_impl->nameTransform(keyURI, ".key");
Yingdi Yu2d9c50f2014-01-21 18:25:00 -0800284 // FileSource(symKeyFileName, true, new HexDecoder(new StringSink(keyBits)));
285
286 // using CryptoPP::AES;
287 // AutoSeededRandomPool rnd;
288 // byte iv[AES::BLOCKSIZE];
289 // rnd.GenerateBlock(iv, AES::BLOCKSIZE);
290
291 // CFB_Mode<AES>::Decryption decryptor;
292 // decryptor.SetKeyWithIV(reinterpret_cast<const uint8_t*>(keyBits.c_str()), keyBits.size(), iv);
293
294 // OBufferStream os;
295 // StringSource(data, dataLength, true, new StreamTransformationFilter(decryptor,new FileSink(os)));
296 // return os.buf();
297
298 // }catch(const CryptoPP::Exception& e){
299 // throw Error(e.what());
300 // }
301 }
302}
303
304ConstBufferPtr
Yingdi Yufc40d872014-02-18 12:56:04 -0800305SecTpmFile::encryptInTpm(const uint8_t* data, size_t dataLength, const Name& keyName, bool isSymmetric)
Yingdi Yu2d9c50f2014-01-21 18:25:00 -0800306{
307 string keyURI = keyName.toUri();
308
309 if (!isSymmetric)
310 {
311 if(!doesKeyExistInTpm(keyName, KEY_CLASS_PUBLIC))
312 throw Error("public key doesn't exist");
313 try
314 {
Yingdi Yu4b752752014-02-18 12:24:03 -0800315 using namespace CryptoPP;
316 AutoSeededRandomPool rng;
Yingdi Yu2d9c50f2014-01-21 18:25:00 -0800317
318 //Read private key
319 ByteQueue bytes;
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800320 FileSource file(m_impl->nameTransform(keyURI, ".pub").string().c_str(), true, new Base64Decoder);
Yingdi Yu2d9c50f2014-01-21 18:25:00 -0800321 file.TransferTo(bytes);
322 bytes.MessageEnd();
323 RSA::PublicKey publicKey;
324 publicKey.Load(bytes);
325
326 OBufferStream os;
327 RSAES_PKCS1v15_Encryptor encryptor(publicKey);
328
329 StringSource(data, dataLength, true, new PK_EncryptorFilter(rng, encryptor, new FileSink(os)));
330 return os.buf();
331 }
332 catch(const CryptoPP::Exception& e){
333 throw Error(e.what());
334 }
335 }
336 else
337 {
338 throw Error("Symmetric encryption is not implemented!");
339 // if(!doesKeyExistInTpm(keyName, KEY_CLASS_SYMMETRIC))
340 // throw Error("symmetric key doesn't exist");
341
342 // try{
343 // string keyBits;
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800344 // string symKeyFileName = m_impl->nameTransform(keyURI, ".key");
Yingdi Yu2d9c50f2014-01-21 18:25:00 -0800345 // FileSource(symKeyFileName, true, new HexDecoder(new StringSink(keyBits)));
346
347 // using CryptoPP::AES;
348 // AutoSeededRandomPool rnd;
349 // byte iv[AES::BLOCKSIZE];
350 // rnd.GenerateBlock(iv, AES::BLOCKSIZE);
351
352 // CFB_Mode<AES>::Encryption encryptor;
353 // encryptor.SetKeyWithIV(reinterpret_cast<const uint8_t*>(keyBits.c_str()), keyBits.size(), iv);
354
355 // OBufferStream os;
356 // StringSource(data, dataLength, true, new StreamTransformationFilter(encryptor, new FileSink(os)));
357 // return os.buf();
358 // }catch(const CryptoPP::Exception& e){
359 // throw Error(e.what());
360 // }
361 }
362}
363
364
365void
366SecTpmFile::generateSymmetricKeyInTpm(const Name & keyName, KeyType keyType, int keySize)
367{
368 string keyURI = keyName.toUri();
369
370 if(doesKeyExistInTpm(keyName, KEY_CLASS_SYMMETRIC))
371 throw Error("symmetric key exists");
372
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800373 string keyFileName = m_impl->maintainMapping(keyURI);
Yingdi Yu2d9c50f2014-01-21 18:25:00 -0800374 string symKeyFileName = keyFileName + ".key";
375
376 try{
377 switch(keyType){
378 case KEY_TYPE_AES:
379 {
Yingdi Yu4b752752014-02-18 12:24:03 -0800380 using namespace CryptoPP;
381 AutoSeededRandomPool rng;
382
Yingdi Yu2d9c50f2014-01-21 18:25:00 -0800383 SecByteBlock key(0x00, keySize);
Yingdi Yu4b752752014-02-18 12:24:03 -0800384 rng.GenerateBlock(key, keySize);
Yingdi Yu2d9c50f2014-01-21 18:25:00 -0800385
386 StringSource(key, key.size(), true, new HexEncoder(new FileSink(symKeyFileName.c_str())));
387
388 chmod(symKeyFileName.c_str(), 0000400);
389 return;
390 }
391 default:
392 throw Error("Unsupported symmetric key type!");
393 }
394 }catch(const CryptoPP::Exception& e){
395 throw Error(e.what());
396 }
397}
398
399bool
400SecTpmFile::doesKeyExistInTpm(const Name & keyName, KeyClass keyClass)
401{
402 string keyURI = keyName.toUri();
403 if (keyClass == KEY_CLASS_PUBLIC)
404 {
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800405 if(boost::filesystem::exists(m_impl->nameTransform(keyURI, ".pub")))
Yingdi Yu2d9c50f2014-01-21 18:25:00 -0800406 return true;
407 else
408 return false;
409 }
410 if (keyClass == KEY_CLASS_PRIVATE)
411 {
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800412 if(boost::filesystem::exists(m_impl->nameTransform(keyURI, ".pri")))
Yingdi Yu2d9c50f2014-01-21 18:25:00 -0800413 return true;
414 else
415 return false;
416 }
417 if (keyClass == KEY_CLASS_SYMMETRIC)
418 {
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800419 if(boost::filesystem::exists(m_impl->nameTransform(keyURI, ".key")))
Yingdi Yu2d9c50f2014-01-21 18:25:00 -0800420 return true;
421 else
422 return false;
423 }
424 return false;
425}
426
Yingdi Yu4b752752014-02-18 12:24:03 -0800427bool
428SecTpmFile::generateRandomBlock(uint8_t* res, size_t size)
429{
430 try{
431 CryptoPP::AutoSeededRandomPool rng;
432 rng.GenerateBlock(res, size);
433 return true;
434 }catch(const CryptoPP::Exception& e){
435 return false;
436 }
437}
438
Yingdi Yufc40d872014-02-18 12:56:04 -0800439} // namespace ndn