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(¶mData, 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 }