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