/ securityd / src / dbcrypto.cpp
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 "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>
 39  
 40  using namespace CssmClient;
 41  using LowLevelMemoryUtilities::fieldOffsetOf;
 42  
 43  
 44  //
 45  // The CryptoCore constructor doesn't do anything interesting.
 46  // It just initializes us to "empty".
 47  //
 48  DatabaseCryptoCore::DatabaseCryptoCore(uint32 requestedVersion) : mBlobVersion(CommonBlob::version_MacOS_10_0), mHaveMaster(false), mIsValid(false)
 49  {
 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();
 53      } else {
 54          mBlobVersion = requestedVersion;
 55      }
 56  }
 57  
 58  DatabaseCryptoCore::~DatabaseCryptoCore()
 59  {
 60      // key objects take care of themselves
 61  }
 62  
 63  
 64  //
 65  // Forget the secrets
 66  //
 67  void DatabaseCryptoCore::invalidate()
 68  {
 69  	mMasterKey.release();
 70  	mHaveMaster = false;
 71  	
 72  	mEncryptionKey.release();
 73  	mSigningKey.release();
 74  	mIsValid = false;
 75  }
 76  
 77  //
 78  // Copy everything from another databasecryptocore
 79  //
 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;
 85      } else {
 86          mHaveMaster = false;
 87      }
 88  
 89      if(core.isValid()) {
 90          importSecrets(core);
 91      } else {
 92          mIsValid = false;
 93      }
 94  
 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;
 98      } else {
 99          mBlobVersion = requestedVersion;
100      }
101  }
102  
103  //
104  // Generate new secrets for this crypto core.
105  //
106  void DatabaseCryptoCore::generateNewSecrets()
107  {
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));
112      
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));
118      
119      // secrets established
120      mIsValid = true;
121  }
122  
123  
124  CssmClient::Key DatabaseCryptoCore::masterKey()
125  {
126  	assert(mHaveMaster);
127  	return mMasterKey;
128  }
129  
130  
131  //
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.
136  //
137  void DatabaseCryptoCore::setup(const DbBlob *blob, const CssmData &passphrase, bool copyVersion /* = true */)
138  {
139      if (blob) {
140          if(copyVersion) {
141              mBlobVersion = blob->version();
142          }
143          memcpy(mSalt, blob->salt, sizeof(mSalt));
144      } else {
145          MacOSError::check(SecRandomCopyBytes(kSecRandomDefault, sizeof(mSalt), mSalt));
146      }
147  
148      mMasterKey = deriveDbMasterKey(passphrase);
149  	mHaveMaster = true;
150  }
151  
152  
153  //
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.
157  //
158  void DatabaseCryptoCore::setup(const DbBlob *blob, CssmClient::Key master, bool copyVersion /* = true */)
159  {
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);
166  	
167  	// accept it
168      if (blob) {
169          if(copyVersion) {
170              mBlobVersion = blob->version();
171          }
172          memcpy(mSalt, blob->salt, sizeof(mSalt));
173      } else {
174          MacOSError::check(SecRandomCopyBytes(kSecRandomDefault, sizeof(mSalt), mSalt));
175      }
176  	mMasterKey = master;
177  	mHaveMaster = true;
178  }
179  
180  bool DatabaseCryptoCore::get_encryption_key(CssmOwnedData &data)
181  {
182      bool result = false;
183      if (isValid()) {
184          data = mEncryptionKey->keyData();
185          result = true;
186      }
187      return result;
188  }
189  
190  //
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.
198  //
199  bool DatabaseCryptoCore::validatePassphrase(const CssmData &passphrase)
200  {
201  	CssmClient::Key master = deriveDbMasterKey(passphrase);
202      return validateKey(master);
203  }
204  
205  bool DatabaseCryptoCore::validateKey(const CssmClient::Key& master) {
206      assert(hasMaster());
207  	// to compare master with mMaster, see if they encrypt alike
208  	StringData probe
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);
217  	
218  	cryptor.key(master);
219  	CssmAutoData cipher1(Server::csp().allocator());
220  	cryptor.encrypt(probe, cipher1.get(), noRemainder);
221  	
222  	cryptor.key(mMasterKey);
223  	CssmAutoData cipher2(Server::csp().allocator());
224  	cryptor.encrypt(probe, cipher2.get(), noRemainder);
225  	
226  	return cipher1 == cipher2;
227  }
228  
229  
230  //
231  // Encode a database blob from the core.
232  //
233  DbBlob *DatabaseCryptoCore::encodeCore(const DbBlob &blobTemplate,
234      const CssmData &publicAcl, const CssmData &privateAcl) const
235  {
236      assert(isValid());		// must have secrets to work from
237  
238      // make a new IV
239      uint8 iv[8];
240      MacOSError::check(SecRandomCopyBytes(kSecRandomDefault, sizeof(iv), iv));
241      
242      // build the encrypted section blob
243      CssmData &encryptionBits = *mEncryptionKey;
244      CssmData &signingBits = *mSigningKey;
245      CssmData incrypt[3];
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);
256      
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);
260      
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());
273      
274      // sign the blob
275      CssmData signChunk[] = {
276  		CssmData(blob->data(), fieldOffsetOf(&DbBlob::blobSignature)),
277  		CssmData(blob->publicAclBlob(), publicAcl.length() + cryptoBlob.length())
278  	};
279      CssmData signature(blob->blobSignature, sizeof(blob->blobSignature));
280  
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
285  #endif
286      GenerateMac signer(Server::csp(), signingAlgorithm);
287      signer.key(mSigningKey);
288      signer.sign(signChunk, 2, signature);
289      assert(signature.length() == sizeof(blob->blobSignature));
290      
291      // all done. Clean up
292      Server::csp()->allocator().free(cryptoBlob);
293      return blob;
294  }
295  
296  
297  //
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.
301  //
302  void DatabaseCryptoCore::decodeCore(const DbBlob *blob, void **privateAclBlob)
303  {
304  	assert(mHaveMaster);	// must have master key installed
305      
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>();
316      
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);
324      
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())
329  	};
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
334  #endif
335      VerifyMac verifier(Server::csp(), verifyAlgorithm);
336      verifier.key(mSigningKey);
337      verifier.verify(signChunk, 2, CssmData::wrap(blob->blobSignature));
338      
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);
345      }
346          
347      // secrets have been established
348      mBlobVersion = blob->version();
349      mIsValid = true;
350      Allocator::standard().free(privateBlob);
351  }
352  
353  
354  //
355  // Make another DatabaseCryptoCore's operational secrets our own.  
356  // Intended for keychain synchronization.  
357  //
358  void DatabaseCryptoCore::importSecrets(const DatabaseCryptoCore &src)
359  {
360  	assert(src.isValid());	// must have called src.decodeCore() first
361  	assert(hasMaster());
362  	mEncryptionKey = src.mEncryptionKey;
363  	mSigningKey = src.mSigningKey;
364      mBlobVersion = src.mBlobVersion;    // make sure we copy over all state
365      mIsValid = true;
366  }
367  
368  //
369  // Encode a key blob
370  //
371  KeyBlob *DatabaseCryptoCore::encodeKeyCore(const CssmKey &inKey,
372      const CssmData &publicAcl, const CssmData &privateAcl,
373  	bool inTheClear) const
374  {
375      CssmKey key = inKey;
376  	uint8 iv[8];
377  	CssmKey wrappedKey;
378  
379  	if(inTheClear && (privateAcl.Length != 0)) {
380  		/* can't store private ACL component in the clear */
381  		CssmError::throwMe(CSSMERR_DL_INVALID_ACCESS_CREDENTIALS);
382  	}
383  	
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);
388      
389  	if(inTheClear) {
390  		/* NULL wrap of public key */
391  		WrapKey wrap(Server::csp(), CSSM_ALGID_NONE);
392  		wrap(key, wrappedKey, NULL);
393  	}
394  	else {
395  		assert(isValid());		// need our database secrets
396  		
397  		// create new IV
398          MacOSError::check(SecRandomCopyBytes(kSecRandomDefault, sizeof(iv), iv));
399  		
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);
409      }
410  	
411      // stick the held attribute bits back in
412  	key.clearAttribute(forcedAttributes);
413      key.setAttribute(heldAttributes);
414      
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);
418      
419      // assemble the KeyBlob
420      memset(blob, 0, sizeof(KeyBlob));	// fill alignment gaps
421      blob->initialize(mBlobVersion);
422  	if(!inTheClear) {
423  		memcpy(blob->iv, iv, sizeof(iv));
424  	}
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());
435      
436   	if(inTheClear) {
437  		/* indicate that this is cleartext for decoding */
438  		blob->setClearTextSignature();
439  	}
440  	else {
441  		// sign the blob
442  		CssmData signChunk[] = {
443  			CssmData(blob->data(), fieldOffsetOf(&KeyBlob::blobSignature)),
444  			CssmData(blob->publicAclBlob(), blob->publicAclBlobLength() + blob->cryptoBlobLength())
445  		};
446  		CssmData signature(blob->blobSignature, sizeof(blob->blobSignature));
447  
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
452  #endif
453          GenerateMac signer(Server::csp(), signingAlgorithm);
454  		signer.key(mSigningKey);
455  		signer.sign(signChunk, 2, signature);
456  		assert(signature.length() == sizeof(blob->blobSignature));
457      }
458  	
459      // all done. Clean up
460      Server::csp()->allocator().free(wrappedKey);
461      return blob;
462  }
463  
464  
465  //
466  // Decode a key blob
467  //
468  void DatabaseCryptoCore::decodeKeyCore(KeyBlob *blob,
469      CssmKey &key, void * &pubAcl, void * &privAcl) const
470  {    
471      // Note that we can't do anything with this key's version().
472  
473      // Assemble the encrypted blob as a CSSM "wrapped key"
474      CssmKey wrappedKey;
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());
482  	
483  	bool inTheClear = blob->isClearText();
484  	if(!inTheClear) {
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())
490  		};
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
495  	#endif
496  		VerifyMac verifier(Server::csp(), verifyAlgorithm);
497  		verifier.key(mSigningKey);
498  		CssmData signature(blob->blobSignature, sizeof(blob->blobSignature));
499  		verifier.verify(signChunk, 2, signature);
500      }
501  	/* else signature indicates cleartext */
502  	
503      // extract and hold some header bits the CSP does not want to see
504      uint32 heldAttributes = n2h(blob->header.attributes()) & managedAttributes;
505     
506  	CssmData privAclData;
507  	if(inTheClear) {
508  		/* NULL unwrap */
509  		UnwrapKey unwrap(Server::csp(), CSSM_ALGID_NONE);
510  		wrappedKey.clearAttribute(managedAttributes);    //@@@ shouldn't be needed(?)
511  		unwrap(wrappedKey,
512  			KeySpec(n2h(blob->header.usage()),
513  				(n2h(blob->header.attributes()) & ~managedAttributes) | forcedAttributes),
514  			key, &privAclData);
515  	}
516  	else {
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(?)
526  		unwrap(wrappedKey,
527  			KeySpec(n2h(blob->header.usage()),
528  				(n2h(blob->header.attributes()) & ~managedAttributes) | forcedAttributes),
529  			key, &privAclData);
530      }
531  	
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;
536  	n2hi(incoming);
537  
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);
543          
544      // re-insert held bits
545      key.header().KeyAttr |= heldAttributes;
546      
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);
550  	}
551  	
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
555  										// cleatext keys
556      // key was set by unwrap operation
557  }
558  
559  
560  //
561  // Derive the blob-specific database blob encryption key from the passphrase and the salt.
562  //
563  CssmClient::Key DatabaseCryptoCore::deriveDbMasterKey(const CssmData &passphrase) const
564  {
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);
570      makeKey.salt(salt);
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(&paramData, KeySpec(CSSM_KEYUSE_ENCRYPT | CSSM_KEYUSE_DECRYPT,
576          CSSM_KEYATTR_RETURN_DATA | CSSM_KEYATTR_EXTRACTABLE));
577  }
578  
579  
580  //
581  // Turn raw keybits into a symmetric key in the CSP
582  //
583  CssmClient::Key DatabaseCryptoCore::makeRawKey(void *data, size_t length,
584      CSSM_ALGORITHMS algid, CSSM_KEYUSE usage)
585  {
586      // build a fake key
587      CssmKey key;
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);
595      
596      // unwrap it into the CSP (but keep it raw)
597      UnwrapKey unwrap(Server::csp(), CSSM_ALGID_NONE);
598      CssmKey unwrappedKey;
599      CssmData descriptiveData;
600      unwrap(key,
601          KeySpec(CSSM_KEYUSE_ANY, CSSM_KEYATTR_RETURN_DATA | CSSM_KEYATTR_EXTRACTABLE),
602          unwrappedKey, &descriptiveData, NULL);
603      return CssmClient::Key(Server::csp(), unwrappedKey);
604  }