diff options
Diffstat (limited to 'src/openssl/ciphers.c')
-rw-r--r-- | src/openssl/ciphers.c | 856 |
1 files changed, 856 insertions, 0 deletions
diff --git a/src/openssl/ciphers.c b/src/openssl/ciphers.c new file mode 100644 index 00000000..1b600625 --- /dev/null +++ b/src/openssl/ciphers.c @@ -0,0 +1,856 @@ +/** + * XMLSec library + * + * This is free software; see Copyright file in the source + * distribution for preciese wording. + * + * Copyright (C) 2002-2003 Aleksey Sanin <aleksey@aleksey.com> + */ +#include "globals.h" + +#include <string.h> + +#include <openssl/evp.h> +#include <openssl/rand.h> + +#include <xmlsec/xmlsec.h> +#include <xmlsec/keys.h> +#include <xmlsec/transforms.h> +#include <xmlsec/errors.h> + +#include <xmlsec/openssl/crypto.h> +#include <xmlsec/openssl/evp.h> + +/* this is not defined in OpenSSL 0.9.6 */ +#ifndef EVP_MAX_BLOCK_LENGTH +#define EVP_MAX_BLOCK_LENGTH 32 +#endif /* EVP_MAX_BLOCK_LENGTH */ + +/************************************************************************** + * + * Internal OpenSSL Block cipher CTX + * + *****************************************************************************/ +typedef struct _xmlSecOpenSSLEvpBlockCipherCtx xmlSecOpenSSLEvpBlockCipherCtx, + *xmlSecOpenSSLEvpBlockCipherCtxPtr; +struct _xmlSecOpenSSLEvpBlockCipherCtx { + const EVP_CIPHER* cipher; + xmlSecKeyDataId keyId; + EVP_CIPHER_CTX cipherCtx; + int keyInitialized; + int ctxInitialized; + xmlSecByte key[EVP_MAX_KEY_LENGTH]; + xmlSecByte iv[EVP_MAX_IV_LENGTH]; + xmlSecByte pad[EVP_MAX_BLOCK_LENGTH]; +}; +static int xmlSecOpenSSLEvpBlockCipherCtxInit (xmlSecOpenSSLEvpBlockCipherCtxPtr ctx, + xmlSecBufferPtr in, + xmlSecBufferPtr out, + int encrypt, + const xmlChar* cipherName, + xmlSecTransformCtxPtr transformCtx); +static int xmlSecOpenSSLEvpBlockCipherCtxUpdate (xmlSecOpenSSLEvpBlockCipherCtxPtr ctx, + xmlSecBufferPtr in, + xmlSecBufferPtr out, + const xmlChar* cipherName, + xmlSecTransformCtxPtr transformCtx); +static int xmlSecOpenSSLEvpBlockCipherCtxFinal (xmlSecOpenSSLEvpBlockCipherCtxPtr ctx, + xmlSecBufferPtr out, + const xmlChar* cipherName, + xmlSecTransformCtxPtr transformCtx); +static int +xmlSecOpenSSLEvpBlockCipherCtxInit(xmlSecOpenSSLEvpBlockCipherCtxPtr ctx, + xmlSecBufferPtr in, xmlSecBufferPtr out, + int encrypt, + const xmlChar* cipherName, + xmlSecTransformCtxPtr transformCtx) { + int ivLen; + int ret; + + xmlSecAssert2(ctx != NULL, -1); + xmlSecAssert2(ctx->cipher != NULL, -1); + xmlSecAssert2(ctx->keyInitialized != 0, -1); + xmlSecAssert2(ctx->ctxInitialized == 0, -1); + xmlSecAssert2(in != NULL, -1); + xmlSecAssert2(out != NULL, -1); + xmlSecAssert2(transformCtx != NULL, -1); + + ivLen = EVP_CIPHER_iv_length(ctx->cipher); + xmlSecAssert2(ivLen > 0, -1); + xmlSecAssert2((xmlSecSize)ivLen <= sizeof(ctx->iv), -1); + + if(encrypt) { + /* generate random iv */ + ret = RAND_bytes(ctx->iv, ivLen); + if(ret != 1) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(cipherName), + "RAND_bytes", + XMLSEC_ERRORS_R_CRYPTO_FAILED, + "size=%d", ivLen); + return(-1); + } + + /* write iv to the output */ + ret = xmlSecBufferAppend(out, ctx->iv, ivLen); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(cipherName), + "xmlSecBufferAppend", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "size=%d", ivLen); + return(-1); + } + + } else { + /* if we don't have enough data, exit and hope that + * we'll have iv next time */ + if(xmlSecBufferGetSize(in) < (xmlSecSize)ivLen) { + return(0); + } + + /* copy iv to our buffer*/ + xmlSecAssert2(xmlSecBufferGetData(in) != NULL, -1); + memcpy(ctx->iv, xmlSecBufferGetData(in), ivLen); + + /* and remove from input */ + ret = xmlSecBufferRemoveHead(in, ivLen); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(cipherName), + "xmlSecBufferRemoveHead", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "size=%d", ivLen); + return(-1); + } + } + + /* set iv */ + ret = EVP_CipherInit(&(ctx->cipherCtx), ctx->cipher, ctx->key, ctx->iv, encrypt); + if(ret != 1) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(cipherName), + "EVP_CipherInit", + XMLSEC_ERRORS_R_CRYPTO_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + + ctx->ctxInitialized = 1; + + /* + * The padding used in XML Enc does not follow RFC 1423 + * and is not supported by OpenSSL. In the case of OpenSSL 0.9.7 + * it is possible to disable padding and do it by yourself + * For OpenSSL 0.9.6 you have interop problems + */ +#ifndef XMLSEC_OPENSSL_096 + EVP_CIPHER_CTX_set_padding(&(ctx->cipherCtx), 0); +#endif /* XMLSEC_OPENSSL_096 */ + return(0); +} + +static int +xmlSecOpenSSLEvpBlockCipherCtxUpdate(xmlSecOpenSSLEvpBlockCipherCtxPtr ctx, + xmlSecBufferPtr in, xmlSecBufferPtr out, + const xmlChar* cipherName, + xmlSecTransformCtxPtr transformCtx) { + int blockLen, fixLength = 0, outLen = 0; + xmlSecSize inSize, outSize; + xmlSecByte* outBuf; + int ret; + + xmlSecAssert2(ctx != NULL, -1); + xmlSecAssert2(ctx->keyInitialized != 0, -1); + xmlSecAssert2(ctx->ctxInitialized != 0, -1); + xmlSecAssert2(in != NULL, -1); + xmlSecAssert2(out != NULL, -1); + xmlSecAssert2(transformCtx != NULL, -1); + + blockLen = EVP_CIPHER_block_size(ctx->cipher); + xmlSecAssert2(blockLen > 0, -1); + + inSize = xmlSecBufferGetSize(in); + outSize = xmlSecBufferGetSize(out); + + if(inSize == 0) { + /* wait for more data */ + return(0); + } + + /* OpenSSL docs: The amount of data written depends on the block + * alignment of the encrypted data: as a result the amount of data + * written may be anything from zero bytes to (inl + cipher_block_size - 1). + */ + ret = xmlSecBufferSetMaxSize(out, outSize + inSize + blockLen); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(cipherName), + "xmlSecBufferSetMaxSize", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "size=%d", outSize + inSize + blockLen); + return(-1); + } + outBuf = xmlSecBufferGetData(out) + outSize; + + /* + * The padding used in XML Enc does not follow RFC 1423 + * and is not supported by OpenSSL. In the case of OpenSSL 0.9.7 + * it is possible to disable padding and do it by yourself + * For OpenSSL 0.9.6 you have interop problems. + * + * The logic below is copied from EVP_DecryptUpdate() function. + * This is a hack but it's the only way I can provide binary + * compatibility with previous versions of xmlsec. + * This needs to be fixed in the next XMLSEC API refresh. + */ +#ifndef XMLSEC_OPENSSL_096 + if(!ctx->cipherCtx.encrypt) { + if(ctx->cipherCtx.final_used) { + memcpy(outBuf, ctx->cipherCtx.final, blockLen); + outBuf += blockLen; + fixLength = 1; + } else { + fixLength = 0; + } + } +#endif /* XMLSEC_OPENSSL_096 */ + + /* encrypt/decrypt */ + ret = EVP_CipherUpdate(&(ctx->cipherCtx), outBuf, &outLen, xmlSecBufferGetData(in), inSize); + if(ret != 1) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(cipherName), + "EVP_CipherUpdate", + XMLSEC_ERRORS_R_CRYPTO_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + +#ifndef XMLSEC_OPENSSL_096 + if(!ctx->cipherCtx.encrypt) { + /* + * The logic below is copied from EVP_DecryptUpdate() function. + * This is a hack but it's the only way I can provide binary + * compatibility with previous versions of xmlsec. + * This needs to be fixed in the next XMLSEC API refresh. + */ + if (blockLen > 1 && !ctx->cipherCtx.buf_len) { + outLen -= blockLen; + ctx->cipherCtx.final_used = 1; + memcpy(ctx->cipherCtx.final, &outBuf[outLen], blockLen); + } else { + ctx->cipherCtx.final_used = 0; + } + if (fixLength) { + outLen += blockLen; + } + } +#endif /* XMLSEC_OPENSSL_096 */ + + /* set correct output buffer size */ + ret = xmlSecBufferSetSize(out, outSize + outLen); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(cipherName), + "xmlSecBufferSetSize", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "size=%d", outSize + outLen); + return(-1); + } + + /* remove the processed block from input */ + ret = xmlSecBufferRemoveHead(in, inSize); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(cipherName), + "xmlSecBufferRemoveHead", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "size=%d", inSize); + return(-1); + } + return(0); +} + +static int +xmlSecOpenSSLEvpBlockCipherCtxFinal(xmlSecOpenSSLEvpBlockCipherCtxPtr ctx, + xmlSecBufferPtr out, + const xmlChar* cipherName, + xmlSecTransformCtxPtr transformCtx) { + int blockLen, outLen = 0, outLen2 = 0; + xmlSecSize outSize; + xmlSecByte* outBuf; + int ret; + + xmlSecAssert2(ctx != NULL, -1); + xmlSecAssert2(ctx->keyInitialized != 0, -1); + xmlSecAssert2(ctx->ctxInitialized != 0, -1); + xmlSecAssert2(out != NULL, -1); + xmlSecAssert2(transformCtx != NULL, -1); + + blockLen = EVP_CIPHER_block_size(ctx->cipher); + xmlSecAssert2(blockLen > 0, -1); + + outSize = xmlSecBufferGetSize(out); + + /* OpenSSL docs: The encrypted final data is written to out which should + * have sufficient space for one cipher block. We might have to write + * one more block with padding + */ + ret = xmlSecBufferSetMaxSize(out, outSize + 2 * blockLen); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(cipherName), + "xmlSecBufferSetMaxSize", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "size=%d", outSize + 2 * blockLen); + return(-1); + } + outBuf = xmlSecBufferGetData(out) + outSize; + + /* + * The padding used in XML Enc does not follow RFC 1423 + * and is not supported by OpenSSL. In the case of OpenSSL 0.9.7 + * it is possible to disable padding and do it by yourself + * For OpenSSL 0.9.6 you have interop problems. + * + * The logic below is copied from EVP_DecryptFinal() function. + * This is a hack but it's the only way I can provide binary + * compatibility with previous versions of xmlsec. + * This needs to be fixed in the next XMLSEC API refresh. + */ +#ifndef XMLSEC_OPENSSL_096 + if(ctx->cipherCtx.encrypt) { + int padLen; + + xmlSecAssert2(blockLen <= EVP_MAX_BLOCK_LENGTH, -1); + + padLen = blockLen - ctx->cipherCtx.buf_len; + xmlSecAssert2(padLen > 0, -1); + + /* generate random padding */ + if(padLen > 1) { + ret = RAND_bytes(ctx->pad, padLen - 1); + if(ret != 1) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(cipherName), + "RAND_bytes", + XMLSEC_ERRORS_R_CRYPTO_FAILED, + "size=%d", padLen - 1); + return(-1); + } + } + ctx->pad[padLen - 1] = padLen; + + /* write padding */ + ret = EVP_CipherUpdate(&(ctx->cipherCtx), outBuf, &outLen, ctx->pad, padLen); + if(ret != 1) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(cipherName), + "EVP_CipherUpdate", + XMLSEC_ERRORS_R_CRYPTO_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + outBuf += outLen; + } +#endif /* XMLSEC_OPENSSL_096 */ + + /* finalize transform */ + ret = EVP_CipherFinal(&(ctx->cipherCtx), outBuf, &outLen2); + if(ret != 1) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(cipherName), + "EVP_CipherFinal", + XMLSEC_ERRORS_R_CRYPTO_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + + /* + * The padding used in XML Enc does not follow RFC 1423 + * and is not supported by OpenSSL. In the case of OpenSSL 0.9.7 + * it is possible to disable padding and do it by yourself + * For OpenSSL 0.9.6 you have interop problems. + * + * The logic below is copied from EVP_DecryptFinal() function. + * This is a hack but it's the only way I can provide binary + * compatibility with previous versions of xmlsec. + * This needs to be fixed in the next XMLSEC API refresh. + */ +#ifndef XMLSEC_OPENSSL_096 + if(!ctx->cipherCtx.encrypt) { + /* we instructed openssl to do not use padding so there + * should be no final block + */ + xmlSecAssert2(outLen2 == 0, -1); + xmlSecAssert2(ctx->cipherCtx.buf_len == 0, -1); + xmlSecAssert2(ctx->cipherCtx.final_used, -1); + + if(blockLen > 1) { + outLen2 = blockLen - ctx->cipherCtx.final[blockLen - 1]; + if(outLen2 > 0) { + memcpy(outBuf, ctx->cipherCtx.final, outLen2); + } else if(outLen2 < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(cipherName), + NULL, + XMLSEC_ERRORS_R_INVALID_DATA, + "padding=%d;buffer=%d", + ctx->cipherCtx.final[blockLen - 1], blockLen); + return(-1); + } + } + } +#endif /* XMLSEC_OPENSSL_096 */ + + /* set correct output buffer size */ + ret = xmlSecBufferSetSize(out, outSize + outLen + outLen2); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(cipherName), + "xmlSecBufferSetSize", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "size=%d", outSize + outLen + outLen2); + return(-1); + } + + return(0); +} + + +/****************************************************************************** + * + * EVP Block Cipher transforms + * + * xmlSecOpenSSLEvpBlockCipherCtx block is located after xmlSecTransform structure + * + *****************************************************************************/ +#define xmlSecOpenSSLEvpBlockCipherSize \ + (sizeof(xmlSecTransform) + sizeof(xmlSecOpenSSLEvpBlockCipherCtx)) +#define xmlSecOpenSSLEvpBlockCipherGetCtx(transform) \ + ((xmlSecOpenSSLEvpBlockCipherCtxPtr)(((xmlSecByte*)(transform)) + sizeof(xmlSecTransform))) + +static int xmlSecOpenSSLEvpBlockCipherInitialize (xmlSecTransformPtr transform); +static void xmlSecOpenSSLEvpBlockCipherFinalize (xmlSecTransformPtr transform); +static int xmlSecOpenSSLEvpBlockCipherSetKeyReq (xmlSecTransformPtr transform, + xmlSecKeyReqPtr keyReq); +static int xmlSecOpenSSLEvpBlockCipherSetKey (xmlSecTransformPtr transform, + xmlSecKeyPtr key); +static int xmlSecOpenSSLEvpBlockCipherExecute (xmlSecTransformPtr transform, + int last, + xmlSecTransformCtxPtr transformCtx); +static int xmlSecOpenSSLEvpBlockCipherCheckId (xmlSecTransformPtr transform); + + + +static int +xmlSecOpenSSLEvpBlockCipherCheckId(xmlSecTransformPtr transform) { +#ifndef XMLSEC_NO_DES + if(xmlSecTransformCheckId(transform, xmlSecOpenSSLTransformDes3CbcId)) { + return(1); + } +#endif /* XMLSEC_NO_DES */ + +#ifndef XMLSEC_NO_AES + if(xmlSecTransformCheckId(transform, xmlSecOpenSSLTransformAes128CbcId) || + xmlSecTransformCheckId(transform, xmlSecOpenSSLTransformAes192CbcId) || + xmlSecTransformCheckId(transform, xmlSecOpenSSLTransformAes256CbcId)) { + + return(1); + } +#endif /* XMLSEC_NO_AES */ + + return(0); +} + +static int +xmlSecOpenSSLEvpBlockCipherInitialize(xmlSecTransformPtr transform) { + xmlSecOpenSSLEvpBlockCipherCtxPtr ctx; + + xmlSecAssert2(xmlSecOpenSSLEvpBlockCipherCheckId(transform), -1); + xmlSecAssert2(xmlSecTransformCheckSize(transform, xmlSecOpenSSLEvpBlockCipherSize), -1); + + ctx = xmlSecOpenSSLEvpBlockCipherGetCtx(transform); + xmlSecAssert2(ctx != NULL, -1); + + memset(ctx, 0, sizeof(xmlSecOpenSSLEvpBlockCipherCtx)); + +#ifndef XMLSEC_NO_DES + if(transform->id == xmlSecOpenSSLTransformDes3CbcId) { + ctx->cipher = EVP_des_ede3_cbc(); + ctx->keyId = xmlSecOpenSSLKeyDataDesId; + } else +#endif /* XMLSEC_NO_DES */ + +#ifndef XMLSEC_NO_AES + if(transform->id == xmlSecOpenSSLTransformAes128CbcId) { + ctx->cipher = EVP_aes_128_cbc(); + ctx->keyId = xmlSecOpenSSLKeyDataAesId; + } else if(transform->id == xmlSecOpenSSLTransformAes192CbcId) { + ctx->cipher = EVP_aes_192_cbc(); + ctx->keyId = xmlSecOpenSSLKeyDataAesId; + } else if(transform->id == xmlSecOpenSSLTransformAes256CbcId) { + ctx->cipher = EVP_aes_256_cbc(); + ctx->keyId = xmlSecOpenSSLKeyDataAesId; + } else +#endif /* XMLSEC_NO_AES */ + + if(1) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecTransformGetName(transform)), + NULL, + XMLSEC_ERRORS_R_INVALID_TRANSFORM, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + + EVP_CIPHER_CTX_init(&(ctx->cipherCtx)); + return(0); +} + +static void +xmlSecOpenSSLEvpBlockCipherFinalize(xmlSecTransformPtr transform) { + xmlSecOpenSSLEvpBlockCipherCtxPtr ctx; + + xmlSecAssert(xmlSecOpenSSLEvpBlockCipherCheckId(transform)); + xmlSecAssert(xmlSecTransformCheckSize(transform, xmlSecOpenSSLEvpBlockCipherSize)); + + ctx = xmlSecOpenSSLEvpBlockCipherGetCtx(transform); + xmlSecAssert(ctx != NULL); + + EVP_CIPHER_CTX_cleanup(&(ctx->cipherCtx)); + memset(ctx, 0, sizeof(xmlSecOpenSSLEvpBlockCipherCtx)); +} + +static int +xmlSecOpenSSLEvpBlockCipherSetKeyReq(xmlSecTransformPtr transform, xmlSecKeyReqPtr keyReq) { + xmlSecOpenSSLEvpBlockCipherCtxPtr ctx; + int cipherKeyLen; + + xmlSecAssert2(xmlSecOpenSSLEvpBlockCipherCheckId(transform), -1); + xmlSecAssert2((transform->operation == xmlSecTransformOperationEncrypt) || (transform->operation == xmlSecTransformOperationDecrypt), -1); + xmlSecAssert2(xmlSecTransformCheckSize(transform, xmlSecOpenSSLEvpBlockCipherSize), -1); + xmlSecAssert2(keyReq != NULL, -1); + + ctx = xmlSecOpenSSLEvpBlockCipherGetCtx(transform); + xmlSecAssert2(ctx != NULL, -1); + xmlSecAssert2(ctx->cipher != NULL, -1); + xmlSecAssert2(ctx->keyId != NULL, -1); + + keyReq->keyId = ctx->keyId; + keyReq->keyType = xmlSecKeyDataTypeSymmetric; + if(transform->operation == xmlSecTransformOperationEncrypt) { + keyReq->keyUsage = xmlSecKeyUsageEncrypt; + } else { + keyReq->keyUsage = xmlSecKeyUsageDecrypt; + } + + cipherKeyLen = EVP_CIPHER_key_length(ctx->cipher); + xmlSecAssert2(cipherKeyLen > 0, -1); + + keyReq->keyBitsSize = (xmlSecSize)(8 * cipherKeyLen); + return(0); +} + +static int +xmlSecOpenSSLEvpBlockCipherSetKey(xmlSecTransformPtr transform, xmlSecKeyPtr key) { + xmlSecOpenSSLEvpBlockCipherCtxPtr ctx; + xmlSecBufferPtr buffer; + int cipherKeyLen; + + xmlSecAssert2(xmlSecOpenSSLEvpBlockCipherCheckId(transform), -1); + xmlSecAssert2((transform->operation == xmlSecTransformOperationEncrypt) || (transform->operation == xmlSecTransformOperationDecrypt), -1); + xmlSecAssert2(xmlSecTransformCheckSize(transform, xmlSecOpenSSLEvpBlockCipherSize), -1); + xmlSecAssert2(key != NULL, -1); + + ctx = xmlSecOpenSSLEvpBlockCipherGetCtx(transform); + xmlSecAssert2(ctx != NULL, -1); + xmlSecAssert2(ctx->cipher != NULL, -1); + xmlSecAssert2(ctx->keyInitialized == 0, -1); + xmlSecAssert2(ctx->keyId != NULL, -1); + xmlSecAssert2(xmlSecKeyCheckId(key, ctx->keyId), -1); + + cipherKeyLen = EVP_CIPHER_key_length(ctx->cipher); + xmlSecAssert2(cipherKeyLen > 0, -1); + xmlSecAssert2((xmlSecSize)cipherKeyLen <= sizeof(ctx->key), -1); + + buffer = xmlSecKeyDataBinaryValueGetBuffer(xmlSecKeyGetValue(key)); + xmlSecAssert2(buffer != NULL, -1); + + if(xmlSecBufferGetSize(buffer) < (xmlSecSize)cipherKeyLen) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecTransformGetName(transform)), + NULL, + XMLSEC_ERRORS_R_INVALID_KEY_DATA_SIZE, + "keySize=%d;expected=%d", + xmlSecBufferGetSize(buffer), cipherKeyLen); + return(-1); + } + + xmlSecAssert2(xmlSecBufferGetData(buffer) != NULL, -1); + memcpy(ctx->key, xmlSecBufferGetData(buffer), cipherKeyLen); + + ctx->keyInitialized = 1; + return(0); +} + +static int +xmlSecOpenSSLEvpBlockCipherExecute(xmlSecTransformPtr transform, int last, xmlSecTransformCtxPtr transformCtx) { + xmlSecOpenSSLEvpBlockCipherCtxPtr ctx; + xmlSecBufferPtr in, out; + int ret; + + xmlSecAssert2(xmlSecOpenSSLEvpBlockCipherCheckId(transform), -1); + xmlSecAssert2((transform->operation == xmlSecTransformOperationEncrypt) || (transform->operation == xmlSecTransformOperationDecrypt), -1); + xmlSecAssert2(xmlSecTransformCheckSize(transform, xmlSecOpenSSLEvpBlockCipherSize), -1); + xmlSecAssert2(transformCtx != NULL, -1); + + in = &(transform->inBuf); + out = &(transform->outBuf); + + ctx = xmlSecOpenSSLEvpBlockCipherGetCtx(transform); + xmlSecAssert2(ctx != NULL, -1); + + if(transform->status == xmlSecTransformStatusNone) { + transform->status = xmlSecTransformStatusWorking; + } + + if(transform->status == xmlSecTransformStatusWorking) { + if(ctx->ctxInitialized == 0) { + ret = xmlSecOpenSSLEvpBlockCipherCtxInit(ctx, in, out, + (transform->operation == xmlSecTransformOperationEncrypt) ? 1 : 0, + xmlSecTransformGetName(transform), transformCtx); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecTransformGetName(transform)), + "xmlSecOpenSSLEvpBlockCipherCtxInit", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + } + if((ctx->ctxInitialized == 0) && (last != 0)) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecTransformGetName(transform)), + NULL, + XMLSEC_ERRORS_R_INVALID_DATA, + "not enough data to initialize transform"); + return(-1); + } + + if(ctx->ctxInitialized != 0) { + ret = xmlSecOpenSSLEvpBlockCipherCtxUpdate(ctx, in, out, + xmlSecTransformGetName(transform), + transformCtx); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecTransformGetName(transform)), + "xmlSecOpenSSLEvpBlockCipherCtxUpdate", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + } + + if(last != 0) { + /* by now there should be no input */ + xmlSecAssert2(xmlSecBufferGetSize(in) == 0, -1); + ret = xmlSecOpenSSLEvpBlockCipherCtxFinal(ctx, out, + xmlSecTransformGetName(transform), + transformCtx); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecTransformGetName(transform)), + "xmlSecOpenSSLEvpBlockCipherCtxFinal", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + transform->status = xmlSecTransformStatusFinished; + } + } else if(transform->status == xmlSecTransformStatusFinished) { + /* the only way we can get here is if there is no input */ + xmlSecAssert2(xmlSecBufferGetSize(in) == 0, -1); + } else if(transform->status == xmlSecTransformStatusNone) { + /* the only way we can get here is if there is no enough data in the input */ + xmlSecAssert2(last == 0, -1); + } else { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecTransformGetName(transform)), + NULL, + XMLSEC_ERRORS_R_INVALID_STATUS, + "status=%d", transform->status); + return(-1); + } + + return(0); +} + + +#ifndef XMLSEC_NO_AES +/********************************************************************* + * + * AES CBC cipher transforms + * + ********************************************************************/ +static xmlSecTransformKlass xmlSecOpenSSLAes128CbcKlass = { + /* klass/object sizes */ + sizeof(xmlSecTransformKlass), /* xmlSecSize klassSize */ + xmlSecOpenSSLEvpBlockCipherSize, /* xmlSecSize objSize */ + + xmlSecNameAes128Cbc, /* const xmlChar* name; */ + xmlSecHrefAes128Cbc, /* const xmlChar* href; */ + xmlSecTransformUsageEncryptionMethod, /* xmlSecAlgorithmUsage usage; */ + + xmlSecOpenSSLEvpBlockCipherInitialize, /* xmlSecTransformInitializeMethod initialize; */ + xmlSecOpenSSLEvpBlockCipherFinalize, /* xmlSecTransformFinalizeMethod finalize; */ + NULL, /* xmlSecTransformNodeReadMethod readNode; */ + NULL, /* xmlSecTransformNodeWriteMethod writeNode; */ + xmlSecOpenSSLEvpBlockCipherSetKeyReq, /* xmlSecTransformSetKeyMethod setKeyReq; */ + xmlSecOpenSSLEvpBlockCipherSetKey, /* xmlSecTransformSetKeyMethod setKey; */ + NULL, /* xmlSecTransformValidateMethod validate; */ + xmlSecTransformDefaultGetDataType, /* xmlSecTransformGetDataTypeMethod getDataType; */ + xmlSecTransformDefaultPushBin, /* xmlSecTransformPushBinMethod pushBin; */ + xmlSecTransformDefaultPopBin, /* xmlSecTransformPopBinMethod popBin; */ + NULL, /* xmlSecTransformPushXmlMethod pushXml; */ + NULL, /* xmlSecTransformPopXmlMethod popXml; */ + xmlSecOpenSSLEvpBlockCipherExecute, /* xmlSecTransformExecuteMethod execute; */ + + NULL, /* void* reserved0; */ + NULL, /* void* reserved1; */ +}; + +/** + * xmlSecOpenSSLTransformAes128CbcGetKlass: + * + * AES 128 CBC encryption transform klass. + * + * Returns: pointer to AES 128 CBC encryption transform. + */ +xmlSecTransformId +xmlSecOpenSSLTransformAes128CbcGetKlass(void) { + return(&xmlSecOpenSSLAes128CbcKlass); +} + +static xmlSecTransformKlass xmlSecOpenSSLAes192CbcKlass = { + /* klass/object sizes */ + sizeof(xmlSecTransformKlass), /* xmlSecSize klassSize */ + xmlSecOpenSSLEvpBlockCipherSize, /* xmlSecSize objSize */ + + xmlSecNameAes192Cbc, /* const xmlChar* name; */ + xmlSecHrefAes192Cbc, /* const xmlChar* href; */ + xmlSecTransformUsageEncryptionMethod, /* xmlSecAlgorithmUsage usage; */ + + xmlSecOpenSSLEvpBlockCipherInitialize, /* xmlSecTransformInitializeMethod initialize; */ + xmlSecOpenSSLEvpBlockCipherFinalize, /* xmlSecTransformFinalizeMethod finalize; */ + NULL, /* xmlSecTransformNodeReadMethod readNode; */ + NULL, /* xmlSecTransformNodeWriteMethod writeNode; */ + xmlSecOpenSSLEvpBlockCipherSetKeyReq, /* xmlSecTransformSetKeyMethod setKeyReq; */ + xmlSecOpenSSLEvpBlockCipherSetKey, /* xmlSecTransformSetKeyMethod setKey; */ + NULL, /* xmlSecTransformValidateMethod validate; */ + xmlSecTransformDefaultGetDataType, /* xmlSecTransformGetDataTypeMethod getDataType; */ + xmlSecTransformDefaultPushBin, /* xmlSecTransformPushBinMethod pushBin; */ + xmlSecTransformDefaultPopBin, /* xmlSecTransformPopBinMethod popBin; */ + NULL, /* xmlSecTransformPushXmlMethod pushXml; */ + NULL, /* xmlSecTransformPopXmlMethod popXml; */ + xmlSecOpenSSLEvpBlockCipherExecute, /* xmlSecTransformExecuteMethod execute; */ + + NULL, /* void* reserved0; */ + NULL, /* void* reserved1; */ +}; + +/** + * xmlSecOpenSSLTransformAes192CbcGetKlass: + * + * AES 192 CBC encryption transform klass. + * + * Returns: pointer to AES 192 CBC encryption transform. + */ +xmlSecTransformId +xmlSecOpenSSLTransformAes192CbcGetKlass(void) { + return(&xmlSecOpenSSLAes192CbcKlass); +} + +static xmlSecTransformKlass xmlSecOpenSSLAes256CbcKlass = { + /* klass/object sizes */ + sizeof(xmlSecTransformKlass), /* xmlSecSize klassSize */ + xmlSecOpenSSLEvpBlockCipherSize, /* xmlSecSize objSize */ + + xmlSecNameAes256Cbc, /* const xmlChar* name; */ + xmlSecHrefAes256Cbc, /* const xmlChar* href; */ + xmlSecTransformUsageEncryptionMethod, /* xmlSecAlgorithmUsage usage; */ + + xmlSecOpenSSLEvpBlockCipherInitialize, /* xmlSecTransformInitializeMethod initialize; */ + xmlSecOpenSSLEvpBlockCipherFinalize, /* xmlSecTransformFinalizeMethod finalize; */ + NULL, /* xmlSecTransformNodeReadMethod readNode; */ + NULL, /* xmlSecTransformNodeWriteMethod writeNode; */ + xmlSecOpenSSLEvpBlockCipherSetKeyReq, /* xmlSecTransformSetKeyMethod setKeyReq; */ + xmlSecOpenSSLEvpBlockCipherSetKey, /* xmlSecTransformSetKeyMethod setKey; */ + NULL, /* xmlSecTransformValidateMethod validate; */ + xmlSecTransformDefaultGetDataType, /* xmlSecTransformGetDataTypeMethod getDataType; */ + xmlSecTransformDefaultPushBin, /* xmlSecTransformPushBinMethod pushBin; */ + xmlSecTransformDefaultPopBin, /* xmlSecTransformPopBinMethod popBin; */ + NULL, /* xmlSecTransformPushXmlMethod pushXml; */ + NULL, /* xmlSecTransformPopXmlMethod popXml; */ + xmlSecOpenSSLEvpBlockCipherExecute, /* xmlSecTransformExecuteMethod execute; */ + + NULL, /* void* reserved0; */ + NULL, /* void* reserved1; */ +}; + +/** + * xmlSecOpenSSLTransformAes256CbcGetKlass: + * + * AES 256 CBC encryption transform klass. + * + * Returns: pointer to AES 256 CBC encryption transform. + */ +xmlSecTransformId +xmlSecOpenSSLTransformAes256CbcGetKlass(void) { + return(&xmlSecOpenSSLAes256CbcKlass); +} + +#endif /* XMLSEC_NO_AES */ + +#ifndef XMLSEC_NO_DES +static xmlSecTransformKlass xmlSecOpenSSLDes3CbcKlass = { + /* klass/object sizes */ + sizeof(xmlSecTransformKlass), /* xmlSecSize klassSize */ + xmlSecOpenSSLEvpBlockCipherSize, /* xmlSecSize objSize */ + + xmlSecNameDes3Cbc, /* const xmlChar* name; */ + xmlSecHrefDes3Cbc, /* const xmlChar* href; */ + xmlSecTransformUsageEncryptionMethod, /* xmlSecAlgorithmUsage usage; */ + + xmlSecOpenSSLEvpBlockCipherInitialize, /* xmlSecTransformInitializeMethod initialize; */ + xmlSecOpenSSLEvpBlockCipherFinalize, /* xmlSecTransformFinalizeMethod finalize; */ + NULL, /* xmlSecTransformNodeReadMethod readNode; */ + NULL, /* xmlSecTransformNodeWriteMethod writeNode; */ + xmlSecOpenSSLEvpBlockCipherSetKeyReq, /* xmlSecTransformSetKeyMethod setKeyReq; */ + xmlSecOpenSSLEvpBlockCipherSetKey, /* xmlSecTransformSetKeyMethod setKey; */ + NULL, /* xmlSecTransformValidateMethod validate; */ + xmlSecTransformDefaultGetDataType, /* xmlSecTransformGetDataTypeMethod getDataType; */ + xmlSecTransformDefaultPushBin, /* xmlSecTransformPushBinMethod pushBin; */ + xmlSecTransformDefaultPopBin, /* xmlSecTransformPopBinMethod popBin; */ + NULL, /* xmlSecTransformPushXmlMethod pushXml; */ + NULL, /* xmlSecTransformPopXmlMethod popXml; */ + xmlSecOpenSSLEvpBlockCipherExecute, /* xmlSecTransformExecuteMethod execute; */ + + NULL, /* void* reserved0; */ + NULL, /* void* reserved1; */ +}; + +/** + * xmlSecOpenSSLTransformDes3CbcGetKlass: + * + * Triple DES CBC encryption transform klass. + * + * Returns: pointer to Triple DES encryption transform. + */ +xmlSecTransformId +xmlSecOpenSSLTransformDes3CbcGetKlass(void) { + return(&xmlSecOpenSSLDes3CbcKlass); +} +#endif /* XMLSEC_NO_DES */ + |