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