]> git.saurik.com Git - apple/security.git/blob - securityd/src/dbcrypto.cpp
Security-57337.50.23.tar.gz
[apple/security.git] / securityd / src / dbcrypto.cpp
1 /*
2 * Copyright (c) 2000-2006,2013 Apple Inc. All Rights Reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
11 * file.
12 *
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
20 *
21 * @APPLE_LICENSE_HEADER_END@
22 */
23
24
25 //
26 // dbcrypto - cryptographic core for database and key blob cryptography
27 //
28 #include "dbcrypto.h"
29 #include <securityd_client/ssblob.h>
30 #include "server.h" // just for Server::csp()
31 #include <security_cdsa_client/genkey.h>
32 #include <security_cdsa_client/cryptoclient.h>
33 #include <security_cdsa_client/keyclient.h>
34 #include <security_cdsa_client/macclient.h>
35 #include <security_cdsa_client/wrapkey.h>
36 #include <security_cdsa_utilities/cssmendian.h>
37
38 using namespace CssmClient;
39 using LowLevelMemoryUtilities::fieldOffsetOf;
40
41
42 //
43 // The CryptoCore constructor doesn't do anything interesting.
44 // It just initializes us to "empty".
45 //
46 DatabaseCryptoCore::DatabaseCryptoCore() : mBlobVersion(CommonBlob::version_MacOS_10_0), mHaveMaster(false), mIsValid(false)
47 {
48 mBlobVersion = CommonBlob::getCurrentVersion();
49 }
50
51 DatabaseCryptoCore::~DatabaseCryptoCore()
52 {
53 // key objects take care of themselves
54 }
55
56
57 //
58 // Forget the secrets
59 //
60 void DatabaseCryptoCore::invalidate()
61 {
62 mMasterKey.release();
63 mHaveMaster = false;
64
65 mEncryptionKey.release();
66 mSigningKey.release();
67 mIsValid = false;
68 }
69
70
71 //
72 // Generate new secrets for this crypto core.
73 //
74 void DatabaseCryptoCore::generateNewSecrets()
75 {
76 // create a random DES3 key
77 GenerateKey desGenerator(Server::csp(), CSSM_ALGID_3DES_3KEY_EDE, 24 * 8);
78 mEncryptionKey = desGenerator(KeySpec(CSSM_KEYUSE_WRAP | CSSM_KEYUSE_UNWRAP,
79 CSSM_KEYATTR_RETURN_DATA | CSSM_KEYATTR_EXTRACTABLE));
80
81 // create a random 20 byte HMAC/SHA1 signing "key"
82 GenerateKey signGenerator(Server::csp(), CSSM_ALGID_SHA1HMAC,
83 sizeof(DbBlob::PrivateBlob::SigningKey) * 8);
84 mSigningKey = signGenerator(KeySpec(CSSM_KEYUSE_SIGN | CSSM_KEYUSE_VERIFY,
85 CSSM_KEYATTR_RETURN_DATA | CSSM_KEYATTR_EXTRACTABLE));
86
87 // secrets established
88 mIsValid = true;
89 }
90
91
92 CssmClient::Key DatabaseCryptoCore::masterKey()
93 {
94 assert(mHaveMaster);
95 return mMasterKey;
96 }
97
98
99 //
100 // Establish the master secret as derived from a passphrase passed in.
101 // If a DbBlob is passed, take the salt from it and remember it.
102 // If a NULL DbBlob is passed, generate a new (random) salt.
103 // Note that the passphrase is NOT remembered; only the master key.
104 //
105 void DatabaseCryptoCore::setup(const DbBlob *blob, const CssmData &passphrase, bool copyVersion /* = true */)
106 {
107 if (blob) {
108 if(copyVersion) {
109 mBlobVersion = blob->version();
110 }
111 memcpy(mSalt, blob->salt, sizeof(mSalt));
112 } else
113 Server::active().random(mSalt);
114 mMasterKey = deriveDbMasterKey(passphrase);
115 mHaveMaster = true;
116 }
117
118
119 //
120 // Establish the master secret directly from a master key passed in.
121 // We will copy the KeyData (caller still owns its copy).
122 // Blob/salt handling as above.
123 //
124 void DatabaseCryptoCore::setup(const DbBlob *blob, CssmClient::Key master, bool copyVersion /* = true */)
125 {
126 // pre-screen the key
127 CssmKey::Header header = master.header();
128 if (header.keyClass() != CSSM_KEYCLASS_SESSION_KEY)
129 CssmError::throwMe(CSSMERR_CSP_INVALID_KEY_CLASS);
130 if (header.algorithm() != CSSM_ALGID_3DES_3KEY_EDE)
131 CssmError::throwMe(CSSMERR_CSP_INVALID_ALGORITHM);
132
133 // accept it
134 if (blob) {
135 if(copyVersion) {
136 mBlobVersion = blob->version();
137 }
138 memcpy(mSalt, blob->salt, sizeof(mSalt));
139 } else
140 Server::active().random(mSalt);
141 mMasterKey = master;
142 mHaveMaster = true;
143 }
144
145 bool DatabaseCryptoCore::get_encryption_key(CssmOwnedData &data)
146 {
147 bool result = false;
148 if (isValid()) {
149 data = mEncryptionKey->keyData();
150 result = true;
151 }
152 return result;
153 }
154
155 //
156 // Given a putative passphrase, determine whether that passphrase
157 // properly generates the database's master secret.
158 // Return a boolean accordingly. Do not change our state.
159 // The database must have a master secret (to compare with).
160 // Note that any errors thrown by the cryptography here will actually
161 // throw out of validatePassphrase, since they "should not happen" and
162 // thus indicate a problem *beyond* (just) a bad passphrase.
163 //
164 bool DatabaseCryptoCore::validatePassphrase(const CssmData &passphrase)
165 {
166 assert(hasMaster());
167 CssmClient::Key master = deriveDbMasterKey(passphrase);
168
169 // to compare master with mMaster, see if they encrypt alike
170 StringData probe
171 ("Now is the time for all good processes to come to the aid of their kernel.");
172 CssmData noRemainder((void *)1, 0); // no cipher overflow
173 Encrypt cryptor(Server::csp(), CSSM_ALGID_3DES_3KEY_EDE);
174 cryptor.mode(CSSM_ALGMODE_CBCPadIV8);
175 cryptor.padding(CSSM_PADDING_PKCS1);
176 uint8 iv[8]; // leave uninitialized; pseudo-random is cool
177 cryptor.initVector(CssmData::wrap(iv));
178
179 cryptor.key(master);
180 CssmAutoData cipher1(Server::csp().allocator());
181 cryptor.encrypt(probe, cipher1.get(), noRemainder);
182
183 cryptor.key(mMasterKey);
184 CssmAutoData cipher2(Server::csp().allocator());
185 cryptor.encrypt(probe, cipher2.get(), noRemainder);
186
187 return cipher1 == cipher2;
188 }
189
190
191 //
192 // Encode a database blob from the core.
193 //
194 DbBlob *DatabaseCryptoCore::encodeCore(const DbBlob &blobTemplate,
195 const CssmData &publicAcl, const CssmData &privateAcl) const
196 {
197 assert(isValid()); // must have secrets to work from
198
199 // make a new IV
200 uint8 iv[8];
201 Server::active().random(iv);
202
203 // build the encrypted section blob
204 CssmData &encryptionBits = *mEncryptionKey;
205 CssmData &signingBits = *mSigningKey;
206 CssmData incrypt[3];
207 incrypt[0] = encryptionBits;
208 incrypt[1] = signingBits;
209 incrypt[2] = privateAcl;
210 CssmData cryptoBlob, remData;
211 Encrypt cryptor(Server::csp(), CSSM_ALGID_3DES_3KEY_EDE);
212 cryptor.mode(CSSM_ALGMODE_CBCPadIV8);
213 cryptor.padding(CSSM_PADDING_PKCS1);
214 cryptor.key(mMasterKey);
215 CssmData ivd(iv, sizeof(iv)); cryptor.initVector(ivd);
216 cryptor.encrypt(incrypt, 3, &cryptoBlob, 1, remData);
217
218 // allocate the final DbBlob, uh, blob
219 size_t length = sizeof(DbBlob) + publicAcl.length() + cryptoBlob.length();
220 DbBlob *blob = Allocator::standard().malloc<DbBlob>(length);
221
222 // assemble the DbBlob
223 memset(blob, 0x7d, sizeof(DbBlob)); // deterministically fill any alignment gaps
224 blob->initialize(mBlobVersion);
225 blob->randomSignature = blobTemplate.randomSignature;
226 blob->sequence = blobTemplate.sequence;
227 blob->params = blobTemplate.params;
228 memcpy(blob->salt, mSalt, sizeof(blob->salt));
229 memcpy(blob->iv, iv, sizeof(iv));
230 memcpy(blob->publicAclBlob(), publicAcl, publicAcl.length());
231 blob->startCryptoBlob = sizeof(DbBlob) + publicAcl.length();
232 memcpy(blob->cryptoBlob(), cryptoBlob, cryptoBlob.length());
233 blob->totalLength = blob->startCryptoBlob + cryptoBlob.length();
234
235 // sign the blob
236 CssmData signChunk[] = {
237 CssmData(blob->data(), fieldOffsetOf(&DbBlob::blobSignature)),
238 CssmData(blob->publicAclBlob(), publicAcl.length() + cryptoBlob.length())
239 };
240 CssmData signature(blob->blobSignature, sizeof(blob->blobSignature));
241
242 CSSM_ALGORITHMS signingAlgorithm = CSSM_ALGID_SHA1HMAC;
243 #if defined(COMPAT_OSX_10_0)
244 if (blob->version() == blob->version_MacOS_10_0)
245 signingAlgorithm = CSSM_ALGID_SHA1HMAC_LEGACY; // BSafe bug compatibility
246 #endif
247 GenerateMac signer(Server::csp(), signingAlgorithm);
248 signer.key(mSigningKey);
249 signer.sign(signChunk, 2, signature);
250 assert(signature.length() == sizeof(blob->blobSignature));
251
252 // all done. Clean up
253 Server::csp()->allocator().free(cryptoBlob);
254 return blob;
255 }
256
257
258 //
259 // Decode a database blob into the core.
260 // Throws exceptions if decoding fails.
261 // Memory returned in privateAclBlob is allocated and becomes owned by caller.
262 //
263 void DatabaseCryptoCore::decodeCore(const DbBlob *blob, void **privateAclBlob)
264 {
265 assert(mHaveMaster); // must have master key installed
266
267 // try to decrypt the cryptoblob section
268 Decrypt decryptor(Server::csp(), CSSM_ALGID_3DES_3KEY_EDE);
269 decryptor.mode(CSSM_ALGMODE_CBCPadIV8);
270 decryptor.padding(CSSM_PADDING_PKCS1);
271 decryptor.key(mMasterKey);
272 CssmData ivd = CssmData::wrap(blob->iv); decryptor.initVector(ivd);
273 CssmData cryptoBlob = CssmData::wrap(blob->cryptoBlob(), blob->cryptoBlobLength());
274 CssmData decryptedBlob, remData;
275 decryptor.decrypt(cryptoBlob, decryptedBlob, remData);
276 DbBlob::PrivateBlob *privateBlob = decryptedBlob.interpretedAs<DbBlob::PrivateBlob>();
277
278 // tentatively establish keys
279 mEncryptionKey = makeRawKey(privateBlob->encryptionKey,
280 sizeof(privateBlob->encryptionKey), CSSM_ALGID_3DES_3KEY_EDE,
281 CSSM_KEYUSE_WRAP | CSSM_KEYUSE_UNWRAP);
282 mSigningKey = makeRawKey(privateBlob->signingKey,
283 sizeof(privateBlob->signingKey), CSSM_ALGID_SHA1HMAC,
284 CSSM_KEYUSE_SIGN | CSSM_KEYUSE_VERIFY);
285
286 // verify signature on the whole blob
287 CssmData signChunk[] = {
288 CssmData::wrap(blob->data(), fieldOffsetOf(&DbBlob::blobSignature)),
289 CssmData::wrap(blob->publicAclBlob(), blob->publicAclBlobLength() + blob->cryptoBlobLength())
290 };
291 CSSM_ALGORITHMS verifyAlgorithm = CSSM_ALGID_SHA1HMAC;
292 #if defined(COMPAT_OSX_10_0)
293 if (blob->version() == blob->version_MacOS_10_0)
294 verifyAlgorithm = CSSM_ALGID_SHA1HMAC_LEGACY; // BSafe bug compatibility
295 #endif
296 VerifyMac verifier(Server::csp(), verifyAlgorithm);
297 verifier.key(mSigningKey);
298 verifier.verify(signChunk, 2, CssmData::wrap(blob->blobSignature));
299
300 // all checks out; start extracting fields
301 if (privateAclBlob) {
302 // extract private ACL blob as a separately allocated area
303 uint32 blobLength = decryptedBlob.length() - sizeof(DbBlob::PrivateBlob);
304 *privateAclBlob = Allocator::standard().malloc(blobLength);
305 memcpy(*privateAclBlob, privateBlob->privateAclBlob(), blobLength);
306 }
307
308 // secrets have been established
309 mBlobVersion = blob->version();
310 mIsValid = true;
311 Allocator::standard().free(privateBlob);
312 }
313
314
315 //
316 // Make another DatabaseCryptoCore's operational secrets our own.
317 // Intended for keychain synchronization.
318 //
319 void DatabaseCryptoCore::importSecrets(const DatabaseCryptoCore &src)
320 {
321 assert(src.isValid()); // must have called src.decodeCore() first
322 assert(hasMaster());
323 mEncryptionKey = src.mEncryptionKey;
324 mSigningKey = src.mSigningKey;
325 mBlobVersion = src.mBlobVersion; // make sure we copy over all state
326 mIsValid = true;
327 }
328
329 //
330 // Encode a key blob
331 //
332 KeyBlob *DatabaseCryptoCore::encodeKeyCore(const CssmKey &inKey,
333 const CssmData &publicAcl, const CssmData &privateAcl,
334 bool inTheClear) const
335 {
336 CssmKey key = inKey;
337 uint8 iv[8];
338 CssmKey wrappedKey;
339
340 if(inTheClear && (privateAcl.Length != 0)) {
341 /* can't store private ACL component in the clear */
342 CssmError::throwMe(CSSMERR_DL_INVALID_ACCESS_CREDENTIALS);
343 }
344
345 // extract and hold some header bits the CSP does not want to see
346 uint32 heldAttributes = key.attributes() & managedAttributes;
347 key.clearAttribute(managedAttributes);
348 key.setAttribute(forcedAttributes);
349
350 if(inTheClear) {
351 /* NULL wrap of public key */
352 WrapKey wrap(Server::csp(), CSSM_ALGID_NONE);
353 wrap(key, wrappedKey, NULL);
354 }
355 else {
356 assert(isValid()); // need our database secrets
357
358 // create new IV
359 Server::active().random(iv);
360
361 // use a CMS wrap to encrypt the key
362 WrapKey wrap(Server::csp(), CSSM_ALGID_3DES_3KEY_EDE);
363 wrap.key(mEncryptionKey);
364 wrap.mode(CSSM_ALGMODE_CBCPadIV8);
365 wrap.padding(CSSM_PADDING_PKCS1);
366 CssmData ivd(iv, sizeof(iv)); wrap.initVector(ivd);
367 wrap.add(CSSM_ATTRIBUTE_WRAPPED_KEY_FORMAT,
368 uint32(CSSM_KEYBLOB_WRAPPED_FORMAT_APPLE_CUSTOM));
369 wrap(key, wrappedKey, &privateAcl);
370 }
371
372 // stick the held attribute bits back in
373 key.clearAttribute(forcedAttributes);
374 key.setAttribute(heldAttributes);
375
376 // allocate the final KeyBlob, uh, blob
377 size_t length = sizeof(KeyBlob) + publicAcl.length() + wrappedKey.length();
378 KeyBlob *blob = Allocator::standard().malloc<KeyBlob>(length);
379
380 // assemble the KeyBlob
381 memset(blob, 0, sizeof(KeyBlob)); // fill alignment gaps
382 blob->initialize(mBlobVersion);
383 if(!inTheClear) {
384 memcpy(blob->iv, iv, sizeof(iv));
385 }
386 blob->header = key.header();
387 h2ni(blob->header); // endian-correct the header
388 blob->wrappedHeader.blobType = wrappedKey.blobType();
389 blob->wrappedHeader.blobFormat = wrappedKey.blobFormat();
390 blob->wrappedHeader.wrapAlgorithm = wrappedKey.wrapAlgorithm();
391 blob->wrappedHeader.wrapMode = wrappedKey.wrapMode();
392 memcpy(blob->publicAclBlob(), publicAcl, publicAcl.length());
393 blob->startCryptoBlob = sizeof(KeyBlob) + publicAcl.length();
394 memcpy(blob->cryptoBlob(), wrappedKey.data(), wrappedKey.length());
395 blob->totalLength = blob->startCryptoBlob + wrappedKey.length();
396
397 if(inTheClear) {
398 /* indicate that this is cleartext for decoding */
399 blob->setClearTextSignature();
400 }
401 else {
402 // sign the blob
403 CssmData signChunk[] = {
404 CssmData(blob->data(), fieldOffsetOf(&KeyBlob::blobSignature)),
405 CssmData(blob->publicAclBlob(), blob->publicAclBlobLength() + blob->cryptoBlobLength())
406 };
407 CssmData signature(blob->blobSignature, sizeof(blob->blobSignature));
408
409 CSSM_ALGORITHMS signingAlgorithm = CSSM_ALGID_SHA1HMAC;
410 #if defined(COMPAT_OSX_10_0)
411 if (blob->version() == blob->version_MacOS_10_0)
412 signingAlgorithm = CSSM_ALGID_SHA1HMAC_LEGACY; // BSafe bug compatibility
413 #endif
414 GenerateMac signer(Server::csp(), signingAlgorithm);
415 signer.key(mSigningKey);
416 signer.sign(signChunk, 2, signature);
417 assert(signature.length() == sizeof(blob->blobSignature));
418 }
419
420 // all done. Clean up
421 Server::csp()->allocator().free(wrappedKey);
422 return blob;
423 }
424
425
426 //
427 // Decode a key blob
428 //
429 void DatabaseCryptoCore::decodeKeyCore(KeyBlob *blob,
430 CssmKey &key, void * &pubAcl, void * &privAcl) const
431 {
432 // Note that we can't do anything with this key's version().
433
434 // Assemble the encrypted blob as a CSSM "wrapped key"
435 CssmKey wrappedKey;
436 wrappedKey.KeyHeader = blob->header;
437 h2ni(wrappedKey.KeyHeader);
438 wrappedKey.blobType(blob->wrappedHeader.blobType);
439 wrappedKey.blobFormat(blob->wrappedHeader.blobFormat);
440 wrappedKey.wrapAlgorithm(blob->wrappedHeader.wrapAlgorithm);
441 wrappedKey.wrapMode(blob->wrappedHeader.wrapMode);
442 wrappedKey.KeyData = CssmData(blob->cryptoBlob(), blob->cryptoBlobLength());
443
444 bool inTheClear = blob->isClearText();
445 if(!inTheClear) {
446 // verify signature (check against corruption)
447 assert(isValid()); // need our database secrets
448 CssmData signChunk[] = {
449 CssmData::wrap(blob, fieldOffsetOf(&KeyBlob::blobSignature)),
450 CssmData(blob->publicAclBlob(), blob->publicAclBlobLength() + blob->cryptoBlobLength())
451 };
452 CSSM_ALGORITHMS verifyAlgorithm = CSSM_ALGID_SHA1HMAC;
453 #if defined(COMPAT_OSX_10_0)
454 if (blob->version() == blob->version_MacOS_10_0)
455 verifyAlgorithm = CSSM_ALGID_SHA1HMAC_LEGACY; // BSafe bug compatibility
456 #endif
457 VerifyMac verifier(Server::csp(), verifyAlgorithm);
458 verifier.key(mSigningKey);
459 CssmData signature(blob->blobSignature, sizeof(blob->blobSignature));
460 verifier.verify(signChunk, 2, signature);
461 }
462 /* else signature indicates cleartext */
463
464 // extract and hold some header bits the CSP does not want to see
465 uint32 heldAttributes = n2h(blob->header.attributes()) & managedAttributes;
466
467 CssmData privAclData;
468 if(inTheClear) {
469 /* NULL unwrap */
470 UnwrapKey unwrap(Server::csp(), CSSM_ALGID_NONE);
471 wrappedKey.clearAttribute(managedAttributes); //@@@ shouldn't be needed(?)
472 unwrap(wrappedKey,
473 KeySpec(n2h(blob->header.usage()),
474 (n2h(blob->header.attributes()) & ~managedAttributes) | forcedAttributes),
475 key, &privAclData);
476 }
477 else {
478 // decrypt the key using an unwrapping operation
479 UnwrapKey unwrap(Server::csp(), CSSM_ALGID_3DES_3KEY_EDE);
480 unwrap.key(mEncryptionKey);
481 unwrap.mode(CSSM_ALGMODE_CBCPadIV8);
482 unwrap.padding(CSSM_PADDING_PKCS1);
483 CssmData ivd(blob->iv, sizeof(blob->iv)); unwrap.initVector(ivd);
484 unwrap.add(CSSM_ATTRIBUTE_WRAPPED_KEY_FORMAT,
485 uint32(CSSM_KEYBLOB_WRAPPED_FORMAT_APPLE_CUSTOM));
486 wrappedKey.clearAttribute(managedAttributes); //@@@ shouldn't be needed(?)
487 unwrap(wrappedKey,
488 KeySpec(n2h(blob->header.usage()),
489 (n2h(blob->header.attributes()) & ~managedAttributes) | forcedAttributes),
490 key, &privAclData);
491 }
492
493 // compare retrieved key headers with blob headers (sanity check)
494 // @@@ this should probably be checked over carefully
495 CssmKey::Header &real = key.header();
496 CssmKey::Header &incoming = blob->header;
497 n2hi(incoming);
498
499 if (real.HeaderVersion != incoming.HeaderVersion ||
500 real.cspGuid() != incoming.cspGuid())
501 CssmError::throwMe(CSSMERR_CSP_INVALID_KEY);
502 if (real.algorithm() != incoming.algorithm())
503 CssmError::throwMe(CSSMERR_CSP_INVALID_ALGORITHM);
504
505 // re-insert held bits
506 key.header().KeyAttr |= heldAttributes;
507
508 if(inTheClear && (real.keyClass() != CSSM_KEYCLASS_PUBLIC_KEY)) {
509 /* Spoof - cleartext KeyBlob passed off as private key */
510 CssmError::throwMe(CSSMERR_CSP_INVALID_KEY);
511 }
512
513 // got a valid key: return the pieces
514 pubAcl = blob->publicAclBlob(); // points into blob (shared)
515 privAcl = privAclData; // was allocated by CSP decrypt, else NULL for
516 // cleatext keys
517 // key was set by unwrap operation
518 }
519
520
521 //
522 // Derive the blob-specific database blob encryption key from the passphrase and the salt.
523 //
524 CssmClient::Key DatabaseCryptoCore::deriveDbMasterKey(const CssmData &passphrase) const
525 {
526 // derive an encryption key and IV from passphrase and salt
527 CssmClient::DeriveKey makeKey(Server::csp(),
528 CSSM_ALGID_PKCS5_PBKDF2, CSSM_ALGID_3DES_3KEY_EDE, 24 * 8);
529 makeKey.iterationCount(1000);
530 CssmData salt = CssmData::wrap(mSalt);
531 makeKey.salt(salt);
532 CSSM_PKCS5_PBKDF2_PARAMS params;
533 params.Passphrase = passphrase;
534 params.PseudoRandomFunction = CSSM_PKCS5_PBKDF2_PRF_HMAC_SHA1;
535 CssmData paramData = CssmData::wrap(params);
536 return makeKey(&paramData, KeySpec(CSSM_KEYUSE_ENCRYPT | CSSM_KEYUSE_DECRYPT,
537 CSSM_KEYATTR_RETURN_DATA | CSSM_KEYATTR_EXTRACTABLE));
538 }
539
540
541 //
542 // Turn raw keybits into a symmetric key in the CSP
543 //
544 CssmClient::Key DatabaseCryptoCore::makeRawKey(void *data, size_t length,
545 CSSM_ALGORITHMS algid, CSSM_KEYUSE usage)
546 {
547 // build a fake key
548 CssmKey key;
549 key.header().BlobType = CSSM_KEYBLOB_RAW;
550 key.header().Format = CSSM_KEYBLOB_RAW_FORMAT_OCTET_STRING;
551 key.header().AlgorithmId = algid;
552 key.header().KeyClass = CSSM_KEYCLASS_SESSION_KEY;
553 key.header().KeyUsage = usage;
554 key.header().KeyAttr = 0;
555 key.KeyData = CssmData(data, length);
556
557 // unwrap it into the CSP (but keep it raw)
558 UnwrapKey unwrap(Server::csp(), CSSM_ALGID_NONE);
559 CssmKey unwrappedKey;
560 CssmData descriptiveData;
561 unwrap(key,
562 KeySpec(CSSM_KEYUSE_ANY, CSSM_KEYATTR_RETURN_DATA | CSSM_KEYATTR_EXTRACTABLE),
563 unwrappedKey, &descriptiveData, NULL);
564 return CssmClient::Key(Server::csp(), unwrappedKey);
565 }