blob: 97adf7a8332788074c5f976d787f22560ce37b59 [file] [log] [blame]
Alexander Afanasyevc169a812014-05-20 20:37:29 -04001/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
Yingdi Yu8dceb1d2014-02-18 12:45:10 -08002/**
Alexander Afanasyevc169a812014-05-20 20:37:29 -04003 * Copyright (c) 2013-2014 Regents of the University of California.
Alexander Afanasyevdfa52c42014-04-24 21:10:11 -07004 *
5 * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions).
Alexander Afanasyevdfa52c42014-04-24 21:10:11 -07006 *
Alexander Afanasyevc169a812014-05-20 20:37:29 -04007 * ndn-cxx library is free software: you can redistribute it and/or modify it under the
8 * terms of the GNU Lesser General Public License as published by the Free Software
9 * Foundation, either version 3 of the License, or (at your option) any later version.
10 *
11 * ndn-cxx library is distributed in the hope that it will be useful, but WITHOUT ANY
12 * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
13 * PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
14 *
15 * You should have received copies of the GNU General Public License and GNU Lesser
16 * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see
17 * <http://www.gnu.org/licenses/>.
18 *
19 * See AUTHORS.md for complete list of ndn-cxx authors and contributors.
Alexander Afanasyevdfa52c42014-04-24 21:10:11 -070020 *
21 * @author Yingdi Yu <http://irl.cs.ucla.edu/~yingdi/>
Yingdi Yu8dceb1d2014-02-18 12:45:10 -080022 */
23
24#include "sec-tpm.hpp"
25
Alexander Afanasyev258ec2b2014-05-14 16:15:37 -070026#include "../encoding/oid.hpp"
27#include "../encoding/buffer-stream.hpp"
Junxiao Shi482ccc52014-03-31 13:05:24 -070028#include "cryptopp.hpp"
Yingdi Yu8dceb1d2014-02-18 12:45:10 -080029
Yingdi Yu8dceb1d2014-02-18 12:45:10 -080030namespace ndn {
31
Yingdi Yu5ec0ee32014-06-24 16:26:09 -070032using std::string;
33
Yingdi Yu8dceb1d2014-02-18 12:45:10 -080034ConstBufferPtr
Yingdi Yu5e96e002014-04-23 18:32:15 -070035SecTpm::exportPrivateKeyPkcs5FromTpm(const Name& keyName, const string& passwordStr)
Yingdi Yu8dceb1d2014-02-18 12:45:10 -080036{
Yingdi Yu2e57a582014-02-20 23:34:43 -080037 using namespace CryptoPP;
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -070038
Yingdi Yu8dceb1d2014-02-18 12:45:10 -080039 uint8_t salt[8] = {0};
40 uint8_t iv[8] = {0};
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -070041
Yingdi Yu2e57a582014-02-20 23:34:43 -080042 // derive key
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -070043 if (!generateRandomBlock(salt, 8) || !generateRandomBlock(iv, 8))
Yingdi Yu2e57a582014-02-20 23:34:43 -080044 throw Error("Cannot generate salt or iv");
Yingdi Yu8dceb1d2014-02-18 12:45:10 -080045
Yingdi Yu2e57a582014-02-20 23:34:43 -080046 uint32_t iterationCount = 2048;
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -070047
Yingdi Yu2e57a582014-02-20 23:34:43 -080048 PKCS5_PBKDF2_HMAC<SHA1> keyGenerator;
49 size_t derivedLen = 24; //For DES-EDE3-CBC-PAD
50 byte derived[24] = {0};
51 byte purpose = 0;
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -070052
Yingdi Yu2e57a582014-02-20 23:34:43 -080053 try
Yingdi Yu8dceb1d2014-02-18 12:45:10 -080054 {
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -070055 keyGenerator.DeriveKey(derived, derivedLen, purpose,
56 reinterpret_cast<const byte*>(passwordStr.c_str()), passwordStr.size(),
Yingdi Yu2e57a582014-02-20 23:34:43 -080057 salt, 8, iterationCount);
Yingdi Yu8dceb1d2014-02-18 12:45:10 -080058 }
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -070059 catch (CryptoPP::Exception& e)
Yingdi Yu2e57a582014-02-20 23:34:43 -080060 {
61 throw Error("Cannot derived the encryption key");
62 }
Yingdi Yu8dceb1d2014-02-18 12:45:10 -080063
Yingdi Yu2e57a582014-02-20 23:34:43 -080064 //encrypt
65 CBC_Mode< DES_EDE3 >::Encryption e;
66 e.SetKeyWithIV(derived, derivedLen, iv);
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -070067
Yingdi Yu5e96e002014-04-23 18:32:15 -070068 ConstBufferPtr pkcs8PrivateKey = exportPrivateKeyPkcs8FromTpm(keyName);
Yingdi Yu9d9d5992014-06-25 12:25:16 -070069
Yingdi Yu5e96e002014-04-23 18:32:15 -070070 if (!static_cast<bool>(pkcs8PrivateKey))
Yingdi Yu2e57a582014-02-20 23:34:43 -080071 throw Error("Cannot export the private key, #1");
72
73 OBufferStream encryptedOs;
74 try
75 {
Yingdi Yu5e96e002014-04-23 18:32:15 -070076 StringSource stringSource(pkcs8PrivateKey->buf(), pkcs8PrivateKey->size(), true,
Yingdi Yu2e57a582014-02-20 23:34:43 -080077 new StreamTransformationFilter(e, new FileSink(encryptedOs)));
78 }
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -070079 catch (CryptoPP::Exception& e)
Yingdi Yu2e57a582014-02-20 23:34:43 -080080 {
81 throw Error("Cannot export the private key, #2");
82 }
83
84 //encode
85 OID pbes2Id("1.2.840.113549.1.5.13");
86 OID pbkdf2Id("1.2.840.113549.1.5.12");
87 OID pbes2encsId("1.2.840.113549.3.7");
88
89 OBufferStream pkcs8Os;
90 try
91 {
92 FileSink sink(pkcs8Os);
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -070093
Yingdi Yu2e57a582014-02-20 23:34:43 -080094 // EncryptedPrivateKeyInfo ::= SEQUENCE {
95 // encryptionAlgorithm EncryptionAlgorithmIdentifier,
96 // encryptedData OCTET STRING }
97 DERSequenceEncoder encryptedPrivateKeyInfo(sink);
98 {
99 // EncryptionAlgorithmIdentifier ::= SEQUENCE {
100 // algorithm OBJECT IDENTIFIER {{PBES2-id}},
101 // parameters SEQUENCE {{PBES2-params}} }
102 DERSequenceEncoder encryptionAlgorithm(encryptedPrivateKeyInfo);
103 {
104 pbes2Id.encode(encryptionAlgorithm);
105 // PBES2-params ::= SEQUENCE {
106 // keyDerivationFunc AlgorithmIdentifier {{PBES2-KDFs}},
107 // encryptionScheme AlgorithmIdentifier {{PBES2-Encs}} }
108 DERSequenceEncoder pbes2Params(encryptionAlgorithm);
109 {
110 // AlgorithmIdentifier ::= SEQUENCE {
111 // algorithm OBJECT IDENTIFIER {{PBKDF2-id}},
112 // parameters SEQUENCE {{PBKDF2-params}} }
113 DERSequenceEncoder pbes2KDFs(pbes2Params);
114 {
115 pbkdf2Id.encode(pbes2KDFs);
116 // AlgorithmIdentifier ::= SEQUENCE {
117 // salt OCTET STRING,
118 // iterationCount INTEGER (1..MAX),
119 // keyLength INTEGER (1..MAX) OPTIONAL,
120 // prf AlgorithmIdentifier {{PBKDF2-PRFs}} DEFAULT algid-hmacWithSHA1 }
121 DERSequenceEncoder pbkdf2Params(pbes2KDFs);
122 {
123 DEREncodeOctetString(pbkdf2Params, salt, 8);
124 DEREncodeUnsigned<uint32_t>(pbkdf2Params, iterationCount, INTEGER);
125 }
126 pbkdf2Params.MessageEnd();
127 }
128 pbes2KDFs.MessageEnd();
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700129
Yingdi Yu2e57a582014-02-20 23:34:43 -0800130 // AlgorithmIdentifier ::= SEQUENCE {
131 // algorithm OBJECT IDENTIFIER {{DES-EDE3-CBC-PAD}},
132 // parameters OCTET STRING} {{iv}} }
133 DERSequenceEncoder pbes2Encs(pbes2Params);
134 {
135 pbes2encsId.encode(pbes2Encs);
136 DEREncodeOctetString(pbes2Encs, iv, 8);
137 }
138 pbes2Encs.MessageEnd();
139 }
140 pbes2Params.MessageEnd();
141 }
142 encryptionAlgorithm.MessageEnd();
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700143
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700144 DEREncodeOctetString(encryptedPrivateKeyInfo,
145 encryptedOs.buf()->buf(), encryptedOs.buf()->size());
Yingdi Yu2e57a582014-02-20 23:34:43 -0800146 }
147 encryptedPrivateKeyInfo.MessageEnd();
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700148
Yingdi Yu2e57a582014-02-20 23:34:43 -0800149 return pkcs8Os.buf();
150 }
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700151 catch (CryptoPP::Exception& e)
Yingdi Yu2e57a582014-02-20 23:34:43 -0800152 {
153 throw Error("Cannot export the private key, #3");
154 }
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800155}
156
157bool
Yingdi Yu5e96e002014-04-23 18:32:15 -0700158SecTpm::importPrivateKeyPkcs5IntoTpm(const Name& keyName,
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700159 const uint8_t* buf, size_t size,
160 const string& passwordStr)
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800161{
Yingdi Yu2e57a582014-02-20 23:34:43 -0800162 using namespace CryptoPP;
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700163
Yingdi Yu2e57a582014-02-20 23:34:43 -0800164 OID pbes2Id;
165 OID pbkdf2Id;
166 SecByteBlock saltBlock;
167 uint32_t iterationCount;
168 OID pbes2encsId;
169 SecByteBlock ivBlock;
170 SecByteBlock encryptedDataBlock;
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700171
Yingdi Yu2e57a582014-02-20 23:34:43 -0800172 try
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800173 {
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700174 // decode some decoding processes are not necessary for now,
175 // because we assume only one encryption scheme.
Yingdi Yu2e57a582014-02-20 23:34:43 -0800176 StringSource source(buf, size, true);
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700177
Yingdi Yu2e57a582014-02-20 23:34:43 -0800178 // EncryptedPrivateKeyInfo ::= SEQUENCE {
179 // encryptionAlgorithm EncryptionAlgorithmIdentifier,
180 // encryptedData OCTET STRING }
181 BERSequenceDecoder encryptedPrivateKeyInfo(source);
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800182 {
Yingdi Yu2e57a582014-02-20 23:34:43 -0800183 // EncryptionAlgorithmIdentifier ::= SEQUENCE {
184 // algorithm OBJECT IDENTIFIER {{PBES2-id}},
185 // parameters SEQUENCE {{PBES2-params}} }
186 BERSequenceDecoder encryptionAlgorithm(encryptedPrivateKeyInfo);
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800187 {
Yingdi Yu2e57a582014-02-20 23:34:43 -0800188 pbes2Id.decode(encryptionAlgorithm);
189 // PBES2-params ::= SEQUENCE {
190 // keyDerivationFunc AlgorithmIdentifier {{PBES2-KDFs}},
191 // encryptionScheme AlgorithmIdentifier {{PBES2-Encs}} }
192 BERSequenceDecoder pbes2Params(encryptionAlgorithm);
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800193 {
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800194 // AlgorithmIdentifier ::= SEQUENCE {
Yingdi Yu2e57a582014-02-20 23:34:43 -0800195 // algorithm OBJECT IDENTIFIER {{PBKDF2-id}},
196 // parameters SEQUENCE {{PBKDF2-params}} }
197 BERSequenceDecoder pbes2KDFs(pbes2Params);
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800198 {
Yingdi Yu2e57a582014-02-20 23:34:43 -0800199 pbkdf2Id.decode(pbes2KDFs);
200 // AlgorithmIdentifier ::= SEQUENCE {
201 // salt OCTET STRING,
202 // iterationCount INTEGER (1..MAX),
203 // keyLength INTEGER (1..MAX) OPTIONAL,
204 // prf AlgorithmIdentifier {{PBKDF2-PRFs}} DEFAULT algid-hmacWithSHA1 }
205 BERSequenceDecoder pbkdf2Params(pbes2KDFs);
206 {
207 BERDecodeOctetString(pbkdf2Params, saltBlock);
208 BERDecodeUnsigned<uint32_t>(pbkdf2Params, iterationCount, INTEGER);
209 }
210 pbkdf2Params.MessageEnd();
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800211 }
Yingdi Yu2e57a582014-02-20 23:34:43 -0800212 pbes2KDFs.MessageEnd();
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700213
Yingdi Yu2e57a582014-02-20 23:34:43 -0800214 // AlgorithmIdentifier ::= SEQUENCE {
215 // algorithm OBJECT IDENTIFIER {{DES-EDE3-CBC-PAD}},
216 // parameters OCTET STRING} {{iv}} }
217 BERSequenceDecoder pbes2Encs(pbes2Params);
218 {
219 pbes2encsId.decode(pbes2Encs);
220 BERDecodeOctetString(pbes2Encs, ivBlock);
221 }
222 pbes2Encs.MessageEnd();
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800223 }
Yingdi Yu2e57a582014-02-20 23:34:43 -0800224 pbes2Params.MessageEnd();
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800225 }
Yingdi Yu2e57a582014-02-20 23:34:43 -0800226 encryptionAlgorithm.MessageEnd();
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800227
Yingdi Yu2e57a582014-02-20 23:34:43 -0800228 BERDecodeOctetString(encryptedPrivateKeyInfo, encryptedDataBlock);
229 }
230 encryptedPrivateKeyInfo.MessageEnd();
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800231 }
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700232 catch (CryptoPP::Exception& e)
Yingdi Yu2e57a582014-02-20 23:34:43 -0800233 {
234 return false;
235 }
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800236
Yingdi Yu2e57a582014-02-20 23:34:43 -0800237 PKCS5_PBKDF2_HMAC<SHA1> keyGenerator;
238 size_t derivedLen = 24; //For DES-EDE3-CBC-PAD
239 byte derived[24] = {0};
240 byte purpose = 0;
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700241
Yingdi Yu2e57a582014-02-20 23:34:43 -0800242 try
243 {
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700244 keyGenerator.DeriveKey(derived, derivedLen,
245 purpose,
246 reinterpret_cast<const byte*>(passwordStr.c_str()), passwordStr.size(),
247 saltBlock.BytePtr(), saltBlock.size(),
Yingdi Yu2e57a582014-02-20 23:34:43 -0800248 iterationCount);
249 }
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700250 catch (CryptoPP::Exception& e)
Yingdi Yu2e57a582014-02-20 23:34:43 -0800251 {
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800252 return false;
Yingdi Yu2e57a582014-02-20 23:34:43 -0800253 }
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800254
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700255 //decrypt
256 CBC_Mode< DES_EDE3 >::Decryption d;
257 d.SetKeyWithIV(derived, derivedLen, ivBlock.BytePtr());
258
259 OBufferStream privateKeyOs;
260 try
261 {
262 StringSource encryptedSource(encryptedDataBlock.BytePtr(), encryptedDataBlock.size(), true,
263 new StreamTransformationFilter(d, new FileSink(privateKeyOs)));
264 }
265 catch (CryptoPP::Exception& e)
266 {
267 return false;
268 }
269
Yingdi Yu5e96e002014-04-23 18:32:15 -0700270 if (!importPrivateKeyPkcs8IntoTpm(keyName,
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700271 privateKeyOs.buf()->buf(), privateKeyOs.buf()->size()))
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800272 return false;
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700273
Yingdi Yu9d9d5992014-06-25 12:25:16 -0700274 //determine key type
275 StringSource privateKeySource(privateKeyOs.buf()->buf(), privateKeyOs.buf()->size(), true);
276
277 KeyType publicKeyType = KEY_TYPE_NULL;
278 SecByteBlock rawKeyBits;
279 // PrivateKeyInfo ::= SEQUENCE {
280 // INTEGER,
281 // SEQUENCE,
282 // OCTECT STRING}
283 BERSequenceDecoder privateKeyInfo(privateKeySource);
284 {
285 uint32_t versionNum;
286 BERDecodeUnsigned<uint32_t>(privateKeyInfo, versionNum, INTEGER);
287 BERSequenceDecoder sequenceDecoder(privateKeyInfo);
288 {
289 OID keyTypeOID;
290 keyTypeOID.decode(sequenceDecoder);
291 if (keyTypeOID == oid::RSA)
292 publicKeyType = KEY_TYPE_RSA;
293 else if (keyTypeOID == oid::ECDSA)
294 publicKeyType = KEY_TYPE_ECDSA;
295 else
296 return false; // Unsupported key type;
297 }
298 }
299
300
Yingdi Yu2e57a582014-02-20 23:34:43 -0800301 //derive public key
302 OBufferStream publicKeyOs;
303
Yingdi Yu9d9d5992014-06-25 12:25:16 -0700304 try {
305 switch (publicKeyType) {
306 case KEY_TYPE_RSA:
307 {
308 RSA::PrivateKey privateKey;
309 privateKey.Load(StringStore(privateKeyOs.buf()->buf(), privateKeyOs.buf()->size()).Ref());
310 RSAFunction publicKey(privateKey);
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700311
Yingdi Yu9d9d5992014-06-25 12:25:16 -0700312 FileSink publicKeySink(publicKeyOs);
313 publicKey.DEREncode(publicKeySink);
314 publicKeySink.MessageEnd();
315 break;
316 }
317 case KEY_TYPE_ECDSA:
318 {
319 ECDSA<ECP, SHA256>::PrivateKey privateKey;
320 privateKey.Load(StringStore(privateKeyOs.buf()->buf(), privateKeyOs.buf()->size()).Ref());
321
322 ECDSA<ECP, SHA256>::PublicKey publicKey;
323 privateKey.MakePublicKey(publicKey);
324 publicKey.AccessGroupParameters().SetEncodeAsOID(true);
325
326 FileSink publicKeySink(publicKeyOs);
327 publicKey.DEREncode(publicKeySink);
328 publicKeySink.MessageEnd();
329 break;
330 }
331 default:
Yingdi Yu2e57a582014-02-20 23:34:43 -0800332 return false;
333 }
Yingdi Yu9d9d5992014-06-25 12:25:16 -0700334 }
335 catch (CryptoPP::Exception& e) {
336 return false;
337 }
Yingdi Yu2e57a582014-02-20 23:34:43 -0800338
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700339 if (!importPublicKeyPkcs1IntoTpm(keyName, publicKeyOs.buf()->buf(), publicKeyOs.buf()->size()))
Yingdi Yu2e57a582014-02-20 23:34:43 -0800340 return false;
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700341
Yingdi Yu2e57a582014-02-20 23:34:43 -0800342 return true;
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800343}
344
Yingdi Yu7036ce22014-06-19 18:53:37 -0700345bool
346SecTpm::getImpExpPassWord(std::string& password, const std::string& prompt)
347{
348 bool isInitialized = false;
349
350 char* pw0 = 0;
351
352 pw0 = getpass(prompt.c_str());
353 if (0 == pw0)
354 return false;
355 std::string password1 = pw0;
356 memset(pw0, 0, strlen(pw0));
357
358 pw0 = getpass("Confirm:");
359 if (0 == pw0)
360 {
361 std::fill(password1.begin(), password1.end(), 0);
362 return false;
363 }
364
365 if (0 == password1.compare(pw0))
366 {
367 isInitialized = true;
368 password.swap(password1);
369 }
370
371 std::fill(password1.begin(), password1.end(), 0);
372 memset(pw0, 0, strlen(pw0));
373
374 if (password.empty())
375 return false;
376
377 return isInitialized;
378}
379
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800380
Yingdi Yufc40d872014-02-18 12:56:04 -0800381} // namespace ndn