2  * Copyright (c) 2000-2006,2013 Apple Inc. All Rights Reserved. 
   4  * @APPLE_LICENSE_HEADER_START@ 
   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 
  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. 
  21  * @APPLE_LICENSE_HEADER_END@ 
  26 // dbcrypto - cryptographic core for database and key blob cryptography 
  29 #include "SecRandom.h" 
  30 #include <security_utilities/casts.h> 
  31 #include <securityd_client/ssblob.h> 
  32 #include "server.h"             // just for Server::csp() 
  33 #include <security_cdsa_client/genkey.h> 
  34 #include <security_cdsa_client/cryptoclient.h> 
  35 #include <security_cdsa_client/keyclient.h> 
  36 #include <security_cdsa_client/macclient.h> 
  37 #include <security_cdsa_client/wrapkey.h> 
  38 #include <security_cdsa_utilities/cssmendian.h> 
  40 using namespace CssmClient
; 
  41 using LowLevelMemoryUtilities::fieldOffsetOf
; 
  45 // The CryptoCore constructor doesn't do anything interesting. 
  46 // It just initializes us to "empty". 
  48 DatabaseCryptoCore::DatabaseCryptoCore(uint32 requestedVersion
) : mBlobVersion(CommonBlob::version_MacOS_10_0
), mHaveMaster(false), mIsValid(false) 
  50     // If there's a specific version our callers want, give them that. Otherwise, ask CommonBlob what to do. 
  51     if(requestedVersion 
== CommonBlob::version_none
) { 
  52         mBlobVersion 
= CommonBlob::getCurrentVersion(); 
  54         mBlobVersion 
= requestedVersion
; 
  58 DatabaseCryptoCore::~DatabaseCryptoCore() 
  60     // key objects take care of themselves 
  67 void DatabaseCryptoCore::invalidate() 
  72         mEncryptionKey
.release(); 
  73         mSigningKey
.release(); 
  78 // Copy everything from another databasecryptocore 
  80 void DatabaseCryptoCore::initializeFrom(DatabaseCryptoCore
& core
, uint32 requestedVersion
) { 
  81     if(core
.hasMaster()) { 
  82         mMasterKey 
= core
.mMasterKey
; 
  83         memcpy(mSalt
, core
.mSalt
, sizeof(mSalt
)); 
  84         mHaveMaster 
= core
.mHaveMaster
; 
  95     // As the last thing we do, check if we should be changing the version of this blob. 
  96     if(requestedVersion 
== CommonBlob::version_none
) { 
  97         mBlobVersion 
= core
.mBlobVersion
; 
  99         mBlobVersion 
= requestedVersion
; 
 104 // Generate new secrets for this crypto core. 
 106 void DatabaseCryptoCore::generateNewSecrets() 
 108     // create a random DES3 key 
 109     GenerateKey 
desGenerator(Server::csp(), CSSM_ALGID_3DES_3KEY_EDE
, 24 * 8); 
 110     mEncryptionKey 
= desGenerator(KeySpec(CSSM_KEYUSE_WRAP 
| CSSM_KEYUSE_UNWRAP
, 
 111         CSSM_KEYATTR_RETURN_DATA 
| CSSM_KEYATTR_EXTRACTABLE
)); 
 113     // create a random 20 byte HMAC/SHA1 signing "key" 
 114     GenerateKey 
signGenerator(Server::csp(), CSSM_ALGID_SHA1HMAC
, 
 115         sizeof(DbBlob::PrivateBlob::SigningKey
) * 8); 
 116     mSigningKey 
= signGenerator(KeySpec(CSSM_KEYUSE_SIGN 
| CSSM_KEYUSE_VERIFY
, 
 117         CSSM_KEYATTR_RETURN_DATA 
| CSSM_KEYATTR_EXTRACTABLE
)); 
 119     // secrets established 
 124 CssmClient::Key 
DatabaseCryptoCore::masterKey() 
 132 // Establish the master secret as derived from a passphrase passed in. 
 133 // If a DbBlob is passed, take the salt from it and remember it. 
 134 // If a NULL DbBlob is passed, generate a new (random) salt. 
 135 // Note that the passphrase is NOT remembered; only the master key. 
 137 void DatabaseCryptoCore::setup(const DbBlob 
*blob
, const CssmData 
&passphrase
, bool copyVersion 
/* = true */) 
 141             mBlobVersion 
= blob
->version(); 
 143         memcpy(mSalt
, blob
->salt
, sizeof(mSalt
)); 
 145         MacOSError::check(SecRandomCopyBytes(kSecRandomDefault
, sizeof(mSalt
), mSalt
)); 
 148     mMasterKey 
= deriveDbMasterKey(passphrase
); 
 154 // Establish the master secret directly from a master key passed in. 
 155 // We will copy the KeyData (caller still owns its copy). 
 156 // Blob/salt handling as above. 
 158 void DatabaseCryptoCore::setup(const DbBlob 
*blob
, CssmClient::Key master
, bool copyVersion 
/* = true */) 
 160         // pre-screen the key 
 161         CssmKey::Header header 
= master
.header(); 
 162         if (header
.keyClass() != CSSM_KEYCLASS_SESSION_KEY
) 
 163                 CssmError::throwMe(CSSMERR_CSP_INVALID_KEY_CLASS
); 
 164         if (header
.algorithm() != CSSM_ALGID_3DES_3KEY_EDE
) 
 165                 CssmError::throwMe(CSSMERR_CSP_INVALID_ALGORITHM
); 
 170             mBlobVersion 
= blob
->version(); 
 172         memcpy(mSalt
, blob
->salt
, sizeof(mSalt
)); 
 174         MacOSError::check(SecRandomCopyBytes(kSecRandomDefault
, sizeof(mSalt
), mSalt
)); 
 180 bool DatabaseCryptoCore::get_encryption_key(CssmOwnedData 
&data
) 
 184         data 
= mEncryptionKey
->keyData(); 
 191 // Given a putative passphrase, determine whether that passphrase 
 192 // properly generates the database's master secret. 
 193 // Return a boolean accordingly. Do not change our state. 
 194 // The database must have a master secret (to compare with). 
 195 // Note that any errors thrown by the cryptography here will actually 
 196 // throw out of validatePassphrase, since they "should not happen" and 
 197 // thus indicate a problem *beyond* (just) a bad passphrase. 
 199 bool DatabaseCryptoCore::validatePassphrase(const CssmData 
&passphrase
) 
 201         CssmClient::Key master 
= deriveDbMasterKey(passphrase
); 
 202     return validateKey(master
); 
 205 bool DatabaseCryptoCore::validateKey(const CssmClient::Key
& master
) { 
 207         // to compare master with mMaster, see if they encrypt alike 
 209                 ("Now is the time for all good processes to come to the aid of their kernel."); 
 210         CssmData 
noRemainder((void *)1, 0);     // no cipher overflow 
 211         Encrypt 
cryptor(Server::csp(), CSSM_ALGID_3DES_3KEY_EDE
); 
 212         cryptor
.mode(CSSM_ALGMODE_CBCPadIV8
); 
 213         cryptor
.padding(CSSM_PADDING_PKCS1
); 
 214         uint8 iv
[8];    // leave uninitialized; pseudo-random is cool 
 215     CssmData ivData 
= CssmData::wrap(iv
); 
 216         cryptor
.initVector(ivData
); 
 219         CssmAutoData 
cipher1(Server::csp().allocator()); 
 220         cryptor
.encrypt(probe
, cipher1
.get(), noRemainder
); 
 222         cryptor
.key(mMasterKey
); 
 223         CssmAutoData 
cipher2(Server::csp().allocator()); 
 224         cryptor
.encrypt(probe
, cipher2
.get(), noRemainder
); 
 226         return cipher1 
== cipher2
; 
 231 // Encode a database blob from the core. 
 233 DbBlob 
*DatabaseCryptoCore::encodeCore(const DbBlob 
&blobTemplate
, 
 234     const CssmData 
&publicAcl
, const CssmData 
&privateAcl
) const 
 236     assert(isValid());          // must have secrets to work from 
 240     MacOSError::check(SecRandomCopyBytes(kSecRandomDefault
, sizeof(iv
), iv
)); 
 242     // build the encrypted section blob 
 243     CssmData 
&encryptionBits 
= *mEncryptionKey
; 
 244     CssmData 
&signingBits 
= *mSigningKey
; 
 246     incrypt
[0] = encryptionBits
; 
 247     incrypt
[1] = signingBits
; 
 248     incrypt
[2] = privateAcl
; 
 249     CssmData cryptoBlob
, remData
; 
 250     Encrypt 
cryptor(Server::csp(), CSSM_ALGID_3DES_3KEY_EDE
); 
 251     cryptor
.mode(CSSM_ALGMODE_CBCPadIV8
); 
 252     cryptor
.padding(CSSM_PADDING_PKCS1
); 
 253     cryptor
.key(mMasterKey
); 
 254     CssmData 
ivd(iv
, sizeof(iv
)); cryptor
.initVector(ivd
); 
 255     cryptor
.encrypt(incrypt
, 3, &cryptoBlob
, 1, remData
); 
 257     // allocate the final DbBlob, uh, blob 
 258     size_t length 
= sizeof(DbBlob
) + publicAcl
.length() + cryptoBlob
.length(); 
 259     DbBlob 
*blob 
= Allocator::standard().malloc
<DbBlob
>(length
); 
 261     // assemble the DbBlob 
 262     memset(blob
, 0x7d, sizeof(DbBlob
)); // deterministically fill any alignment gaps 
 263     blob
->initialize(mBlobVersion
); 
 264     blob
->randomSignature 
= blobTemplate
.randomSignature
; 
 265     blob
->sequence 
= blobTemplate
.sequence
; 
 266     blob
->params 
= blobTemplate
.params
; 
 267         memcpy(blob
->salt
, mSalt
, sizeof(blob
->salt
)); 
 268     memcpy(blob
->iv
, iv
, sizeof(iv
)); 
 269     memcpy(blob
->publicAclBlob(), publicAcl
, publicAcl
.length()); 
 270     blob
->startCryptoBlob 
= sizeof(DbBlob
) + int_cast
<size_t, uint32_t>(publicAcl
.length()); 
 271     memcpy(blob
->cryptoBlob(), cryptoBlob
, cryptoBlob
.length()); 
 272     blob
->totalLength 
= blob
->startCryptoBlob 
+ int_cast
<size_t, uint32_t>(cryptoBlob
.length()); 
 275     CssmData signChunk
[] = { 
 276                 CssmData(blob
->data(), fieldOffsetOf(&DbBlob::blobSignature
)), 
 277                 CssmData(blob
->publicAclBlob(), publicAcl
.length() + cryptoBlob
.length()) 
 279     CssmData 
signature(blob
->blobSignature
, sizeof(blob
->blobSignature
)); 
 281     CSSM_ALGORITHMS signingAlgorithm 
= CSSM_ALGID_SHA1HMAC
; 
 282 #if defined(COMPAT_OSX_10_0) 
 283     if (blob
->version() == blob
->version_MacOS_10_0
) 
 284         signingAlgorithm 
= CSSM_ALGID_SHA1HMAC_LEGACY
;  // BSafe bug compatibility 
 286     GenerateMac 
signer(Server::csp(), signingAlgorithm
); 
 287     signer
.key(mSigningKey
); 
 288     signer
.sign(signChunk
, 2, signature
); 
 289     assert(signature
.length() == sizeof(blob
->blobSignature
)); 
 291     // all done. Clean up 
 292     Server::csp()->allocator().free(cryptoBlob
); 
 298 // Decode a database blob into the core. 
 299 // Throws exceptions if decoding fails. 
 300 // Memory returned in privateAclBlob is allocated and becomes owned by caller. 
 302 void DatabaseCryptoCore::decodeCore(const DbBlob 
*blob
, void **privateAclBlob
) 
 304         assert(mHaveMaster
);    // must have master key installed 
 306     // try to decrypt the cryptoblob section 
 307     Decrypt 
decryptor(Server::csp(), CSSM_ALGID_3DES_3KEY_EDE
); 
 308     decryptor
.mode(CSSM_ALGMODE_CBCPadIV8
); 
 309     decryptor
.padding(CSSM_PADDING_PKCS1
); 
 310     decryptor
.key(mMasterKey
); 
 311     CssmData ivd 
= CssmData::wrap(blob
->iv
); decryptor
.initVector(ivd
); 
 312     CssmData cryptoBlob 
= CssmData::wrap(blob
->cryptoBlob(), blob
->cryptoBlobLength()); 
 313     CssmData decryptedBlob
, remData
; 
 314     decryptor
.decrypt(cryptoBlob
, decryptedBlob
, remData
); 
 315     DbBlob::PrivateBlob 
*privateBlob 
= decryptedBlob
.interpretedAs
<DbBlob::PrivateBlob
>(); 
 317     // tentatively establish keys 
 318     mEncryptionKey 
= makeRawKey(privateBlob
->encryptionKey
, 
 319         sizeof(privateBlob
->encryptionKey
), CSSM_ALGID_3DES_3KEY_EDE
, 
 320         CSSM_KEYUSE_WRAP 
| CSSM_KEYUSE_UNWRAP
); 
 321     mSigningKey 
= makeRawKey(privateBlob
->signingKey
, 
 322         sizeof(privateBlob
->signingKey
), CSSM_ALGID_SHA1HMAC
, 
 323         CSSM_KEYUSE_SIGN 
| CSSM_KEYUSE_VERIFY
); 
 325     // verify signature on the whole blob 
 326     CssmData signChunk
[] = { 
 327                 CssmData::wrap(blob
->data(), fieldOffsetOf(&DbBlob::blobSignature
)), 
 328         CssmData::wrap(blob
->publicAclBlob(), blob
->publicAclBlobLength() + blob
->cryptoBlobLength()) 
 330     CSSM_ALGORITHMS verifyAlgorithm 
= CSSM_ALGID_SHA1HMAC
; 
 331 #if defined(COMPAT_OSX_10_0) 
 332     if (blob
->version() == blob
->version_MacOS_10_0
) 
 333         verifyAlgorithm 
= CSSM_ALGID_SHA1HMAC_LEGACY
;   // BSafe bug compatibility 
 335     VerifyMac 
verifier(Server::csp(), verifyAlgorithm
); 
 336     verifier
.key(mSigningKey
); 
 337     verifier
.verify(signChunk
, 2, CssmData::wrap(blob
->blobSignature
)); 
 339     // all checks out; start extracting fields 
 340     if (privateAclBlob
) { 
 341         // extract private ACL blob as a separately allocated area 
 342         uint32 blobLength 
= (uint32
) decryptedBlob
.length() - sizeof(DbBlob::PrivateBlob
); 
 343         *privateAclBlob 
= Allocator::standard().malloc(blobLength
); 
 344         memcpy(*privateAclBlob
, privateBlob
->privateAclBlob(), blobLength
); 
 347     // secrets have been established 
 348     mBlobVersion 
= blob
->version(); 
 350     Allocator::standard().free(privateBlob
); 
 355 // Make another DatabaseCryptoCore's operational secrets our own.   
 356 // Intended for keychain synchronization.   
 358 void DatabaseCryptoCore::importSecrets(const DatabaseCryptoCore 
&src
) 
 360         assert(src
.isValid());  // must have called src.decodeCore() first 
 362         mEncryptionKey 
= src
.mEncryptionKey
; 
 363         mSigningKey 
= src
.mSigningKey
; 
 364     mBlobVersion 
= src
.mBlobVersion
;    // make sure we copy over all state 
 371 KeyBlob 
*DatabaseCryptoCore::encodeKeyCore(const CssmKey 
&inKey
, 
 372     const CssmData 
&publicAcl
, const CssmData 
&privateAcl
, 
 373         bool inTheClear
) const 
 379         if(inTheClear 
&& (privateAcl
.Length 
!= 0)) { 
 380                 /* can't store private ACL component in the clear */ 
 381                 CssmError::throwMe(CSSMERR_DL_INVALID_ACCESS_CREDENTIALS
); 
 384     // extract and hold some header bits the CSP does not want to see 
 385     uint32 heldAttributes 
= key
.attributes() & managedAttributes
; 
 386     key
.clearAttribute(managedAttributes
); 
 387         key
.setAttribute(forcedAttributes
); 
 390                 /* NULL wrap of public key */ 
 391                 WrapKey 
wrap(Server::csp(), CSSM_ALGID_NONE
); 
 392                 wrap(key
, wrappedKey
, NULL
); 
 395                 assert(isValid());              // need our database secrets 
 398         MacOSError::check(SecRandomCopyBytes(kSecRandomDefault
, sizeof(iv
), iv
)); 
 400            // use a CMS wrap to encrypt the key 
 401                 WrapKey 
wrap(Server::csp(), CSSM_ALGID_3DES_3KEY_EDE
); 
 402                 wrap
.key(mEncryptionKey
); 
 403                 wrap
.mode(CSSM_ALGMODE_CBCPadIV8
); 
 404                 wrap
.padding(CSSM_PADDING_PKCS1
); 
 405                 CssmData 
ivd(iv
, sizeof(iv
)); wrap
.initVector(ivd
); 
 406                 wrap
.add(CSSM_ATTRIBUTE_WRAPPED_KEY_FORMAT
, 
 407                         uint32(CSSM_KEYBLOB_WRAPPED_FORMAT_APPLE_CUSTOM
)); 
 408                 wrap(key
, wrappedKey
, &privateAcl
); 
 411     // stick the held attribute bits back in 
 412         key
.clearAttribute(forcedAttributes
); 
 413     key
.setAttribute(heldAttributes
); 
 415     // allocate the final KeyBlob, uh, blob 
 416     size_t length 
= sizeof(KeyBlob
) + publicAcl
.length() + wrappedKey
.length(); 
 417     KeyBlob 
*blob 
= Allocator::standard().malloc
<KeyBlob
>(length
); 
 419     // assemble the KeyBlob 
 420     memset(blob
, 0, sizeof(KeyBlob
));   // fill alignment gaps 
 421     blob
->initialize(mBlobVersion
); 
 423                 memcpy(blob
->iv
, iv
, sizeof(iv
)); 
 425     blob
->header 
= key
.header(); 
 426         h2ni(blob
->header
);     // endian-correct the header 
 427     blob
->wrappedHeader
.blobType 
= wrappedKey
.blobType(); 
 428     blob
->wrappedHeader
.blobFormat 
= wrappedKey
.blobFormat(); 
 429     blob
->wrappedHeader
.wrapAlgorithm 
= wrappedKey
.wrapAlgorithm(); 
 430     blob
->wrappedHeader
.wrapMode 
= wrappedKey
.wrapMode(); 
 431     memcpy(blob
->publicAclBlob(), publicAcl
, publicAcl
.length()); 
 432     blob
->startCryptoBlob 
= sizeof(KeyBlob
) + int_cast
<size_t, uint32_t>(publicAcl
.length()); 
 433     memcpy(blob
->cryptoBlob(), wrappedKey
.data(), wrappedKey
.length()); 
 434     blob
->totalLength 
= blob
->startCryptoBlob 
+ int_cast
<size_t, uint32_t>(wrappedKey
.length()); 
 437                 /* indicate that this is cleartext for decoding */ 
 438                 blob
->setClearTextSignature(); 
 442                 CssmData signChunk
[] = { 
 443                         CssmData(blob
->data(), fieldOffsetOf(&KeyBlob::blobSignature
)), 
 444                         CssmData(blob
->publicAclBlob(), blob
->publicAclBlobLength() + blob
->cryptoBlobLength()) 
 446                 CssmData 
signature(blob
->blobSignature
, sizeof(blob
->blobSignature
)); 
 448         CSSM_ALGORITHMS signingAlgorithm 
= CSSM_ALGID_SHA1HMAC
; 
 449 #if defined(COMPAT_OSX_10_0) 
 450         if (blob
->version() == blob
->version_MacOS_10_0
) 
 451             signingAlgorithm 
= CSSM_ALGID_SHA1HMAC_LEGACY
;      // BSafe bug compatibility 
 453         GenerateMac 
signer(Server::csp(), signingAlgorithm
); 
 454                 signer
.key(mSigningKey
); 
 455                 signer
.sign(signChunk
, 2, signature
); 
 456                 assert(signature
.length() == sizeof(blob
->blobSignature
)); 
 459     // all done. Clean up 
 460     Server::csp()->allocator().free(wrappedKey
); 
 468 void DatabaseCryptoCore::decodeKeyCore(KeyBlob 
*blob
, 
 469     CssmKey 
&key
, void * &pubAcl
, void * &privAcl
) const 
 471     // Note that we can't do anything with this key's version(). 
 473     // Assemble the encrypted blob as a CSSM "wrapped key" 
 475     wrappedKey
.KeyHeader 
= blob
->header
; 
 476         h2ni(wrappedKey
.KeyHeader
); 
 477     wrappedKey
.blobType(blob
->wrappedHeader
.blobType
); 
 478     wrappedKey
.blobFormat(blob
->wrappedHeader
.blobFormat
); 
 479     wrappedKey
.wrapAlgorithm(blob
->wrappedHeader
.wrapAlgorithm
); 
 480     wrappedKey
.wrapMode(blob
->wrappedHeader
.wrapMode
); 
 481     wrappedKey
.KeyData 
= CssmData(blob
->cryptoBlob(), blob
->cryptoBlobLength()); 
 483         bool inTheClear 
= blob
->isClearText(); 
 485                 // verify signature (check against corruption) 
 486                 assert(isValid());              // need our database secrets 
 487                 CssmData signChunk
[] = { 
 488                         CssmData::wrap(blob
, fieldOffsetOf(&KeyBlob::blobSignature
)), 
 489                         CssmData(blob
->publicAclBlob(), blob
->publicAclBlobLength() + blob
->cryptoBlobLength()) 
 491                 CSSM_ALGORITHMS verifyAlgorithm 
= CSSM_ALGID_SHA1HMAC
; 
 492         #if defined(COMPAT_OSX_10_0) 
 493                 if (blob
->version() == blob
->version_MacOS_10_0
) 
 494                         verifyAlgorithm 
= CSSM_ALGID_SHA1HMAC_LEGACY
;   // BSafe bug compatibility 
 496                 VerifyMac 
verifier(Server::csp(), verifyAlgorithm
); 
 497                 verifier
.key(mSigningKey
); 
 498                 CssmData 
signature(blob
->blobSignature
, sizeof(blob
->blobSignature
)); 
 499                 verifier
.verify(signChunk
, 2, signature
); 
 501         /* else signature indicates cleartext */ 
 503     // extract and hold some header bits the CSP does not want to see 
 504     uint32 heldAttributes 
= n2h(blob
->header
.attributes()) & managedAttributes
; 
 506         CssmData privAclData
; 
 509                 UnwrapKey 
unwrap(Server::csp(), CSSM_ALGID_NONE
); 
 510                 wrappedKey
.clearAttribute(managedAttributes
);    //@@@ shouldn't be needed(?) 
 512                         KeySpec(n2h(blob
->header
.usage()), 
 513                                 (n2h(blob
->header
.attributes()) & ~managedAttributes
) | forcedAttributes
), 
 517                 // decrypt the key using an unwrapping operation 
 518                 UnwrapKey 
unwrap(Server::csp(), CSSM_ALGID_3DES_3KEY_EDE
); 
 519                 unwrap
.key(mEncryptionKey
); 
 520                 unwrap
.mode(CSSM_ALGMODE_CBCPadIV8
); 
 521                 unwrap
.padding(CSSM_PADDING_PKCS1
); 
 522                 CssmData 
ivd(blob
->iv
, sizeof(blob
->iv
)); unwrap
.initVector(ivd
); 
 523                 unwrap
.add(CSSM_ATTRIBUTE_WRAPPED_KEY_FORMAT
, 
 524                         uint32(CSSM_KEYBLOB_WRAPPED_FORMAT_APPLE_CUSTOM
)); 
 525                 wrappedKey
.clearAttribute(managedAttributes
);    //@@@ shouldn't be needed(?) 
 527                         KeySpec(n2h(blob
->header
.usage()), 
 528                                 (n2h(blob
->header
.attributes()) & ~managedAttributes
) | forcedAttributes
), 
 532     // compare retrieved key headers with blob headers (sanity check) 
 533     // @@@ this should probably be checked over carefully 
 534     CssmKey::Header 
&real 
= key
.header(); 
 535     CssmKey::Header 
&incoming 
= blob
->header
; 
 538     if (real
.HeaderVersion 
!= incoming
.HeaderVersion 
|| 
 539         real
.cspGuid() != incoming
.cspGuid()) 
 540         CssmError::throwMe(CSSMERR_CSP_INVALID_KEY
); 
 541     if (real
.algorithm() != incoming
.algorithm()) 
 542         CssmError::throwMe(CSSMERR_CSP_INVALID_ALGORITHM
); 
 544     // re-insert held bits 
 545     key
.header().KeyAttr 
|= heldAttributes
; 
 547         if(inTheClear 
&& (real
.keyClass() != CSSM_KEYCLASS_PUBLIC_KEY
)) { 
 548                 /* Spoof - cleartext KeyBlob passed off as private key */ 
 549         CssmError::throwMe(CSSMERR_CSP_INVALID_KEY
); 
 552     // got a valid key: return the pieces 
 553     pubAcl 
= blob
->publicAclBlob();             // points into blob (shared) 
 554     privAcl 
= privAclData
;                              // was allocated by CSP decrypt, else NULL for 
 556     // key was set by unwrap operation 
 561 // Derive the blob-specific database blob encryption key from the passphrase and the salt. 
 563 CssmClient::Key 
DatabaseCryptoCore::deriveDbMasterKey(const CssmData 
&passphrase
) const 
 565     // derive an encryption key and IV from passphrase and salt 
 566     CssmClient::DeriveKey 
makeKey(Server::csp(), 
 567         CSSM_ALGID_PKCS5_PBKDF2
, CSSM_ALGID_3DES_3KEY_EDE
, 24 * 8); 
 568     makeKey
.iterationCount(1000); 
 569         CssmData salt 
= CssmData::wrap(mSalt
); 
 571     CSSM_PKCS5_PBKDF2_PARAMS params
; 
 572     params
.Passphrase 
= passphrase
; 
 573     params
.PseudoRandomFunction 
= CSSM_PKCS5_PBKDF2_PRF_HMAC_SHA1
; 
 574         CssmData paramData 
= CssmData::wrap(params
); 
 575     return makeKey(¶mData
, KeySpec(CSSM_KEYUSE_ENCRYPT 
| CSSM_KEYUSE_DECRYPT
, 
 576         CSSM_KEYATTR_RETURN_DATA 
| CSSM_KEYATTR_EXTRACTABLE
)); 
 581 // Turn raw keybits into a symmetric key in the CSP 
 583 CssmClient::Key 
DatabaseCryptoCore::makeRawKey(void *data
, size_t length
, 
 584     CSSM_ALGORITHMS algid
, CSSM_KEYUSE usage
) 
 588     key
.header().BlobType 
= CSSM_KEYBLOB_RAW
; 
 589     key
.header().Format 
= CSSM_KEYBLOB_RAW_FORMAT_OCTET_STRING
; 
 590     key
.header().AlgorithmId 
= algid
; 
 591     key
.header().KeyClass 
= CSSM_KEYCLASS_SESSION_KEY
; 
 592     key
.header().KeyUsage 
= usage
; 
 593     key
.header().KeyAttr 
= 0; 
 594     key
.KeyData 
= CssmData(data
, length
); 
 596     // unwrap it into the CSP (but keep it raw) 
 597     UnwrapKey 
unwrap(Server::csp(), CSSM_ALGID_NONE
); 
 598     CssmKey unwrappedKey
; 
 599     CssmData descriptiveData
; 
 601         KeySpec(CSSM_KEYUSE_ANY
, CSSM_KEYATTR_RETURN_DATA 
| CSSM_KEYATTR_EXTRACTABLE
), 
 602         unwrappedKey
, &descriptiveData
, NULL
); 
 603     return CssmClient::Key(Server::csp(), unwrappedKey
);