xsec/xenc/impl/XENCAlgorithmHandlerDefault.cpp (770 lines of code) (raw):

/** * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ /* * XSEC * * XSECAlgorithmHandlerDefault := Interface class to define handling of * default encryption algorithms * * $Id$ * */ // XSEC Includes #include <xsec/dsig/DSIGConstants.hpp> #include <xsec/enc/XSECCryptoKey.hpp> #include <xsec/enc/XSECCryptoSymmetricKey.hpp> #include <xsec/framework/XSECError.hpp> #include <xsec/transformers/TXFMChain.hpp> #include <xsec/transformers/TXFMCipher.hpp> #include <xsec/transformers/TXFMBase64.hpp> #include <xsec/transformers/TXFMSB.hpp> #include <xsec/xenc/XENCEncryptionMethod.hpp> #include "../../utils/XSECAutoPtr.hpp" #include "../../utils/XSECDOMUtils.hpp" #include "XENCAlgorithmHandlerDefault.hpp" #include <xercesc/dom/DOM.hpp> #include <xercesc/util/Janitor.hpp> XERCES_CPP_NAMESPACE_USE #define _MY_MAX_KEY_SIZE 2048 unsigned char s_3DES_CMS_IV [] = { 0x4a, 0xdd, 0xa2, 0x2c, 0x79, 0xe8, 0x21, 0x05 }; unsigned char s_AES_IV [] = { 0xA6, 0xA6, 0xA6, 0xA6, 0xA6, 0xA6, 0xA6, 0xA6 }; // -------------------------------------------------------------------------------- // Compare URI to key type // -------------------------------------------------------------------------------- void XENCAlgorithmHandlerDefault::mapURIToKey(const XMLCh* uri, const XSECCryptoKey* key, XSECCryptoKey::KeyType& kt, XSECCryptoSymmetricKey::SymmetricKeyType& skt, bool& isSymmetricKeyWrap, XSECCryptoSymmetricKey::SymmetricKeyMode& skm, unsigned int& taglen) const { if (key == NULL) { throw XSECException(XSECException::CipherError, "XENCAlgorithmHandlerDefault::mapURIToKey - trying to process a NULL key"); } XSECCryptoSymmetricKey* keySymmetric; bool keyOK = false; kt = key->getKeyType(); skt = XSECCryptoSymmetricKey::KEY_NONE; isSymmetricKeyWrap = false; skm = XSECCryptoSymmetricKey::MODE_NONE; taglen = 0; switch (kt) { case XSECCryptoKey::KEY_RSA_PUBLIC : case XSECCryptoKey::KEY_RSA_PAIR : case XSECCryptoKey::KEY_RSA_PRIVATE : keyOK = strEquals(uri, DSIGConstants::s_unicodeStrURIRSA_1_5) || strEquals(uri, DSIGConstants::s_unicodeStrURIRSA_OAEP_MGFP1) || strEquals(uri, DSIGConstants::s_unicodeStrURIRSA_OAEP); break; case XSECCryptoKey::KEY_SYMMETRIC : keySymmetric = (XSECCryptoSymmetricKey*) key; if (keySymmetric != NULL) { skt = keySymmetric->getSymmetricKeyType(); switch (skt) { case XSECCryptoSymmetricKey::KEY_3DES_192 : if (strEquals(uri, DSIGConstants::s_unicodeStrURIKW_3DES)) { keyOK = true; isSymmetricKeyWrap = true; skm = XSECCryptoSymmetricKey::MODE_CBC; } else if (strEquals(uri, DSIGConstants::s_unicodeStrURI3DES_CBC)) { keyOK = true; skm = XSECCryptoSymmetricKey::MODE_CBC; } break; case XSECCryptoSymmetricKey::KEY_AES_128 : if (strEquals(uri, DSIGConstants::s_unicodeStrURIKW_AES128) || strEquals(uri, DSIGConstants::s_unicodeStrURIKW_AES128_PAD)) { keyOK = true; isSymmetricKeyWrap = true; skm = XSECCryptoSymmetricKey::MODE_ECB; } else if (strEquals(uri, DSIGConstants::s_unicodeStrURIAES128_CBC)) { keyOK = true; skm = XSECCryptoSymmetricKey::MODE_CBC; } else if (strEquals(uri, DSIGConstants::s_unicodeStrURIAES128_GCM)) { keyOK = true; skm = XSECCryptoSymmetricKey::MODE_GCM; taglen = 16; } break; case XSECCryptoSymmetricKey::KEY_AES_192 : if (strEquals(uri, DSIGConstants::s_unicodeStrURIKW_AES192) || strEquals(uri, DSIGConstants::s_unicodeStrURIKW_AES192_PAD)) { keyOK = true; isSymmetricKeyWrap = true; skm = XSECCryptoSymmetricKey::MODE_ECB; } else if (strEquals(uri, DSIGConstants::s_unicodeStrURIAES192_CBC)) { keyOK = true; skm = XSECCryptoSymmetricKey::MODE_CBC; } else if (strEquals(uri, DSIGConstants::s_unicodeStrURIAES192_GCM)) { keyOK = true; skm = XSECCryptoSymmetricKey::MODE_GCM; taglen = 16; } break; case XSECCryptoSymmetricKey::KEY_AES_256 : if (strEquals(uri, DSIGConstants::s_unicodeStrURIKW_AES256) || strEquals(uri, DSIGConstants::s_unicodeStrURIKW_AES256_PAD)) { keyOK = true; isSymmetricKeyWrap = true; skm = XSECCryptoSymmetricKey::MODE_ECB; } else if (strEquals(uri, DSIGConstants::s_unicodeStrURIAES256_CBC)) { keyOK = true; skm = XSECCryptoSymmetricKey::MODE_CBC; } else if (strEquals(uri, DSIGConstants::s_unicodeStrURIAES256_GCM)) { keyOK = true; skm = XSECCryptoSymmetricKey::MODE_GCM; taglen = 16; } break; default: break; } } break; default: break; } if (keyOK == false) { throw XSECException(XSECException::CipherError, "XENCAlgorithmHandlerDefault::mapURIToKey - key inappropriate for URI"); } } // -------------------------------------------------------------------------------- // AES Key wrap/unwrap // -------------------------------------------------------------------------------- unsigned int XENCAlgorithmHandlerDefault::unwrapKeyAES( TXFMChain* cipherText, const XSECCryptoKey* key, safeBuffer& result) const { // Cat the encrypted key XMLByte buf[_MY_MAX_KEY_SIZE]; XMLByte aesBuf[16]; XMLByte aesOutBuf[16]; TXFMBase* b = cipherText->getLastTxfm(); unsigned int sz = (unsigned int) b->readBytes(buf, _MY_MAX_KEY_SIZE); if (sz <= 0) { throw XSECException(XSECException::CipherError, "XENCAlgorithmHandlerDefault - AES Wrapped Key not found"); } if (sz == _MY_MAX_KEY_SIZE) { throw XSECException(XSECException::CipherError, "XENCAlgorithmHandlerDefault - Key to decrypt too big!"); } // Find number of blocks, and ensure we are a multiple of 64 bits if (sz % 8 != 0) { throw XSECException(XSECException::CipherError, "XENCAlgorithmHandlerDefault - AES wrapped key not a multiple of 64"); } // Do the decrypt - this cast will throw if wrong, but we should // not have been able to get through algorithm checks otherwise XSECCryptoSymmetricKey* sk = (XSECCryptoSymmetricKey*) key; int blocks = sz / 8; int n = blocks - 1; for (int j = 5; j >= 0; j--) { for (int i = n ; i > 0 ; --i) { // Gather blocks to decrypt // A memcpy(aesBuf, buf, 8); // Ri memcpy(&aesBuf[8], &buf[8* i], 8); // A mod t aesBuf[7] ^= ((n * j) + i); // do decrypt sk->decryptInit(false, XSECCryptoSymmetricKey::MODE_ECB); // No padding int sz = sk->decrypt(aesBuf, aesOutBuf, 16, 16); sz += sk->decryptFinish(&aesOutBuf[sz], 16 - sz); if (sz != 16) { throw XSECException(XSECException::CipherError, "XENCAlgorithmHandlerDefault - Error performing decrypt in AES Unwrap"); } // Copy back to where we are // A memcpy(buf, aesOutBuf, 8); // Ri memcpy(&buf[8 * i], &aesOutBuf[8], 8); } } // Check is valid if (memcmp(buf, s_AES_IV, 8) != 0) { throw XSECException(XSECException::CipherError, "XENCAlgorithmHandlerDefault - decrypt failed - AES IV is not correct"); } // Copy to safebuffer result.sbMemcpyIn(&buf[8], n * 8); return n * 8; } bool XENCAlgorithmHandlerDefault::wrapKeyAES( TXFMChain* cipherText, const XSECCryptoKey* key, safeBuffer& result) const { // get the raw key XMLByte buf[_MY_MAX_KEY_SIZE + 8]; memcpy(buf, s_AES_IV, 8); XMLByte aesBuf[16]; XMLByte aesOutBuf[32]; // Give this an extra block for WinCAPI TXFMBase* b = cipherText->getLastTxfm(); unsigned int sz = (unsigned int) b->readBytes(&buf[8], _MY_MAX_KEY_SIZE); if (sz <= 0) { throw XSECException(XSECException::CipherError, "XENCAlgorithmHandlerDefault - Key not found"); } if (sz == _MY_MAX_KEY_SIZE) { throw XSECException(XSECException::CipherError, "XENCAlgorithmHandlerDefault - Key to encrypt too big!"); } // Find number of blocks, and ensure we are a multiple of 64 bits if (sz % 8 != 0) { throw XSECException(XSECException::CipherError, "XENCAlgorithmHandlerDefault - AES wrapped key not a multiple of 64"); } // Do the decrypt - this cast will throw if wrong, but we should // not have been able to get through algorithm checks otherwise XSECCryptoSymmetricKey* sk = (XSECCryptoSymmetricKey*) key; int n = sz / 8; for (int j = 0; j <= 5; ++j) { for (int i = 1 ; i <= n ; ++i) { // Gather blocks to decrypt // A memcpy(aesBuf, buf, 8); // Ri memcpy(&aesBuf[8], &buf[8 * i], 8); // do encrypt sk->encryptInit(false, XSECCryptoSymmetricKey::MODE_ECB); int sz = sk->encrypt(aesBuf, aesOutBuf, 16, 32); sz += sk->encryptFinish(&aesOutBuf[sz], 32 - sz); if (sz != 16) { throw XSECException(XSECException::CipherError, "XENCAlgorithmHandlerDefault - Error performing encrypt in AES wrap"); } // Copy back to where we are // A memcpy(buf, aesOutBuf, 8); // A mod t buf[7] ^= ((n * j) + i); // Ri memcpy(&buf[8 * i], &aesOutBuf[8], 8); } } // Now we have to base64 encode XSECCryptoBase64* b64 = XSECPlatformUtils::g_cryptoProvider->base64(); if (!b64) { throw XSECException(XSECException::CryptoProviderError, "XENCAlgorithmHandlerDefault - Error getting base64 encoder in AES wrap"); } Janitor<XSECCryptoBase64> j_b64(b64); unsigned char* b64Buffer; int bufLen = ((n + 1) * 8) * 3; XSECnew(b64Buffer, unsigned char[bufLen + 1]);// Overkill ArrayJanitor<unsigned char> j_b64Buffer(b64Buffer); b64->encodeInit(); int outputLen = b64->encode (buf, (n+1) * 8, b64Buffer, bufLen); outputLen += b64->encodeFinish(&b64Buffer[outputLen], bufLen - outputLen); b64Buffer[outputLen] = '\0'; // Copy to safebuffer result.sbStrcpyIn((const char*) b64Buffer); return true; } // -------------------------------------------------------------------------------- // DES CMS Key wrap/unwrap // -------------------------------------------------------------------------------- unsigned int XENCAlgorithmHandlerDefault::unwrapKey3DES( TXFMChain* cipherText, const XSECCryptoKey* key, safeBuffer& result) const { // Perform an unwrap on the key safeBuffer cipherSB; // Cat the encrypted key XMLByte buf[_MY_MAX_KEY_SIZE]; TXFMBase* b = cipherText->getLastTxfm(); unsigned int offset = 0; unsigned int sz = (unsigned int) b->readBytes(buf, _MY_MAX_KEY_SIZE); while (sz > 0) { cipherSB.sbMemcpyIn(offset, buf, sz); offset += sz; sz = (unsigned int) b->readBytes(buf, _MY_MAX_KEY_SIZE); } if (offset > _MY_MAX_KEY_SIZE) { throw XSECException(XSECException::CipherError, "XENCAlgorithmHandlerDefault - Key to decrypt too big!"); } // Do the decrypt - this cast will throw if wrong, but we should // not have been able to get through algorithm checks otherwise XSECCryptoSymmetricKey* sk = (XSECCryptoSymmetricKey*) key; sk->decryptInit(false, XSECCryptoSymmetricKey::MODE_CBC, s_3DES_CMS_IV); // If key is bigger than this, then we have a problem sz = sk->decrypt(cipherSB.rawBuffer(), buf, offset, _MY_MAX_KEY_SIZE); sz += sk->decryptFinish(&buf[sz], _MY_MAX_KEY_SIZE - sz); if (sz <= 0) { throw XSECException(XSECException::CipherError, "XENCAlgorithmHandlerDefault - Error decrypting key!"); } // We now have the first cut, reverse the cipher text XMLByte buf2[_MY_MAX_KEY_SIZE]; for (unsigned int i = 0; i < sz; ++ i) { buf2[sz - i - 1] = buf[i]; } // decrypt again sk->decryptInit(false); offset = sk->decrypt(buf2, buf, sz, _MY_MAX_KEY_SIZE); offset += sk->decryptFinish(&buf[offset], _MY_MAX_KEY_SIZE - offset); // Calculate the CMS Key Checksum XSECCryptoHash* sha1 = XSECPlatformUtils::g_cryptoProvider->hash(XSECCryptoHash::HASH_SHA1); if (!sha1) { throw XSECException(XSECException::CryptoProviderError, "XENCAlgorithmHandlerDefault - Error getting SHA-1 object in 3DES unwrap"); } Janitor<XSECCryptoHash> j_sha1(sha1); sha1->reset(); sha1->hash(buf, offset - 8); sha1->finish(buf2, _MY_MAX_KEY_SIZE); // Compare for (unsigned int j = 0; j < 8; ++j) { if (buf[offset - 8 + j] != buf2[j]) { throw XSECException(XSECException::CipherError, "XENCAlgorithmHandlerDefault::unwrapKey3DES - CMS Key Checksum does not match"); } } result.sbMemcpyIn(buf, offset - 8); return offset - 8; } bool XENCAlgorithmHandlerDefault::wrapKey3DES( TXFMChain* cipherText, const XSECCryptoKey* key, safeBuffer& result) const { // Cat the plaintext key XMLByte buf[_MY_MAX_KEY_SIZE + 16]; TXFMBase* b = cipherText->getLastTxfm(); int offset = 0; unsigned int sz = (unsigned int) b->readBytes(buf, _MY_MAX_KEY_SIZE); if (sz <= 0) { throw XSECException(XSECException::CipherError, "XENCAlgorithmHandlerDefault::wrapKey3DES - Unable to read key"); } if (sz >= _MY_MAX_KEY_SIZE) { throw XSECException(XSECException::CipherError, "XENCAlgorithmHandlerDefault::wrapKey3DES - Key to decrypt too big!"); } if (sz % 8 != 0) { throw XSECException(XSECException::CipherError, "XENCAlgorithmHandlerDefault::wrapKey3DES - Key to encrypt not a multiple of 8 bytes"); } // Calculate the CMS Key Checksum // Do the first encrypt XMLByte buf2[_MY_MAX_KEY_SIZE + 16]; XSECCryptoHash* sha1 = XSECPlatformUtils::g_cryptoProvider->hash(XSECCryptoHash::HASH_SHA1); if (!sha1) { throw XSECException(XSECException::CryptoProviderError, "XENCAlgorithmHandlerDefault - Error getting SHA-1 object in 3DES wrap"); } Janitor<XSECCryptoHash> j_sha1(sha1); sha1->reset(); sha1->hash(buf, sz); sha1->finish(buf2, _MY_MAX_KEY_SIZE); for (int j = 0; j < 8 ; ++j) buf[sz++] = buf2[j]; // Do the first encrypt - this cast will throw if wrong, but we should // not have been able to get through algorithm checks otherwise XSECCryptoSymmetricKey* sk = (XSECCryptoSymmetricKey*) key; sk->encryptInit(false); // If key is bigger than this, then we have a problem sz = sk->encrypt(buf, buf2, sz, _MY_MAX_KEY_SIZE); sz += sk->encryptFinish(&buf2[sz], _MY_MAX_KEY_SIZE - sz); if (sz <= 0) { throw XSECException(XSECException::CipherError, "XENCAlgorithmHandlerDefault::wrapKey3DES - Error encrypting key!"); } // We now have the first cut, reverse the cipher text for (unsigned int i = 0; i < sz; ++ i) { buf[sz - i - 1] = buf2[i]; } // encrypt again sk->encryptInit(false, XSECCryptoSymmetricKey::MODE_CBC, s_3DES_CMS_IV); offset = sk->encrypt(buf, buf2, sz, _MY_MAX_KEY_SIZE); offset += sk->encryptFinish(&buf2[offset], _MY_MAX_KEY_SIZE - offset); // Base64 encode XSECCryptoBase64* b64 = XSECPlatformUtils::g_cryptoProvider->base64(); if (!b64) { throw XSECException(XSECException::CryptoProviderError, "XENCAlgorithmHandlerDefault - Error getting base64 encoder in 3DES wrap"); } Janitor<XSECCryptoBase64> j_b64(b64); unsigned char* b64Buffer; int bufLen = (offset + 9) * 3; XSECnew(b64Buffer, unsigned char[bufLen + 1]);// Overkill ArrayJanitor<unsigned char> j_b64Buffer(b64Buffer); b64->encodeInit(); int outputLen = b64->encode (&buf2[8], offset-8, b64Buffer, bufLen); outputLen += b64->encodeFinish(&b64Buffer[outputLen], bufLen - outputLen); b64Buffer[outputLen] = '\0'; // Copy to safebuffer result.sbStrcpyIn((const char*) b64Buffer); return true; } // -------------------------------------------------------------------------------- // InputStream decryption // -------------------------------------------------------------------------------- bool XENCAlgorithmHandlerDefault::appendDecryptCipherTXFM( TXFMChain* cipherText, XENCEncryptionMethod* encryptionMethod, const XSECCryptoKey* key, XERCES_CPP_NAMESPACE_QUALIFIER DOMDocument* doc ) const { // We only support this for bulk Symmetric key algorithms XSECCryptoKey::KeyType kt; XSECCryptoSymmetricKey::SymmetricKeyType skt; bool isKeyWrap = false; XSECCryptoSymmetricKey::SymmetricKeyMode skm; unsigned int taglen; mapURIToKey(encryptionMethod->getAlgorithm(), key, kt, skt, isKeyWrap, skm, taglen); if (kt != XSECCryptoKey::KEY_SYMMETRIC || isKeyWrap == true) { throw XSECException(XSECException::CipherError, "XENCAlgorithmHandlerDefault::appendDecryptCipherTXFM - only supports bulk symmetric algorithms"); } if (skm == XSECCryptoSymmetricKey::MODE_GCM) { // GCM doesn't fit the pipelined model of the existing code, so we have a custom // routine that decrypts to a safeBuffer directly. safeBuffer result; unsigned int sz = doGCMDecryptToSafeBuffer(cipherText, key, taglen, result); // Now we hijack the original tansform chain with a safeBuffer-sourced link. TXFMSB* tsb; XSECnew(tsb, TXFMSB(doc)); tsb->setInput(result, sz); cipherText->appendTxfm(tsb); result.cleanseBuffer(); return true; } // Add the decryption TXFM TXFMCipher* tcipher; XSECnew(tcipher, TXFMCipher(doc, key, false)); cipherText->appendTxfm(tcipher); return true; } // -------------------------------------------------------------------------------- // GCM SafeBuffer decryption // -------------------------------------------------------------------------------- unsigned int XENCAlgorithmHandlerDefault::doGCMDecryptToSafeBuffer( TXFMChain* cipherText, const XSECCryptoKey* key, unsigned int taglen, safeBuffer& result) const { // Only works with symmetric key if (key->getKeyType() != XSECCryptoKey::KEY_SYMMETRIC) { throw XSECException(XSECException::CipherError, "XENCAlgorithmHandlerDefault - GCM Decrypt must use symmetric key"); } // First read in all the data so we can get to the tag. safeBuffer cipherBuf(""); XMLByte inbuf[3072]; unsigned int szTotal = 0, sz = cipherText->getLastTxfm()->readBytes(inbuf, 3072); while (sz > 0) { cipherBuf.sbMemcpyIn(szTotal, inbuf, sz); szTotal += sz; sz = cipherText->getLastTxfm()->readBytes(inbuf, 3072); } if (szTotal <= taglen) { throw XSECException(XSECException::CipherError, "XENCAlgorithmHandlerDefault - GCM ciphertext size not large enough to include authentication tag"); } const unsigned char* cipherPtr = cipherBuf.rawBuffer(); // Init the cipher with the tag at the end of the cipher text and omit it from later decryption. szTotal -= taglen; ((XSECCryptoSymmetricKey*) key)->decryptInit(false, XSECCryptoSymmetricKey::MODE_GCM, NULL, cipherPtr + szTotal, taglen); unsigned int plainOffset = 0; do { // Feed the data in at most 2048-byte chunks. sz = ((XSECCryptoSymmetricKey*) key)->decrypt(cipherPtr, inbuf, (szTotal > 2048 ? 2048 : szTotal), 3072); cipherPtr += (szTotal > 2048 ? 2048 : szTotal); szTotal -= (szTotal > 2048 ? 2048 : szTotal); if (sz > 0) { result.sbMemcpyIn(plainOffset, inbuf, sz); plainOffset += sz; } } while (szTotal > 0); // Wrap it up. sz = ((XSECCryptoSymmetricKey*) key)->decryptFinish(inbuf, 3072); if (sz > 0) { result.sbMemcpyIn(plainOffset, inbuf, sz); plainOffset += sz; } // In case any plaintext is left lying around. memset(inbuf, 0, 3072); return plainOffset; } // -------------------------------------------------------------------------------- // RSA SafeBuffer decryption // -------------------------------------------------------------------------------- unsigned int XENCAlgorithmHandlerDefault::doRSADecryptToSafeBuffer( TXFMChain* cipherText, XENCEncryptionMethod* encryptionMethod, const XSECCryptoKey* key, DOMDocument* doc, safeBuffer& result) const { // Only works with RSA_PRIVATE or PAIR if (key->getKeyType() == XSECCryptoKey::KEY_RSA_PUBLIC) { throw XSECException(XSECException::CipherError, "XENCAlgorithmHandlerDefault - RSA Decrypt must use private key"); } // Know this is an RSA key, so just cast XSECCryptoKeyRSA* rsa = (XSECCryptoKeyRSA*) key; // Allocate an output buffer unsigned char* decBuf; XSECnew(decBuf, unsigned char[rsa->getLength()]); ArrayJanitor<unsigned char> j_decBuf(decBuf); // Input TXFMBase* b = cipherText->getLastTxfm(); safeBuffer cipherSB; XMLByte buf[1024]; unsigned int offset = 0; unsigned int bytesRead = (unsigned int) b->readBytes(buf, 1024); while (bytesRead > 0) { cipherSB.sbMemcpyIn(offset, buf, bytesRead); offset += bytesRead; bytesRead = (unsigned int) b->readBytes(buf, 1024); } unsigned int decryptLen; // Now we find out what kind of padding if (strEquals(encryptionMethod->getAlgorithm(), DSIGConstants::s_unicodeStrURIRSA_1_5)) { // Do decrypt decryptLen = rsa->privateDecrypt(cipherSB.rawBuffer(), decBuf, offset, rsa->getLength(), XSECCryptoKeyRSA::PAD_PKCS_1_5); } else if (strEquals(encryptionMethod->getAlgorithm(), DSIGConstants::s_unicodeStrURIRSA_OAEP_MGFP1) || strEquals(encryptionMethod->getAlgorithm(), DSIGConstants::s_unicodeStrURIRSA_OAEP)) { const XMLCh* digmeth = encryptionMethod->getDigestMethod(); if (!digmeth|| !*digmeth) { digmeth = DSIGConstants::s_unicodeStrURISHA1; } const XMLCh* mgfalg = encryptionMethod->getMGF(); if (!mgfalg || !*mgfalg) { mgfalg = DSIGConstants::s_unicodeStrURIMGF1_SHA1; } // Read out any OAEP params unsigned char* oaepParamsBuf = NULL; unsigned int oaepParamsLen = 0; const XMLCh* oaepParams = encryptionMethod->getOAEPparams(); if (oaepParams != NULL) { XSECAutoPtrChar oaepParamsStr(oaepParams); unsigned int bufLen = (unsigned int) strlen(oaepParamsStr.get()); oaepParamsBuf = new unsigned char[bufLen]; XSECCryptoBase64* b64 = XSECPlatformUtils::g_cryptoProvider->base64(); Janitor<XSECCryptoBase64> j_b64(b64); b64->decodeInit(); oaepParamsLen = b64->decode((unsigned char*) oaepParamsStr.get(), bufLen, oaepParamsBuf, bufLen); oaepParamsLen += b64->decodeFinish(&oaepParamsBuf[oaepParamsLen], bufLen - oaepParamsLen); } ArrayJanitor<unsigned char> j_oaepParamsBuf(oaepParamsBuf); decryptLen = rsa->privateDecrypt(cipherSB.rawBuffer(), decBuf, offset, rsa->getLength(), XSECCryptoKeyRSA::PAD_OAEP, digmeth, mgfalg, oaepParamsBuf, oaepParamsLen); } else { throw XSECException(XSECException::CipherError, "XENCAlgorithmHandlerDefault::doRSADecryptToSafeBuffer - Unknown padding type"); } // Copy to output result.sbMemcpyIn(decBuf, decryptLen); memset(decBuf, 0, decryptLen); return decryptLen; } // -------------------------------------------------------------------------------- // SafeBuffer decryption // -------------------------------------------------------------------------------- unsigned int XENCAlgorithmHandlerDefault::decryptToSafeBuffer( TXFMChain* cipherText, XENCEncryptionMethod* encryptionMethod, const XSECCryptoKey* key, DOMDocument* doc, safeBuffer& result ) const { XSECCryptoKey::KeyType kt; XSECCryptoSymmetricKey::SymmetricKeyType skt; bool isKeyWrap = false; XSECCryptoSymmetricKey::SymmetricKeyMode skm; unsigned int taglen; if (encryptionMethod == NULL) { throw XSECException(XSECException::CipherError, "XENCAlgorithmHandlerDefault::decryptToSafeBuffer - Cannot operate with NULL encryption Method"); } // Check the uri against the key type mapURIToKey(encryptionMethod->getAlgorithm(), key, kt, skt, isKeyWrap, skm, taglen); // RSA? if (kt == XSECCryptoKey::KEY_RSA_PAIR || kt == XSECCryptoKey::KEY_RSA_PUBLIC || kt == XSECCryptoKey::KEY_RSA_PRIVATE) { return doRSADecryptToSafeBuffer(cipherText, encryptionMethod, key, doc, result); } // Ensure is symmetric before we continue if (kt != XSECCryptoKey::KEY_SYMMETRIC) { throw XSECException(XSECException::CipherError, "XENCAlgorithmHandlerDefault::decryptToSafeBuffer - Not an RSA key, but not symmetric"); } // Key wrap? if (isKeyWrap == true) { if (skt == XSECCryptoSymmetricKey::KEY_AES_128 || skt == XSECCryptoSymmetricKey::KEY_AES_192 || skt == XSECCryptoSymmetricKey::KEY_AES_256) { return unwrapKeyAES(cipherText, key, result); } else if (skt == XSECCryptoSymmetricKey::KEY_3DES_192) { return unwrapKey3DES(cipherText, key, result); } else { throw XSECException(XSECException::CipherError, "XENCAlgorithmHandlerDefault::decryptToSafeBuffer - don't know how to do key wrap for algorithm"); } } if (skm == XSECCryptoSymmetricKey::MODE_GCM) { // GCM doesn't fit the pipelined model of the existing code, so we have a custom // routine that decrypts to a safeBuffer directly. return doGCMDecryptToSafeBuffer(cipherText, key, taglen, result); } // It's symmetric and it's not a key wrap or GCM, so just treat as a block algorithm. TXFMCipher* tcipher; XSECnew(tcipher, TXFMCipher(doc, key, false)); cipherText->appendTxfm(tcipher); // Do the decrypt to the safeBuffer. result.sbStrcpyIn(""); unsigned int offset = 0; XMLByte buf[1024]; TXFMBase* b = cipherText->getLastTxfm(); unsigned int bytesRead = (unsigned int) b->readBytes(buf, 1024); while (bytesRead > 0) { result.sbMemcpyIn(offset, buf, bytesRead); offset += bytesRead; bytesRead = (unsigned int) b->readBytes(buf, 1024); } result[offset] = '\0'; return offset; } // -------------------------------------------------------------------------------- // RSA SafeBuffer encryption // -------------------------------------------------------------------------------- bool XENCAlgorithmHandlerDefault::doRSAEncryptToSafeBuffer( TXFMChain* plainText, XENCEncryptionMethod* encryptionMethod, const XSECCryptoKey* key, XERCES_CPP_NAMESPACE_QUALIFIER DOMDocument* doc, safeBuffer& result ) const { // Only works with RSA_PRIVATE or PAIR if (key->getKeyType() == XSECCryptoKey::KEY_RSA_PRIVATE) { throw XSECException(XSECException::CipherError, "XENCAlgorithmHandlerDefault - RSA Encrypt must use public key"); } XSECCryptoKeyRSA* rsa = (XSECCryptoKeyRSA*) key; // Allocate an output buffer unsigned char* encBuf; XSECnew(encBuf, unsigned char[rsa->getLength()]); ArrayJanitor<unsigned char> j_encBuf(encBuf); // Input TXFMBase* b = plainText->getLastTxfm(); safeBuffer plainSB; plainSB.isSensitive(); XMLByte buf[1024]; unsigned int offset = 0; unsigned int bytesRead = (unsigned int) b->readBytes(buf, 1024); while (bytesRead > 0) { plainSB.sbMemcpyIn(offset, buf, bytesRead); offset += bytesRead; bytesRead = (unsigned int) b->readBytes(buf, 1024); } unsigned int encryptLen; // Do encrypt if (strEquals(encryptionMethod->getAlgorithm(), DSIGConstants::s_unicodeStrURIRSA_1_5)) { encryptLen = rsa->publicEncrypt(plainSB.rawBuffer(), encBuf, offset, rsa->getLength(), XSECCryptoKeyRSA::PAD_PKCS_1_5); } else if (strEquals(encryptionMethod->getAlgorithm(), DSIGConstants::s_unicodeStrURIRSA_OAEP_MGFP1) || strEquals(encryptionMethod->getAlgorithm(), DSIGConstants::s_unicodeStrURIRSA_OAEP)) { const XMLCh* digmeth = encryptionMethod->getDigestMethod(); if (!digmeth || !*digmeth) { digmeth = DSIGConstants::s_unicodeStrURISHA1; } const XMLCh* mgfalg = encryptionMethod->getMGF(); if (!mgfalg || !*mgfalg) { mgfalg = DSIGConstants::s_unicodeStrURIMGF1_SHA1; } // Read out any OAEP params unsigned char* oaepParamsBuf = NULL; unsigned int oaepParamsLen = 0; const XMLCh* oaepParams = encryptionMethod->getOAEPparams(); if (oaepParams != NULL) { XSECAutoPtrChar oaepParamsStr(oaepParams); unsigned int bufLen = (unsigned int) strlen(oaepParamsStr.get()); oaepParamsBuf = new unsigned char[bufLen]; XSECCryptoBase64* b64 = XSECPlatformUtils::g_cryptoProvider->base64(); Janitor<XSECCryptoBase64> j_b64(b64); b64->decodeInit(); oaepParamsLen = b64->decode((unsigned char*) oaepParamsStr.get(), bufLen, oaepParamsBuf, bufLen); oaepParamsLen += b64->decodeFinish(&oaepParamsBuf[oaepParamsLen], bufLen - oaepParamsLen); } ArrayJanitor<unsigned char> j_oaepParamsBuf(oaepParamsBuf); encryptLen = rsa->publicEncrypt(plainSB.rawBuffer(), encBuf, offset, rsa->getLength(), XSECCryptoKeyRSA::PAD_OAEP, digmeth, mgfalg, oaepParamsBuf, oaepParamsLen); } else { throw XSECException(XSECException::CipherError, "XENCAlgorithmHandlerDefault::doRSAEncryptToSafeBuffer - Unknown padding type"); } // Now need to base64 encode XSECCryptoBase64* b64 = XSECPlatformUtils::g_cryptoProvider->base64(); Janitor<XSECCryptoBase64> j_b64(b64); b64->encodeInit(); encryptLen = b64->encode(encBuf, encryptLen, buf, 1024); result.sbMemcpyIn(buf, encryptLen); unsigned int finalLen = b64->encodeFinish(buf, 1024); result.sbMemcpyIn(encryptLen, buf, finalLen); result[encryptLen + finalLen] = '\0'; // This is a string, so set the buffer correctly result.setBufferType(safeBuffer::BUFFER_CHAR); return true; } // -------------------------------------------------------------------------------- // SafeBuffer encryption // -------------------------------------------------------------------------------- bool XENCAlgorithmHandlerDefault::encryptToSafeBuffer( TXFMChain* plainText, XENCEncryptionMethod* encryptionMethod, const XSECCryptoKey* key, XERCES_CPP_NAMESPACE_QUALIFIER DOMDocument* doc, safeBuffer& result ) const { XSECCryptoKey::KeyType kt; XSECCryptoSymmetricKey::SymmetricKeyType skt; bool isKeyWrap = false; XSECCryptoSymmetricKey::SymmetricKeyMode skm; unsigned int taglen; if (encryptionMethod == NULL) { throw XSECException(XSECException::CipherError, "XENCAlgorithmHandlerDefault::encryptToSafeBuffer - Cannot operate with NULL encryption Method"); } // Check the uri against the key type mapURIToKey(encryptionMethod->getAlgorithm(), key, kt, skt, isKeyWrap, skm, taglen); // RSA? if (kt == XSECCryptoKey::KEY_RSA_PRIVATE || kt == XSECCryptoKey::KEY_RSA_PUBLIC || kt == XSECCryptoKey::KEY_RSA_PAIR) { return doRSAEncryptToSafeBuffer(plainText, encryptionMethod, key, doc, result); } // Ensure is symmetric before we continue if (kt != XSECCryptoKey::KEY_SYMMETRIC) { throw XSECException(XSECException::CipherError, "XENCAlgorithmHandlerDefault::encryptToSafeBuffer - Not an RSA key, but not symmetric"); } if (isKeyWrap == true) { if (skt == XSECCryptoSymmetricKey::KEY_AES_128 || skt == XSECCryptoSymmetricKey::KEY_AES_192 || skt == XSECCryptoSymmetricKey::KEY_AES_256) { return wrapKeyAES(plainText, key, result); } if (skt == XSECCryptoSymmetricKey::KEY_3DES_192) { return wrapKey3DES(plainText, key, result); } else { throw XSECException(XSECException::CipherError, "XENCAlgorithmHandlerDefault::decryptToSafeBuffer - don't know how to do key wrap for algorithm"); } } // Must be bulk symmetric - do the encryption TXFMCipher* tcipher; XSECnew(tcipher, TXFMCipher(doc, key, true, skm, taglen)); plainText->appendTxfm(tcipher); // Transform to Base64 TXFMBase64* tb64; XSECnew(tb64, TXFMBase64(doc, false)); plainText->appendTxfm(tb64); // Read into the safeBuffer result = ""; result << plainText->getLastTxfm(); return true; } // -------------------------------------------------------------------------------- // Key Creation // -------------------------------------------------------------------------------- XSECCryptoKey* XENCAlgorithmHandlerDefault::createKeyForURI( const XMLCh* uri, const unsigned char* keyBuffer, unsigned int keyLen ) const { XSECCryptoSymmetricKey* sk = NULL; if (strEquals(uri, DSIGConstants::s_unicodeStrURI3DES_CBC)) { if (keyLen < 192 / 8) throw XSECException(XSECException::CipherError, "XENCAlgorithmHandlerDefault - key size was invalid"); sk = XSECPlatformUtils::g_cryptoProvider->keySymmetric(XSECCryptoSymmetricKey::KEY_3DES_192); } else if (strEquals(uri, DSIGConstants::s_unicodeStrURIAES128_CBC) || strEquals(uri, DSIGConstants::s_unicodeStrURIAES128_GCM)) { if (keyLen < 128 / 8) throw XSECException(XSECException::CipherError, "XENCAlgorithmHandlerDefault - key size was invalid"); sk = XSECPlatformUtils::g_cryptoProvider->keySymmetric(XSECCryptoSymmetricKey::KEY_AES_128); } else if (strEquals(uri, DSIGConstants::s_unicodeStrURIAES192_CBC) || strEquals(uri, DSIGConstants::s_unicodeStrURIAES192_GCM)) { if (keyLen < 192 / 8) throw XSECException(XSECException::CipherError, "XENCAlgorithmHandlerDefault - key size was invalid"); sk = XSECPlatformUtils::g_cryptoProvider->keySymmetric(XSECCryptoSymmetricKey::KEY_AES_192); } else if (strEquals(uri, DSIGConstants::s_unicodeStrURIAES256_CBC) || strEquals(uri, DSIGConstants::s_unicodeStrURIAES256_GCM)) { if (keyLen < 256 / 8) throw XSECException(XSECException::CipherError, "XENCAlgorithmHandlerDefault - key size was invalid"); sk = XSECPlatformUtils::g_cryptoProvider->keySymmetric(XSECCryptoSymmetricKey::KEY_AES_256); } if (sk != NULL) { sk->setKey(keyBuffer, keyLen); return sk; } throw XSECException(XSECException::CipherError, "XENCAlgorithmHandlerDefault - URI Provided, but cannot create associated key"); } // -------------------------------------------------------------------------------- // Clone // -------------------------------------------------------------------------------- XSECAlgorithmHandler* XENCAlgorithmHandlerDefault::clone(void) const { XENCAlgorithmHandlerDefault* ret; XSECnew(ret, XENCAlgorithmHandlerDefault); return ret; } // -------------------------------------------------------------------------------- // Unsupported operations // -------------------------------------------------------------------------------- unsigned int XENCAlgorithmHandlerDefault::signToSafeBuffer( TXFMChain* inputBytes, const XMLCh* URI, const XSECCryptoKey* key, unsigned int outputLength, safeBuffer& result) const { throw XSECException(XSECException::AlgorithmMapperError, "XENCAlgorithmHandlerDefault - Signature operations not supported"); } bool XENCAlgorithmHandlerDefault::appendSignatureHashTxfm( TXFMChain* inputBytes, const XMLCh* URI, const XSECCryptoKey* key) const { throw XSECException(XSECException::AlgorithmMapperError, "XENCAlgorithmHandlerDefault - Signature operations not supported"); } bool XENCAlgorithmHandlerDefault::verifyBase64Signature( TXFMChain* inputBytes, const XMLCh* URI, const char* sig, unsigned int outputLength, const XSECCryptoKey* key) const { throw XSECException(XSECException::AlgorithmMapperError, "XENCAlgorithmHandlerDefault - Signature operations not supported"); } bool XENCAlgorithmHandlerDefault::appendHashTxfm( TXFMChain* inputBytes, const XMLCh* URI) const { throw XSECException(XSECException::AlgorithmMapperError, "XENCAlgorithmHandlerDefault - Hash operations not supported"); }