blob: 47cf83bc829bf9e8b473f0ed73750299ac7b082e [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>
25
26#include <sys/types.h>
27#include <sys/stat.h>
28
29using namespace CryptoPP;
30using namespace ndn;
31using namespace std;
32
33namespace ndn
34{
35
36class SecTpmFile::Impl {
37public:
Yingdi Yu4b752752014-02-18 12:24:03 -080038 Impl(const string& dir)
Yingdi Yu2d9c50f2014-01-21 18:25:00 -080039 {
40 if(dir.empty())
Yingdi Yu04020922014-01-22 12:46:53 -080041 m_keystorePath = boost::filesystem::path(getenv("HOME")) / ".ndnx" / "ndnsec-tpm-file";
Yingdi Yu2d9c50f2014-01-21 18:25:00 -080042 else
43 m_keystorePath = dir;
44
45 boost::filesystem::create_directories (m_keystorePath);
46 }
47
48public:
49 boost::filesystem::path m_keystorePath;
50};
51
Yingdi Yu4b752752014-02-18 12:24:03 -080052
Yingdi Yu2d9c50f2014-01-21 18:25:00 -080053SecTpmFile::SecTpmFile(const string & dir)
Yingdi Yu4b752752014-02-18 12:24:03 -080054 : m_impl(new Impl(dir))
Yingdi Yu2d9c50f2014-01-21 18:25:00 -080055{}
56
57void
58SecTpmFile::generateKeyPairInTpm(const Name & keyName, KeyType keyType, int keySize)
59{
60 string keyURI = keyName.toUri();
61
62 if(doesKeyExistInTpm(keyName, KEY_CLASS_PUBLIC))
63 throw Error("public key exists");
64 if(doesKeyExistInTpm(keyName, KEY_CLASS_PRIVATE))
65 throw Error("private key exists");
66
67 string keyFileName = nameTransform(keyURI, "");
68 maintainMapping(keyURI, keyFileName);
69
70 try{
71 switch(keyType){
72 case KEY_TYPE_RSA:
73 {
Yingdi Yu4b752752014-02-18 12:24:03 -080074 using namespace CryptoPP;
75 AutoSeededRandomPool rng;
76
Yingdi Yu2d9c50f2014-01-21 18:25:00 -080077 InvertibleRSAFunction privateKey;
78 privateKey.Initialize(rng, keySize);
79
80 string privateKeyFileName = keyFileName + ".pri";
81 Base64Encoder privateKeySink(new FileSink(privateKeyFileName.c_str()));
82 privateKey.DEREncode(privateKeySink);
83 privateKeySink.MessageEnd();
84
85 RSAFunction publicKey(privateKey);
86 string publicKeyFileName = keyFileName + ".pub";
87 Base64Encoder publicKeySink(new FileSink(publicKeyFileName.c_str()));
88 publicKey.DEREncode(publicKeySink);
89 publicKeySink.MessageEnd();
90
91 /*set file permission*/
92 chmod(privateKeyFileName.c_str(), 0000400);
93 chmod(publicKeyFileName.c_str(), 0000444);
94 return;
95 }
96 default:
97 throw Error("Unsupported key type!");
98 }
99 }catch(const CryptoPP::Exception& e){
100 throw Error(e.what());
101 }
102}
103
Yingdi Yu28fd32f2014-01-28 19:03:03 -0800104void
105SecTpmFile::deleteKeyPairInTpm(const Name &keyName)
106{
107 boost::filesystem::path publicKeyPath(nameTransform(keyName.toUri(), ".pub"));
108 boost::filesystem::path privateKeyPath(nameTransform(keyName.toUri(), ".pri"));
109
110 if(boost::filesystem::exists(publicKeyPath))
111 boost::filesystem::remove(publicKeyPath);
112
113 if(boost::filesystem::exists(privateKeyPath))
114 boost::filesystem::remove(privateKeyPath);
115}
116
Yingdi Yu2d9c50f2014-01-21 18:25:00 -0800117ptr_lib::shared_ptr<PublicKey>
118SecTpmFile::getPublicKeyFromTpm(const Name & keyName)
119{
120 string keyURI = keyName.toUri();
121
122 if(!doesKeyExistInTpm(keyName, KEY_CLASS_PUBLIC))
123 throw Error("public key doesn't exists");
124
125 string publicKeyFileName = nameTransform(keyURI, ".pub");
126 std::ostringstream os;
127 try{
128 FileSource(publicKeyFileName.c_str(), true, new Base64Decoder(new FileSink(os)));
129 }catch(const CryptoPP::Exception& e){
130 throw Error(e.what());
131 }
132
133 return ptr_lib::make_shared<PublicKey>(reinterpret_cast<const uint8_t*>(os.str().c_str()), os.str().size());
134}
135
136Block
137SecTpmFile::signInTpm(const uint8_t *data, size_t dataLength, const Name& keyName, DigestAlgorithm digestAlgorithm)
138{
139 string keyURI = keyName.toUri();
140
141 if(!doesKeyExistInTpm(keyName, KEY_CLASS_PRIVATE))
142 throw Error("private key doesn't exists");
143
144 try{
Yingdi Yu4b752752014-02-18 12:24:03 -0800145 using namespace CryptoPP;
Yingdi Yu2d9c50f2014-01-21 18:25:00 -0800146 AutoSeededRandomPool rng;
Yingdi Yu4b752752014-02-18 12:24:03 -0800147
Yingdi Yu2d9c50f2014-01-21 18:25:00 -0800148 //Read private key
149 ByteQueue bytes;
150 string privateKeyFileName = nameTransform(keyURI, ".pri");
151 FileSource file(privateKeyFileName.c_str(), true, new Base64Decoder);
152 file.TransferTo(bytes);
153 bytes.MessageEnd();
154 RSA::PrivateKey privateKey;
155 privateKey.Load(bytes);
156
157 //Sign message
158 switch(digestAlgorithm){
159 case DIGEST_ALGORITHM_SHA256:
160 {
161 RSASS<PKCS1v15, SHA256>::Signer signer(privateKey);
162
163 OBufferStream os;
164 StringSource(data, dataLength, true, new SignerFilter(rng, signer, new FileSink(os)));
165
166 return Block(Tlv::SignatureValue, os.buf());
167 }
168 default:
169 throw Error("Unsupported digest algorithm!");
170 }
171 }catch(const CryptoPP::Exception& e){
172 throw Error(e.what());
173 }
174}
175
176
177ConstBufferPtr
178SecTpmFile::decryptInTpm(const Name& keyName, const uint8_t* data, size_t dataLength, bool isSymmetric)
179{
180 string keyURI = keyName.toUri();
181 if (!isSymmetric)
182 {
183 if(!doesKeyExistInTpm(keyName, KEY_CLASS_PRIVATE))
184 throw Error("private key doesn't exist");
185
186 try{
Yingdi Yu4b752752014-02-18 12:24:03 -0800187 using namespace CryptoPP;
188 AutoSeededRandomPool rng;
189
Yingdi Yu2d9c50f2014-01-21 18:25:00 -0800190 //Read private key
191 ByteQueue bytes;
192 string privateKeyFileName = nameTransform(keyURI, ".pri");
193 FileSource file(privateKeyFileName.c_str(), true, new Base64Decoder);
194 file.TransferTo(bytes);
195 bytes.MessageEnd();
196 RSA::PrivateKey privateKey;
197 privateKey.Load(bytes);
198 RSAES_PKCS1v15_Decryptor decryptor(privateKey);
199
200 OBufferStream os;
201 StringSource(data, dataLength, true, new PK_DecryptorFilter(rng, decryptor, new FileSink(os)));
202
203 return os.buf();
204 }
205 catch(const CryptoPP::Exception& e){
206 throw Error(e.what());
207 }
208 }
209 else
210 {
211 throw Error("Symmetric encryption is not implemented!");
212 // if(!doesKeyExistInTpm(keyName, KEY_CLASS_SYMMETRIC))
213 // throw Error("symmetric key doesn't exist");
214
215 // try{
216 // string keyBits;
217 // string symKeyFileName = nameTransform(keyURI, ".key");
218 // FileSource(symKeyFileName, true, new HexDecoder(new StringSink(keyBits)));
219
220 // using CryptoPP::AES;
221 // AutoSeededRandomPool rnd;
222 // byte iv[AES::BLOCKSIZE];
223 // rnd.GenerateBlock(iv, AES::BLOCKSIZE);
224
225 // CFB_Mode<AES>::Decryption decryptor;
226 // decryptor.SetKeyWithIV(reinterpret_cast<const uint8_t*>(keyBits.c_str()), keyBits.size(), iv);
227
228 // OBufferStream os;
229 // StringSource(data, dataLength, true, new StreamTransformationFilter(decryptor,new FileSink(os)));
230 // return os.buf();
231
232 // }catch(const CryptoPP::Exception& e){
233 // throw Error(e.what());
234 // }
235 }
236}
237
238ConstBufferPtr
239SecTpmFile::encryptInTpm(const Name& keyName, const uint8_t* data, size_t dataLength, bool isSymmetric)
240{
241 string keyURI = keyName.toUri();
242
243 if (!isSymmetric)
244 {
245 if(!doesKeyExistInTpm(keyName, KEY_CLASS_PUBLIC))
246 throw Error("public key doesn't exist");
247 try
248 {
Yingdi Yu4b752752014-02-18 12:24:03 -0800249 using namespace CryptoPP;
250 AutoSeededRandomPool rng;
Yingdi Yu2d9c50f2014-01-21 18:25:00 -0800251
252 //Read private key
253 ByteQueue bytes;
254 string publicKeyFileName = nameTransform(keyURI, ".pub");
255 FileSource file(publicKeyFileName.c_str(), true, new Base64Decoder);
256 file.TransferTo(bytes);
257 bytes.MessageEnd();
258 RSA::PublicKey publicKey;
259 publicKey.Load(bytes);
260
261 OBufferStream os;
262 RSAES_PKCS1v15_Encryptor encryptor(publicKey);
263
264 StringSource(data, dataLength, true, new PK_EncryptorFilter(rng, encryptor, new FileSink(os)));
265 return os.buf();
266 }
267 catch(const CryptoPP::Exception& e){
268 throw Error(e.what());
269 }
270 }
271 else
272 {
273 throw Error("Symmetric encryption is not implemented!");
274 // if(!doesKeyExistInTpm(keyName, KEY_CLASS_SYMMETRIC))
275 // throw Error("symmetric key doesn't exist");
276
277 // try{
278 // string keyBits;
279 // string symKeyFileName = nameTransform(keyURI, ".key");
280 // FileSource(symKeyFileName, true, new HexDecoder(new StringSink(keyBits)));
281
282 // using CryptoPP::AES;
283 // AutoSeededRandomPool rnd;
284 // byte iv[AES::BLOCKSIZE];
285 // rnd.GenerateBlock(iv, AES::BLOCKSIZE);
286
287 // CFB_Mode<AES>::Encryption encryptor;
288 // encryptor.SetKeyWithIV(reinterpret_cast<const uint8_t*>(keyBits.c_str()), keyBits.size(), iv);
289
290 // OBufferStream os;
291 // StringSource(data, dataLength, true, new StreamTransformationFilter(encryptor, new FileSink(os)));
292 // return os.buf();
293 // }catch(const CryptoPP::Exception& e){
294 // throw Error(e.what());
295 // }
296 }
297}
298
299
300void
301SecTpmFile::generateSymmetricKeyInTpm(const Name & keyName, KeyType keyType, int keySize)
302{
303 string keyURI = keyName.toUri();
304
305 if(doesKeyExistInTpm(keyName, KEY_CLASS_SYMMETRIC))
306 throw Error("symmetric key exists");
307
308 string keyFileName = nameTransform(keyURI, "");
309 maintainMapping(keyURI, keyFileName);
310 string symKeyFileName = keyFileName + ".key";
311
312 try{
313 switch(keyType){
314 case KEY_TYPE_AES:
315 {
Yingdi Yu4b752752014-02-18 12:24:03 -0800316 using namespace CryptoPP;
317 AutoSeededRandomPool rng;
318
Yingdi Yu2d9c50f2014-01-21 18:25:00 -0800319 SecByteBlock key(0x00, keySize);
Yingdi Yu4b752752014-02-18 12:24:03 -0800320 rng.GenerateBlock(key, keySize);
Yingdi Yu2d9c50f2014-01-21 18:25:00 -0800321
322 StringSource(key, key.size(), true, new HexEncoder(new FileSink(symKeyFileName.c_str())));
323
324 chmod(symKeyFileName.c_str(), 0000400);
325 return;
326 }
327 default:
328 throw Error("Unsupported symmetric key type!");
329 }
330 }catch(const CryptoPP::Exception& e){
331 throw Error(e.what());
332 }
333}
334
335bool
336SecTpmFile::doesKeyExistInTpm(const Name & keyName, KeyClass keyClass)
337{
338 string keyURI = keyName.toUri();
339 if (keyClass == KEY_CLASS_PUBLIC)
340 {
341 string publicKeyName = SecTpmFile::nameTransform(keyURI, ".pub");
342 fstream fin(publicKeyName.c_str(),ios::in);
343 if (fin)
344 return true;
345 else
346 return false;
347 }
348 if (keyClass == KEY_CLASS_PRIVATE)
349 {
350 string privateKeyName = SecTpmFile::nameTransform(keyURI, ".pri");
351 fstream fin(privateKeyName.c_str(),ios::in);
352 if (fin)
353 return true;
354 else
355 return false;
356 }
357 if (keyClass == KEY_CLASS_SYMMETRIC)
358 {
359 string symmetricKeyName = SecTpmFile::nameTransform(keyURI, ".key");
360 fstream fin(symmetricKeyName.c_str(),ios::in);
361 if (fin)
362 return true;
363 else
364 return false;
365 }
366 return false;
367}
368
369std::string SecTpmFile::nameTransform(const string &keyName, const string &extension)
370{
371 std::string digest;
372 CryptoPP::SHA256 hash;
373 CryptoPP::StringSource foo(keyName, true,
374 new CryptoPP::HashFilter(hash,
375 new CryptoPP::Base64Encoder (new CryptoPP::StringSink(digest))
376 )
377 );
378 boost::algorithm::trim(digest);
379 for (std::string::iterator ch = digest.begin(); ch != digest.end(); ch++)
380 {
381 if (*ch == '/')
382 {
383 *ch = '%';
384 }
385 }
386
Yingdi Yu4b752752014-02-18 12:24:03 -0800387 return (m_impl->m_keystorePath / (digest + extension)).string();
Yingdi Yu2d9c50f2014-01-21 18:25:00 -0800388}
389
390void
391SecTpmFile::maintainMapping(string str1, string str2)
392{
393 std::ofstream outfile;
Yingdi Yu4b752752014-02-18 12:24:03 -0800394 string dirFile = (m_impl->m_keystorePath / "mapping.txt").string();
Yingdi Yu2d9c50f2014-01-21 18:25:00 -0800395
396 outfile.open(dirFile.c_str(), std::ios_base::app);
397 outfile << str1 << ' ' << str2 << '\n';
398 outfile.close();
399}
400
Yingdi Yu4b752752014-02-18 12:24:03 -0800401bool
402SecTpmFile::generateRandomBlock(uint8_t* res, size_t size)
403{
404 try{
405 CryptoPP::AutoSeededRandomPool rng;
406 rng.GenerateBlock(res, size);
407 return true;
408 }catch(const CryptoPP::Exception& e){
409 return false;
410 }
411}
412
Yingdi Yu2d9c50f2014-01-21 18:25:00 -0800413} //ndn