blob: 56c39b8a14eff2741fd5dec929e119604899f8fb [file] [log] [blame]
Yingdi Yu8dceb1d2014-02-18 12:45:10 -08001/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil -*- */
2/**
3 * Copyright (C) 2013 Regents of the University of California.
4 * @author: Yingdi Yu <yingdi@cs.ucla.edu>
5 * See COPYING for copyright and distribution information.
6 */
7
8#include "sec-tpm.hpp"
9
10#include <cryptopp/rsa.h>
11#include <cryptopp/files.h>
12#include <cryptopp/base64.h>
13#include <cryptopp/hex.h>
14#include <cryptopp/osrng.h>
15#include <cryptopp/sha.h>
16#include <cryptopp/pssr.h>
17#include <cryptopp/modes.h>
18#include <cryptopp/pwdbased.h>
19#include <cryptopp/sha.h>
20#include <cryptopp/des.h>
21
22using namespace std;
23
24namespace ndn {
25
26ConstBufferPtr
Yingdi Yube4150e2014-02-18 13:02:46 -080027SecTpm::exportPrivateKeyPkcs8FromTpm(const Name& keyName, const string& passwordStr)
Yingdi Yu8dceb1d2014-02-18 12:45:10 -080028{
Yingdi Yu2e57a582014-02-20 23:34:43 -080029 using namespace CryptoPP;
30
Yingdi Yu8dceb1d2014-02-18 12:45:10 -080031 uint8_t salt[8] = {0};
32 uint8_t iv[8] = {0};
33
Yingdi Yu2e57a582014-02-20 23:34:43 -080034 // derive key
35 if(!generateRandomBlock(salt, 8) || !generateRandomBlock(iv, 8))
36 throw Error("Cannot generate salt or iv");
Yingdi Yu8dceb1d2014-02-18 12:45:10 -080037
Yingdi Yu2e57a582014-02-20 23:34:43 -080038 uint32_t iterationCount = 2048;
Yingdi Yu8dceb1d2014-02-18 12:45:10 -080039
Yingdi Yu2e57a582014-02-20 23:34:43 -080040 PKCS5_PBKDF2_HMAC<SHA1> keyGenerator;
41 size_t derivedLen = 24; //For DES-EDE3-CBC-PAD
42 byte derived[24] = {0};
43 byte purpose = 0;
44
45 try
Yingdi Yu8dceb1d2014-02-18 12:45:10 -080046 {
Yingdi Yu2e57a582014-02-20 23:34:43 -080047 keyGenerator.DeriveKey(derived, derivedLen, purpose,
48 reinterpret_cast<const byte*>(passwordStr.c_str()), passwordStr.size(),
49 salt, 8, iterationCount);
Yingdi Yu8dceb1d2014-02-18 12:45:10 -080050 }
Yingdi Yu2e57a582014-02-20 23:34:43 -080051 catch(CryptoPP::Exception& e)
52 {
53 throw Error("Cannot derived the encryption key");
54 }
Yingdi Yu8dceb1d2014-02-18 12:45:10 -080055
Yingdi Yu2e57a582014-02-20 23:34:43 -080056 //encrypt
57 CBC_Mode< DES_EDE3 >::Encryption e;
58 e.SetKeyWithIV(derived, derivedLen, iv);
59
60 ConstBufferPtr pkcs1PrivateKey = exportPrivateKeyPkcs1FromTpm(keyName);
61 if(!static_cast<bool>(pkcs1PrivateKey))
62 throw Error("Cannot export the private key, #1");
63
64 OBufferStream encryptedOs;
65 try
66 {
67 StringSource stringSource(pkcs1PrivateKey->buf(), pkcs1PrivateKey->size(), true,
68 new StreamTransformationFilter(e, new FileSink(encryptedOs)));
69 }
70 catch(CryptoPP::Exception& e)
71 {
72 throw Error("Cannot export the private key, #2");
73 }
74
75 //encode
76 OID pbes2Id("1.2.840.113549.1.5.13");
77 OID pbkdf2Id("1.2.840.113549.1.5.12");
78 OID pbes2encsId("1.2.840.113549.3.7");
79
80 OBufferStream pkcs8Os;
81 try
82 {
83 FileSink sink(pkcs8Os);
84
85 // EncryptedPrivateKeyInfo ::= SEQUENCE {
86 // encryptionAlgorithm EncryptionAlgorithmIdentifier,
87 // encryptedData OCTET STRING }
88 DERSequenceEncoder encryptedPrivateKeyInfo(sink);
89 {
90 // EncryptionAlgorithmIdentifier ::= SEQUENCE {
91 // algorithm OBJECT IDENTIFIER {{PBES2-id}},
92 // parameters SEQUENCE {{PBES2-params}} }
93 DERSequenceEncoder encryptionAlgorithm(encryptedPrivateKeyInfo);
94 {
95 pbes2Id.encode(encryptionAlgorithm);
96 // PBES2-params ::= SEQUENCE {
97 // keyDerivationFunc AlgorithmIdentifier {{PBES2-KDFs}},
98 // encryptionScheme AlgorithmIdentifier {{PBES2-Encs}} }
99 DERSequenceEncoder pbes2Params(encryptionAlgorithm);
100 {
101 // AlgorithmIdentifier ::= SEQUENCE {
102 // algorithm OBJECT IDENTIFIER {{PBKDF2-id}},
103 // parameters SEQUENCE {{PBKDF2-params}} }
104 DERSequenceEncoder pbes2KDFs(pbes2Params);
105 {
106 pbkdf2Id.encode(pbes2KDFs);
107 // AlgorithmIdentifier ::= SEQUENCE {
108 // salt OCTET STRING,
109 // iterationCount INTEGER (1..MAX),
110 // keyLength INTEGER (1..MAX) OPTIONAL,
111 // prf AlgorithmIdentifier {{PBKDF2-PRFs}} DEFAULT algid-hmacWithSHA1 }
112 DERSequenceEncoder pbkdf2Params(pbes2KDFs);
113 {
114 DEREncodeOctetString(pbkdf2Params, salt, 8);
115 DEREncodeUnsigned<uint32_t>(pbkdf2Params, iterationCount, INTEGER);
116 }
117 pbkdf2Params.MessageEnd();
118 }
119 pbes2KDFs.MessageEnd();
120
121 // AlgorithmIdentifier ::= SEQUENCE {
122 // algorithm OBJECT IDENTIFIER {{DES-EDE3-CBC-PAD}},
123 // parameters OCTET STRING} {{iv}} }
124 DERSequenceEncoder pbes2Encs(pbes2Params);
125 {
126 pbes2encsId.encode(pbes2Encs);
127 DEREncodeOctetString(pbes2Encs, iv, 8);
128 }
129 pbes2Encs.MessageEnd();
130 }
131 pbes2Params.MessageEnd();
132 }
133 encryptionAlgorithm.MessageEnd();
134
135 DEREncodeOctetString(encryptedPrivateKeyInfo, encryptedOs.buf()->buf(), encryptedOs.buf()->size());
136 }
137 encryptedPrivateKeyInfo.MessageEnd();
138
139 return pkcs8Os.buf();
140 }
141 catch(CryptoPP::Exception& e)
142 {
143 throw Error("Cannot export the private key, #3");
144 }
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800145}
146
147bool
Yingdi Yube4150e2014-02-18 13:02:46 -0800148SecTpm::importPrivateKeyPkcs8IntoTpm(const Name& keyName, const uint8_t* buf, size_t size, const string& passwordStr)
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800149{
Yingdi Yu2e57a582014-02-20 23:34:43 -0800150 using namespace CryptoPP;
151
152 OID pbes2Id;
153 OID pbkdf2Id;
154 SecByteBlock saltBlock;
155 uint32_t iterationCount;
156 OID pbes2encsId;
157 SecByteBlock ivBlock;
158 SecByteBlock encryptedDataBlock;
159
160 try
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800161 {
Yingdi Yu2e57a582014-02-20 23:34:43 -0800162 //decode some decoding processes are not necessary for now, because we assume only one encryption scheme.
163 StringSource source(buf, size, true);
164
165 // EncryptedPrivateKeyInfo ::= SEQUENCE {
166 // encryptionAlgorithm EncryptionAlgorithmIdentifier,
167 // encryptedData OCTET STRING }
168 BERSequenceDecoder encryptedPrivateKeyInfo(source);
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800169 {
Yingdi Yu2e57a582014-02-20 23:34:43 -0800170 // EncryptionAlgorithmIdentifier ::= SEQUENCE {
171 // algorithm OBJECT IDENTIFIER {{PBES2-id}},
172 // parameters SEQUENCE {{PBES2-params}} }
173 BERSequenceDecoder encryptionAlgorithm(encryptedPrivateKeyInfo);
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800174 {
Yingdi Yu2e57a582014-02-20 23:34:43 -0800175 pbes2Id.decode(encryptionAlgorithm);
176 // PBES2-params ::= SEQUENCE {
177 // keyDerivationFunc AlgorithmIdentifier {{PBES2-KDFs}},
178 // encryptionScheme AlgorithmIdentifier {{PBES2-Encs}} }
179 BERSequenceDecoder pbes2Params(encryptionAlgorithm);
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800180 {
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800181 // AlgorithmIdentifier ::= SEQUENCE {
Yingdi Yu2e57a582014-02-20 23:34:43 -0800182 // algorithm OBJECT IDENTIFIER {{PBKDF2-id}},
183 // parameters SEQUENCE {{PBKDF2-params}} }
184 BERSequenceDecoder pbes2KDFs(pbes2Params);
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800185 {
Yingdi Yu2e57a582014-02-20 23:34:43 -0800186 pbkdf2Id.decode(pbes2KDFs);
187 // AlgorithmIdentifier ::= SEQUENCE {
188 // salt OCTET STRING,
189 // iterationCount INTEGER (1..MAX),
190 // keyLength INTEGER (1..MAX) OPTIONAL,
191 // prf AlgorithmIdentifier {{PBKDF2-PRFs}} DEFAULT algid-hmacWithSHA1 }
192 BERSequenceDecoder pbkdf2Params(pbes2KDFs);
193 {
194 BERDecodeOctetString(pbkdf2Params, saltBlock);
195 BERDecodeUnsigned<uint32_t>(pbkdf2Params, iterationCount, INTEGER);
196 }
197 pbkdf2Params.MessageEnd();
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800198 }
Yingdi Yu2e57a582014-02-20 23:34:43 -0800199 pbes2KDFs.MessageEnd();
200
201 // AlgorithmIdentifier ::= SEQUENCE {
202 // algorithm OBJECT IDENTIFIER {{DES-EDE3-CBC-PAD}},
203 // parameters OCTET STRING} {{iv}} }
204 BERSequenceDecoder pbes2Encs(pbes2Params);
205 {
206 pbes2encsId.decode(pbes2Encs);
207 BERDecodeOctetString(pbes2Encs, ivBlock);
208 }
209 pbes2Encs.MessageEnd();
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800210 }
Yingdi Yu2e57a582014-02-20 23:34:43 -0800211 pbes2Params.MessageEnd();
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800212 }
Yingdi Yu2e57a582014-02-20 23:34:43 -0800213 encryptionAlgorithm.MessageEnd();
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800214
Yingdi Yu2e57a582014-02-20 23:34:43 -0800215 BERDecodeOctetString(encryptedPrivateKeyInfo, encryptedDataBlock);
216 }
217 encryptedPrivateKeyInfo.MessageEnd();
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800218 }
Yingdi Yu2e57a582014-02-20 23:34:43 -0800219 catch(CryptoPP::Exception& e)
220 {
221 return false;
222 }
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800223
224
Yingdi Yu2e57a582014-02-20 23:34:43 -0800225 PKCS5_PBKDF2_HMAC<SHA1> keyGenerator;
226 size_t derivedLen = 24; //For DES-EDE3-CBC-PAD
227 byte derived[24] = {0};
228 byte purpose = 0;
229
230 try
231 {
232 keyGenerator.DeriveKey(derived, derivedLen,
233 purpose,
234 reinterpret_cast<const byte*>(passwordStr.c_str()), passwordStr.size(),
235 saltBlock.BytePtr(), saltBlock.size(),
236 iterationCount);
237 }
238 catch(CryptoPP::Exception& e)
239 {
240 return false;
241 }
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800242
Yingdi Yu2e57a582014-02-20 23:34:43 -0800243 //decrypt
244 CBC_Mode< DES_EDE3 >::Decryption d;
245 d.SetKeyWithIV(derived, derivedLen, ivBlock.BytePtr());
246
247 OBufferStream privateKeyOs;
248 try
249 {
250 StringSource encryptedSource(encryptedDataBlock.BytePtr(), encryptedDataBlock.size(), true,
251 new StreamTransformationFilter(d, new FileSink(privateKeyOs)));
252 }
253 catch(CryptoPP::Exception& e)
254 {
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800255 return false;
Yingdi Yu2e57a582014-02-20 23:34:43 -0800256 }
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800257
Yingdi Yu2e57a582014-02-20 23:34:43 -0800258 if(!importPrivateKeyPkcs1IntoTpm(keyName, privateKeyOs.buf()->buf(), privateKeyOs.buf()->size()))
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800259 return false;
Yingdi Yu2e57a582014-02-20 23:34:43 -0800260
261 //derive public key
262 OBufferStream publicKeyOs;
263
264 try
265 {
266 RSA::PrivateKey privateKey;
267 privateKey.Load(StringStore(privateKeyOs.buf()->buf(), privateKeyOs.buf()->size()).Ref());
268 RSAFunction publicKey(privateKey);
269
270 FileSink publicKeySink(publicKeyOs);
271 publicKey.DEREncode(publicKeySink);
272 publicKeySink.MessageEnd();
273 }
274 catch(CryptoPP::Exception& e)
275 {
276 return false;
277 }
278
279 if(!importPublicKeyPkcs1IntoTpm(keyName, publicKeyOs.buf()->buf(), publicKeyOs.buf()->size()))
280 return false;
281
282 return true;
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800283}
284
285
Yingdi Yufc40d872014-02-18 12:56:04 -0800286} // namespace ndn