blob: e4e131535213e084c03751d5ad702e61bb15216b [file] [log] [blame]
Yingdi Yu8dceb1d2014-02-18 12:45:10 -08001/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil -*- */
2/**
Alexander Afanasyevdfa52c42014-04-24 21:10:11 -07003 * Copyright (c) 2013-2014, Regents of the University of California.
4 * All rights reserved.
5 *
6 * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions).
7 * See AUTHORS.md for complete list of ndn-cxx authors and contributors.
8 *
9 * This file licensed under New BSD License. See COPYING for detailed information about
10 * ndn-cxx library copyright, permissions, and redistribution restrictions.
11 *
12 * @author Yingdi Yu <http://irl.cs.ucla.edu/~yingdi/>
Yingdi Yu8dceb1d2014-02-18 12:45:10 -080013 */
14
15#include "sec-tpm.hpp"
16
Junxiao Shi482ccc52014-03-31 13:05:24 -070017#include "cryptopp.hpp"
Yingdi Yu8dceb1d2014-02-18 12:45:10 -080018
19using namespace std;
20
21namespace ndn {
22
23ConstBufferPtr
Yingdi Yu5e96e002014-04-23 18:32:15 -070024SecTpm::exportPrivateKeyPkcs5FromTpm(const Name& keyName, const string& passwordStr)
Yingdi Yu8dceb1d2014-02-18 12:45:10 -080025{
Yingdi Yu2e57a582014-02-20 23:34:43 -080026 using namespace CryptoPP;
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -070027
Yingdi Yu8dceb1d2014-02-18 12:45:10 -080028 uint8_t salt[8] = {0};
29 uint8_t iv[8] = {0};
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -070030
Yingdi Yu2e57a582014-02-20 23:34:43 -080031 // derive key
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -070032 if (!generateRandomBlock(salt, 8) || !generateRandomBlock(iv, 8))
Yingdi Yu2e57a582014-02-20 23:34:43 -080033 throw Error("Cannot generate salt or iv");
Yingdi Yu8dceb1d2014-02-18 12:45:10 -080034
Yingdi Yu2e57a582014-02-20 23:34:43 -080035 uint32_t iterationCount = 2048;
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -070036
Yingdi Yu2e57a582014-02-20 23:34:43 -080037 PKCS5_PBKDF2_HMAC<SHA1> keyGenerator;
38 size_t derivedLen = 24; //For DES-EDE3-CBC-PAD
39 byte derived[24] = {0};
40 byte purpose = 0;
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -070041
Yingdi Yu2e57a582014-02-20 23:34:43 -080042 try
Yingdi Yu8dceb1d2014-02-18 12:45:10 -080043 {
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -070044 keyGenerator.DeriveKey(derived, derivedLen, purpose,
45 reinterpret_cast<const byte*>(passwordStr.c_str()), passwordStr.size(),
Yingdi Yu2e57a582014-02-20 23:34:43 -080046 salt, 8, iterationCount);
Yingdi Yu8dceb1d2014-02-18 12:45:10 -080047 }
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -070048 catch (CryptoPP::Exception& e)
Yingdi Yu2e57a582014-02-20 23:34:43 -080049 {
50 throw Error("Cannot derived the encryption key");
51 }
Yingdi Yu8dceb1d2014-02-18 12:45:10 -080052
Yingdi Yu2e57a582014-02-20 23:34:43 -080053 //encrypt
54 CBC_Mode< DES_EDE3 >::Encryption e;
55 e.SetKeyWithIV(derived, derivedLen, iv);
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -070056
Yingdi Yu5e96e002014-04-23 18:32:15 -070057 ConstBufferPtr pkcs8PrivateKey = exportPrivateKeyPkcs8FromTpm(keyName);
58 if (!static_cast<bool>(pkcs8PrivateKey))
Yingdi Yu2e57a582014-02-20 23:34:43 -080059 throw Error("Cannot export the private key, #1");
60
61 OBufferStream encryptedOs;
62 try
63 {
Yingdi Yu5e96e002014-04-23 18:32:15 -070064 StringSource stringSource(pkcs8PrivateKey->buf(), pkcs8PrivateKey->size(), true,
Yingdi Yu2e57a582014-02-20 23:34:43 -080065 new StreamTransformationFilter(e, new FileSink(encryptedOs)));
66 }
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -070067 catch (CryptoPP::Exception& e)
Yingdi Yu2e57a582014-02-20 23:34:43 -080068 {
69 throw Error("Cannot export the private key, #2");
70 }
71
72 //encode
73 OID pbes2Id("1.2.840.113549.1.5.13");
74 OID pbkdf2Id("1.2.840.113549.1.5.12");
75 OID pbes2encsId("1.2.840.113549.3.7");
76
77 OBufferStream pkcs8Os;
78 try
79 {
80 FileSink sink(pkcs8Os);
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -070081
Yingdi Yu2e57a582014-02-20 23:34:43 -080082 // EncryptedPrivateKeyInfo ::= SEQUENCE {
83 // encryptionAlgorithm EncryptionAlgorithmIdentifier,
84 // encryptedData OCTET STRING }
85 DERSequenceEncoder encryptedPrivateKeyInfo(sink);
86 {
87 // EncryptionAlgorithmIdentifier ::= SEQUENCE {
88 // algorithm OBJECT IDENTIFIER {{PBES2-id}},
89 // parameters SEQUENCE {{PBES2-params}} }
90 DERSequenceEncoder encryptionAlgorithm(encryptedPrivateKeyInfo);
91 {
92 pbes2Id.encode(encryptionAlgorithm);
93 // PBES2-params ::= SEQUENCE {
94 // keyDerivationFunc AlgorithmIdentifier {{PBES2-KDFs}},
95 // encryptionScheme AlgorithmIdentifier {{PBES2-Encs}} }
96 DERSequenceEncoder pbes2Params(encryptionAlgorithm);
97 {
98 // AlgorithmIdentifier ::= SEQUENCE {
99 // algorithm OBJECT IDENTIFIER {{PBKDF2-id}},
100 // parameters SEQUENCE {{PBKDF2-params}} }
101 DERSequenceEncoder pbes2KDFs(pbes2Params);
102 {
103 pbkdf2Id.encode(pbes2KDFs);
104 // AlgorithmIdentifier ::= SEQUENCE {
105 // salt OCTET STRING,
106 // iterationCount INTEGER (1..MAX),
107 // keyLength INTEGER (1..MAX) OPTIONAL,
108 // prf AlgorithmIdentifier {{PBKDF2-PRFs}} DEFAULT algid-hmacWithSHA1 }
109 DERSequenceEncoder pbkdf2Params(pbes2KDFs);
110 {
111 DEREncodeOctetString(pbkdf2Params, salt, 8);
112 DEREncodeUnsigned<uint32_t>(pbkdf2Params, iterationCount, INTEGER);
113 }
114 pbkdf2Params.MessageEnd();
115 }
116 pbes2KDFs.MessageEnd();
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700117
Yingdi Yu2e57a582014-02-20 23:34:43 -0800118 // AlgorithmIdentifier ::= SEQUENCE {
119 // algorithm OBJECT IDENTIFIER {{DES-EDE3-CBC-PAD}},
120 // parameters OCTET STRING} {{iv}} }
121 DERSequenceEncoder pbes2Encs(pbes2Params);
122 {
123 pbes2encsId.encode(pbes2Encs);
124 DEREncodeOctetString(pbes2Encs, iv, 8);
125 }
126 pbes2Encs.MessageEnd();
127 }
128 pbes2Params.MessageEnd();
129 }
130 encryptionAlgorithm.MessageEnd();
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700131
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700132 DEREncodeOctetString(encryptedPrivateKeyInfo,
133 encryptedOs.buf()->buf(), encryptedOs.buf()->size());
Yingdi Yu2e57a582014-02-20 23:34:43 -0800134 }
135 encryptedPrivateKeyInfo.MessageEnd();
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700136
Yingdi Yu2e57a582014-02-20 23:34:43 -0800137 return pkcs8Os.buf();
138 }
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700139 catch (CryptoPP::Exception& e)
Yingdi Yu2e57a582014-02-20 23:34:43 -0800140 {
141 throw Error("Cannot export the private key, #3");
142 }
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800143}
144
145bool
Yingdi Yu5e96e002014-04-23 18:32:15 -0700146SecTpm::importPrivateKeyPkcs5IntoTpm(const Name& keyName,
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700147 const uint8_t* buf, size_t size,
148 const string& passwordStr)
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800149{
Yingdi Yu2e57a582014-02-20 23:34:43 -0800150 using namespace CryptoPP;
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700151
Yingdi Yu2e57a582014-02-20 23:34:43 -0800152 OID pbes2Id;
153 OID pbkdf2Id;
154 SecByteBlock saltBlock;
155 uint32_t iterationCount;
156 OID pbes2encsId;
157 SecByteBlock ivBlock;
158 SecByteBlock encryptedDataBlock;
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700159
Yingdi Yu2e57a582014-02-20 23:34:43 -0800160 try
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800161 {
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700162 // decode some decoding processes are not necessary for now,
163 // because we assume only one encryption scheme.
Yingdi Yu2e57a582014-02-20 23:34:43 -0800164 StringSource source(buf, size, true);
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700165
Yingdi Yu2e57a582014-02-20 23:34:43 -0800166 // EncryptedPrivateKeyInfo ::= SEQUENCE {
167 // encryptionAlgorithm EncryptionAlgorithmIdentifier,
168 // encryptedData OCTET STRING }
169 BERSequenceDecoder encryptedPrivateKeyInfo(source);
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800170 {
Yingdi Yu2e57a582014-02-20 23:34:43 -0800171 // EncryptionAlgorithmIdentifier ::= SEQUENCE {
172 // algorithm OBJECT IDENTIFIER {{PBES2-id}},
173 // parameters SEQUENCE {{PBES2-params}} }
174 BERSequenceDecoder encryptionAlgorithm(encryptedPrivateKeyInfo);
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800175 {
Yingdi Yu2e57a582014-02-20 23:34:43 -0800176 pbes2Id.decode(encryptionAlgorithm);
177 // PBES2-params ::= SEQUENCE {
178 // keyDerivationFunc AlgorithmIdentifier {{PBES2-KDFs}},
179 // encryptionScheme AlgorithmIdentifier {{PBES2-Encs}} }
180 BERSequenceDecoder pbes2Params(encryptionAlgorithm);
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800181 {
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800182 // AlgorithmIdentifier ::= SEQUENCE {
Yingdi Yu2e57a582014-02-20 23:34:43 -0800183 // algorithm OBJECT IDENTIFIER {{PBKDF2-id}},
184 // parameters SEQUENCE {{PBKDF2-params}} }
185 BERSequenceDecoder pbes2KDFs(pbes2Params);
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800186 {
Yingdi Yu2e57a582014-02-20 23:34:43 -0800187 pbkdf2Id.decode(pbes2KDFs);
188 // AlgorithmIdentifier ::= SEQUENCE {
189 // salt OCTET STRING,
190 // iterationCount INTEGER (1..MAX),
191 // keyLength INTEGER (1..MAX) OPTIONAL,
192 // prf AlgorithmIdentifier {{PBKDF2-PRFs}} DEFAULT algid-hmacWithSHA1 }
193 BERSequenceDecoder pbkdf2Params(pbes2KDFs);
194 {
195 BERDecodeOctetString(pbkdf2Params, saltBlock);
196 BERDecodeUnsigned<uint32_t>(pbkdf2Params, iterationCount, INTEGER);
197 }
198 pbkdf2Params.MessageEnd();
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800199 }
Yingdi Yu2e57a582014-02-20 23:34:43 -0800200 pbes2KDFs.MessageEnd();
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700201
Yingdi Yu2e57a582014-02-20 23:34:43 -0800202 // AlgorithmIdentifier ::= SEQUENCE {
203 // algorithm OBJECT IDENTIFIER {{DES-EDE3-CBC-PAD}},
204 // parameters OCTET STRING} {{iv}} }
205 BERSequenceDecoder pbes2Encs(pbes2Params);
206 {
207 pbes2encsId.decode(pbes2Encs);
208 BERDecodeOctetString(pbes2Encs, ivBlock);
209 }
210 pbes2Encs.MessageEnd();
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800211 }
Yingdi Yu2e57a582014-02-20 23:34:43 -0800212 pbes2Params.MessageEnd();
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800213 }
Yingdi Yu2e57a582014-02-20 23:34:43 -0800214 encryptionAlgorithm.MessageEnd();
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800215
Yingdi Yu2e57a582014-02-20 23:34:43 -0800216 BERDecodeOctetString(encryptedPrivateKeyInfo, encryptedDataBlock);
217 }
218 encryptedPrivateKeyInfo.MessageEnd();
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800219 }
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700220 catch (CryptoPP::Exception& e)
Yingdi Yu2e57a582014-02-20 23:34:43 -0800221 {
222 return false;
223 }
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800224
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700225
Yingdi Yu2e57a582014-02-20 23:34:43 -0800226 PKCS5_PBKDF2_HMAC<SHA1> keyGenerator;
227 size_t derivedLen = 24; //For DES-EDE3-CBC-PAD
228 byte derived[24] = {0};
229 byte purpose = 0;
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700230
Yingdi Yu2e57a582014-02-20 23:34:43 -0800231 try
232 {
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700233 keyGenerator.DeriveKey(derived, derivedLen,
234 purpose,
235 reinterpret_cast<const byte*>(passwordStr.c_str()), passwordStr.size(),
236 saltBlock.BytePtr(), saltBlock.size(),
Yingdi Yu2e57a582014-02-20 23:34:43 -0800237 iterationCount);
238 }
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700239 catch (CryptoPP::Exception& e)
Yingdi Yu2e57a582014-02-20 23:34:43 -0800240 {
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800241 return false;
Yingdi Yu2e57a582014-02-20 23:34:43 -0800242 }
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800243
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700244 //decrypt
245 CBC_Mode< DES_EDE3 >::Decryption d;
246 d.SetKeyWithIV(derived, derivedLen, ivBlock.BytePtr());
247
248 OBufferStream privateKeyOs;
249 try
250 {
251 StringSource encryptedSource(encryptedDataBlock.BytePtr(), encryptedDataBlock.size(), true,
252 new StreamTransformationFilter(d, new FileSink(privateKeyOs)));
253 }
254 catch (CryptoPP::Exception& e)
255 {
256 return false;
257 }
258
Yingdi Yu5e96e002014-04-23 18:32:15 -0700259 if (!importPrivateKeyPkcs8IntoTpm(keyName,
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700260 privateKeyOs.buf()->buf(), privateKeyOs.buf()->size()))
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800261 return false;
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700262
Yingdi Yu2e57a582014-02-20 23:34:43 -0800263 //derive public key
264 OBufferStream publicKeyOs;
265
266 try
267 {
268 RSA::PrivateKey privateKey;
269 privateKey.Load(StringStore(privateKeyOs.buf()->buf(), privateKeyOs.buf()->size()).Ref());
270 RSAFunction publicKey(privateKey);
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700271
Yingdi Yu2e57a582014-02-20 23:34:43 -0800272 FileSink publicKeySink(publicKeyOs);
273 publicKey.DEREncode(publicKeySink);
274 publicKeySink.MessageEnd();
275 }
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700276 catch (CryptoPP::Exception& e)
Yingdi Yu2e57a582014-02-20 23:34:43 -0800277 {
278 return false;
279 }
280
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700281 if (!importPublicKeyPkcs1IntoTpm(keyName, publicKeyOs.buf()->buf(), publicKeyOs.buf()->size()))
Yingdi Yu2e57a582014-02-20 23:34:43 -0800282 return false;
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700283
Yingdi Yu2e57a582014-02-20 23:34:43 -0800284 return true;
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800285}
286
287
Yingdi Yufc40d872014-02-18 12:56:04 -0800288} // namespace ndn