00001
00010 #include "PKIFCryptUtils.h"
00011 #include "PKIFNSSDatabase.h"
00012 #include "PKIFNSSPasswordStorage.h"
00013
00014 #ifdef _WIN32
00015 #include "PKIFCAPIRaw.h"
00016 #include "PKIFCAPI2.h"
00017 #include "PKIFBCryptGuard.h"
00018 #include "PKIFCNGCAPI.h"
00019 #include "PKIFCNGCAPIRaw.h"
00020 #else
00021 #include "PKIFCryptoPPRaw.h"
00022 #endif //_WIN32
00023
00024 #include "PKIFKeyMaterial.h"
00025 #include "Buffer.h"
00026 #include "IPKIFCryptoRaw.h"
00027 #include "ToolkitUtils.h"
00028 #include "components.h"
00029 #include "PKIFAlgorithm.h"
00030 #include "PKIFCryptoConstants.h"
00031 #include "PKIFCryptoErrors.h"
00032 #include "PKIFCryptoException.h"
00033 #include "PKIFMemoryUtils.h"
00034 #include "OID.h"
00035
00036 #include <cstring>
00037 #include <sstream>
00038 #include <boost/scoped_array.hpp>
00039 #include <boost/cstdint.hpp>
00040 using namespace std;
00041 using namespace boost;
00042 #ifdef _WIN32
00043 static CPKIFCAPIRaw sRaw;
00044 #else
00045 static CPKIFCryptoPPRaw sRaw;
00046 #endif //_WIN32
00047
00048 static bool sInited = false;
00049
00050 static const unsigned char rfc3394iv[] = { 0xA6, 0xA6, 0xA6, 0xA6, 0xA6, 0xA6, 0xA6, 0xA6 };
00051 static const int rfc3394ivLen = 8;
00052 static void increment_and_xor(unsigned char *A, unsigned char *T);
00053 static void xor_and_decrement(unsigned char *A, unsigned char *T);
00054 static void set_t(unsigned char *pt, unsigned long t);
00055 static CPKIFAlgorithm * get_symmetric_alg_for_wrap_alg(const CPKIFKeyMaterialPtr & km);
00056
00066 IPKIFCryptoRaw * GetPlatformCryptoRaw(void)
00067 {
00068 if(!sInited)
00069 {
00070 sRaw.Initialize();
00071 sInited = true;
00072 }
00073 return &sRaw;
00074 }
00075
00085 IPKIFCryptoMisc * GetPlatformCryptoMisc(void)
00086 {
00087 if(!sInited)
00088 {
00089 sRaw.Initialize();
00090 sInited = true;
00091 }
00092 return &sRaw;
00093 }
00094
00103 IPKIFColleaguePtr MakeDefaultKeyIDColleague(void)
00104 {
00105 #ifdef _WIN32
00106 CPKIFBCryptGuard cngGuard;
00107 if(!cngGuard.IsCNGAvailable())
00108 {
00109 CPKIFCAPI2Ptr tmp(new CPKIFCAPI2);
00110 return dynamic_pointer_cast<IPKIFColleague, CPKIFCAPI2>(tmp);
00111 } else {
00112 CPKIFCNGCAPIPtr tmp(new CPKIFCNGCAPI);
00113 return dynamic_pointer_cast<IPKIFColleague, CPKIFCNGCAPI>(tmp);
00114 }
00115 #else
00116 IPKIFColleaguePtr empty;
00117 return empty;
00118 #endif //_WIN32
00119 }
00120
00129 IPKIFColleaguePtr MakeDefaultRawColleague(void)
00130 {
00131 #ifdef _WIN32
00132 CPKIFBCryptGuard cngGuard;
00133 if(!cngGuard.IsCNGAvailable())
00134 {
00135 CPKIFCAPIRawPtr tmp(new CPKIFCAPIRaw);
00136 return dynamic_pointer_cast<IPKIFColleague, CPKIFCAPIRaw>(tmp);
00137 } else {
00138 CPKIFCNGCAPIRawPtr tmp(new CPKIFCNGCAPIRaw);
00139 return dynamic_pointer_cast<IPKIFColleague, CPKIFCNGCAPIRaw>(tmp);
00140 }
00141 #else
00142 CPKIFCryptoPPRawPtr tmp(new CPKIFCryptoPPRaw);
00143 return dynamic_pointer_cast<IPKIFColleague, CPKIFCryptoPPRaw>(tmp);
00144 #endif //_WIN32
00145 }
00146
00154 void ShutdownCrypto(void)
00155 {
00156 CPKIFNSSDatabase * db = 0;
00157 try {
00158 db = CPKIFNSSDatabase::GetInstance();
00159 }catch(...){
00160
00161 }
00162 try {
00163 if(db) {
00164 CPKIFNSSPasswordStorage::SetUserCallback(0);
00165 db->Shutdown();
00166 }
00167 }catch(...) {
00168
00169 }
00170 }
00179 std::string GetCurrentNSSDBDir(void)
00180 {
00181 CPKIFNSSDatabase * db = CPKIFNSSDatabase::GetInstance();
00182 std::string rv = db->GetDBDir();
00183
00184 return rv;
00185 }
00193 bool IsNSSDBInitialized(void)
00194 {
00195 return CPKIFNSSDatabase::IsInitialized();
00196 }
00197
00213 CPKIFBufferPtr WrapSymmKey(
00215 const CPKIFKeyMaterialPtr & kek,
00217 const CPKIFKeyMaterialPtr & key,
00219 const IPKIFCryptoRawOperations * crypto)
00220 {
00221 CPKIFBufferPtr rv;
00222
00223
00224
00225 IPKIFCryptoRawOperations * cc = const_cast<IPKIFCryptoRawOperations *>(crypto);
00226 if(!kek) throw CPKIFCryptoException(TOOLKIT_CRYPTO_MISC,COMMON_INVALID_INPUT,"WrapSymmKey called without a KEK");
00227 if(!key) throw CPKIFCryptoException(TOOLKIT_CRYPTO_MISC,COMMON_INVALID_INPUT,"WrapSymmKey called without a key");
00228 CPKIFAlgorithm * kwAlg = CPKIFAlgorithm::GetAlg(kek->GetSymmetricKeyAlgorithm());
00229 if(!kwAlg) {
00230 throw CPKIFCryptoException(TOOLKIT_CRYPTO_MISC,CRYPTO_ALG_NOT_SUPPORTED,"WrapSymmKey called with invalid KEK");
00231 } else {
00232 CPKIFOIDPtr kwOid = kwAlg->OID();
00233 if( *kwOid != *g_aes128Wrap &&
00234 *kwOid != *g_aes192Wrap &&
00235 *kwOid != *g_aes256Wrap )
00236 {
00237 ostringstream oss;
00238 oss << kwOid->ToString() << " is not a supported key wrap algorithm." << endl;
00239 throw CPKIFCryptoException(TOOLKIT_CRYPTO_MISC,CRYPTO_ALG_NOT_SUPPORTED,oss.str().c_str());
00240 }
00241 }
00242 if(0 != key->GetSymmetricKeyLength() % kwAlg->BlockSize()) {
00243 throw CPKIFCryptoException(TOOLKIT_CRYPTO_MISC,COMMON_INVALID_INPUT,"WrapSymmKey called with a key that can't be wrapped using this algorithm");
00244 }
00245 if(!cc) {
00246 cc = GetPlatformCryptoRaw();
00247 }
00248 CPKIFAlgorithm * baseAlg = get_symmetric_alg_for_wrap_alg(kek);
00249 if(!baseAlg) {
00250 throw CPKIFCryptoException(TOOLKIT_CRYPTO_MISC,COMMON_INVALID_INPUT,"WrapSymmKey called with an unimplemented wrap algorithm");
00251 }
00252
00253 CPKIFKeyMaterialPtr baseKM = CPKIFKeyMaterial::CreateWithSymmetricKey(kek);
00254 baseKM->SetSymmetricKeyAlgorithm(baseAlg->SymkeyAlg());
00255 baseKM->SetMode(baseAlg->SymkeyMode());
00256
00257
00258 if(!cc || !cc->SupportsAlgorithm(*baseKM))
00259 {
00260 throw CPKIFCryptoException(TOOLKIT_CRYPTO_MISC,CRYPTO_ALG_NOT_SUPPORTED,
00261 "No colleague was specified and the default can't be used.");
00262 }
00263
00264 int ivLen = 0;
00265 baseKM->GetIV(NULL,&ivLen);
00266
00267 if(!ivLen) {
00268 baseKM->SetIV(rfc3394iv,rfc3394ivLen);
00269 ivLen = rfc3394ivLen;
00270 }
00271
00272 scoped_array<unsigned char> iv(new unsigned char[ivLen]);
00273 baseKM->GetIV(iv.get(),&ivLen);
00274 if(ivLen != rfc3394ivLen) {
00275 throw CPKIFCryptoException(TOOLKIT_CRYPTO_MISC,COMMON_INVALID_INPUT,
00276 "An IV was supplied for AES Key wrap but the length was incorrect.");
00277 }
00278
00279
00280 rv = CPKIFBufferPtr(new CPKIFBuffer());
00281 int bs = kwAlg->BlockSize();
00282 int plainLen = key->GetSymmetricKeyLength();
00283 unsigned char * ctBuf =
00284 rv->AllocateBuffer(plainLen+bs);
00285 const unsigned char * plainBuf = key->GetSymmetricKey();
00286 unsigned int n = plainLen/bs;
00287 boost::scoped_array<boost::uint64_t> Rp(new boost::uint64_t[n+1]);
00288 boost::uint64_t * R = Rp.get();
00289 boost::uint64_t wbuf[2];
00290 boost::uint64_t * A = &wbuf[0];
00291 boost::uint64_t t;
00292 memset(&t,0x00,sizeof(boost::uint64_t));
00293 int baseBS = baseAlg->BlockSize();
00294 int baseOut = baseBS;
00295
00296
00297
00298
00299 memcpy(A,iv.get(),rfc3394ivLen);
00300
00301 memcpy(&R[1],plainBuf,plainLen);
00302 try {
00303 for(unsigned int j = 0; j <= 5; ++j)
00304 {
00305 for(unsigned int i = 1; i <= n; ++i)
00306 {
00307
00308
00309
00310
00311 wbuf[1] = R[i];
00312 cc->Encrypt(*baseKM,(unsigned char *)wbuf,baseBS,
00313 (unsigned char *)wbuf,&baseOut,false);
00314 increment_and_xor((unsigned char *)A,(unsigned char *)&t);
00315 R[i] = wbuf[1];
00316 }
00317 }
00318 R[0] = *A;
00319 memcpy(ctBuf,R,plainLen+bs);
00320
00321 }catch(...){
00322
00323
00324 PKIFZero(R,n+1*sizeof(boost::uint64_t));
00325 throw;
00326 }
00327
00328 return rv;
00329
00330 }
00331
00350 CPKIFKeyMaterialPtr UnwrapSymmKey(
00352 const CPKIFKeyMaterialPtr & kek,
00354 const CPKIFBufferPtr & key,
00356 const IPKIFCryptoRawOperations * crypto)
00357 {
00358 CPKIFKeyMaterialPtr rv;
00359
00360
00361
00362 IPKIFCryptoRawOperations * cc = const_cast<IPKIFCryptoRawOperations *>(crypto);
00363 if(!kek) throw CPKIFCryptoException(TOOLKIT_CRYPTO_MISC,COMMON_INVALID_INPUT,"UnwrapSymmKey called without a KEK");
00364 if(!key) throw CPKIFCryptoException(TOOLKIT_CRYPTO_MISC,COMMON_INVALID_INPUT,"UnwrapSymmKey called without a key");
00365 CPKIFAlgorithm * kwAlg = CPKIFAlgorithm::GetAlg(kek->GetSymmetricKeyAlgorithm());
00366 if(!kwAlg) {
00367 throw CPKIFCryptoException(TOOLKIT_CRYPTO_MISC,CRYPTO_ALG_NOT_SUPPORTED,"UnwrapSymmKey called with invalid KEK");
00368 } else {
00369 CPKIFOIDPtr kwOid = kwAlg->OID();
00370 if( *kwOid != *g_aes128Wrap &&
00371 *kwOid != *g_aes192Wrap &&
00372 *kwOid != *g_aes256Wrap )
00373 {
00374 ostringstream oss;
00375 oss << kwOid->ToString() << " is not a supported key wrap algorithm." << endl;
00376 throw CPKIFCryptoException(TOOLKIT_CRYPTO_MISC,CRYPTO_ALG_NOT_SUPPORTED,oss.str().c_str());
00377 }
00378 }
00379 if(!cc) {
00380 cc = GetPlatformCryptoRaw();
00381 }
00382 CPKIFAlgorithm * baseAlg = get_symmetric_alg_for_wrap_alg(kek);
00383 if(!baseAlg) {
00384 throw CPKIFCryptoException(TOOLKIT_CRYPTO_MISC,COMMON_INVALID_INPUT,"UnwrapSymmKey called with an unimplemented wrap algorithm");
00385 }
00386
00387 int bs = kwAlg->BlockSize();
00388 int cipherLen = key->GetLength();
00389 if( cipherLen < bs*3 && 0 != (cipherLen % bs)) {
00390 throw CPKIFCryptoException(TOOLKIT_CRYPTO_MISC,COMMON_INVALID_INPUT,"UnwrapSymmKey called with invalid ciphertext");
00391 }
00392
00393 CPKIFKeyMaterialPtr baseKM = CPKIFKeyMaterial::CreateWithSymmetricKey(kek);
00394 baseKM->SetSymmetricKeyAlgorithm(baseAlg->SymkeyAlg());
00395 baseKM->SetMode(baseAlg->SymkeyMode());
00396
00397
00398 if(!cc )
00399 {
00400 throw CPKIFCryptoException(TOOLKIT_CRYPTO_MISC,CRYPTO_ALG_NOT_SUPPORTED,
00401 "No colleague was specified and the default can't be used.");
00402 }
00403
00404 int ivLen = 0;
00405 baseKM->GetIV(NULL,&ivLen);
00406
00407 if(!ivLen) {
00408 baseKM->SetIV(rfc3394iv,rfc3394ivLen);
00409 ivLen = rfc3394ivLen;
00410 }
00411
00412 scoped_array<unsigned char> iv(new unsigned char[ivLen]);
00413 baseKM->GetIV(iv.get(),&ivLen);
00414 if(ivLen != rfc3394ivLen) {
00415 throw CPKIFCryptoException(TOOLKIT_CRYPTO_MISC,COMMON_INVALID_INPUT,
00416 "An IV was supplied for AES Key wrap but the length was incorrect.");
00417 }
00418
00419
00420 rv = CPKIFKeyMaterialPtr(new CPKIFKeyMaterial());
00421
00422 const unsigned char * ctBuf = key->GetBuffer();
00423 unsigned int n = cipherLen/bs;
00424
00425 boost::scoped_array<boost::uint64_t> Rp(new boost::uint64_t[n]);
00426 boost::uint64_t * R = Rp.get();
00427 boost::uint64_t wbuf[2];
00428 boost::uint64_t t;
00429 memset(&t,0x00,sizeof(boost::uint64_t));
00430 int baseBS = baseAlg->BlockSize();
00431 int baseOut = baseBS;
00432 int outLen = cipherLen-bs;
00433 int nOut = outLen/bs;
00434
00435
00436
00437
00438 memcpy(&R[0],ctBuf,cipherLen);
00439 boost::uint64_t * A = &wbuf[0];
00440 *A = R[0];
00441 set_t((unsigned char *)&t,(unsigned long)6*nOut);
00442 try {
00443 for(unsigned int j = 0; j <= 5; ++j)
00444 {
00445 for(unsigned int i = nOut; i != 0; --i)
00446 {
00447 xor_and_decrement((unsigned char *)A,(unsigned char *)&t);
00448 wbuf[1] = R[i];
00449 cc->Decrypt(*baseKM,(unsigned char *)wbuf,baseBS,
00450 (unsigned char *)wbuf,&baseOut,false);
00451 R[i] = wbuf[1];
00452 }
00453 }
00454 if(0 != memcmp(baseKM->GetIV(),A,bs)) {
00455 throw CPKIFCryptoException(TOOLKIT_CRYPTO_MISC,COMMON_INVALID_INPUT,
00456 "Bad ciphertext.");
00457 }
00458 rv->SetSymmetricKey((unsigned char *)(&R[1]),outLen);
00459 PKIFZero(wbuf,2*sizeof(boost::uint64_t));
00460 PKIFZero(R,cipherLen);
00461
00462 }catch(...){
00463
00464
00465 PKIFZero(wbuf,2*sizeof(boost::uint64_t));
00466 PKIFZero(R,cipherLen);
00467 throw;
00468 }
00469
00470 return rv;
00471
00472 }
00473
00474
00475
00476 static CPKIFAlgorithm * get_symmetric_alg_for_wrap_alg(const CPKIFKeyMaterialPtr & km)
00477 {
00478 CPKIFAlgorithm * baseAlg = 0;
00479 switch(km->GetSymmetricKeyAlgorithm())
00480 {
00481 case PKIFCRYPTO::AES128Wrap:
00482 baseAlg = CPKIFAlgorithm::GetAlg(PKIFCRYPTO::AES128);
00483 break;
00484 case PKIFCRYPTO::AES192Wrap:
00485 baseAlg = CPKIFAlgorithm::GetAlg(PKIFCRYPTO::AES192);
00486 break;
00487 case PKIFCRYPTO::AES256Wrap:
00488 baseAlg = CPKIFAlgorithm::GetAlg(PKIFCRYPTO::AES256);
00489 break;
00490 default:
00491 break;
00492 }
00493 return baseAlg;
00494 }
00495
00496
00497
00498
00499
00500
00501
00502
00503
00504
00505
00506
00507
00508
00509
00510
00511
00512 static void
00513 increment_and_xor(unsigned char *A, unsigned char *T)
00514 {
00515 if (!++T[7])
00516 if (!++T[6])
00517 if (!++T[5])
00518 if (!++T[4])
00519 if (!++T[3])
00520 if (!++T[2])
00521 if (!++T[1])
00522 ++T[0];
00523
00524 A[0] ^= T[0];
00525 A[1] ^= T[1];
00526 A[2] ^= T[2];
00527 A[3] ^= T[3];
00528 A[4] ^= T[4];
00529 A[5] ^= T[5];
00530 A[6] ^= T[6];
00531 A[7] ^= T[7];
00532 }
00533
00534
00535
00536
00537
00538 static void
00539 xor_and_decrement(unsigned char *A, unsigned char *T)
00540 {
00541 A[0] ^= T[0];
00542 A[1] ^= T[1];
00543 A[2] ^= T[2];
00544 A[3] ^= T[3];
00545 A[4] ^= T[4];
00546 A[5] ^= T[5];
00547 A[6] ^= T[6];
00548 A[7] ^= T[7];
00549
00550 if (!T[7]--)
00551 if (!T[6]--)
00552 if (!T[5]--)
00553 if (!T[4]--)
00554 if (!T[3]--)
00555 if (!T[2]--)
00556 if (!T[1]--)
00557 T[0]--;
00558
00559 }
00560
00561
00562
00563
00564 static void
00565 set_t(unsigned char *pt, unsigned long t)
00566 {
00567 pt[7] = (unsigned char)t; t >>= 8;
00568 pt[6] = (unsigned char)t; t >>= 8;
00569 pt[5] = (unsigned char)t; t >>= 8;
00570 pt[4] = (unsigned char)t; t >>= 8;
00571 pt[3] = (unsigned char)t; t >>= 8;
00572 pt[2] = (unsigned char)t; t >>= 8;
00573 pt[1] = (unsigned char)t; t >>= 8;
00574 pt[0] = (unsigned char)t;
00575 }