PKIFCryptoPP.cpp

Go to the documentation of this file.
00001 
00009 #include "PKIFCryptoPP.h"
00010 #include "PKIFCryptoPPCredential.h"
00011 #include "PKIFCryptoPPKeyMaterial.h"
00012 #include "PKIFCryptoPPExternalDigest.h"
00013 #include "PKIFCryptoPPKAContext.h"
00014 
00015 #include "ToolkitUtils.h"
00016 #include "PKIFCryptoErrors.h"
00017 #include "PKIFCryptoPPErrors.h"
00018 #include "PKIFCryptoException.h"
00019 #include "KeyUsage.h"
00020 #include "PKIFAlgorithm.h"
00021 #include "Buffer.h"
00022 #include "SubjectPublicKeyInfo.h"
00023 #include "Certificate.h"
00024 
00025 #include "ASN1Helper.h"
00026 #include "ECC-CMS.h"
00027 
00028 #include "cryptlib.h"
00029 #include "pubkey.h"
00030 #include "sha.h"
00031 #include "queue.h"
00032 #include "osrng.h"
00033 #include "rsa.h"
00034 #include "dsa.h"
00035 #include "eccrypto.h"
00036 #include "asn.h"
00037 #include "dsa.h"
00038 #include "modes.h"
00039 #include "aes.h"
00040 #include "hmac.h"
00041 #define CRYPTOPP_ENABLE_NAMESPACE_WEAK 1
00042 #include "md5.h"
00043 
00044 #include <oids.h>
00045 
00046 
00047 #include <boost/scoped_ptr.hpp>
00048 
00049 using namespace CryptoPP;
00050 using namespace std;
00051 using namespace boost;
00052 
00053 #include <sstream>
00054 
00055 #include "boost/numeric/conversion/cast.hpp"
00056 
00057 #if defined(WIN32) || defined(_WIN32)
00058     #include <Winsock2.h>
00059 #endif
00060 
00061 #if !defined(_WIN32)
00062 #include <netinet/in.h>
00063 #endif
00064 
00065 using boost::numeric_cast;
00066 using boost::bad_numeric_cast;
00067 
00068 using namespace std;
00069 using namespace CryptoPP;
00070 
00072 struct CPKIFCryptoPPImpl
00073 {
00074 };
00076 
00085 CPKIFCryptoPP::CPKIFCryptoPP()
00086 :m_impl(new CPKIFCryptoPPImpl)
00087 {
00088     LOG_STRING_DEBUG(__FUNCTION__,TOOLKIT_CRYPTO_CRYPTOPP,0,this);
00089 }
00097 CPKIFCryptoPP::~CPKIFCryptoPP()
00098 {
00099     LOG_STRING_DEBUG(__FUNCTION__,TOOLKIT_CRYPTO_CRYPTOPP,0,this);
00100     if(!m_impl) {
00101         delete m_impl;
00102         m_impl = 0;
00103     }
00104 }
00105 
00115 void CPKIFCryptoPP::Initialize()
00116 {
00117     LOG_STRING_DEBUG(__FUNCTION__,TOOLKIT_CRYPTO_CRYPTOPP,0,this);
00118 }
00119 
00130 void CPKIFCryptoPP::GetKeyList(
00132     CPKIFCredentialList& v,
00134     CPKIFKeyUsagePtr& ku)
00135 {
00136     throw CPKIFCryptoException(TOOLKIT_CRYPTO_CRYPTOPP, COMMON_NOT_IMPLEMENTED, "The crypto++ colleague does not store keys.");
00137 }
00138 
00149 void CPKIFCryptoPP::GetKeyList(
00151     CPKIFCredentialList& v,
00153     std::bitset<9>* ku)
00154 {
00155     throw CPKIFCryptoException(TOOLKIT_CRYPTO_CRYPTOPP, COMMON_NOT_IMPLEMENTED, "The crypto++ colleague does not store keys.");
00156 }
00157 
00167 bool CPKIFCryptoPP::OwnsKey(
00169     const CPKIFCredential& keyID) const
00170 {
00171     LOG_STRING_DEBUG(__FUNCTION__,TOOLKIT_CRYPTO_CRYPTOPP,0,this);
00172     // Since the CPKIFCryptoPPCredential object carries all the key material it needs, if we can cast it we own it
00173     const CPKIFCryptoPPCredential * cryptoppkey = dynamic_cast<const CPKIFCryptoPPCredential *>(&keyID);
00174     return (0 != cryptoppkey);
00175 }
00184 CPKIFCredentialPtr CPKIFCryptoPP::MakeKeyID(
00187     const std::string& asciiHexKeyID)
00188 {
00189     LOG_STRING_DEBUG(__FUNCTION__,TOOLKIT_CRYPTO_CRYPTOPP,0,this);
00190     throw CPKIFCryptoException(TOOLKIT_CRYPTO_CRYPTOPP, COMMON_NOT_IMPLEMENTED, "The crypto++ colleague does not store keys.");
00191 }
00212 void CPKIFCryptoPP::Sign(
00214     const CPKIFCredential& key, 
00216     unsigned char* pHashData, 
00218     int nHashDataLen, 
00220     unsigned char* pSignature, 
00223     int* nSignatureLen,
00225     PKIFCRYPTO::HASH_ALG ha
00226     )
00227 
00228 {
00229     LOG_STRING_DEBUG(__FUNCTION__,TOOLKIT_CRYPTO_CRYPTOPP,0,this);
00230     CPKIFCryptoPPCredential * cryptoppkey = const_cast<CPKIFCryptoPPCredential *>(dynamic_cast<const CPKIFCryptoPPCredential *>(&key));
00231     if(!cryptoppkey) {
00232         RAISE_CRYPTO_EXCEPTION("Crypto++ Crypto colleague was given a non-crypto++ credential",
00233             thisComponent,CRYPTO_UNRECOGNIZED_CREDENTIAL,this);
00234     }
00235     CPKIFAlgorithm * keyAlg = cryptoppkey->GetAlgorithm();
00236     if(!keyAlg) {
00237         RAISE_CRYPTO_EXCEPTION("Crypto++ credential has not been properly populated",thisComponent,COMMON_INVALID_INPUT,this);
00238     }
00239     bool isDSA = false;
00240     PK_Signer * signer = 0;
00241     ByteQueue keyReader;
00242     keyReader.Put(cryptoppkey->m_keyBuf->GetBuffer(),cryptoppkey->m_keyBuf->GetLength());
00243     switch(keyAlg->AsymkeyAlg()) {
00244         case PKIFCRYPTO::RSA:
00245             switch(ha) {
00246                 case PKIFCRYPTO::MD5:
00247                     signer = new RSASS<PKCS1v15,CryptoPP::Weak::MD5>::Signer(keyReader);
00248                     break;
00249                 case PKIFCRYPTO::SHA1:
00250                     signer = new RSASS<PKCS1v15,CryptoPP::SHA1>::Signer(keyReader);
00251                     break;
00252                 case PKIFCRYPTO::SHA256:
00253                     signer = new RSASS<PKCS1v15,CryptoPP::SHA256>::Signer(keyReader);
00254                     break;
00255                 case PKIFCRYPTO::SHA384:
00256                     signer = new RSASS<PKCS1v15,CryptoPP::SHA384>::Signer(keyReader);
00257                     break;
00258                 case PKIFCRYPTO::SHA512:
00259                     signer = new RSASS<PKCS1v15,CryptoPP::SHA512>::Signer(keyReader);
00260                     break;
00261                 default:
00262                     throw CPKIFCryptoException(TOOLKIT_CRYPTO_CRYPTOPP, PKIF_CRYPTOPP_UNSUPPORTED_ALG);
00263                     break;
00264             }
00265             break;
00266         case PKIFCRYPTO::ECC:
00267             isDSA = true;
00268             switch(ha) {
00269                 case PKIFCRYPTO::SHA1:
00270                     signer = new ECDSA<ECP,CryptoPP::SHA1>::Signer(keyReader);
00271                     break;
00272                 case PKIFCRYPTO::SHA256:
00273                     signer = new ECDSA<ECP,CryptoPP::SHA256>::Signer(keyReader);
00274                     break;
00275                 case PKIFCRYPTO::SHA384:
00276                     signer = new ECDSA<ECP,CryptoPP::SHA384>::Signer(keyReader);
00277                     break;
00278                 case PKIFCRYPTO::SHA512:
00279                     signer = new ECDSA<ECP,CryptoPP::SHA512>::Signer(keyReader);
00280                     break;
00281                 default:
00282                     throw CPKIFCryptoException(TOOLKIT_CRYPTO_CRYPTOPP, PKIF_CRYPTOPP_UNSUPPORTED_ALG);
00283                     break;
00284             }
00285             break;
00286         case PKIFCRYPTO::DSS:
00287             isDSA = true;
00288             switch(ha) {
00289                 case PKIFCRYPTO::SHA1:
00290                     signer = new DSA::Signer(keyReader);
00291                     break;
00292                 default:
00293                     throw CPKIFCryptoException(TOOLKIT_CRYPTO_CRYPTOPP, PKIF_CRYPTOPP_UNSUPPORTED_ALG);
00294                     break;
00295             }
00296             break;
00297         default:
00298             throw CPKIFCryptoException(TOOLKIT_CRYPTO_CRYPTOPP, PKIF_CRYPTOPP_UNSUPPORTED_ALG);
00299             break;
00300     }
00301     int expectedLen = static_cast<int>(signer->SignatureLength());
00302     if(*nSignatureLen < expectedLen) {
00303         delete signer;
00304         throw CPKIFCryptoException(TOOLKIT_CRYPTO_CRYPTOPP, COMMON_INVALID_INPUT, "Signature buffer too short");
00305     }
00306     
00307     PKIFCryptoPPExternalDigestAccumulator * ed = NewEDAccumulator(pHashData,nHashDataLen);
00308     static RandomPool rng;
00309     
00310     
00311     // crypto++ does DSA in the IEEE format. Since this is PKIF, all signatures will be expected to be DER.
00312     if(!isDSA) {
00313         signer->Sign(rng,ed,pSignature);
00314         *nSignatureLen = expectedLen;
00315     } else {
00316         unsigned char * rawSig = new unsigned char[expectedLen];
00317         // DSA does some funky stuff with the message accumulator in the initializer that
00318         // our external digest accumulator doesn't handle.
00319         // let the signer make one then copy the initialization into ours.
00320         
00321         //Removed the signature formatting to be consistent with NSS
00322         PK_MessageAccumulatorBase * acc = dynamic_cast<PK_MessageAccumulatorBase *>(signer->NewSignatureAccumulator(rng));
00323         ed->m_presignature = acc->m_presignature;
00324         ed->m_k = acc->m_k;
00325         //signer->Sign(rng,ed,rawSig);
00326         signer->Sign(rng,ed,pSignature);
00327         *nSignatureLen = expectedLen;
00328         //size_t outLen = DSAConvertSignatureFormat(pSignature,*nSignatureLen,DSA_DER,rawSig,expectedLen,DSA_P1363);
00329         //*nSignatureLen = static_cast<int>(outLen);
00330     }
00331 }
00332 
00345 void CPKIFCryptoPP::Decrypt(
00348     const CPKIFCredential& key,
00350     unsigned char* pData,
00352     int nDataLen, 
00354     unsigned char* pResult,
00357     int* pnResultLen)
00358 {
00359     LOG_STRING_DEBUG(__FUNCTION__,TOOLKIT_CRYPTO_CRYPTOPP,0,this);
00360     const CPKIFCryptoPPCredential * cryptoppkey = dynamic_cast<const CPKIFCryptoPPCredential *>(&key);
00361     if(!cryptoppkey) {
00362         RAISE_CRYPTO_EXCEPTION("Crypto++ Crypto colleague was given a non-Crypto++ credential",
00363             thisComponent,CRYPTO_UNRECOGNIZED_CREDENTIAL,this);
00364     }
00365     
00366     throw CPKIFCryptoException(TOOLKIT_CRYPTO_CRYPTOPP, COMMON_NOT_IMPLEMENTED, "The crypto++ colleague does not store keys.");
00367 }
00368 
00380 void CPKIFCryptoPP::Encrypt(
00383     const CPKIFCredential& key,
00385     unsigned char* pData, 
00387     int nDataLen, 
00389     unsigned char* pResult, 
00392     int* pnResultLen)
00393 {
00394     RAISE_CRYPTO_EXCEPTION("Encryption is unimplemented for stored key material.",thisComponent,COMMON_NOT_IMPLEMENTED,this);
00395 }
00409 bool CPKIFCryptoPP::Verify(
00412     const CPKIFCredential& key,
00415     unsigned char* pHashData, 
00417     int nHashDataLen, 
00419     unsigned char* pSignature, 
00421     int nSignatureLen,
00423     PKIFCRYPTO::HASH_ALG ha
00424     )
00425 {
00426     RAISE_CRYPTO_EXCEPTION("Verification is unimplemented for stored key material.",thisComponent,COMMON_NOT_IMPLEMENTED,this);
00427     return false;
00428 }
00442 IPKIFCryptContext* CPKIFCryptoPP::CryptInit(
00445     CPKIFCredentialPtr& key,
00447     bool pad)
00448 {
00449     RAISE_CRYPTO_EXCEPTION("Context-based operations are unimplemented for Crypto++ stored key material.",thisComponent,COMMON_NOT_IMPLEMENTED,this);
00450     return 0;
00451 }
00464 void CPKIFCryptoPP::Decrypt(
00467     IPKIFCryptContext* cryptContext, 
00469     unsigned char* pData, 
00471     int nDataLen, 
00473     unsigned char* pResult, 
00476     int* pnResultLen, 
00479     bool final)
00480 {
00481     RAISE_CRYPTO_EXCEPTION("Context-based decryption is unimplemented for stored key material.",thisComponent,COMMON_NOT_IMPLEMENTED,this);
00482 }
00495 void CPKIFCryptoPP::Encrypt(IPKIFCryptContext* cryptContext, unsigned char* pData, int nDataLen, unsigned char* pResult, int* pnResultLen, bool final)
00496 {
00497     RAISE_CRYPTO_EXCEPTION("Encryption is unimplemented for stored key material.",thisComponent,COMMON_NOT_IMPLEMENTED,this);
00498 }
00499 
00506 void GetPrivateExponent(CryptoPP::SecByteBlock & exp, CryptoPP::DL_PrivateKey_EC<CryptoPP::ECP> & key)
00507 {
00508     exp.New(key.GetPrivateExponent().ByteCount());
00509     key.GetPrivateExponent().Encode(exp,exp.m_size);
00510 }
00511 
00519 void GetEncodedPublicKey(CryptoPP::SecByteBlock & enc, CryptoPP::DL_PublicKey_EC<CryptoPP::ECP> & key)
00520 {
00521     CryptoPP::ByteQueue bq;
00522     key.DEREncodePublicKey(bq);
00523     
00524     size_t len;
00525     try {
00526         len = boost::numeric_cast<size_t,CryptoPP::lword>(bq.MaxRetrievable());
00527     }catch(boost::numeric::bad_numeric_cast &){
00528         throw CPKIFCryptoException(TOOLKIT_CRYPTO_CRYPTOPP, COMMON_INVALID_INPUT, "Failed to decode public key");
00529     }
00530     enc.New(len);
00531     bq.Get(enc,len);
00532 }
00533 
00547 IPKIFKeyAgreeContextPtr CPKIFCryptoPP::SecretAgree(
00550                                         CPKIFCredentialPtr& myPrivateKey,
00552                                         const CPKIFCertificatePtr& theirCert,
00554                                         const CPKIFAlgorithm * alg)
00555 {
00556     // use a CPKIFCryptoPPKeyMaterial object since it can easily produce whichever format
00557     // is needed for the public key
00558     CPKIFCryptoPPKeyMaterialPtr km(new CPKIFCryptoPPKeyMaterial(*theirCert));
00559     CPKIFBufferPtr rawKey = km->GetRawSPKI();
00560     return SecretAgree(myPrivateKey, rawKey, alg);
00561 }
00562 
00580 // If myPrivateKey is absent, theirPublicKey needs to be a whole subject public key info structure.
00581 // If myPrivateKey is supplied, theirPublicKey is assumed to be just the integer.
00582 
00583 IPKIFKeyAgreeContextPtr CPKIFCryptoPP::SecretAgree(
00586                                         CPKIFCredentialPtr& myPrivateKey,
00590                                         const CPKIFBufferPtr& theirPublicKey,
00592                                         const CPKIFAlgorithm * alg)
00593 {
00594     CPKIFOIDPtr kaOID = alg->OID();
00595     CryptoPP::SecByteBlock theirPubInteger;
00596     CPKIFCryptoPPCredentialPtr myCppCred;
00597 
00598 
00599     CryptoPP::DL_PublicKey_EC<CryptoPP::ECP> theirPub;
00600     CryptoPP::ByteQueue pubq;
00601     pubq.Put(theirPublicKey->GetBuffer(),theirPublicKey->GetLength());
00602     try {
00603         theirPub.BERDecode(pubq);
00604     } catch(CryptoPP::BERDecodeErr &) {
00605         RAISE_CRYPTO_EXCEPTION("Unable to decode public key for ECDH",thisComponent,CRYPTO_UNRECOGNIZED_CREDENTIAL,this);
00606     }
00607     
00608     // Unlike much of crypto++, Agree() expects just the integer, not the whole spki
00609     GetEncodedPublicKey(theirPubInteger,theirPub);
00610 
00611     // Generate a new ephemeral keypair if needed. Parameters will match their public key.
00612     if(!myPrivateKey) {
00613 
00614         CryptoPP::AutoSeededRandomPool rng;
00615         CryptoPP::DL_PrivateKey_EC<CryptoPP::ECP> ephemeralPriv;
00616         ephemeralPriv.Initialize(rng,theirPub.GetGroupParameters());
00617 
00618         // this is round-about, but encoding it here and stuffing it into a credential object
00619         // makes it easier to support originator/recipient with less code and conveys the nice bonus
00620         // of making static-static easy
00621         CryptoPP::ByteQueue ephemq;
00622         ephemeralPriv.DEREncode(ephemq);
00623         CPKIFCryptoPPCredential * ephemeralCred = new CPKIFCryptoPPCredential();
00624         CPKIFBufferPtr keyBuf(new CPKIFBuffer());
00625         unsigned char * keyBufRaw = keyBuf->AllocateBuffer(static_cast<int>(ephemq.MaxRetrievable()));
00626         ephemq.Get(keyBufRaw,keyBuf->GetLength());
00627         ephemeralCred->SetPrivateKey(keyBuf);
00628         myCppCred = CPKIFCryptoPPCredentialPtr(ephemeralCred);
00629         myCppCred->SetAlgorithm(CPKIFAlgorithm::GetAlg(PKIFCRYPTO::ECC));
00630         // make sure the caller gets the newly generated key for further encoding, etc.
00631         myPrivateKey = dynamic_pointer_cast<CPKIFCredential, CPKIFCryptoPPCredential>(myCppCred);
00632         
00633     }
00634 
00635 
00636     if(!myCppCred) {
00637         RAISE_CRYPTO_EXCEPTION("Crypto++ Crypto colleague was given a non-Crypto++ credential",
00638             thisComponent,CRYPTO_UNRECOGNIZED_CREDENTIAL,this);
00639     }
00640     
00641     // whether it was generated or passed in, decode now
00642     CryptoPP::ByteQueue privq;
00643     privq.Put(myCppCred->m_keyBuf->GetBuffer(),myCppCred->m_keyBuf->GetLength());
00644     CryptoPP::DL_PrivateKey_EC<CryptoPP::ECP> myPriv;
00645     myPriv.BERDecode(privq);
00646 
00647     bool kaResult = false;
00648     CryptoPP::ECDH<CryptoPP::ECP>::Domain * ecdh = 0;
00649 
00650     if(*kaOID == *g_ecdh_std_sha256kdf || *kaOID == *g_ecdh_std_sha384kdf) {
00651         // ECDH parameters should come from caller's keypair
00652         ecdh = new CryptoPP::ECDH<CryptoPP::ECP>::Domain(myPriv.GetGroupParameters());
00653         
00654     } else {
00655         RAISE_CRYPTO_EXCEPTION("Unsupported key agreement scheme",thisComponent,PKIF_CRYPTOPP_UNSUPPORTED_ALG,this);        
00656     }
00657 
00658     // this really shouldn't ever happen. normally we've either caught the unsupported scheme above
00659     // or you wouldn't have been able to get the credential in here in the first place.
00660     if(!ecdh) {
00661         RAISE_CRYPTO_EXCEPTION("Unable to initialize ECDH key agreement", thisComponent, COMMON_UNKNOWN_ERROR, this);
00662     }
00663     CPKIFCryptoPPKAContextPtr kaCtx(new CPKIFCryptoPPKAContext());
00664     kaCtx->SetOwner(this);
00665     kaCtx->SetAlgorithm(alg);
00666     CPKIFBufferPtr sharedSecret(new CPKIFBuffer());
00667     unsigned char* ss = sharedSecret->AllocateBuffer(ecdh->AgreedValueLength());
00668     CryptoPP::SecByteBlock myExp;
00669     GetPrivateExponent(myExp,myPriv);
00670 
00671     
00672     kaResult = ecdh->Agree(ss, myExp, theirPubInteger);
00673 
00674     if(!kaResult) {
00675         // if Agree() returned false, that generally indicates either a decoding failure or
00676         // incompatible domain parameters. As the explanation for PKIF_CRYPTOPP_INVALID_KEY_AGREEMENT indicates,
00677         // in this code it will nearly always be incompatible domain parameters, since the encoding has had to
00678         // traverse so many pipes to even get here.
00679         RAISE_CRYPTO_EXCEPTION("Unable to complete key agreement operation", thisComponent, PKIF_CRYPTOPP_INVALID_KEY_AGREEMENT, this);
00680     }
00681 
00682     kaCtx->SetSecret(sharedSecret);
00683     return dynamic_pointer_cast<IPKIFKeyAgreeContext,CPKIFCryptoPPKAContext>(kaCtx);
00684 }
00685 
00686 // originator interfaces for authenticated key agreement
00701 // to re-use an ephemeral keypair, pass one in. if an invalid smart pointer is passed, a new, compatible
00702 // pair will be generated
00703 IPKIFKeyAgreeContextPtr CPKIFCryptoPP::SecretAgree(
00705                                         const CPKIFCredentialPtr& myPrivateKey,
00707                                         CPKIFCredentialPtr & ephemeralKeyPair,
00709                                         const CPKIFCertificatePtr& theirCert,
00711                                         const CPKIFAlgorithm * alg)
00712 {
00713     CPKIFCryptoPPKeyMaterialPtr km(new CPKIFCryptoPPKeyMaterial(*theirCert));
00714     CPKIFBufferPtr rawKey = km->GetRawSPKI();
00715     return SecretAgree(myPrivateKey, ephemeralKeyPair, rawKey, alg);
00716 }
00717 
00735 // to re-use an ephemeral keypair, pass one in. if an invalid smart pointer is passed, a new, compatible
00736 // pair will be generated
00737 IPKIFKeyAgreeContextPtr CPKIFCryptoPP::SecretAgree(
00739                                         const CPKIFCredentialPtr& myPrivateKey,
00741                                         CPKIFCredentialPtr & ephemeralKeyPair,
00743                                         const CPKIFBufferPtr& theirPublicKey,
00745                                         const CPKIFAlgorithm * alg)
00746 {
00747     CPKIFOIDPtr kaOID = alg->OID();
00748     if(*kaOID != *g_ecmqv_sha1kdf) {
00749         RAISE_CRYPTO_EXCEPTION("Crypto++ SecretAgree() called with an unsupported algorithm",
00750             thisComponent,CRYPTO_ALG_NOT_SUPPORTED,this);
00751     }
00752 
00753     CPKIFCryptoPPCredentialPtr myCppCred = dynamic_pointer_cast<CPKIFCryptoPPCredential, CPKIFCredential>(myPrivateKey);
00754     if(!myCppCred) {
00755         RAISE_CRYPTO_EXCEPTION("Crypto++ Crypto colleague was given a non-Crypto++ credential",
00756             thisComponent,CRYPTO_UNRECOGNIZED_CREDENTIAL,this);
00757     }
00758 
00759     // import the originator static keypair so parameters are available for generation of the ephemeral
00760     // keypair if needed
00761     CryptoPP::ByteQueue privq;
00762     privq.Put(myCppCred->m_keyBuf->GetBuffer(),myCppCred->m_keyBuf->GetLength());
00763     CryptoPP::DL_PrivateKey_EC<CryptoPP::ECP> myPriv;
00764     myPriv.BERDecode(privq);
00765 
00766     // Generate a new ephemeral keypair if needed
00767     CPKIFCryptoPPCredentialPtr ephemCppCred;
00768     if(!ephemeralKeyPair) {
00769         CryptoPP::AutoSeededRandomPool rng;
00770         CryptoPP::DL_PrivateKey_EC<CryptoPP::ECP> ephemeralPriv;
00771         // parameters need to be the same as our private and their public
00772         ephemeralPriv.Initialize(rng,myPriv.GetGroupParameters());
00773         CryptoPP::ByteQueue ephemq;
00774         ephemeralPriv.DEREncode(ephemq);
00775         CPKIFCryptoPPCredential * ephemeralCred = new CPKIFCryptoPPCredential();
00776         ephemeralCred->SetAlgorithm(myCppCred->GetAlgorithm());
00777         CPKIFBufferPtr keyBuf(new CPKIFBuffer());
00778         // cast should be safe given that this is a key we just generated
00779         unsigned char * keyBufRaw = keyBuf->AllocateBuffer((int)ephemq.MaxRetrievable());
00780         ephemq.Get(keyBufRaw,keyBuf->GetLength());
00781         ephemeralCred->SetPrivateKey(keyBuf);
00782         ephemCppCred = CPKIFCryptoPPCredentialPtr(ephemeralCred);
00783         // place it in the credential pointer so it can be re-used later for encoding, etc. if needed
00784         ephemeralKeyPair = dynamic_pointer_cast<CPKIFCredential, CPKIFCryptoPPCredential>(ephemCppCred);
00785     } else {
00786         ephemCppCred = dynamic_pointer_cast<CPKIFCryptoPPCredential, CPKIFCredential>(ephemeralKeyPair);
00787     }
00788     if(!ephemCppCred) {
00789         RAISE_CRYPTO_EXCEPTION("Crypto++ Crypto colleague was given a non-Crypto++ credential",
00790             thisComponent,CRYPTO_UNRECOGNIZED_CREDENTIAL,this);
00791     }
00792 
00793     // need to decode the ephemeral pair here in case it was passed in rather than generated
00794     CryptoPP::ByteQueue ephemq;
00795     ephemq.Put(ephemCppCred->m_keyBuf->GetBuffer(),ephemCppCred->m_keyBuf->GetLength());
00796     CryptoPP::DL_PrivateKey_EC<CryptoPP::ECP> ephemPriv;
00797     try {
00798         ephemPriv.BERDecode(ephemq);
00799     } catch(CryptoPP::BERDecodeErr &){
00800         RAISE_CRYPTO_EXCEPTION("Unable to decode ephemeral keypair for MQV",thisComponent,CRYPTO_UNRECOGNIZED_CREDENTIAL,this);
00801     }
00802 
00803     CryptoPP::SecByteBlock myprivbb;
00804     GetPrivateExponent(myprivbb,myPriv);
00805 
00806     // XXX *** Allow either a full SubjectPublicKeyInfo structure or an integer to work
00807     CryptoPP::SecByteBlock theirPubInteger;
00808     CryptoPP::DL_PublicKey_EC<CryptoPP::ECP> theirPubTmp;
00809     CryptoPP::ByteQueue pubq;
00810     
00811     try {
00812         pubq.Put(theirPublicKey->GetBuffer(),theirPublicKey->GetLength());
00813         theirPubTmp.BERDecode(pubq);
00814         GetEncodedPublicKey(theirPubInteger,theirPubTmp);
00815     } catch(CryptoPP::Exception &) {
00816         theirPubInteger.New(theirPublicKey->GetLength());
00817         memcpy(theirPubInteger,theirPublicKey->GetBuffer(),theirPublicKey->GetLength());
00818     }
00819 
00820     
00821 
00822     CryptoPP::DL_PublicKey_EC<CryptoPP::ECP> ephemPub;
00823     ephemPriv.MakePublicKey(ephemPub);
00824 
00825     CryptoPP::SecByteBlock eprivbb;
00826     CryptoPP::SecByteBlock epubbb;
00827     CryptoPP::SecByteBlock econcat;
00828 
00829     // Crypto++ MQV expects the ephemeral private key to have the public key material
00830     // tacked onto the end of the buffer
00831     GetPrivateExponent(eprivbb,ephemPriv);
00832     GetEncodedPublicKey(epubbb,ephemPub);
00833     econcat.New(eprivbb.m_size+epubbb.m_size);
00834     memcpy(econcat,eprivbb,eprivbb.m_size);
00835     memcpy(econcat+eprivbb.m_size,epubbb,epubbb.m_size);
00836 
00837     CryptoPP::ECMQV<CryptoPP::ECP>::Domain ecmqv(myPriv.GetGroupParameters());
00838     CPKIFCryptoPPKAContextPtr ctx(new CPKIFCryptoPPKAContext());
00839     ctx->SetOwner(this);
00840     ctx->SetAlgorithm(alg);
00841     CPKIFBufferPtr sharedSecret(new CPKIFBuffer());
00842     unsigned char* ss = sharedSecret->AllocateBuffer(ecmqv.AgreedValueLength());
00843     bool kaResult = ecmqv.Agree(ss,myprivbb,econcat,theirPubInteger,theirPubInteger);
00844 
00845     if(!kaResult) {
00846         // if Agree() returned false, that generally indicates either a decoding failure or
00847         // incompatible domain parameters. As the explanation for PKIF_CRYPTOPP_INVALID_KEY_AGREEMENT indicates,
00848         // in this code it will nearly always be incompatible domain parameters, since the encoding has had to
00849         // traverse so many pipes to even get here.
00850         RAISE_CRYPTO_EXCEPTION("Unable to complete key agreement operation", thisComponent, PKIF_CRYPTOPP_INVALID_KEY_AGREEMENT, this);
00851     }
00852     ctx->SetSecret(sharedSecret);
00853     return dynamic_pointer_cast<IPKIFKeyAgreeContext,CPKIFCryptoPPKAContext>(ctx);
00854 
00855 }
00856 
00857 // recipient interfaces for authenticated key agreement
00858 
00874 IPKIFKeyAgreeContextPtr CPKIFCryptoPP::SecretAgree(
00876                                         const CPKIFCredentialPtr& myPrivateKey,
00879                                         const CPKIFBufferPtr& ephemeralPublicKey,
00881                                         const CPKIFCertificatePtr& theirCert,
00883                                         const CPKIFAlgorithm * alg)
00884 {
00885     CPKIFCryptoPPKeyMaterialPtr km(new CPKIFCryptoPPKeyMaterial(*theirCert));
00886     CPKIFBufferPtr rawKey = km->GetRawSPKI();
00887     return SecretAgree(myPrivateKey, ephemeralPublicKey, rawKey, alg);
00888 }
00889 
00908 IPKIFKeyAgreeContextPtr CPKIFCryptoPP::SecretAgree(
00910                                         const CPKIFCredentialPtr& myPrivateKey,
00913                                         const CPKIFBufferPtr& ephemeralPublicKey,
00915                                         const CPKIFBufferPtr& theirPublicKey,
00917                                         const CPKIFAlgorithm * alg)
00918 {
00919     CPKIFOIDPtr kaOID = alg->OID();
00920     if(*kaOID != *g_ecmqv_sha1kdf) {
00921         RAISE_CRYPTO_EXCEPTION("Crypto++ KeyAgreement() called with an unsupported algorithm",
00922             thisComponent,CRYPTO_ALG_NOT_SUPPORTED,this);
00923     }
00924     CPKIFCryptoPPCredentialPtr myCppCred = dynamic_pointer_cast<CPKIFCryptoPPCredential, CPKIFCredential>(myPrivateKey);
00925     if(!myCppCred) {
00926         RAISE_CRYPTO_EXCEPTION("Crypto++ Crypto colleague was given a non-Crypto++ credential",
00927             thisComponent,CRYPTO_UNRECOGNIZED_CREDENTIAL,this);
00928     }
00929     CryptoPP::ByteQueue privq;
00930     privq.Put(myCppCred->m_keyBuf->GetBuffer(),myCppCred->m_keyBuf->GetLength());
00931     CryptoPP::DL_PrivateKey_EC<CryptoPP::ECP> myPriv;
00932     myPriv.BERDecode(privq);
00933     CryptoPP::DL_PublicKey_EC<CryptoPP::ECP> myPub;
00934     myPriv.MakePublicKey(myPub);
00935     
00936     CryptoPP::SecByteBlock epbb(ephemeralPublicKey->GetLength());
00937     memcpy(epbb, ephemeralPublicKey->GetBuffer(), ephemeralPublicKey->GetLength());
00938 
00939     // using a raw key instead. parameters will be taken from our static key
00940     
00941 
00942     CryptoPP::SecByteBlock myprivbb;
00943     GetPrivateExponent(myprivbb,myPriv);
00944 
00945     CryptoPP::SecByteBlock mypubbb;
00946     GetEncodedPublicKey(mypubbb,myPub);
00947 
00948     // XXX *** Allow either a full SubjectPublicKeyInfo structure or an integer to work
00949     CryptoPP::SecByteBlock theirPubInteger;
00950     CryptoPP::DL_PublicKey_EC<CryptoPP::ECP> theirPubTmp;
00951     CryptoPP::ByteQueue pubq;
00952     
00953     try {
00954         pubq.Put(theirPublicKey->GetBuffer(),theirPublicKey->GetLength());
00955         theirPubTmp.BERDecode(pubq);
00956         GetEncodedPublicKey(theirPubInteger,theirPubTmp);
00957     } catch(CryptoPP::Exception &) {
00958         theirPubInteger.New(theirPublicKey->GetLength());
00959         memcpy(theirPubInteger,theirPublicKey->GetBuffer(),theirPublicKey->GetLength());
00960     }
00961 
00962     CryptoPP::SecByteBlock myconcat;
00963 
00964     // Crypto++ MQV expects the ephemeral private key to have the public key material
00965     // tacked onto the end of the buffer
00966     myconcat.New(myprivbb.m_size+mypubbb.m_size);
00967     memcpy(myconcat,myprivbb,myprivbb.m_size);
00968     memcpy(myconcat+myprivbb.m_size,mypubbb,mypubbb.m_size);
00969 
00970     CryptoPP::ECMQV<CryptoPP::ECP>::Domain ecmqv(myPriv.GetGroupParameters());
00971     CPKIFCryptoPPKAContextPtr ctx(new CPKIFCryptoPPKAContext());
00972     ctx->SetOwner(this);
00973     ctx->SetAlgorithm(alg);
00974     CPKIFBufferPtr sharedSecret(new CPKIFBuffer());
00975     unsigned char* ss = sharedSecret->AllocateBuffer(ecmqv.AgreedValueLength());
00976     bool kaResult = ecmqv.Agree(ss,myprivbb,myconcat,theirPubInteger,epbb);
00977 
00978     if(!kaResult) {
00979         // if Agree() returned false, that generally indicates either a decoding failure or
00980         // incompatible domain parameters. As the explanation for PKIF_CRYPTOPP_INVALID_KEY_AGREEMENT indicates,
00981         // in this code it will nearly always be incompatible domain parameters, since the encoding has had to
00982         // traverse so many pipes to even get here.
00983         RAISE_CRYPTO_EXCEPTION("Unable to complete key agreement operation", thisComponent, PKIF_CRYPTOPP_INVALID_KEY_AGREEMENT, this);
00984     }
00985     ctx->SetSecret(sharedSecret);
00986     return dynamic_pointer_cast<IPKIFKeyAgreeContext,CPKIFCryptoPPKAContext>(ctx);
00987 }
00988 
00989 
01000 CPKIFKeyMaterialPtr CPKIFCryptoPP::DeriveKey(
01002                                             const IPKIFKeyAgreeContextPtr & context,
01004                                             unsigned long keyLen
01005                                             )
01006 {
01007     const CPKIFAlgorithm * kaAlg = context->GetAlgorithm();
01008     CPKIFOIDPtr kaOID = kaAlg->OID();
01009     if( *kaOID != *g_ecdh_std_sha256kdf &&
01010         *kaOID != *g_ecdh_std_sha384kdf )
01011     {
01012         RAISE_CRYPTO_EXCEPTION("CPKIFCryptoPP::DeriveKey() called with an invalid algorithm",
01013             thisComponent,COMMON_INVALID_INPUT,this);
01014     }
01015     CPKIFCryptoPPKAContextPtr cppCtx = dynamic_pointer_cast<CPKIFCryptoPPKAContext,IPKIFKeyAgreeContext>(context);
01016     if(!cppCtx) {
01017         RAISE_CRYPTO_EXCEPTION("CPKIFCryptoPP::DeriveKey() called with an invalid context",
01018             thisComponent,COMMON_INVALID_INPUT,this);
01019     }
01020 
01021     unsigned long digestSize = 0;
01022     try {
01023         digestSize = boost::numeric_cast<unsigned long,int>(kaAlg->DigestSize());
01024     }catch(...){
01025         RAISE_CRYPTO_EXCEPTION("CPKIFCryptoPP::DeriveKey() called with an invalid algorithm parameter",
01026             thisComponent,COMMON_INVALID_INPUT,this);
01027     }
01028 
01029     
01030     CPKIFBufferList appendedBuffers = context->GetAppendedSharedInfo();
01031     if(appendedBuffers.size() != 1) {
01032         RAISE_CRYPTO_EXCEPTION("CPKIFCryptoPP::DeriveKey() called with invalid shared info input",
01033             thisComponent,COMMON_INVALID_INPUT,this);
01034     }
01035     CPKIFBufferList prependedBuffers = context->GetPrependedSharedInfo();
01036     if(prependedBuffers.size() != 0) {
01037         RAISE_CRYPTO_EXCEPTION("CPKIFCryptoPP::DeriveKey() called with invalid shared info input",
01038             thisComponent,COMMON_INVALID_INPUT,this);
01039     }
01040     CPKIFBufferPtr sharedInfo = appendedBuffers[0];
01041 
01042 
01043     CACASNWRAPPER_CREATE(ECC_CMS_SharedInfo,ecsPDU);
01044 
01045     
01046     
01047     // if the caller did not specify a key length, attempt to pull it out of the sharedInfo structure
01048     if(0 == keyLen) {
01049         ECC_CMS_SharedInfo * ecsi = ecsPDU.Decode(sharedInfo->GetBuffer(),sharedInfo->GetLength());
01050         if(!ecsi) throw CPKIFException(TOOLKIT_CRYPTO, COMMON_INVALID_INPUT, "keyLen is invalid and not in sharedInfo.");
01051         u_long nwKeySize32;
01052         if(ecsi->suppPubInfo.numocts > sizeof(u_long)) throw CPKIFException(TOOLKIT_CRYPTO, COMMON_INVALID_INPUT, "sharedInfo is invalid.");
01053         memcpy(&nwKeySize32,ecsi->suppPubInfo.data,ecsi->suppPubInfo.numocts);
01054         u_long keySize32 = ntohl(nwKeySize32);
01055         keyLen = keySize32;
01056     }
01057     
01058     if(keyLen > digestSize || keyLen <= 0) {
01059         RAISE_CRYPTO_EXCEPTION("CPKIFCryptoPP::DeriveKey() called with invalid parameters",
01060             thisComponent,COMMON_INVALID_INPUT,this);
01061     }
01062 
01063     CryptoPP::HashTransformation * sha = 0;
01064 
01065     switch(kaAlg->HashAlg())
01066     {
01067     case PKIFCRYPTO::SHA256:
01068         sha = new CryptoPP::SHA256;
01069         break;
01070     case PKIFCRYPTO::SHA384:
01071         sha = new CryptoPP::SHA384;
01072         break;
01073     default:
01074         // throw below
01075         break;
01076     }
01077 
01078     boost::scoped_ptr<CryptoPP::HashTransformation> pSha(sha);
01079     if(!pSha) {
01080         RAISE_CRYPTO_EXCEPTION("CPKIFCryptoPP::DeriveKey() called with incompatible digest",
01081             thisComponent,COMMON_INVALID_INPUT,this);
01082     }
01083     
01084     // counter is constant for this
01085     unsigned char counter[4] = {0x00,0x00,0x00,0x01};
01086     CPKIFBufferPtr secret = cppCtx->GetSecret();
01087     pSha->Update(secret->GetBuffer(),secret->GetLength());
01088     pSha->Update(counter,4);
01089     pSha->Update(sharedInfo->GetBuffer(),sharedInfo->GetLength());
01090     unsigned int digestLen = sha->DigestSize();
01091     // SecByteBlock will zero itself in its dtor
01092     CryptoPP::SecByteBlock tmpKey;
01093     tmpKey.New(digestLen);
01094     pSha->Final(tmpKey);
01095     CPKIFCryptoPPKeyMaterialPtr cppKM(new CPKIFCryptoPPKeyMaterial());
01096     cppKM->SetKeyAlg(kaAlg);
01097     // copy the first keyLen bytes out
01098     cppKM->SetSymmetricKey(tmpKey,keyLen);
01099     return dynamic_pointer_cast<CPKIFKeyMaterial,CPKIFCryptoPPKeyMaterial>(cppKM);
01100 }

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