blob: 93d288612950a5796c5888c34d163af46c34c219 [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 Yu2e57a582014-02-20 23:34:43 -0800154 throw Error("Public Key already exist");
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 Yu2e57a582014-02-20 23:34:43 -0800161 throw Error(e.what());
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{
Yingdi Yu2e57a582014-02-20 23:34:43 -0800248 throw Error("SecTpmFile::decryptInTpm is not supported!");
249 // string keyURI = keyName.toUri();
250 // if (!isSymmetric)
251 // {
252 // if(!doesKeyExistInTpm(keyName, KEY_CLASS_PRIVATE))
253 // throw Error("private key doesn't exist");
Yingdi Yu2d9c50f2014-01-21 18:25:00 -0800254
Yingdi Yu2e57a582014-02-20 23:34:43 -0800255 // try{
256 // using namespace CryptoPP;
257 // AutoSeededRandomPool rng;
Yingdi Yu4b752752014-02-18 12:24:03 -0800258
Yingdi Yu2e57a582014-02-20 23:34:43 -0800259 // //Read private key
260 // ByteQueue bytes;
261 // FileSource file(m_impl->nameTransform(keyURI, ".pri").string().c_str(), true, new Base64Decoder);
262 // file.TransferTo(bytes);
263 // bytes.MessageEnd();
264 // RSA::PrivateKey privateKey;
265 // privateKey.Load(bytes);
266 // RSAES_PKCS1v15_Decryptor decryptor(privateKey);
Yingdi Yu2d9c50f2014-01-21 18:25:00 -0800267
Yingdi Yu2e57a582014-02-20 23:34:43 -0800268 // OBufferStream os;
269 // StringSource(data, dataLength, true, new PK_DecryptorFilter(rng, decryptor, new FileSink(os)));
Yingdi Yu2d9c50f2014-01-21 18:25:00 -0800270
Yingdi Yu2e57a582014-02-20 23:34:43 -0800271 // return os.buf();
272 // }
273 // catch(const CryptoPP::Exception& e){
274 // throw Error(e.what());
275 // }
276 // }
277 // else
278 // {
279 // throw Error("Symmetric encryption is not implemented!");
280 // // if(!doesKeyExistInTpm(keyName, KEY_CLASS_SYMMETRIC))
281 // // throw Error("symmetric key doesn't exist");
Yingdi Yu2d9c50f2014-01-21 18:25:00 -0800282
Yingdi Yu2e57a582014-02-20 23:34:43 -0800283 // // try{
284 // // string keyBits;
285 // // string symKeyFileName = m_impl->nameTransform(keyURI, ".key");
286 // // FileSource(symKeyFileName, true, new HexDecoder(new StringSink(keyBits)));
Yingdi Yu2d9c50f2014-01-21 18:25:00 -0800287
Yingdi Yu2e57a582014-02-20 23:34:43 -0800288 // // using CryptoPP::AES;
289 // // AutoSeededRandomPool rnd;
290 // // byte iv[AES::BLOCKSIZE];
291 // // rnd.GenerateBlock(iv, AES::BLOCKSIZE);
Yingdi Yu2d9c50f2014-01-21 18:25:00 -0800292
Yingdi Yu2e57a582014-02-20 23:34:43 -0800293 // // CFB_Mode<AES>::Decryption decryptor;
294 // // decryptor.SetKeyWithIV(reinterpret_cast<const uint8_t*>(keyBits.c_str()), keyBits.size(), iv);
Yingdi Yu2d9c50f2014-01-21 18:25:00 -0800295
Yingdi Yu2e57a582014-02-20 23:34:43 -0800296 // // OBufferStream os;
297 // // StringSource(data, dataLength, true, new StreamTransformationFilter(decryptor,new FileSink(os)));
298 // // return os.buf();
Yingdi Yu2d9c50f2014-01-21 18:25:00 -0800299
Yingdi Yu2e57a582014-02-20 23:34:43 -0800300 // // }catch(const CryptoPP::Exception& e){
301 // // throw Error(e.what());
302 // // }
303 // }
Yingdi Yu2d9c50f2014-01-21 18:25:00 -0800304}
305
306ConstBufferPtr
Yingdi Yufc40d872014-02-18 12:56:04 -0800307SecTpmFile::encryptInTpm(const uint8_t* data, size_t dataLength, const Name& keyName, bool isSymmetric)
Yingdi Yu2d9c50f2014-01-21 18:25:00 -0800308{
Yingdi Yu2e57a582014-02-20 23:34:43 -0800309 throw Error("SecTpmFile::encryptInTpm is not supported!");
310 // string keyURI = keyName.toUri();
Yingdi Yu2d9c50f2014-01-21 18:25:00 -0800311
Yingdi Yu2e57a582014-02-20 23:34:43 -0800312 // if (!isSymmetric)
313 // {
314 // if(!doesKeyExistInTpm(keyName, KEY_CLASS_PUBLIC))
315 // throw Error("public key doesn't exist");
316 // try
317 // {
318 // using namespace CryptoPP;
319 // AutoSeededRandomPool rng;
Yingdi Yu2d9c50f2014-01-21 18:25:00 -0800320
Yingdi Yu2e57a582014-02-20 23:34:43 -0800321 // //Read private key
322 // ByteQueue bytes;
323 // FileSource file(m_impl->nameTransform(keyURI, ".pub").string().c_str(), true, new Base64Decoder);
324 // file.TransferTo(bytes);
325 // bytes.MessageEnd();
326 // RSA::PublicKey publicKey;
327 // publicKey.Load(bytes);
Yingdi Yu2d9c50f2014-01-21 18:25:00 -0800328
Yingdi Yu2e57a582014-02-20 23:34:43 -0800329 // OBufferStream os;
330 // RSAES_PKCS1v15_Encryptor encryptor(publicKey);
Yingdi Yu2d9c50f2014-01-21 18:25:00 -0800331
Yingdi Yu2e57a582014-02-20 23:34:43 -0800332 // StringSource(data, dataLength, true, new PK_EncryptorFilter(rng, encryptor, new FileSink(os)));
333 // return os.buf();
334 // }
335 // catch(const CryptoPP::Exception& e){
336 // throw Error(e.what());
337 // }
338 // }
339 // else
340 // {
341 // throw Error("Symmetric encryption is not implemented!");
342 // // if(!doesKeyExistInTpm(keyName, KEY_CLASS_SYMMETRIC))
343 // // throw Error("symmetric key doesn't exist");
Yingdi Yu2d9c50f2014-01-21 18:25:00 -0800344
Yingdi Yu2e57a582014-02-20 23:34:43 -0800345 // // try{
346 // // string keyBits;
347 // // string symKeyFileName = m_impl->nameTransform(keyURI, ".key");
348 // // FileSource(symKeyFileName, true, new HexDecoder(new StringSink(keyBits)));
Yingdi Yu2d9c50f2014-01-21 18:25:00 -0800349
Yingdi Yu2e57a582014-02-20 23:34:43 -0800350 // // using CryptoPP::AES;
351 // // AutoSeededRandomPool rnd;
352 // // byte iv[AES::BLOCKSIZE];
353 // // rnd.GenerateBlock(iv, AES::BLOCKSIZE);
Yingdi Yu2d9c50f2014-01-21 18:25:00 -0800354
Yingdi Yu2e57a582014-02-20 23:34:43 -0800355 // // CFB_Mode<AES>::Encryption encryptor;
356 // // encryptor.SetKeyWithIV(reinterpret_cast<const uint8_t*>(keyBits.c_str()), keyBits.size(), iv);
Yingdi Yu2d9c50f2014-01-21 18:25:00 -0800357
Yingdi Yu2e57a582014-02-20 23:34:43 -0800358 // // OBufferStream os;
359 // // StringSource(data, dataLength, true, new StreamTransformationFilter(encryptor, new FileSink(os)));
360 // // return os.buf();
361 // // }catch(const CryptoPP::Exception& e){
362 // // throw Error(e.what());
363 // // }
364 // }
Yingdi Yu2d9c50f2014-01-21 18:25:00 -0800365}
366
367
368void
369SecTpmFile::generateSymmetricKeyInTpm(const Name & keyName, KeyType keyType, int keySize)
370{
Yingdi Yu2e57a582014-02-20 23:34:43 -0800371 throw Error("SecTpmFile::generateSymmetricKeyInTpm is not supported!");
372 // string keyURI = keyName.toUri();
Yingdi Yu2d9c50f2014-01-21 18:25:00 -0800373
Yingdi Yu2e57a582014-02-20 23:34:43 -0800374 // if(doesKeyExistInTpm(keyName, KEY_CLASS_SYMMETRIC))
375 // throw Error("symmetric key exists");
Yingdi Yu2d9c50f2014-01-21 18:25:00 -0800376
Yingdi Yu2e57a582014-02-20 23:34:43 -0800377 // string keyFileName = m_impl->maintainMapping(keyURI);
378 // string symKeyFileName = keyFileName + ".key";
Yingdi Yu2d9c50f2014-01-21 18:25:00 -0800379
Yingdi Yu2e57a582014-02-20 23:34:43 -0800380 // try{
381 // switch(keyType){
382 // case KEY_TYPE_AES:
383 // {
384 // using namespace CryptoPP;
385 // AutoSeededRandomPool rng;
Yingdi Yu4b752752014-02-18 12:24:03 -0800386
Yingdi Yu2e57a582014-02-20 23:34:43 -0800387 // SecByteBlock key(0x00, keySize);
388 // rng.GenerateBlock(key, keySize);
Yingdi Yu2d9c50f2014-01-21 18:25:00 -0800389
Yingdi Yu2e57a582014-02-20 23:34:43 -0800390 // StringSource(key, key.size(), true, new HexEncoder(new FileSink(symKeyFileName.c_str())));
Yingdi Yu2d9c50f2014-01-21 18:25:00 -0800391
Yingdi Yu2e57a582014-02-20 23:34:43 -0800392 // chmod(symKeyFileName.c_str(), 0000400);
393 // return;
394 // }
395 // default:
396 // throw Error("Unsupported symmetric key type!");
397 // }
398 // }catch(const CryptoPP::Exception& e){
399 // throw Error(e.what());
400 // }
Yingdi Yu2d9c50f2014-01-21 18:25:00 -0800401}
402
403bool
404SecTpmFile::doesKeyExistInTpm(const Name & keyName, KeyClass keyClass)
405{
406 string keyURI = keyName.toUri();
407 if (keyClass == KEY_CLASS_PUBLIC)
408 {
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800409 if(boost::filesystem::exists(m_impl->nameTransform(keyURI, ".pub")))
Yingdi Yu2d9c50f2014-01-21 18:25:00 -0800410 return true;
411 else
412 return false;
413 }
414 if (keyClass == KEY_CLASS_PRIVATE)
415 {
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800416 if(boost::filesystem::exists(m_impl->nameTransform(keyURI, ".pri")))
Yingdi Yu2d9c50f2014-01-21 18:25:00 -0800417 return true;
418 else
419 return false;
420 }
421 if (keyClass == KEY_CLASS_SYMMETRIC)
422 {
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800423 if(boost::filesystem::exists(m_impl->nameTransform(keyURI, ".key")))
Yingdi Yu2d9c50f2014-01-21 18:25:00 -0800424 return true;
425 else
426 return false;
427 }
428 return false;
429}
430
Yingdi Yu4b752752014-02-18 12:24:03 -0800431bool
432SecTpmFile::generateRandomBlock(uint8_t* res, size_t size)
433{
434 try{
435 CryptoPP::AutoSeededRandomPool rng;
436 rng.GenerateBlock(res, size);
437 return true;
438 }catch(const CryptoPP::Exception& e){
439 return false;
440 }
441}
442
Yingdi Yufc40d872014-02-18 12:56:04 -0800443} // namespace ndn