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