| /** |
| * 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"); |
| } |