PKIFCryptoPPRaw.cpp

Go to the documentation of this file.
00001 
00010 #include "PKIFCryptoPPRaw.h"
00011 #include "PKIFCryptoPPRawContext.h"
00012 #include "PKIFCryptoPPUtils.h"
00013 
00014 #include "PKIFCryptoException.h"
00015 #include "PKIFKeyMaterial.h"
00016 #include "SubjectPublicKeyInfo.h"
00017 #include "PKIFAlgorithm.h"
00018 
00019 #include "ToolkitUtils.h"
00020 #include "PKIFCryptoPPErrors.h"
00021 #include "PKIFCryptoErrors.h"
00022 #include "Certificate.h"
00023 #include "Buffer.h"
00024 
00025 #include "PKIFCryptUtils.h"
00026 
00027 #include "PKIFCryptoPPKeyMaterial.h"
00028 
00029 #include <sstream>
00030 
00031 #include "boost/numeric/conversion/cast.hpp"
00032 
00033 #include "cryptlib.h"
00034 #include "pubkey.h"
00035 #include "sha.h"
00036 #include "queue.h"
00037 #include "osrng.h"
00038 #include "rsa.h"
00039 #include "dsa.h"
00040 #include "eccrypto.h"
00041 #include "asn.h"
00042 #include "dsa.h"
00043 #include "modes.h"
00044 #include "aes.h"
00045 #include "hmac.h"
00046 #define CRYPTOPP_ENABLE_NAMESPACE_WEAK 1
00047 #include "md5.h"
00048 
00049 #include "PKIFCryptoPPExternalDigest.h"
00050 
00051 using namespace CryptoPP;
00052 
00053 template<bool _CryptDirection>
00054 static void _ASymCrypt(const CPKIFKeyMaterial& key, unsigned char* pData, int nDataLen, unsigned char* pResult, int* pnResultLen, bool pad = true);
00055 
00056 
00057 
00066 CPKIFCryptoPPRaw::CPKIFCryptoPPRaw(void)
00067 {
00068     LOG_STRING_DEBUG("CPKIFCryptoPPRaw::CPKIFCryptoPPRaw(void)", TOOLKIT_CRYPTO_CRYPTOPPRAW, 0, this);
00069 }
00077 CPKIFCryptoPPRaw::~CPKIFCryptoPPRaw(void)
00078 {
00079     LOG_STRING_DEBUG("CPKIFCryptoPPRaw::~CPKIFCryptoPPRaw(void)", TOOLKIT_CRYPTO_CRYPTOPPRAW, 0, this);
00080 }
00088 void CPKIFCryptoPPRaw::Initialize()
00089 {
00090     LOG_STRING_DEBUG("CPKIFCryptoPPRaw::Initialize()", TOOLKIT_CRYPTO_CRYPTOPPRAW, 0, this);
00091 }
00103 bool CPKIFCryptoPPRaw::SupportsAlgorithm(
00105     const CPKIFKeyMaterial& key)
00106 {
00107     LOG_STRING_DEBUG("CPKIFCryptoPPRaw::SupportsAlgorithm(const CPKIFKeyMaterial& key)", TOOLKIT_CRYPTO_CRYPTOPPRAW, 0, this);
00108     if(key.ContainsSymmetricKeyMaterial())
00109     {   
00110         try
00111         {
00112             switch(key.GetSymmetricKeyAlgorithm()) {
00113                 case PKIFCRYPTO::AES:
00114                 case PKIFCRYPTO::AES128:
00115                 case PKIFCRYPTO::AES192:
00116                 case PKIFCRYPTO::AES256:
00117                 //case PKIFCRYPTO::TDES: This colleague does not currently implement DES or 3DES
00118                     return true;
00119                     break;
00120                 default:
00121                     return false;
00122                     break;
00123             }
00124         }
00125         catch(CPKIFCryptoException& e)
00126         {
00127             if(CRYPTO_ALG_NOT_SUPPORTED == e.GetErrorCode())
00128             {
00129                 //EXCEPTION DELETION
00130                 //The GetSymAlgorithm function throws upon failure but
00131                 //this function should return false.
00132                 //delete e;
00133                 return false;
00134             }
00135             else
00136                 throw e; //should never happen
00137         }
00138     } else {
00139         CPKIFSubjectPublicKeyInfoPtr spki = key.GetSubjectPublicKeyInfo();
00140         if(!spki) {
00141             CPKIFCryptoPPKeyMaterialPtr cppKM(new CPKIFCryptoPPKeyMaterial(key));
00142             spki = cppKM->GetSubjectPublicKeyInfo();
00143         }
00144         if(!spki) return false;
00145         CPKIFAlgorithm * alg = CPKIFAlgorithm::GetAlg(spki->alg()->oid());
00146         switch(alg->AsymkeyAlg()) {
00147             case PKIFCRYPTO::RSA:
00148             case PKIFCRYPTO::ECC:
00149             case PKIFCRYPTO::DSS:           
00150                 return true;
00151                 break;
00152             default:
00153                 return false;
00154         }
00155     }
00156     return false;
00157 }
00168 void CPKIFCryptoPPRaw::Sign(
00170     const CPKIFKeyMaterial& key,
00172     unsigned char* pHashData, 
00174     int nHashDataLen, 
00176     unsigned char* pSignature, 
00179     int* nSignatureLen,
00181     PKIFCRYPTO::HASH_ALG hashAlg)
00182 {
00183     LOG_STRING_DEBUG("CPKIFCryptoPPRaw::Sign(const CPKIFKeyMaterial& key,...)", TOOLKIT_CRYPTO_CRYPTOPPRAW, 0, this);
00184     // Don't do raw signature generation since we don't have a way of slinging raw private keys around
00185     RAISE_CRYPTO_EXCEPTION("Signing operations are not implemented for raw key material.", thisComponent, COMMON_NOT_IMPLEMENTED, this);
00186 }
00187 
00195 void CPKIFCryptoPPRaw::Decrypt( 
00197     const CPKIFKeyMaterial& key,
00199     unsigned char* pData, 
00201     int nDataLen, 
00203     unsigned char* pResult, 
00206     int* pnResultLen, 
00210     bool pad)
00211 {
00212     if(key.ContainsSymmetricKeyMaterial()) {
00213         CPKIFCryptoPPRawContext * ctx = static_cast<CPKIFCryptoPPRawContext *>(this->CryptInit(key,pad));
00214         try {
00215             Decrypt(ctx,pData,nDataLen,pResult,pnResultLen,true);
00216         } catch(...) {
00217             delete ctx;
00218             throw;
00219         }
00220         delete ctx;
00221     } else {
00222         _ASymCrypt<false>(key, pData, nDataLen, pResult, pnResultLen, pad);
00223     }
00224 }
00232 void CPKIFCryptoPPRaw::Encrypt(
00234     const CPKIFKeyMaterial& key,
00236     unsigned char* pData, 
00238     int nDataLen, 
00240     unsigned char* pResult, 
00243     int* pnResultLen, 
00247     bool pad)
00248 {
00249     if(key.ContainsSymmetricKeyMaterial()) {
00250         CPKIFCryptoPPRawContext * ctx = static_cast<CPKIFCryptoPPRawContext *>(this->CryptInit(key,pad));
00251         try {
00252             Encrypt(ctx,pData,nDataLen,pResult,pnResultLen,true);
00253         } catch(...) {
00254             delete ctx;
00255             throw;
00256         }
00257         delete ctx;
00258     } else {
00259         _ASymCrypt<true>(key, pData, nDataLen, pResult, pnResultLen, pad);
00260     }
00261 }
00262 
00280 IPKIFRawCryptContext* CPKIFCryptoPPRaw::HMACInit(const CPKIFKeyMaterial &key, PKIFCRYPTO::HASH_ALG ha)
00281 {
00282     LOG_STRING_DEBUG("CPKIFCryptoPPRaw::HMACInit(const CPKIFKeyMaterial& key, HASH_ALG ha)", TOOLKIT_CRYPTO_CRYPTOPPRAW, 0, this);
00283     // the iterative crypt functions are a bad idea with RSA or DSA keys...
00284     if(!key.ContainsSymmetricKeyMaterial())
00285     {
00286         throw CPKIFCryptoException(TOOLKIT_CRYPTO_CRYPTOPPRAW, COMMON_INVALID_INPUT, "HMACInit() only makes sense for symmetric keys.");
00287     }
00288 
00289     CPKIFCryptoPPRawContext * ctx = new CPKIFCryptoPPRawContext();
00290     try {
00291         switch(ha) {
00292             case PKIFCRYPTO::SHA1:
00293                 ctx->m_hashCtx = new HMAC<CryptoPP::SHA1>(key.GetSymmetricKey(),key.GetSymmetricKeyLength());
00294                 break;
00295     #if !defined(FIPS_MODE)
00296             case PKIFCRYPTO::MD5:
00297                 ctx->m_hashCtx = new HMAC<CryptoPP::Weak::MD5>(key.GetSymmetricKey(),key.GetSymmetricKeyLength());
00298                 break;
00299     #endif 
00300             case PKIFCRYPTO::SHA224:
00301                 ctx->m_hashCtx = new HMAC<CryptoPP::SHA224>(key.GetSymmetricKey(),key.GetSymmetricKeyLength());
00302                 break;
00303             case PKIFCRYPTO::SHA256:
00304                 ctx->m_hashCtx = new HMAC<CryptoPP::SHA256>(key.GetSymmetricKey(),key.GetSymmetricKeyLength());
00305                 break;
00306             case PKIFCRYPTO::SHA384:
00307                 ctx->m_hashCtx = new HMAC<CryptoPP::SHA384>(key.GetSymmetricKey(),key.GetSymmetricKeyLength());
00308                 break;
00309             case PKIFCRYPTO::SHA512:
00310                 ctx->m_hashCtx = new HMAC<CryptoPP::SHA512>(key.GetSymmetricKey(),key.GetSymmetricKeyLength());
00311                 break;
00312             default:
00313                 std::ostringstream os;
00314                 os << "Unsupported hash algorithm encountered: " << ha;
00315                 RAISE_CRYPTO_EXCEPTION(os.str().c_str(), thisComponent, CRYPTO_ALG_NOT_SUPPORTED, NULL);
00316                 break;
00317         }
00318     }catch(CryptoPP::Exception &) {
00319         RAISE_CRYPTO_EXCEPTION("Invalid key material for HMAC algorithm", thisComponent, COMMON_INVALID_INPUT, NULL);
00320     }
00321     
00322     return ctx;
00323 }
00324 
00336 void CPKIFCryptoPPRaw::HMACUpdate(IPKIFRawCryptContext* ctx, unsigned char* pData, int nDataLen)
00337 {
00338     LOG_STRING_DEBUG("CPKIFCryptoPPRaw::HMACUpdate(IPKIFRawCryptContext* ctx, unsigned char* pData, int nDataLen)", TOOLKIT_CRYPTO_CRYPTOPPRAW, 0, this);
00339     //sanity check the inputs: 
00340     //  hash must not be NULL, must be of a type this class supports and must not be empty
00341     //  pData MAY be NULL (if not it is assumed to be at least nDataLen bytes)
00342     //  nDataLen must not be less than zero
00343     if(NULL == ctx || 0 > nDataLen)
00344         throw CPKIFCryptoException(thisComponent, COMMON_INVALID_INPUT, "NULL input passed to HMACUpdate.");
00345 
00346     //cast the context to the type this class handles.  if the cast fails
00347     //then the context is not the correct type.
00348     CPKIFCryptoPPRawContext* ictx = dynamic_cast<CPKIFCryptoPPRawContext*>(ctx);
00349     if(NULL == ictx)
00350         throw CPKIFCryptoException(thisComponent, PKIFCRYPTOPP_INCORRECT_HASH_CONTEXT, "Incorrect context passed to HMACUpdate.");
00351 
00352     if(NULL == ictx->m_hashCtx)
00353         throw CPKIFCryptoException(thisComponent, PKIFCRYPTOPP_EMPTY_HASH_CONTEXT, "Empty context passed to HMACUpdate.");
00354     if(nDataLen) ictx->m_hashCtx->Update(pData,nDataLen);
00355 }
00356 
00369 void CPKIFCryptoPPRaw::HMACFinal(IPKIFRawCryptContext* ctx, unsigned char* pResult, int* pnResultLen)
00370 {
00371     LOG_STRING_DEBUG("CPKIFCryptoPPRaw::HMACFinal(IPKIFRawContext* ctx, unsigned char* pResult, int* pnResultLen)", TOOLKIT_CRYPTO_CRYPTOPPRAW, 0, this);
00372 
00373     //sanity check the inputs: 
00374     //  ctx must not be NULL, must be of a type this class supports and must not be empty
00375     //  result must not be NULL (it is assumed to be at least *pnResultLen bytes)
00376     //  pnResultLen must not be NULL and *pnResultLen must not be less than or equal to zero
00377     if(NULL == ctx || NULL == pResult || NULL == pnResultLen || 0 >= *pnResultLen)
00378         throw CPKIFCryptoException(thisComponent, COMMON_INVALID_INPUT, "NULL input passed to HMACFinal.");
00379 
00380     CPKIFCryptoPPRawContext* hmacCtx = dynamic_cast<CPKIFCryptoPPRawContext*>(ctx);
00381     if(NULL == hmacCtx)
00382         throw CPKIFCryptoException(thisComponent, PKIFCRYPTOPP_INCORRECT_HASH_CONTEXT, "Incorrect context passed to HMACFinal().");
00383 
00384     if(NULL == hmacCtx->m_hashCtx)
00385         throw CPKIFCryptoException(thisComponent, PKIFCRYPTOPP_EMPTY_HASH_CONTEXT, "Empty context passed to HMACFinal().");
00386     try {
00387         if(hmacCtx->m_hashCtx->DigestSize() > boost::numeric_cast<unsigned int, int>(*pnResultLen))
00388             throw CPKIFCryptoException(thisComponent, PKIFCRYPTOPP_INCORRECT_HASH_CONTEXT, "Mismatch between buffer size and hash context passed to HashFinal.");
00389     }catch( boost::numeric::bad_numeric_cast & ) {
00390         throw CPKIFCryptoException(thisComponent, PKIFCRYPTOPP_INCORRECT_HASH_CONTEXT, "Comparison error between buffer size and hash context passed to HashFinal.");
00391     }
00392 
00393     hmacCtx->m_hashCtx->Final(pResult);
00394     *pnResultLen = hmacCtx->m_hashCtx->DigestSize();
00395     
00396 }
00397 
00398 
00410 static bool _Verify(
00412     const CPKIFKeyMaterial& key,
00415     unsigned char* pHashData, 
00417     int nHashDataLen, 
00419     unsigned char* pSignature, 
00421     int nSignatureLen,
00423     PKIFCRYPTO::HASH_ALG hashAlg
00424     )
00425 {
00426     LOG_STRING_DEBUG("_Verify(const CPKIFKeyMaterial& key, unsigned char* pHashData, int nHashDataLen, unsigned char* pSignature, int nSignatureLen)", TOOLKIT_CRYPTO_CRYPTOPPRAW, 0, NULL);
00427     CPKIFCryptoPPKeyMaterial * km = 0;
00428     km = dynamic_cast<CPKIFCryptoPPKeyMaterial *>(const_cast<CPKIFKeyMaterial *>(&key));
00429 
00430     // if the CPKIFKeyMaterial wasn't a CPKIFCryptoPPKeyMaterial, use it to make one.
00431     // Use a smart pointer to clean it up *only* in the event that it's created here
00432     CPKIFCryptoPPKeyMaterialPtr kmp;
00433     if(!km) {
00434         try {
00435             kmp = CPKIFCryptoPPKeyMaterialPtr(new CPKIFCryptoPPKeyMaterial(key));
00436         }catch(CPKIFException &){
00437             // we'll throw properly in the next block
00438             kmp = CPKIFCryptoPPKeyMaterialPtr((CPKIFCryptoPPKeyMaterial *)0);
00439         }
00440         km = kmp.get();     
00441     }
00442 
00443     if(!km)
00444     {
00445         throw CPKIFCryptoException(TOOLKIT_CRYPTO_CRYPTOPPRAW, PKIF_CRYPTOPP_UNSUPPORTED_ALG);
00446     }
00447 
00448     CPKIFBufferPtr spkiBuf = km->GetRawSPKI();
00449     ByteQueue keyReader;
00450     keyReader.Put(spkiBuf->GetBuffer(), spkiBuf->GetLength());
00451 
00452     PK_Verifier * verifier = 0;
00453     const CPKIFAlgorithm * alg = km->GetKeyAlg();
00454     bool isDSA = false;
00455     switch(alg->AsymkeyAlg()) {
00456         case PKIFCRYPTO::RSA:
00457             switch(hashAlg) {
00458                 case PKIFCRYPTO::SHA1:
00459                     verifier = new RSASS<PKCS1v15,CryptoPP::SHA1>::Verifier(keyReader);
00460                     break;
00461                 case PKIFCRYPTO::SHA256:
00462                     verifier = new RSASS<PKCS1v15,CryptoPP::SHA256>::Verifier(keyReader);
00463                     break;
00464                 case PKIFCRYPTO::SHA384:
00465                     verifier = new RSASS<PKCS1v15,CryptoPP::SHA384>::Verifier(keyReader);
00466                     break;
00467                 case PKIFCRYPTO::SHA512:
00468                     verifier = new RSASS<PKCS1v15,CryptoPP::SHA512>::Verifier(keyReader);
00469                     break;
00470                 default:
00471                     throw CPKIFCryptoException(TOOLKIT_CRYPTO_CRYPTOPPRAW, PKIF_CRYPTOPP_UNSUPPORTED_ALG);
00472                     break;
00473             }
00474             break;
00475         case PKIFCRYPTO::ECC:
00476             isDSA = true;
00477             switch(hashAlg) {
00478                 case PKIFCRYPTO::SHA1:
00479                     verifier = new ECDSA<ECP,CryptoPP::SHA1>::Verifier(keyReader);
00480                     break;
00481                 case PKIFCRYPTO::SHA256:
00482                     verifier = new ECDSA<ECP,CryptoPP::SHA256>::Verifier(keyReader);
00483                     break;
00484                 case PKIFCRYPTO::SHA384:
00485                     verifier = new ECDSA<ECP,CryptoPP::SHA384>::Verifier(keyReader);
00486                     break;
00487                 case PKIFCRYPTO::SHA512:
00488                     verifier = new ECDSA<ECP,CryptoPP::SHA512>::Verifier(keyReader);
00489                     break;
00490                 default:
00491                     throw CPKIFCryptoException(TOOLKIT_CRYPTO_CRYPTOPPRAW, PKIF_CRYPTOPP_UNSUPPORTED_ALG);
00492                     break;
00493             }
00494             break;
00495         case PKIFCRYPTO::DSS:
00496             // in the case of DSA keys, PKIF needs to keep track of whether (either inherited or explicit)
00497             // paramters are present, as crypto++ communicates their absence by dereferencing a NULL
00498             // pointer.
00499             if(!km->HasParams())
00500                 throw CPKIFCryptoException(TOOLKIT_CRYPTO_CRYPTOPPRAW, PKIF_CRYPTOPP_RAW_IMPORT_FAILED);
00501             isDSA = true;
00502             switch(hashAlg) {
00503                 case PKIFCRYPTO::SHA1:
00504                     verifier = new DSA::Verifier(keyReader);
00505                     break;
00506                 default:
00507                     throw CPKIFCryptoException(TOOLKIT_CRYPTO_CRYPTOPPRAW, PKIF_CRYPTOPP_UNSUPPORTED_ALG);
00508                     break;
00509             }
00510             break;
00511         default:
00512             throw CPKIFCryptoException(TOOLKIT_CRYPTO_CRYPTOPPRAW, PKIF_CRYPTOPP_UNSUPPORTED_ALG);
00513             break;
00514     }
00515     
00516     PKIFCryptoPPExternalDigestAccumulator * ed = NewEDAccumulator(pHashData,nHashDataLen);
00517     if(!isDSA) {
00518         verifier->InputSignature(*ed,pSignature,nSignatureLen);
00519     }else{
00520         // PKIF deals in DER, so assume any incoming signatures are in DER format.
00521         // Crypto++ wants IEEE P1363.
00522         size_t targetLen = verifier->SignatureLength();
00523         unsigned char * converted = new unsigned char[targetLen];
00524         try {
00525             targetLen = DSAConvertSignatureFormat(converted,targetLen,DSA_P1363,pSignature,nSignatureLen,DSA_DER);
00526         }catch(BERDecodeErr &){
00527             // if this throws, let crypto++ assume it's IEEE P1363 and try the verification anyway
00528             delete[] converted;
00529             converted = 0;
00530         }
00531         if(converted) {
00532             verifier->InputSignature(*ed,converted,targetLen);
00533             delete[] converted;
00534             converted = 0;
00535         } else {
00536             verifier->InputSignature(*ed,pSignature,nSignatureLen);
00537         }
00538     }
00539     bool verified = verifier->Verify(ed);
00540     delete verifier;
00541     return verified;
00542 }
00551 bool CPKIFCryptoPPRaw::VerifyCertificate(
00554     const CPKIFCertificate& issCert, 
00557     const CPKIFCertificate& subCert)
00558 {
00559     CPKIFCryptoPPKeyMaterial issKey(issCert);
00560 
00561     // crypto++ doesn't really know anything about certificates, so the tbsCertificate must
00562     // be manually extracted. it may be worth adding a function to the certificate class to retrieve that
00563     CPKIFBufferPtr tbsCertificate = GetTBSCertSequence(subCert);
00564     CPKIFAlgorithm * sigAlg = CPKIFAlgorithm::GetAlg(subCert.SignatureAlgorithm()->oid());
00565     if(!sigAlg) {
00566         throw CPKIFCryptoException(TOOLKIT_CRYPTO_CRYPTOPPRAW, PKIF_CRYPTOPP_UNSUPPORTED_ALG);
00567     }
00568     IPKIFHashContext * dig = HashInit(sigAlg->HashAlg());
00569     boost::shared_ptr<IPKIFHashContext> digPtr(dig);
00570     HashUpdate(digPtr.get(),const_cast<unsigned char *>(tbsCertificate->GetBuffer()),tbsCertificate->GetLength());
00571     int hashLen = CPKIFAlgorithm::GetAlg(sigAlg->HashAlg())->DigestSize();
00572     unsigned char * hashVal = new unsigned char[hashLen];
00573     // stuffing this into a smart pointer in case something below throws
00574     CPKIFBufferPtr hashBuf(new CPKIFBuffer(true,hashVal,hashLen));
00575     HashFinal(digPtr.get(),hashVal,&hashLen);
00576     CPKIFBufferPtr sigBuf = subCert.Signature();
00577     return _Verify(issKey,hashVal,hashLen,const_cast<unsigned char *>(sigBuf->GetBuffer()),sigBuf->GetLength(),
00578         sigAlg->HashAlg());
00579 }
00580 
00581 bool VerifyCertificateWithCryptoPP(CPKIFSubjectPublicKeyInfoPtr& spki, const CPKIFCertificate& subCert)
00582 {
00583     CPKIFCryptoPPKeyMaterial issKey(spki);
00584 
00585     // crypto++ doesn't really know anything about certificates, so the tbsCertificate must
00586     // be manually extracted. it may be worth adding a function to the certificate class to retrieve that
00587     CPKIFBufferPtr tbsCertificate = GetTBSCertSequence(subCert);
00588     CPKIFAlgorithm * sigAlg = CPKIFAlgorithm::GetAlg(subCert.SignatureAlgorithm()->oid());
00589     if(!sigAlg) {
00590         throw CPKIFCryptoException(TOOLKIT_CRYPTO_CRYPTOPPRAW, PKIF_CRYPTOPP_UNSUPPORTED_ALG);
00591     }
00592 
00593     IPKIFCryptoMisc* cm = GetPlatformCryptoMisc();
00594 
00595     IPKIFHashContext * dig = cm->HashInit(sigAlg->HashAlg());
00596     boost::shared_ptr<IPKIFHashContext> digPtr(dig);
00597     cm->HashUpdate(digPtr.get(),const_cast<unsigned char *>(tbsCertificate->GetBuffer()),tbsCertificate->GetLength());
00598     int hashLen = CPKIFAlgorithm::GetAlg(sigAlg->HashAlg())->DigestSize();
00599     unsigned char * hashVal = new unsigned char[hashLen];
00600     // stuffing this into a smart pointer in case something below throws
00601     CPKIFBufferPtr hashBuf(new CPKIFBuffer(true,hashVal,hashLen));
00602     cm->HashFinal(digPtr.get(),hashVal,&hashLen);
00603     CPKIFBufferPtr sigBuf = subCert.Signature();
00604     return _Verify(issKey,hashVal,hashLen,const_cast<unsigned char *>(sigBuf->GetBuffer()),sigBuf->GetLength(),
00605         sigAlg->HashAlg());
00606 }
00607 
00618 bool CPKIFCryptoPPRaw::Verify(
00620     const CPKIFKeyMaterial& key,
00622     unsigned char* pHashData, 
00624     int nHashDataLen, 
00626     unsigned char* pSignature, 
00628     int nSignatureLen,
00630     PKIFCRYPTO::HASH_ALG hashAlg)
00631 {
00632     //no state 
00633     return _Verify(key, pHashData, nHashDataLen, pSignature, nSignatureLen, hashAlg);
00634 }
00645 void CPKIFCryptoPPRaw::GenRandom(
00647     unsigned char* buf,
00649     int len)
00650 {
00651     LOG_STRING_DEBUG("CPKIFCryptoPPRaw::GenRandom(unsigned char* buf, int len)", TOOLKIT_CRYPTO_CRYPTOPPRAW, 0, this);
00652 
00653     if(NULL == buf || 0 == len)
00654         return; //no need to raise an exception.  the caller asks for nothing and received nothing.
00655 
00656     if(len && !buf)
00657         throw CPKIFCryptoException(thisComponent, COMMON_INVALID_INPUT, "NULL output buffer passed to GenRandom.");
00658         
00659     // XXX Should this be autoconf'd to allow usage with a manually seeded RNG?
00660     AutoSeededRandomPool rng;
00661     rng.GenerateBlock(buf,len);
00662     
00663 }
00677 IPKIFHashContext* CPKIFCryptoPPRaw::HashInit(
00680     PKIFCRYPTO::HASH_ALG alg)
00681 {
00682     LOG_STRING_DEBUG("CPKIFCryptoPPRaw::HashInit(HASH_ALG alg)", TOOLKIT_CRYPTO_CRYPTOPPRAW, 0, this);
00683     
00684     //create a hash context object and populate it with context and hash objects
00685     //throw bad_alloc; nothing to clean up in this function
00686     CPKIFCryptoPPRawContext* hashCtx = new CPKIFCryptoPPRawContext();
00687     switch(alg)
00688     {
00689     case PKIFCRYPTO::SHA1:
00690         hashCtx->m_hashCtx = new CryptoPP::SHA1();
00691         break;
00692 #ifndef FIPS_MODE
00693     case PKIFCRYPTO::MD5:
00694         hashCtx->m_hashCtx = new CryptoPP::Weak::MD5();
00695         break;
00696 #endif
00697     case PKIFCRYPTO::SHA224:
00698         hashCtx->m_hashCtx = new CryptoPP::SHA224();
00699         break;
00700     case PKIFCRYPTO::SHA256:
00701         hashCtx->m_hashCtx = new CryptoPP::SHA256();
00702         break;
00703     case PKIFCRYPTO::SHA384:
00704         hashCtx->m_hashCtx = new CryptoPP::SHA384();
00705         break;
00706     case PKIFCRYPTO::SHA512:
00707         hashCtx->m_hashCtx = new CryptoPP::SHA512();
00708         break;
00709     default:
00710         std::ostringstream os;
00711         os << "Unsupported hash algorithm encountered: " << alg;
00712         RAISE_CRYPTO_EXCEPTION(os.str().c_str(), thisComponent, CRYPTO_ALG_NOT_SUPPORTED, NULL);
00713     }
00714     return hashCtx;
00715 }
00728 void CPKIFCryptoPPRaw::HashUpdate(
00730     IPKIFHashContext* hash, 
00732     unsigned char* pData, 
00734     int nDataLen)
00735 {
00736     LOG_STRING_DEBUG("CPKIFCryptoPPRaw::HashUpdate(IPKIFHashContext* hash, unsigned char* pData, int nDataLen)", TOOLKIT_CRYPTO_CRYPTOPPRAW, 0, this);
00737     //sanity check the inputs: 
00738     //  hash must not be NULL, must be of a type this class supports and must not be empty
00739     //  pData MAY be NULL (if not it is assumed to be at least nDataLen bytes)
00740     //  nDataLen must not be less than zero
00741     if(0 == hash || 0 > nDataLen)
00742         throw CPKIFCryptoException(thisComponent, COMMON_INVALID_INPUT, "NULL input passed to HashUpdate.");
00743 
00744     //cast the hash context to the type this class handles.  if the cast fails
00745     //then the context is not the correct type.
00746     CPKIFCryptoPPRawContext* hashCtx = dynamic_cast<CPKIFCryptoPPRawContext*>(hash);
00747     if(0 == hashCtx)
00748         throw CPKIFCryptoException(thisComponent, PKIFCRYPTOPP_INCORRECT_HASH_CONTEXT, "Incorrect hash context passed to HashUpdate.");
00749 
00750     if(0 == hashCtx->m_hashCtx)
00751         throw CPKIFCryptoException(thisComponent, PKIFCRYPTOPP_EMPTY_HASH_CONTEXT, "Empty hash context passed to HashUpdate.");
00752     
00753     hashCtx->m_hashCtx->Update(pData, nDataLen);
00754     
00755 }
00768 void CPKIFCryptoPPRaw::HashFinal(
00770     IPKIFHashContext* hash,
00772     unsigned char* pResult, 
00775     int* pnResultLen)
00776 {
00777     LOG_STRING_DEBUG("CPKIFCryptoPPRaw::HashFinal(IPKIFHashContext* hash, unsigned char* pResult, int* pnResultLen)", TOOLKIT_CRYPTO_CRYPTOPPRAW, 0, this);
00778 
00779     //sanity check the inputs: 
00780     //  hash must not be NULL, must be of a type this class supports and must not be empty
00781     //  result must not be NULL (it is assumed to be at least *pnResultLen bytes)
00782     //  pnResultLen must not be NULL and *pnResultLen must not be less than or equal to zero
00783     if(NULL == hash || NULL == pResult || NULL == pnResultLen || 0 >= *pnResultLen)
00784         throw CPKIFCryptoException(thisComponent, COMMON_INVALID_INPUT, "NULL input passed to HashFinal.");
00785 
00786     CPKIFCryptoPPRawContext* hashCtx = dynamic_cast<CPKIFCryptoPPRawContext*>(hash);
00787     if(NULL == hashCtx)
00788         throw CPKIFCryptoException(thisComponent, PKIFCRYPTOPP_INCORRECT_HASH_CONTEXT, "Incorrect hash context passed to HashFinal.");
00789 
00790     if(NULL == hashCtx->m_hashCtx)
00791         throw CPKIFCryptoException(thisComponent, PKIFCRYPTOPP_EMPTY_HASH_CONTEXT, "Empty hash context passed to HashUpdate.");
00792     try {   
00793         if(hashCtx->m_hashCtx->DigestSize() > boost::numeric_cast<unsigned int,int>(*pnResultLen))
00794             throw CPKIFCryptoException(thisComponent, PKIFCRYPTOPP_INCORRECT_HASH_CONTEXT, "Mismatch between buffer size and hash context passed to HashFinal.");
00795     }catch( boost::numeric::bad_numeric_cast & ) {
00796         throw CPKIFCryptoException(thisComponent, PKIFCRYPTOPP_INCORRECT_HASH_CONTEXT, "Comparison error between buffer size and hash context passed to HashFinal.");
00797     }
00798 
00799     hashCtx->m_hashCtx->Final(pResult);
00800     *pnResultLen = hashCtx->m_hashCtx->DigestSize();
00801 }
00802 
00818 IPKIFRawCryptContext* CPKIFCryptoPPRaw::CryptInit(
00821     const CPKIFKeyMaterial& key,
00823     bool pad)
00824 {
00825     LOG_STRING_DEBUG("CPKIFCryptoPPRaw::CryptInit(const CPKIFKeyMaterial& key)", TOOLKIT_CRYPTO_CRYPTOPPRAW, 0, this);
00826 
00827     // the iterative crypt functions are a bad idea with RSA or DSA keys...
00828     if(!key.ContainsSymmetricKeyMaterial()) {
00829         throw CPKIFCryptoException(TOOLKIT_CRYPTO_CRYPTOPPRAW, COMMON_INVALID_INPUT, "CryptInit() only makes sense for symmetric keys.");   
00830     }
00831     // don't even allocate a context if the parameters are wrong
00832     if(key.GetMode() == PKIFCRYPTO::CBC && NULL == key.GetIV()) {
00833         throw CPKIFCryptoException(TOOLKIT_CRYPTO_CRYPTOPPRAW, CRYPTO_MISSING_IV);
00834     }
00835 
00836     switch(key.GetSymmetricKeyAlgorithm()) {
00837         case PKIFCRYPTO::AES:
00838         case PKIFCRYPTO::AES128:
00839         case PKIFCRYPTO::AES192:
00840         case PKIFCRYPTO::AES256:
00841             break;
00842         default:
00843             throw CPKIFCryptoException(TOOLKIT_CRYPTO_CRYPTOPPRAW, PKIF_CRYPTOPP_UNSUPPORTED_ALG);  
00844     }
00845 
00846     // throw bad_alloc... nothing to cleanup
00847     CPKIFCryptoPPRawContext * ctx = new CPKIFCryptoPPRawContext();
00848     //ctx->m_symKey = const_cast<CPKIFKeyMaterial *>(key);
00849     ctx->m_keyLen = key.GetSymmetricKeyLength();
00850     ctx->m_rawKey = new unsigned char[ctx->m_keyLen];
00851     memcpy(ctx->m_rawKey, key.GetSymmetricKey(), ctx->m_keyLen);
00852     if(NULL != key.GetIV())
00853     {
00854         ctx->m_ivLen = CPKIFAlgorithm::GetAlg(key.GetSymmetricKeyAlgorithm())->BlockSize();
00855         ctx->m_iv = new unsigned char[ctx->m_ivLen];
00856         memcpy(ctx->m_iv, key.GetIV(), ctx->m_ivLen);
00857     }
00858     ctx->m_keyMode = key.GetMode();
00859     ctx->m_keyAlgorithm = key.GetSymmetricKeyAlgorithm();
00860 
00861 
00862     ctx->m_bNeedsPad = pad;
00863     // nothing much else can be done to prepare the context here; need to wait until it's known whether
00864     // we're encrypting or decrypting
00865 
00866     return ctx;
00867 }
00876 void CPKIFCryptoPPRaw::Decrypt(
00879     IPKIFRawCryptContext* cryptContext, 
00881     unsigned char* pData, 
00883     int nDataLen, 
00885     unsigned char* pResult,
00888     int* pnResultLen, 
00891     bool final)
00892 {
00893     CryptFunc<false>(cryptContext, pData, nDataLen, pResult, pnResultLen, final);
00894 }
00903 void CPKIFCryptoPPRaw::Encrypt(
00906     IPKIFRawCryptContext* cryptContext, 
00908     unsigned char* pData, 
00910     int nDataLen, 
00912     unsigned char* pResult, 
00915     int* pnResultLen, 
00918     bool final)
00919 {
00920     CryptFunc<true>(cryptContext, pData, nDataLen, pResult, pnResultLen, final);
00921 }
00933 template <bool _CryptDirection>
00934 void CPKIFCryptoPPRaw::CryptFunc(
00937     IPKIFRawCryptContext* cryptContext,
00939     unsigned char* pData, 
00941     int nDataLen, 
00943     unsigned char* pResult, 
00945     int* pnResultLen, 
00948     bool final)
00949 {
00950     LOG_STRING_DEBUG("CPKIFCryptoPPRaw CryptFunc(IPKIFRawCryptContext* cryptContext, unsigned char* pData, int nDataLen, unsigned char* pResult, int* pnResultLen, bool final)", TOOLKIT_CRYPTO_CRYPTOPPRAW, 0, NULL);
00951 
00952     CPKIFCryptoPPRawContext* icc = dynamic_cast<CPKIFCryptoPPRawContext*>(cryptContext);
00953     if(!icc)
00954     { 
00955         RAISE_CRYPTO_EXCEPTION("CPKIFCryptoPPRaw CryptFunc called with an invalid context.", TOOLKIT_CRYPTO_CRYPTOPPRAW, COMMON_INVALID_INPUT, NULL);
00956     }
00957     // the context couldn't be established by init without knowing the direction,
00958     // so the first call needs to set that up
00959     if(!icc->m_ctx)
00960     {
00961         SymmetricCipher * cipher = 0;
00962         int keyLen = icc->m_keyLen;
00963         const unsigned char * rawKey = icc->m_rawKey;
00964         int ivLen = CPKIFAlgorithm::GetAlg(icc->m_keyAlgorithm)->BlockSize();
00965         const unsigned char * iv = icc->m_iv;
00966         
00967         switch(icc->m_keyAlgorithm) {
00968             case PKIFCRYPTO::AES:
00969             case PKIFCRYPTO::AES128:
00970             case PKIFCRYPTO::AES192:
00971             case PKIFCRYPTO::AES256:
00972                 try {
00973                     switch(icc->m_keyMode) {
00974                         case PKIFCRYPTO::CBC:
00975                             if(_CryptDirection){
00976                                 cipher = new CBC_Mode<CryptoPP::AES>::Encryption(rawKey,keyLen,iv);
00977                             } else {
00978                                 cipher = new CBC_Mode<CryptoPP::AES>::Decryption(rawKey,keyLen,iv);
00979                             }
00980                             break;
00981                         case PKIFCRYPTO::ECB:
00982                             if(_CryptDirection){
00983                                 cipher = new ECB_Mode<CryptoPP::AES>::Encryption(rawKey,keyLen);
00984                             } else {
00985                                 cipher = new ECB_Mode<CryptoPP::AES>::Decryption(rawKey,keyLen);
00986                             }
00987                             break;
00988                         case PKIFCRYPTO::CTR:
00989                             if(_CryptDirection){
00990                                 cipher = new CTR_Mode<CryptoPP::AES>::Encryption(rawKey,keyLen,iv);
00991                             } else {
00992                                 cipher = new CTR_Mode<CryptoPP::AES>::Decryption(rawKey,keyLen,iv);
00993                             }
00994                             break;
00995                         default:
00996                             RAISE_CRYPTO_EXCEPTION("CPKIFCryptoPPRaw CryptFunc called with an invalid context.", TOOLKIT_CRYPTO_CRYPTOPPRAW, COMMON_INVALID_INPUT, NULL);
00997                             break;
00998                     }
00999                 }catch(CryptoPP::Exception &) {
01000                     RAISE_CRYPTO_EXCEPTION("Crypto++ key material did not match cipher and mode",TOOLKIT_CRYPTO_CRYPTOPPRAW,COMMON_INVALID_INPUT, NULL);
01001                 }catch(CPKIFException &) {
01002                     throw;
01003                 }catch(...){
01004                     RAISE_CRYPTO_EXCEPTION("Unknown error setting up crypto context. Most likely improperly initialized key material.",
01005                         TOOLKIT_CRYPTO_CRYPTOPPRAW, COMMON_INVALID_INPUT, NULL);
01006                 }
01007                 break;
01008             default:
01009                 RAISE_CRYPTO_EXCEPTION("CPKIFCryptoPPRaw CryptFunc called with an invalid context.", TOOLKIT_CRYPTO_CRYPTOPPRAW, COMMON_INVALID_INPUT, NULL);
01010                 break;
01011 
01012         }
01013         // the StreamTransformationFilter should pad as needed but do no harm if not needed.
01014         icc->m_ctx = new StreamTransformationFilter(*cipher, new ByteQueue(),
01015             icc->m_bNeedsPad ?  CryptoPP::StreamTransformationFilter::DEFAULT_PADDING : 
01016                                 CryptoPP::StreamTransformationFilter::NO_PADDING);
01017     }
01018     try {
01019         if(nDataLen > 0) {
01020             icc->m_ctx->Put(pData,nDataLen);
01021         }
01022         if(final) {
01023             icc->m_ctx->MessageEnd();
01024         }
01025     }catch(CryptoPP::Exception & e){
01026         // any crypto++ exception here would generally be due to a bad ciphertext.
01027         RAISE_CRYPTO_EXCEPTION(e.what(),TOOLKIT_CRYPTO_CRYPTOPPRAW,COMMON_INVALID_INPUT,NULL);
01028     }
01029     ByteQueue * outTrans = dynamic_cast<ByteQueue *>(icc->m_ctx->AttachedTransformation());
01030     // XXX This should be OK since the buffer size came in via an int. We may want to
01031     // use one of the boost checked casts here just the same.
01032     int avail = static_cast<int>(outTrans->MaxRetrievable());
01033     if(avail > 0) {
01034         outTrans->Get(pResult,*pnResultLen);
01035         if(*pnResultLen > avail) *pnResultLen = avail;
01036         if(final && outTrans->MaxRetrievable() > 0)
01037             RAISE_CRYPTO_EXCEPTION("CPKIFCryptoPPRaw CryptFunc (finalize) called with a buffer that's too small for the output.",
01038             TOOLKIT_CRYPTO_CRYPTOPPRAW, COMMON_INVALID_INPUT, NULL);
01039     }
01040 }
01041 
01052 template<bool _CryptDirection>
01053 void _ASymCrypt(
01055     const CPKIFKeyMaterial& key, 
01057     unsigned char* pData, 
01059     int nDataLen, 
01061     unsigned char* pResult, 
01063     int* pnResultLen, 
01065     bool pad)
01066 {
01067     throw CPKIFCryptoException(TOOLKIT_CRYPTO_CRYPTOPPRAW, COMMON_NOT_IMPLEMENTED, "The crypto++ raw colleague does not currently support asymmetric encryption operations.");
01068 }

Generated on Mon Nov 15 11:15:54 2010 for PublicKeyInfrastructureFramework(PKIF) by  doxygen 1.5.6