blob: c8dab805d3f6a39ca0f413fff2b3f95e03ffaee4 [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
Yingdi Yu04020922014-01-22 12:46:53 -080010#if __clang__
11#pragma clang diagnostic ignored "-Wtautological-compare"
12#endif
13
Alexander Afanasyev09c613f2014-01-29 00:23:58 -080014#include "security/sec-tpm-file.hpp"
Yingdi Yu2d9c50f2014-01-21 18:25:00 -080015
16#include <string>
17
18#include <boost/filesystem.hpp>
19#include <boost/algorithm/string.hpp>
20
21#include <cryptopp/rsa.h>
22#include <cryptopp/files.h>
23#include <cryptopp/base64.h>
24#include <cryptopp/hex.h>
25#include <cryptopp/osrng.h>
26#include <cryptopp/sha.h>
27#include <cryptopp/pssr.h>
28#include <cryptopp/modes.h>
29
30#include <sys/types.h>
31#include <sys/stat.h>
32
33using namespace CryptoPP;
34using namespace ndn;
35using namespace std;
36
37namespace ndn
38{
39
40class SecTpmFile::Impl {
41public:
42 Impl(const string &dir)
43 {
44 if(dir.empty())
Yingdi Yu04020922014-01-22 12:46:53 -080045 m_keystorePath = boost::filesystem::path(getenv("HOME")) / ".ndnx" / "ndnsec-tpm-file";
Yingdi Yu2d9c50f2014-01-21 18:25:00 -080046 else
47 m_keystorePath = dir;
48
49 boost::filesystem::create_directories (m_keystorePath);
50 }
51
52public:
53 boost::filesystem::path m_keystorePath;
54};
55
56SecTpmFile::SecTpmFile(const string & dir)
57 : impl_(new Impl(dir))
58{}
59
60void
61SecTpmFile::generateKeyPairInTpm(const Name & keyName, KeyType keyType, int keySize)
62{
63 string keyURI = keyName.toUri();
64
65 if(doesKeyExistInTpm(keyName, KEY_CLASS_PUBLIC))
66 throw Error("public key exists");
67 if(doesKeyExistInTpm(keyName, KEY_CLASS_PRIVATE))
68 throw Error("private key exists");
69
70 string keyFileName = nameTransform(keyURI, "");
71 maintainMapping(keyURI, keyFileName);
72
73 try{
74 switch(keyType){
75 case KEY_TYPE_RSA:
76 {
77 AutoSeededRandomPool rng;
78 InvertibleRSAFunction privateKey;
79 privateKey.Initialize(rng, keySize);
80
81 string privateKeyFileName = keyFileName + ".pri";
82 Base64Encoder privateKeySink(new FileSink(privateKeyFileName.c_str()));
83 privateKey.DEREncode(privateKeySink);
84 privateKeySink.MessageEnd();
85
86 RSAFunction publicKey(privateKey);
87 string publicKeyFileName = keyFileName + ".pub";
88 Base64Encoder publicKeySink(new FileSink(publicKeyFileName.c_str()));
89 publicKey.DEREncode(publicKeySink);
90 publicKeySink.MessageEnd();
91
92 /*set file permission*/
93 chmod(privateKeyFileName.c_str(), 0000400);
94 chmod(publicKeyFileName.c_str(), 0000444);
95 return;
96 }
97 default:
98 throw Error("Unsupported key type!");
99 }
100 }catch(const CryptoPP::Exception& e){
101 throw Error(e.what());
102 }
103}
104
Yingdi Yu28fd32f2014-01-28 19:03:03 -0800105void
106SecTpmFile::deleteKeyPairInTpm(const Name &keyName)
107{
108 boost::filesystem::path publicKeyPath(nameTransform(keyName.toUri(), ".pub"));
109 boost::filesystem::path privateKeyPath(nameTransform(keyName.toUri(), ".pri"));
110
111 if(boost::filesystem::exists(publicKeyPath))
112 boost::filesystem::remove(publicKeyPath);
113
114 if(boost::filesystem::exists(privateKeyPath))
115 boost::filesystem::remove(privateKeyPath);
116}
117
Yingdi Yu2d9c50f2014-01-21 18:25:00 -0800118ptr_lib::shared_ptr<PublicKey>
119SecTpmFile::getPublicKeyFromTpm(const Name & keyName)
120{
121 string keyURI = keyName.toUri();
122
123 if(!doesKeyExistInTpm(keyName, KEY_CLASS_PUBLIC))
124 throw Error("public key doesn't exists");
125
126 string publicKeyFileName = nameTransform(keyURI, ".pub");
127 std::ostringstream os;
128 try{
129 FileSource(publicKeyFileName.c_str(), true, new Base64Decoder(new FileSink(os)));
130 }catch(const CryptoPP::Exception& e){
131 throw Error(e.what());
132 }
133
134 return ptr_lib::make_shared<PublicKey>(reinterpret_cast<const uint8_t*>(os.str().c_str()), os.str().size());
135}
136
137Block
138SecTpmFile::signInTpm(const uint8_t *data, size_t dataLength, const Name& keyName, DigestAlgorithm digestAlgorithm)
139{
140 string keyURI = keyName.toUri();
141
142 if(!doesKeyExistInTpm(keyName, KEY_CLASS_PRIVATE))
143 throw Error("private key doesn't exists");
144
145 try{
146 AutoSeededRandomPool rng;
147
148 //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{
187 AutoSeededRandomPool rng;
188
189 //Read private key
190 ByteQueue bytes;
191 string privateKeyFileName = nameTransform(keyURI, ".pri");
192 FileSource file(privateKeyFileName.c_str(), true, new Base64Decoder);
193 file.TransferTo(bytes);
194 bytes.MessageEnd();
195 RSA::PrivateKey privateKey;
196 privateKey.Load(bytes);
197 RSAES_PKCS1v15_Decryptor decryptor(privateKey);
198
199 OBufferStream os;
200 StringSource(data, dataLength, true, new PK_DecryptorFilter(rng, decryptor, new FileSink(os)));
201
202 return os.buf();
203 }
204 catch(const CryptoPP::Exception& e){
205 throw Error(e.what());
206 }
207 }
208 else
209 {
210 throw Error("Symmetric encryption is not implemented!");
211 // if(!doesKeyExistInTpm(keyName, KEY_CLASS_SYMMETRIC))
212 // throw Error("symmetric key doesn't exist");
213
214 // try{
215 // string keyBits;
216 // string symKeyFileName = nameTransform(keyURI, ".key");
217 // FileSource(symKeyFileName, true, new HexDecoder(new StringSink(keyBits)));
218
219 // using CryptoPP::AES;
220 // AutoSeededRandomPool rnd;
221 // byte iv[AES::BLOCKSIZE];
222 // rnd.GenerateBlock(iv, AES::BLOCKSIZE);
223
224 // CFB_Mode<AES>::Decryption decryptor;
225 // decryptor.SetKeyWithIV(reinterpret_cast<const uint8_t*>(keyBits.c_str()), keyBits.size(), iv);
226
227 // OBufferStream os;
228 // StringSource(data, dataLength, true, new StreamTransformationFilter(decryptor,new FileSink(os)));
229 // return os.buf();
230
231 // }catch(const CryptoPP::Exception& e){
232 // throw Error(e.what());
233 // }
234 }
235}
236
237ConstBufferPtr
238SecTpmFile::encryptInTpm(const Name& keyName, const uint8_t* data, size_t dataLength, bool isSymmetric)
239{
240 string keyURI = keyName.toUri();
241
242 if (!isSymmetric)
243 {
244 if(!doesKeyExistInTpm(keyName, KEY_CLASS_PUBLIC))
245 throw Error("public key doesn't exist");
246 try
247 {
248 AutoSeededRandomPool rng;
249
250 //Read private key
251 ByteQueue bytes;
252 string publicKeyFileName = nameTransform(keyURI, ".pub");
253 FileSource file(publicKeyFileName.c_str(), true, new Base64Decoder);
254 file.TransferTo(bytes);
255 bytes.MessageEnd();
256 RSA::PublicKey publicKey;
257 publicKey.Load(bytes);
258
259 OBufferStream os;
260 RSAES_PKCS1v15_Encryptor encryptor(publicKey);
261
262 StringSource(data, dataLength, true, new PK_EncryptorFilter(rng, encryptor, new FileSink(os)));
263 return os.buf();
264 }
265 catch(const CryptoPP::Exception& e){
266 throw Error(e.what());
267 }
268 }
269 else
270 {
271 throw Error("Symmetric encryption is not implemented!");
272 // if(!doesKeyExistInTpm(keyName, KEY_CLASS_SYMMETRIC))
273 // throw Error("symmetric key doesn't exist");
274
275 // try{
276 // string keyBits;
277 // string symKeyFileName = nameTransform(keyURI, ".key");
278 // FileSource(symKeyFileName, true, new HexDecoder(new StringSink(keyBits)));
279
280 // using CryptoPP::AES;
281 // AutoSeededRandomPool rnd;
282 // byte iv[AES::BLOCKSIZE];
283 // rnd.GenerateBlock(iv, AES::BLOCKSIZE);
284
285 // CFB_Mode<AES>::Encryption encryptor;
286 // encryptor.SetKeyWithIV(reinterpret_cast<const uint8_t*>(keyBits.c_str()), keyBits.size(), iv);
287
288 // OBufferStream os;
289 // StringSource(data, dataLength, true, new StreamTransformationFilter(encryptor, new FileSink(os)));
290 // return os.buf();
291 // }catch(const CryptoPP::Exception& e){
292 // throw Error(e.what());
293 // }
294 }
295}
296
297
298void
299SecTpmFile::generateSymmetricKeyInTpm(const Name & keyName, KeyType keyType, int keySize)
300{
301 string keyURI = keyName.toUri();
302
303 if(doesKeyExistInTpm(keyName, KEY_CLASS_SYMMETRIC))
304 throw Error("symmetric key exists");
305
306 string keyFileName = nameTransform(keyURI, "");
307 maintainMapping(keyURI, keyFileName);
308 string symKeyFileName = keyFileName + ".key";
309
310 try{
311 switch(keyType){
312 case KEY_TYPE_AES:
313 {
314 AutoSeededRandomPool rnd;
315 SecByteBlock key(0x00, keySize);
316 rnd.GenerateBlock(key, keySize );
317
318 StringSource(key, key.size(), true, new HexEncoder(new FileSink(symKeyFileName.c_str())));
319
320 chmod(symKeyFileName.c_str(), 0000400);
321 return;
322 }
323 default:
324 throw Error("Unsupported symmetric key type!");
325 }
326 }catch(const CryptoPP::Exception& e){
327 throw Error(e.what());
328 }
329}
330
331bool
332SecTpmFile::doesKeyExistInTpm(const Name & keyName, KeyClass keyClass)
333{
334 string keyURI = keyName.toUri();
335 if (keyClass == KEY_CLASS_PUBLIC)
336 {
337 string publicKeyName = SecTpmFile::nameTransform(keyURI, ".pub");
338 fstream fin(publicKeyName.c_str(),ios::in);
339 if (fin)
340 return true;
341 else
342 return false;
343 }
344 if (keyClass == KEY_CLASS_PRIVATE)
345 {
346 string privateKeyName = SecTpmFile::nameTransform(keyURI, ".pri");
347 fstream fin(privateKeyName.c_str(),ios::in);
348 if (fin)
349 return true;
350 else
351 return false;
352 }
353 if (keyClass == KEY_CLASS_SYMMETRIC)
354 {
355 string symmetricKeyName = SecTpmFile::nameTransform(keyURI, ".key");
356 fstream fin(symmetricKeyName.c_str(),ios::in);
357 if (fin)
358 return true;
359 else
360 return false;
361 }
362 return false;
363}
364
365std::string SecTpmFile::nameTransform(const string &keyName, const string &extension)
366{
367 std::string digest;
368 CryptoPP::SHA256 hash;
369 CryptoPP::StringSource foo(keyName, true,
370 new CryptoPP::HashFilter(hash,
371 new CryptoPP::Base64Encoder (new CryptoPP::StringSink(digest))
372 )
373 );
374 boost::algorithm::trim(digest);
375 for (std::string::iterator ch = digest.begin(); ch != digest.end(); ch++)
376 {
377 if (*ch == '/')
378 {
379 *ch = '%';
380 }
381 }
382
383 return (impl_->m_keystorePath / (digest + extension)).string();
384}
385
386void
387SecTpmFile::maintainMapping(string str1, string str2)
388{
389 std::ofstream outfile;
390 string dirFile = (impl_->m_keystorePath / "mapping.txt").string();
391
392 outfile.open(dirFile.c_str(), std::ios_base::app);
393 outfile << str1 << ' ' << str2 << '\n';
394 outfile.close();
395}
396
397} //ndn