blob: a52d839054e02e3a305a4be7df7d01c0990be0e8 [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
27SecTpm::exportPrivateKeyPkcs8FromTpm(const Name& keyName, bool inTerminal, const string& passwordStr)
28{
29 uint8_t salt[8] = {0};
30 uint8_t iv[8] = {0};
31
32 try{
33 using namespace CryptoPP;
34
35 // check password
36 string password;
37 if(passwordStr.empty())
38 if(!inTerminal)
39 return shared_ptr<Buffer>();
40 else
41 {
42 int count = 0;
43 while(!getPassWord(password, keyName.toUri()))
44 {
45 cerr << "Password mismatch!" << endl;
46 count++;
47 if(count > 3)
48 return shared_ptr<Buffer>();
49 }
50 }
51 else
52 password = passwordStr;
53
54 // derive key
55 if(!generateRandomBlock(salt, 8))
56 return shared_ptr<Buffer>();
57
58 if(!generateRandomBlock(iv, 8))
59 return shared_ptr<Buffer>();
60
61 uint32_t iterationCount = 2048;
62
63 PKCS5_PBKDF2_HMAC<SHA1> keyGenerator;
64 size_t derivedLen = 24; //For DES-EDE3-CBC-PAD
65 byte derived[24] = {0};
66 byte purpose = 0;
67
68 keyGenerator.DeriveKey(derived, derivedLen,
69 purpose,
70 reinterpret_cast<const byte*>(password.c_str()), password.size(),
71 salt, 8,
72 iterationCount);
73
74 memset(const_cast<char*>(password.c_str()), 0, password.size());
75
76 //encrypt
77 CBC_Mode< DES_EDE3 >::Encryption e;
78 e.SetKeyWithIV(derived, derivedLen, iv);
79
80 string encrypted;
81 OBufferStream encryptedOs;
82 ConstBufferPtr pkcs1PrivateKey = exportPrivateKeyPkcs1FromTpm(keyName);
83 StringSource stringSource(pkcs1PrivateKey->buf(), pkcs1PrivateKey->size(), true,
84 new StreamTransformationFilter(e, new FileSink(encryptedOs)));
85
86 //encode
87 OID pbes2Id("1.2.840.113549.1.5.13");
88 OID pbkdf2Id("1.2.840.113549.1.5.12");
89 OID pbes2encsId("1.2.840.113549.3.7");
90
91 OBufferStream pkcs8Os;
92 FileSink sink(pkcs8Os);
93
94 // 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();
129
130 // 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();
143
144 DEREncodeOctetString(encryptedPrivateKeyInfo, encryptedOs.buf()->buf(), encryptedOs.buf()->size());
145 }
146 encryptedPrivateKeyInfo.MessageEnd();
147
148 return pkcs8Os.buf();
149 }catch(...){
150 return shared_ptr<Buffer>();
151 }
152}
153
154bool
155SecTpm::importPrivateKeyPkcs8IntoTpm(const Name& keyName, const uint8_t* buf, size_t size, bool inTerminal, const string& passwordStr)
156{
157 try{
158 using namespace CryptoPP;
159
160 OID pbes2Id;
161 OID pbkdf2Id;
162 SecByteBlock saltBlock;
163 uint32_t iterationCount;
164 OID pbes2encsId;
165 SecByteBlock ivBlock;
166 SecByteBlock encryptedDataBlock;
167
168 //decode some decoding processes are not necessary for now, because we assume only one encryption scheme.
169 StringSource source(buf, size, true);
170
171 // EncryptedPrivateKeyInfo ::= SEQUENCE {
172 // encryptionAlgorithm EncryptionAlgorithmIdentifier,
173 // encryptedData OCTET STRING }
174 BERSequenceDecoder encryptedPrivateKeyInfo(source);
175 {
176 // EncryptionAlgorithmIdentifier ::= SEQUENCE {
177 // algorithm OBJECT IDENTIFIER {{PBES2-id}},
178 // parameters SEQUENCE {{PBES2-params}} }
179 BERSequenceDecoder encryptionAlgorithm(encryptedPrivateKeyInfo);
180 {
181 pbes2Id.decode(encryptionAlgorithm);
182 // PBES2-params ::= SEQUENCE {
183 // keyDerivationFunc AlgorithmIdentifier {{PBES2-KDFs}},
184 // encryptionScheme AlgorithmIdentifier {{PBES2-Encs}} }
185 BERSequenceDecoder pbes2Params(encryptionAlgorithm);
186 {
187 // AlgorithmIdentifier ::= SEQUENCE {
188 // algorithm OBJECT IDENTIFIER {{PBKDF2-id}},
189 // parameters SEQUENCE {{PBKDF2-params}} }
190 BERSequenceDecoder pbes2KDFs(pbes2Params);
191 {
192 pbkdf2Id.decode(pbes2KDFs);
193 // AlgorithmIdentifier ::= SEQUENCE {
194 // salt OCTET STRING,
195 // iterationCount INTEGER (1..MAX),
196 // keyLength INTEGER (1..MAX) OPTIONAL,
197 // prf AlgorithmIdentifier {{PBKDF2-PRFs}} DEFAULT algid-hmacWithSHA1 }
198 BERSequenceDecoder pbkdf2Params(pbes2KDFs);
199 {
200 BERDecodeOctetString(pbkdf2Params, saltBlock);
201 BERDecodeUnsigned<uint32_t>(pbkdf2Params, iterationCount, INTEGER);
202 }
203 pbkdf2Params.MessageEnd();
204 }
205 pbes2KDFs.MessageEnd();
206
207 // AlgorithmIdentifier ::= SEQUENCE {
208 // algorithm OBJECT IDENTIFIER {{DES-EDE3-CBC-PAD}},
209 // parameters OCTET STRING} {{iv}} }
210 BERSequenceDecoder pbes2Encs(pbes2Params);
211 {
212 pbes2encsId.decode(pbes2Encs);
213 BERDecodeOctetString(pbes2Encs, ivBlock);
214 }
215 pbes2Encs.MessageEnd();
216 }
217 pbes2Params.MessageEnd();
218 }
219 encryptionAlgorithm.MessageEnd();
220
221 BERDecodeOctetString(encryptedPrivateKeyInfo, encryptedDataBlock);
222 }
223 encryptedPrivateKeyInfo.MessageEnd();
224
225
226 PKCS5_PBKDF2_HMAC<SHA1> keyGenerator;
227 size_t derivedLen = 24; //For DES-EDE3-CBC-PAD
228 byte derived[24] = {0};
229 byte purpose = 0;
230
231 string password;
232 if(passwordStr.empty())
233 if(inTerminal)
234 {
235 char* pw = getpass("Password for the private key: ");
236 if (!pw)
237 return false;
238 password = pw;
239 memset(pw, 0, strlen(pw));
240 }
241 else
242 return false;
243 else
244 password = passwordStr;
245
246 keyGenerator.DeriveKey(derived, derivedLen,
247 purpose,
248 reinterpret_cast<const byte*>(password.c_str()), password.size(),
249 saltBlock.BytePtr(), saltBlock.size(),
250 iterationCount);
251
252 memset(const_cast<char*>(password.c_str()), 0, password.size());
253
254 //decrypt
255 CBC_Mode< DES_EDE3 >::Decryption d;
256 d.SetKeyWithIV(derived, derivedLen, ivBlock.BytePtr());
257
258 OBufferStream privateKeyOs;
259 StringSource encryptedSource(encryptedDataBlock.BytePtr(), encryptedDataBlock.size(), true,
260 new StreamTransformationFilter(d, new FileSink(privateKeyOs)));
261
262 if(!importPrivateKeyPkcs1IntoTpm(keyName, privateKeyOs.buf()->buf(), privateKeyOs.buf()->size()))
263 return false;
264
265 //derive public key
266 RSA::PrivateKey privateKey;
267 privateKey.Load(StringStore(privateKeyOs.buf()->buf(), privateKeyOs.buf()->size()).Ref());
268
269 RSAFunction publicKey(privateKey);
270
271 OBufferStream publicKeyOs;
272 FileSink publicKeySink(publicKeyOs);
273 publicKey.DEREncode(publicKeySink);
274 publicKeySink.MessageEnd();
275
276 if(!importPublicKeyPkcs1IntoTpm(keyName, publicKeyOs.buf()->buf(), publicKeyOs.buf()->size()))
277 return false;
278
279 return true;
280 }catch(std::runtime_error& e){
281 cerr << e.what() << endl;
282 return false;
283 }
284}
285
286
Yingdi Yufc40d872014-02-18 12:56:04 -0800287} // namespace ndn