summaryrefslogtreecommitdiff
path: root/src/openssl/ciphers.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/openssl/ciphers.c')
-rw-r--r--src/openssl/ciphers.c856
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 */
+