blob: 2011a95896179415ced5ca3336b8ecd2bd30f1e3 [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
30using namespace std;
31
32namespace ndn {
33
34ConstBufferPtr
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);
69 if (!static_cast<bool>(pkcs8PrivateKey))
Yingdi Yu2e57a582014-02-20 23:34:43 -080070 throw Error("Cannot export the private key, #1");
71
72 OBufferStream encryptedOs;
73 try
74 {
Yingdi Yu5e96e002014-04-23 18:32:15 -070075 StringSource stringSource(pkcs8PrivateKey->buf(), pkcs8PrivateKey->size(), true,
Yingdi Yu2e57a582014-02-20 23:34:43 -080076 new StreamTransformationFilter(e, new FileSink(encryptedOs)));
77 }
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -070078 catch (CryptoPP::Exception& e)
Yingdi Yu2e57a582014-02-20 23:34:43 -080079 {
80 throw Error("Cannot export the private key, #2");
81 }
82
83 //encode
84 OID pbes2Id("1.2.840.113549.1.5.13");
85 OID pbkdf2Id("1.2.840.113549.1.5.12");
86 OID pbes2encsId("1.2.840.113549.3.7");
87
88 OBufferStream pkcs8Os;
89 try
90 {
91 FileSink sink(pkcs8Os);
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -070092
Yingdi Yu2e57a582014-02-20 23:34:43 -080093 // EncryptedPrivateKeyInfo ::= SEQUENCE {
94 // encryptionAlgorithm EncryptionAlgorithmIdentifier,
95 // encryptedData OCTET STRING }
96 DERSequenceEncoder encryptedPrivateKeyInfo(sink);
97 {
98 // EncryptionAlgorithmIdentifier ::= SEQUENCE {
99 // algorithm OBJECT IDENTIFIER {{PBES2-id}},
100 // parameters SEQUENCE {{PBES2-params}} }
101 DERSequenceEncoder encryptionAlgorithm(encryptedPrivateKeyInfo);
102 {
103 pbes2Id.encode(encryptionAlgorithm);
104 // PBES2-params ::= SEQUENCE {
105 // keyDerivationFunc AlgorithmIdentifier {{PBES2-KDFs}},
106 // encryptionScheme AlgorithmIdentifier {{PBES2-Encs}} }
107 DERSequenceEncoder pbes2Params(encryptionAlgorithm);
108 {
109 // AlgorithmIdentifier ::= SEQUENCE {
110 // algorithm OBJECT IDENTIFIER {{PBKDF2-id}},
111 // parameters SEQUENCE {{PBKDF2-params}} }
112 DERSequenceEncoder pbes2KDFs(pbes2Params);
113 {
114 pbkdf2Id.encode(pbes2KDFs);
115 // AlgorithmIdentifier ::= SEQUENCE {
116 // salt OCTET STRING,
117 // iterationCount INTEGER (1..MAX),
118 // keyLength INTEGER (1..MAX) OPTIONAL,
119 // prf AlgorithmIdentifier {{PBKDF2-PRFs}} DEFAULT algid-hmacWithSHA1 }
120 DERSequenceEncoder pbkdf2Params(pbes2KDFs);
121 {
122 DEREncodeOctetString(pbkdf2Params, salt, 8);
123 DEREncodeUnsigned<uint32_t>(pbkdf2Params, iterationCount, INTEGER);
124 }
125 pbkdf2Params.MessageEnd();
126 }
127 pbes2KDFs.MessageEnd();
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700128
Yingdi Yu2e57a582014-02-20 23:34:43 -0800129 // AlgorithmIdentifier ::= SEQUENCE {
130 // algorithm OBJECT IDENTIFIER {{DES-EDE3-CBC-PAD}},
131 // parameters OCTET STRING} {{iv}} }
132 DERSequenceEncoder pbes2Encs(pbes2Params);
133 {
134 pbes2encsId.encode(pbes2Encs);
135 DEREncodeOctetString(pbes2Encs, iv, 8);
136 }
137 pbes2Encs.MessageEnd();
138 }
139 pbes2Params.MessageEnd();
140 }
141 encryptionAlgorithm.MessageEnd();
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700142
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700143 DEREncodeOctetString(encryptedPrivateKeyInfo,
144 encryptedOs.buf()->buf(), encryptedOs.buf()->size());
Yingdi Yu2e57a582014-02-20 23:34:43 -0800145 }
146 encryptedPrivateKeyInfo.MessageEnd();
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700147
Yingdi Yu2e57a582014-02-20 23:34:43 -0800148 return pkcs8Os.buf();
149 }
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700150 catch (CryptoPP::Exception& e)
Yingdi Yu2e57a582014-02-20 23:34:43 -0800151 {
152 throw Error("Cannot export the private key, #3");
153 }
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800154}
155
156bool
Yingdi Yu5e96e002014-04-23 18:32:15 -0700157SecTpm::importPrivateKeyPkcs5IntoTpm(const Name& keyName,
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700158 const uint8_t* buf, size_t size,
159 const string& passwordStr)
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800160{
Yingdi Yu2e57a582014-02-20 23:34:43 -0800161 using namespace CryptoPP;
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700162
Yingdi Yu2e57a582014-02-20 23:34:43 -0800163 OID pbes2Id;
164 OID pbkdf2Id;
165 SecByteBlock saltBlock;
166 uint32_t iterationCount;
167 OID pbes2encsId;
168 SecByteBlock ivBlock;
169 SecByteBlock encryptedDataBlock;
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700170
Yingdi Yu2e57a582014-02-20 23:34:43 -0800171 try
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800172 {
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700173 // decode some decoding processes are not necessary for now,
174 // because we assume only one encryption scheme.
Yingdi Yu2e57a582014-02-20 23:34:43 -0800175 StringSource source(buf, size, true);
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700176
Yingdi Yu2e57a582014-02-20 23:34:43 -0800177 // EncryptedPrivateKeyInfo ::= SEQUENCE {
178 // encryptionAlgorithm EncryptionAlgorithmIdentifier,
179 // encryptedData OCTET STRING }
180 BERSequenceDecoder encryptedPrivateKeyInfo(source);
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800181 {
Yingdi Yu2e57a582014-02-20 23:34:43 -0800182 // EncryptionAlgorithmIdentifier ::= SEQUENCE {
183 // algorithm OBJECT IDENTIFIER {{PBES2-id}},
184 // parameters SEQUENCE {{PBES2-params}} }
185 BERSequenceDecoder encryptionAlgorithm(encryptedPrivateKeyInfo);
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800186 {
Yingdi Yu2e57a582014-02-20 23:34:43 -0800187 pbes2Id.decode(encryptionAlgorithm);
188 // PBES2-params ::= SEQUENCE {
189 // keyDerivationFunc AlgorithmIdentifier {{PBES2-KDFs}},
190 // encryptionScheme AlgorithmIdentifier {{PBES2-Encs}} }
191 BERSequenceDecoder pbes2Params(encryptionAlgorithm);
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800192 {
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800193 // AlgorithmIdentifier ::= SEQUENCE {
Yingdi Yu2e57a582014-02-20 23:34:43 -0800194 // algorithm OBJECT IDENTIFIER {{PBKDF2-id}},
195 // parameters SEQUENCE {{PBKDF2-params}} }
196 BERSequenceDecoder pbes2KDFs(pbes2Params);
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800197 {
Yingdi Yu2e57a582014-02-20 23:34:43 -0800198 pbkdf2Id.decode(pbes2KDFs);
199 // AlgorithmIdentifier ::= SEQUENCE {
200 // salt OCTET STRING,
201 // iterationCount INTEGER (1..MAX),
202 // keyLength INTEGER (1..MAX) OPTIONAL,
203 // prf AlgorithmIdentifier {{PBKDF2-PRFs}} DEFAULT algid-hmacWithSHA1 }
204 BERSequenceDecoder pbkdf2Params(pbes2KDFs);
205 {
206 BERDecodeOctetString(pbkdf2Params, saltBlock);
207 BERDecodeUnsigned<uint32_t>(pbkdf2Params, iterationCount, INTEGER);
208 }
209 pbkdf2Params.MessageEnd();
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800210 }
Yingdi Yu2e57a582014-02-20 23:34:43 -0800211 pbes2KDFs.MessageEnd();
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700212
Yingdi Yu2e57a582014-02-20 23:34:43 -0800213 // AlgorithmIdentifier ::= SEQUENCE {
214 // algorithm OBJECT IDENTIFIER {{DES-EDE3-CBC-PAD}},
215 // parameters OCTET STRING} {{iv}} }
216 BERSequenceDecoder pbes2Encs(pbes2Params);
217 {
218 pbes2encsId.decode(pbes2Encs);
219 BERDecodeOctetString(pbes2Encs, ivBlock);
220 }
221 pbes2Encs.MessageEnd();
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800222 }
Yingdi Yu2e57a582014-02-20 23:34:43 -0800223 pbes2Params.MessageEnd();
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800224 }
Yingdi Yu2e57a582014-02-20 23:34:43 -0800225 encryptionAlgorithm.MessageEnd();
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800226
Yingdi Yu2e57a582014-02-20 23:34:43 -0800227 BERDecodeOctetString(encryptedPrivateKeyInfo, encryptedDataBlock);
228 }
229 encryptedPrivateKeyInfo.MessageEnd();
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800230 }
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700231 catch (CryptoPP::Exception& e)
Yingdi Yu2e57a582014-02-20 23:34:43 -0800232 {
233 return false;
234 }
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800235
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700236
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 Yu2e57a582014-02-20 23:34:43 -0800274 //derive public key
275 OBufferStream publicKeyOs;
276
277 try
278 {
279 RSA::PrivateKey privateKey;
280 privateKey.Load(StringStore(privateKeyOs.buf()->buf(), privateKeyOs.buf()->size()).Ref());
281 RSAFunction publicKey(privateKey);
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700282
Yingdi Yu2e57a582014-02-20 23:34:43 -0800283 FileSink publicKeySink(publicKeyOs);
284 publicKey.DEREncode(publicKeySink);
285 publicKeySink.MessageEnd();
286 }
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700287 catch (CryptoPP::Exception& e)
Yingdi Yu2e57a582014-02-20 23:34:43 -0800288 {
289 return false;
290 }
291
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700292 if (!importPublicKeyPkcs1IntoTpm(keyName, publicKeyOs.buf()->buf(), publicKeyOs.buf()->size()))
Yingdi Yu2e57a582014-02-20 23:34:43 -0800293 return false;
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700294
Yingdi Yu2e57a582014-02-20 23:34:43 -0800295 return true;
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800296}
297
Yingdi Yu7036ce22014-06-19 18:53:37 -0700298bool
299SecTpm::getImpExpPassWord(std::string& password, const std::string& prompt)
300{
301 bool isInitialized = false;
302
303 char* pw0 = 0;
304
305 pw0 = getpass(prompt.c_str());
306 if (0 == pw0)
307 return false;
308 std::string password1 = pw0;
309 memset(pw0, 0, strlen(pw0));
310
311 pw0 = getpass("Confirm:");
312 if (0 == pw0)
313 {
314 std::fill(password1.begin(), password1.end(), 0);
315 return false;
316 }
317
318 if (0 == password1.compare(pw0))
319 {
320 isInitialized = true;
321 password.swap(password1);
322 }
323
324 std::fill(password1.begin(), password1.end(), 0);
325 memset(pw0, 0, strlen(pw0));
326
327 if (password.empty())
328 return false;
329
330 return isInitialized;
331}
332
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800333
Yingdi Yufc40d872014-02-18 12:56:04 -0800334} // namespace ndn