blob: 110b926baa3a0b90e5a23c83a0d1b0a7d26c62b8 [file] [log] [blame]
/**
* 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");
}