/** * XMLSec library * * This is free software; see Copyright file in the source * distribution for preciese wording. * * Copyright (C) 2002-2003 Aleksey Sanin */ #include "globals.h" #include #include #include #include #include #include #include #include #include /* 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 */