summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAleksey Sanin <aleksey@src.gnome.org>2003-02-28 05:59:55 +0000
committerAleksey Sanin <aleksey@src.gnome.org>2003-02-28 05:59:55 +0000
commit1c20c86d98f034af13cf90f44336b0469abcfb7d (patch)
tree12eb0644e6018b85931d62bb0e626602f97fd054
parent160d7b3f59bcf9286dbe7c31b3024e5a55ddac05 (diff)
downloadxmlsec1-1c20c86d98f034af13cf90f44336b0469abcfb7d.tar.gz
xmlsec1-1c20c86d98f034af13cf90f44336b0469abcfb7d.tar.bz2
xmlsec1-1c20c86d98f034af13cf90f44336b0469abcfb7d.zip
*** empty log message ***
-rw-r--r--src/openssl/kwaes.c593
-rw-r--r--src/openssl/kwdes.c616
2 files changed, 1209 insertions, 0 deletions
diff --git a/src/openssl/kwaes.c b/src/openssl/kwaes.c
new file mode 100644
index 00000000..697d76fa
--- /dev/null
+++ b/src/openssl/kwaes.c
@@ -0,0 +1,593 @@
+/**
+ *
+ * XMLSec library
+ *
+ * AES Algorithm support
+ *
+ * See Copyright for the status of this software.
+ *
+ * Author: Aleksey Sanin <aleksey@aleksey.com>
+ */
+#ifndef XMLSEC_NO_AES
+#ifndef XMLSEC_OPENSSL_096
+#include "globals.h"
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+#include <openssl/aes.h>
+#include <openssl/rand.h>
+
+#include <xmlsec/xmlsec.h>
+#include <xmlsec/xmltree.h>
+#include <xmlsec/keys.h>
+#include <xmlsec/keyinfo.h>
+#include <xmlsec/transforms.h>
+#include <xmlsec/transformsInternal.h>
+#include <xmlsec/errors.h>
+
+#include <xmlsec/openssl/crypto.h>
+
+#define XMLSEC_OPENSSL_AES128_KEY_SIZE 16
+#define XMLSEC_OPENSSL_AES192_KEY_SIZE 24
+#define XMLSEC_OPENSSL_AES256_KEY_SIZE 32
+#define XMLSEC_OPENSSL_AES_IV_SIZE 16
+#define XMLSEC_OPENSSL_AES_BLOCK_SIZE 16
+
+
+/*********************************************************************
+ *
+ * AES KW transforms
+ *
+ * key (xmlSecBuffer) is located after xmlSecTransform structure
+ *
+ ********************************************************************/
+#define xmlSecOpenSSLKWAesGetKey(transform) \
+ ((xmlSecBufferPtr)(((unsigned char*)(transform)) + sizeof(xmlSecTransform)))
+#define xmlSecOpenSSLKWAesSize \
+ (sizeof(xmlSecTransform) + sizeof(xmlSecBuffer))
+
+static int xmlSecOpenSSLKWAesInitialize (xmlSecTransformPtr transform);
+static void xmlSecOpenSSLKWAesFinalize (xmlSecTransformPtr transform);
+static int xmlSecOpenSSLKWAesSetKeyReq (xmlSecTransformPtr transform,
+ xmlSecKeyInfoCtxPtr keyInfoCtx);
+static int xmlSecOpenSSLKWAesSetKey (xmlSecTransformPtr transform,
+ xmlSecKeyPtr key);
+static int xmlSecOpenSSLKWAesExecute (xmlSecTransformPtr transform,
+ int last,
+ xmlSecTransformCtxPtr transformCtx);
+static size_t xmlSecOpenSSLKWAesGetKeySize (xmlSecTransformPtr transform);
+static int xmlSecOpenSSLKWAesEncode (const unsigned char *key,
+ size_t keySize,
+ const unsigned char* in,
+ size_t inSize,
+ unsigned char* out,
+ size_t outSize);
+static int xmlSecOpenSSLKWAesDecode (const unsigned char *key,
+ size_t keySize,
+ const unsigned char* in,
+ size_t inSize,
+ unsigned char* out,
+ size_t outSize);
+
+static xmlSecTransformKlass xmlSecOpenSSLKWAes128Klass = {
+ /* klass/object sizes */
+ sizeof(xmlSecTransformKlass), /* size_t klassSize */
+ xmlSecOpenSSLKWAesSize, /* size_t objSize */
+
+ xmlSecNameKWAes128,
+ xmlSecTransformTypeBinary, /* xmlSecTransformType type; */
+ xmlSecTransformUsageEncryptionMethod, /* xmlSecAlgorithmUsage usage; */
+ xmlSecHrefKWAes128, /* const xmlChar href; */
+
+ xmlSecOpenSSLKWAesInitialize, /* xmlSecTransformInitializeMethod initialize; */
+ xmlSecOpenSSLKWAesFinalize, /* xmlSecTransformFinalizeMethod finalize; */
+ NULL, /* xmlSecTransformReadMethod read; */
+ xmlSecOpenSSLKWAesSetKeyReq, /* xmlSecTransformSetKeyMethod setKeyReq; */
+ xmlSecOpenSSLKWAesSetKey, /* xmlSecTransformSetKeyMethod setKey; */
+ NULL, /* xmlSecTransformValidateMethod validate; */
+ xmlSecTransformDefaultPushBin, /* xmlSecTransformPushBinMethod pushBin; */
+ xmlSecTransformDefaultPopBin, /* xmlSecTransformPopBinMethod popBin; */
+ NULL, /* xmlSecTransformPushXmlMethod pushXml; */
+ NULL, /* xmlSecTransformPopXmlMethod popXml; */
+ xmlSecOpenSSLKWAesExecute, /* xmlSecTransformExecuteMethod execute; */
+
+ NULL, /* xmlSecTransformExecuteXmlMethod executeXml; */
+ NULL, /* xmlSecTransformExecuteC14NMethod executeC14N; */
+};
+
+static xmlSecTransformKlass xmlSecOpenSSLKWAes192Klass = {
+ /* klass/object sizes */
+ sizeof(xmlSecTransformKlass), /* size_t klassSize */
+ xmlSecOpenSSLKWAesSize, /* size_t objSize */
+
+ xmlSecNameKWAes192,
+ xmlSecTransformTypeBinary, /* xmlSecTransformType type; */
+ xmlSecTransformUsageEncryptionMethod, /* xmlSecAlgorithmUsage usage; */
+ xmlSecHrefKWAes192, /* const xmlChar href; */
+
+ xmlSecOpenSSLKWAesInitialize, /* xmlSecTransformInitializeMethod initialize; */
+ xmlSecOpenSSLKWAesFinalize, /* xmlSecTransformFinalizeMethod finalize; */
+ NULL, /* xmlSecTransformReadMethod read; */
+ xmlSecOpenSSLKWAesSetKeyReq, /* xmlSecTransformSetKeyMethod setKeyReq; */
+ xmlSecOpenSSLKWAesSetKey, /* xmlSecTransformSetKeyMethod setKey; */
+ NULL, /* xmlSecTransformValidateMethod validate; */
+ xmlSecTransformDefaultPushBin, /* xmlSecTransformPushBinMethod pushBin; */
+ xmlSecTransformDefaultPopBin, /* xmlSecTransformPopBinMethod popBin; */
+ NULL, /* xmlSecTransformPushXmlMethod pushXml; */
+ NULL, /* xmlSecTransformPopXmlMethod popXml; */
+ xmlSecOpenSSLKWAesExecute, /* xmlSecTransformExecuteMethod execute; */
+
+ NULL, /* xmlSecTransformExecuteXmlMethod executeXml; */
+ NULL, /* xmlSecTransformExecuteC14NMethod executeC14N; */
+};
+
+static xmlSecTransformKlass xmlSecOpenSSLKWAes256Klass = {
+ /* klass/object sizes */
+ sizeof(xmlSecTransformKlass), /* size_t klassSize */
+ xmlSecOpenSSLKWAesSize, /* size_t objSize */
+
+ xmlSecNameKWAes256,
+ xmlSecTransformTypeBinary, /* xmlSecTransformType type; */
+ xmlSecTransformUsageEncryptionMethod, /* xmlSecAlgorithmUsage usage; */
+ xmlSecHrefKWAes256, /* const xmlChar href; */
+
+ xmlSecOpenSSLKWAesInitialize, /* xmlSecTransformInitializeMethod initialize; */
+ xmlSecOpenSSLKWAesFinalize, /* xmlSecTransformFinalizeMethod finalize; */
+ NULL, /* xmlSecTransformReadMethod read; */
+ xmlSecOpenSSLKWAesSetKeyReq, /* xmlSecTransformSetKeyMethod setKeyReq; */
+ xmlSecOpenSSLKWAesSetKey, /* xmlSecTransformSetKeyMethod setKey; */
+ NULL, /* xmlSecTransformValidateMethod validate; */
+ xmlSecTransformDefaultPushBin, /* xmlSecTransformPushBinMethod pushBin; */
+ xmlSecTransformDefaultPopBin, /* xmlSecTransformPopBinMethod popBin; */
+ NULL, /* xmlSecTransformPushXmlMethod pushXml; */
+ NULL, /* xmlSecTransformPopXmlMethod popXml; */
+ xmlSecOpenSSLKWAesExecute, /* xmlSecTransformExecuteMethod execute; */
+
+ NULL, /* xmlSecTransformExecuteXmlMethod executeXml; */
+ NULL, /* xmlSecTransformExecuteC14NMethod executeC14N; */
+};
+
+#define XMLSEC_OPENSSL_KW_AES_MAGIC_BLOCK_SIZE 8
+
+#define xmlSecOpenSSLKWAesCheckId(transform) \
+ (xmlSecTransformCheckId((transform), xmlSecOpenSSLTransformKWAes128Id) || \
+ xmlSecTransformCheckId((transform), xmlSecOpenSSLTransformKWAes192Id) || \
+ xmlSecTransformCheckId((transform), xmlSecOpenSSLTransformKWAes256Id))
+
+xmlSecTransformId
+xmlSecOpenSSLTransformKWAes128GetKlass(void) {
+ return(&xmlSecOpenSSLKWAes128Klass);
+}
+
+xmlSecTransformId
+xmlSecOpenSSLTransformKWAes192GetKlass(void) {
+ return(&xmlSecOpenSSLKWAes192Klass);
+}
+
+xmlSecTransformId
+xmlSecOpenSSLTransformKWAes256GetKlass(void) {
+ return(&xmlSecOpenSSLKWAes256Klass);
+}
+
+static int
+xmlSecOpenSSLKWAesInitialize(xmlSecTransformPtr transform) {
+ int ret;
+
+ xmlSecAssert2(xmlSecOpenSSLKWAesCheckId(transform), -1);
+ xmlSecAssert2(xmlSecTransformCheckSize(transform, xmlSecOpenSSLKWAesSize), -1);
+
+ ret = xmlSecBufferInitialize(xmlSecOpenSSLKWAesGetKey(transform), 0);
+ if(ret < 0) {
+ xmlSecError(XMLSEC_ERRORS_HERE,
+ xmlSecErrorsSafeString(xmlSecTransformGetName(transform)),
+ "xmlSecOpenSSLKWAesGetKey",
+ XMLSEC_ERRORS_R_XMLSEC_FAILED,
+ XMLSEC_ERRORS_NO_MESSAGE);
+ return(-1);
+ }
+
+ return(0);
+}
+
+static void
+xmlSecOpenSSLKWAesFinalize(xmlSecTransformPtr transform) {
+ xmlSecAssert(xmlSecOpenSSLKWAesCheckId(transform));
+ xmlSecAssert(xmlSecTransformCheckSize(transform, xmlSecOpenSSLKWAesSize));
+
+ if(xmlSecOpenSSLKWAesGetKey(transform) != NULL) {
+ xmlSecBufferFinalize(xmlSecOpenSSLKWAesGetKey(transform));
+ }
+}
+
+static int
+xmlSecOpenSSLKWAesSetKeyReq(xmlSecTransformPtr transform, xmlSecKeyInfoCtxPtr keyInfoCtx) {
+ xmlSecAssert2(xmlSecOpenSSLKWAesCheckId(transform), -1);
+ xmlSecAssert2(xmlSecTransformCheckSize(transform, xmlSecOpenSSLKWAesSize), -1);
+ xmlSecAssert2(keyInfoCtx != NULL, -1);
+
+ keyInfoCtx->keyId = xmlSecOpenSSLKeyDataAesId;
+ keyInfoCtx->keyType = xmlSecKeyDataTypeSymmetric;
+ if(transform->encode) {
+ keyInfoCtx->keyUsage = xmlSecKeyUsageEncrypt;
+ } else {
+ keyInfoCtx->keyUsage = xmlSecKeyUsageDecrypt;
+ }
+
+ return(0);
+}
+
+static int
+xmlSecOpenSSLKWAesSetKey(xmlSecTransformPtr transform, xmlSecKeyPtr key) {
+ xmlSecBufferPtr buffer;
+ size_t keySize;
+ size_t expectedKeySize;
+ int ret;
+
+ xmlSecAssert2(xmlSecOpenSSLKWAesCheckId(transform), -1);
+ xmlSecAssert2(xmlSecTransformCheckSize(transform, xmlSecOpenSSLKWAesSize), -1);
+ xmlSecAssert2(xmlSecOpenSSLKWAesGetKey(transform) != NULL, -1);
+ xmlSecAssert2(key != NULL, -1);
+ xmlSecAssert2(xmlSecKeyDataCheckId(xmlSecKeyGetValue(key), xmlSecOpenSSLKeyDataAesId), -1);
+
+ buffer = xmlSecKeyDataBinaryValueGetBuffer(xmlSecKeyGetValue(key));
+ xmlSecAssert2(buffer != NULL, -1);
+
+ keySize = xmlSecBufferGetSize(buffer);
+ expectedKeySize = xmlSecOpenSSLKWAesGetKeySize(transform);
+ if(keySize < expectedKeySize) {
+ xmlSecError(XMLSEC_ERRORS_HERE,
+ xmlSecErrorsSafeString(xmlSecTransformGetName(transform)),
+ NULL,
+ XMLSEC_ERRORS_R_INVALID_KEY_SIZE,
+ "key=%d;expected=%d",
+ keySize, expectedKeySize);
+ return(-1);
+ }
+
+ ret = xmlSecBufferSetData(xmlSecOpenSSLKWAesGetKey(transform),
+ xmlSecBufferGetData(buffer),
+ expectedKeySize);
+ if(ret < 0) {
+ xmlSecError(XMLSEC_ERRORS_HERE,
+ xmlSecErrorsSafeString(xmlSecTransformGetName(transform)),
+ "xmlSecBufferSetData",
+ XMLSEC_ERRORS_R_XMLSEC_FAILED,
+ "expected-size=%d", expectedKeySize);
+ return(-1);
+ }
+
+ return(0);
+}
+
+static int
+xmlSecOpenSSLKWAesExecute(xmlSecTransformPtr transform, int last, xmlSecTransformCtxPtr transformCtx) {
+ xmlSecBufferPtr in, out, key;
+ size_t inSize, outSize, keySize, expectedKeySize;
+ int ret;
+
+ xmlSecAssert2(xmlSecOpenSSLKWAesCheckId(transform), -1);
+ xmlSecAssert2(xmlSecTransformCheckSize(transform, xmlSecOpenSSLKWAesSize), -1);
+ xmlSecAssert2(transformCtx != NULL, -1);
+
+ key = xmlSecOpenSSLKWAesGetKey(transform);
+ xmlSecAssert2(key != NULL, -1);
+
+ keySize = xmlSecBufferGetSize(key);
+ expectedKeySize = xmlSecOpenSSLKWAesGetKeySize(transform);
+ xmlSecAssert2(keySize == expectedKeySize, -1);
+
+ in = &(transform->inBuf);
+ out = &(transform->outBuf);
+ inSize = xmlSecBufferGetSize(in);
+ outSize = xmlSecBufferGetSize(out);
+ xmlSecAssert2(outSize == 0, -1);
+
+ if(transform->status == xmlSecTransformStatusNone) {
+ transform->status = xmlSecTransformStatusWorking;
+ } else if((transform->status == xmlSecTransformStatusWorking) && (last == 0)) {
+ /* just do nothing */
+ } else if((transform->status == xmlSecTransformStatusWorking) && (last != 0)) {
+ if((inSize % 8) != 0) {
+ xmlSecError(XMLSEC_ERRORS_HERE,
+ xmlSecErrorsSafeString(xmlSecTransformGetName(transform)),
+ NULL,
+ XMLSEC_ERRORS_R_INVALID_SIZE,
+ "size=%d(not 8 bytes aligned)", inSize);
+ return(-1);
+ }
+
+ if(transform->encode) {
+ /* the encoded key might be 8 bytes longer plus 8 bytes just in case */
+ outSize = inSize + XMLSEC_OPENSSL_KW_AES_MAGIC_BLOCK_SIZE +
+ XMLSEC_OPENSSL_AES_BLOCK_SIZE;
+ } else {
+ outSize = inSize + XMLSEC_OPENSSL_AES_BLOCK_SIZE;
+ }
+
+ ret = xmlSecBufferSetMaxSize(out, outSize);
+ if(ret < 0) {
+ xmlSecError(XMLSEC_ERRORS_HERE,
+ xmlSecErrorsSafeString(xmlSecTransformGetName(transform)),
+ "xmlSecBufferSetMaxSize",
+ XMLSEC_ERRORS_R_XMLSEC_FAILED,
+ "outSize=%d", outSize);
+ return(-1);
+ }
+
+ if(transform->encode) {
+ ret = xmlSecOpenSSLKWAesEncode(xmlSecBufferGetData(key), keySize,
+ xmlSecBufferGetData(in), inSize,
+ xmlSecBufferGetData(out), outSize);
+ if(ret < 0) {
+ xmlSecError(XMLSEC_ERRORS_HERE,
+ xmlSecErrorsSafeString(xmlSecTransformGetName(transform)),
+ "xmlSecOpenSSLKWAesEncode",
+ XMLSEC_ERRORS_R_XMLSEC_FAILED,
+ XMLSEC_ERRORS_NO_MESSAGE);
+ return(-1);
+ }
+ outSize = ret;
+ } else {
+ ret = xmlSecOpenSSLKWAesDecode(xmlSecBufferGetData(key), keySize,
+ xmlSecBufferGetData(in), inSize,
+ xmlSecBufferGetData(out), outSize);
+ if(ret < 0) {
+ xmlSecError(XMLSEC_ERRORS_HERE,
+ xmlSecErrorsSafeString(xmlSecTransformGetName(transform)),
+ "xmlSecOpenSSLKWAesDecode",
+ XMLSEC_ERRORS_R_XMLSEC_FAILED,
+ XMLSEC_ERRORS_NO_MESSAGE);
+ return(-1);
+ }
+ outSize = ret;
+ }
+
+ ret = xmlSecBufferSetSize(out, outSize);
+ if(ret < 0) {
+ xmlSecError(XMLSEC_ERRORS_HERE,
+ xmlSecErrorsSafeString(xmlSecTransformGetName(transform)),
+ "xmlSecBufferSetSize",
+ XMLSEC_ERRORS_R_XMLSEC_FAILED,
+ "outSize=%d", outSize);
+ return(-1);
+ }
+
+ ret = xmlSecBufferRemoveHead(in, inSize);
+ if(ret < 0) {
+ xmlSecError(XMLSEC_ERRORS_HERE,
+ xmlSecErrorsSafeString(xmlSecTransformGetName(transform)),
+ "xmlSecBufferRemoveHead",
+ XMLSEC_ERRORS_R_XMLSEC_FAILED,
+ "inSize%d", inSize);
+ 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(&(transform->inBuf)) == 0, -1);
+ } else {
+ xmlSecError(XMLSEC_ERRORS_HERE,
+ xmlSecErrorsSafeString(xmlSecTransformGetName(transform)),
+ NULL,
+ XMLSEC_ERRORS_R_INVALID_STATUS,
+ "status=%d", transform->status);
+ return(-1);
+ }
+ return(0);
+}
+
+static size_t
+xmlSecOpenSSLKWAesGetKeySize(xmlSecTransformPtr transform) {
+ if(xmlSecTransformCheckId(transform, xmlSecOpenSSLTransformKWAes128Id)) {
+ return(XMLSEC_OPENSSL_AES128_KEY_SIZE);
+ } else if(xmlSecTransformCheckId(transform, xmlSecOpenSSLTransformKWAes192Id)) {
+ return(XMLSEC_OPENSSL_AES192_KEY_SIZE);
+ } else if(xmlSecTransformCheckId(transform, xmlSecOpenSSLTransformKWAes256Id)) {
+ return(XMLSEC_OPENSSL_AES256_KEY_SIZE);
+ }
+ return(0);
+}
+
+/**
+ * http://www.w3.org/TR/xmlenc-core/#sec-Alg-SymmetricKeyWrap:
+ *
+ * Assume that the data to be wrapped consists of N 64-bit data blocks
+ * denoted P(1), P(2), P(3) ... P(N). The result of wrapping will be N+1
+ * 64-bit blocks denoted C(0), C(1), C(2), ... C(N). The key encrypting
+ * key is represented by K. Assume integers i, j, and t and intermediate
+ * 64-bit register A, 128-bit register B, and array of 64-bit quantities
+ * R(1) through R(N).
+ *
+ * "|" represents concatentation so x|y, where x and y and 64-bit quantities,
+ * is the 128-bit quantity with x in the most significant bits and y in the
+ * least significant bits. AES(K)enc(x) is the operation of AES encrypting
+ * the 128-bit quantity x under the key K. AES(K)dec(x) is the corresponding
+ * decryption opteration. XOR(x,y) is the bitwise exclusive or of x and y.
+ * MSB(x) and LSB(y) are the most significant 64 bits and least significant
+ * 64 bits of x and y respectively.
+ *
+ * If N is 1, a single AES operation is performed for wrap or unwrap.
+ * If N>1, then 6*N AES operations are performed for wrap or unwrap.
+ *
+ * The key wrap algorithm is as follows:
+ *
+ * 1. If N is 1:
+ * * B=AES(K)enc(0xA6A6A6A6A6A6A6A6|P(1))
+ * * C(0)=MSB(B)
+ * * C(1)=LSB(B)
+ * If N>1, perform the following steps:
+ * 2. Initialize variables:
+ * * Set A to 0xA6A6A6A6A6A6A6A6
+ * * Fori=1 to N,
+ * R(i)=P(i)
+ * 3. Calculate intermediate values:
+ * * Forj=0 to 5,
+ * o For i=1 to N,
+ * t= i + j*N
+ * B=AES(K)enc(A|R(i))
+ * A=XOR(t,MSB(B))
+ * R(i)=LSB(B)
+ * 4. Output the results:
+ * * Set C(0)=A
+ * * For i=1 to N,
+ * C(i)=R(i)
+ *
+ * The key unwrap algorithm is as follows:
+ *
+ * 1. If N is 1:
+ * * B=AES(K)dec(C(0)|C(1))
+ * * P(1)=LSB(B)
+ * * If MSB(B) is 0xA6A6A6A6A6A6A6A6, return success. Otherwise,
+ * return an integrity check failure error.
+ * If N>1, perform the following steps:
+ * 2. Initialize the variables:
+ * * A=C(0)
+ * * For i=1 to N,
+ * R(i)=C(i)
+ * 3. Calculate intermediate values:
+ * * For j=5 to 0,
+ * o For i=N to 1,
+ * t= i + j*N
+ * B=AES(K)dec(XOR(t,A)|R(i))
+ * A=MSB(B)
+ * R(i)=LSB(B)
+ * 4. Output the results:
+ * * For i=1 to N,
+ * P(i)=R(i)
+ * * If A is 0xA6A6A6A6A6A6A6A6, return success. Otherwise, return
+ * an integrity check failure error.
+ */
+static const unsigned char xmlSecOpenSSLKWAesMagicBlock[XMLSEC_OPENSSL_KW_AES_MAGIC_BLOCK_SIZE] = {
+ 0xA6, 0xA6, 0xA6, 0xA6, 0xA6, 0xA6, 0xA6, 0xA6
+};
+
+static int
+xmlSecOpenSSLKWAesEncode(const unsigned char *key, size_t keySize,
+ const unsigned char *in, size_t inSize,
+ unsigned char *out, size_t outSize) {
+ AES_KEY aesKey;
+ unsigned char block[XMLSEC_OPENSSL_AES_BLOCK_SIZE];
+ unsigned char *p;
+ int N, i, j, t;
+ int ret;
+
+ xmlSecAssert2(key != NULL, -1);
+ xmlSecAssert2(keySize > 0, -1);
+ xmlSecAssert2(in != NULL, -1);
+ xmlSecAssert2(inSize > 0, -1);
+ xmlSecAssert2(out != NULL, -1);
+ xmlSecAssert2(outSize >= inSize + 8, -1);
+
+ ret = AES_set_encrypt_key(key, 8 * keySize, &aesKey);
+ if(ret != 0) {
+ xmlSecError(XMLSEC_ERRORS_HERE,
+ NULL,
+ "AES_set_encrypt_key",
+ XMLSEC_ERRORS_R_CRYPTO_FAILED,
+ XMLSEC_ERRORS_NO_MESSAGE);
+ return(-1);
+ }
+
+ /* prepend magic block */
+ if(in != out) {
+ memcpy(out + XMLSEC_OPENSSL_KW_AES_MAGIC_BLOCK_SIZE, in, inSize);
+ } else {
+ memmove(out + XMLSEC_OPENSSL_KW_AES_MAGIC_BLOCK_SIZE, out, inSize);
+ }
+ memcpy(out, xmlSecOpenSSLKWAesMagicBlock, XMLSEC_OPENSSL_KW_AES_MAGIC_BLOCK_SIZE);
+
+ N = (inSize / 8);
+ if(N == 1) {
+ AES_encrypt(out, out, &aesKey);
+ } else {
+ for(j = 0; j <= 5; ++j) {
+ for(i = 1; i <= N; ++i) {
+ t = i + (j * N);
+ p = out + i * 8;
+
+ memcpy(block, out, 8);
+ memcpy(block + 8, p, 8);
+
+ AES_encrypt(block, block, &aesKey);
+ block[7] ^= t;
+ memcpy(out, block, 8);
+ memcpy(p, block + 8, 8);
+ }
+ }
+ }
+
+ return(inSize + 8);
+}
+
+static int
+xmlSecOpenSSLKWAesDecode(const unsigned char *key, size_t keySize,
+ const unsigned char *in, size_t inSize,
+ unsigned char *out, size_t outSize) {
+ AES_KEY aesKey;
+ unsigned char block[XMLSEC_OPENSSL_AES_BLOCK_SIZE];
+ unsigned char *p;
+ int N, i, j, t;
+ int ret;
+
+ xmlSecAssert2(key != NULL, -1);
+ xmlSecAssert2(keySize > 0, -1);
+ xmlSecAssert2(in != NULL, -1);
+ xmlSecAssert2(inSize > 0, -1);
+ xmlSecAssert2(out != NULL, -1);
+ xmlSecAssert2(outSize >= inSize, -1);
+
+ ret = AES_set_decrypt_key(key, 8 * keySize, &aesKey);
+ if(ret != 0) {
+ xmlSecError(XMLSEC_ERRORS_HERE,
+ NULL,
+ "AES_set_decrypt_key",
+ XMLSEC_ERRORS_R_CRYPTO_FAILED,
+ XMLSEC_ERRORS_NO_MESSAGE);
+ return(-1);
+ }
+
+ /* copy input */
+ if(in != out) {
+ memcpy(out, in, inSize);
+ }
+
+ N = (inSize / 8) - 1;
+ if(N == 1) {
+ AES_decrypt(out, out, &aesKey);
+ } else {
+ for(j = 5; j >= 0; --j) {
+ for(i = N; i > 0; --i) {
+ t = i + (j * N);
+ p = out + i * 8;
+
+ memcpy(block, out, 8);
+ memcpy(block + 8, p, 8);
+ block[7] ^= t;
+
+ AES_decrypt(block, block, &aesKey);
+ memcpy(out, block, 8);
+ memcpy(p, block + 8, 8);
+ }
+ }
+ }
+ /* do not left data in memory */
+ memset(block, 0, sizeof(block));
+
+ if(memcmp(xmlSecOpenSSLKWAesMagicBlock, out, XMLSEC_OPENSSL_KW_AES_MAGIC_BLOCK_SIZE) != 0) {
+ xmlSecError(XMLSEC_ERRORS_HERE,
+ NULL,
+ "xmlSecOpenSSLKWAesMagicBlock",
+ XMLSEC_ERRORS_R_INVALID_DATA,
+ XMLSEC_ERRORS_NO_MESSAGE);
+ return(-1);
+ }
+
+ memmove(out, out + XMLSEC_OPENSSL_KW_AES_MAGIC_BLOCK_SIZE, inSize - XMLSEC_OPENSSL_KW_AES_MAGIC_BLOCK_SIZE);
+ return(inSize - XMLSEC_OPENSSL_KW_AES_MAGIC_BLOCK_SIZE);
+}
+
+#endif /* XMLSEC_OPENSSL_096 */
+#endif /* XMLSEC_NO_AES */
diff --git a/src/openssl/kwdes.c b/src/openssl/kwdes.c
new file mode 100644
index 00000000..0d45fcc5
--- /dev/null
+++ b/src/openssl/kwdes.c
@@ -0,0 +1,616 @@
+/**
+ *
+ * XMLSec library
+ *
+ * DES Algorithm support
+ *
+ * See Copyright for the status of this software.
+ *
+ * Author: Aleksey Sanin <aleksey@aleksey.com>
+ */
+#ifndef XMLSEC_NO_DES
+#include "globals.h"
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+#include <openssl/des.h>
+#include <openssl/rand.h>
+
+#include <xmlsec/xmlsec.h>
+#include <xmlsec/xmltree.h>
+#include <xmlsec/keys.h>
+#include <xmlsec/keyinfo.h>
+#include <xmlsec/transforms.h>
+#include <xmlsec/transformsInternal.h>
+#include <xmlsec/errors.h>
+
+#include <xmlsec/openssl/crypto.h>
+
+#define XMLSEC_OPENSSL_DES3_KEY_LENGTH 24
+#define XMLSEC_OPENSSL_DES3_IV_LENGTH 8
+#define XMLSEC_OPENSSL_DES3_BLOCK_LENGTH 8
+
+/*********************************************************************
+ *
+ * Triple DES Key Wrap transform
+ *
+ * key (xmlSecBuffer) is located after xmlSecTransform structure
+ *
+ ********************************************************************/
+#define xmlSecOpenSSLKWDes3GetKey(transform) \
+ ((xmlSecBufferPtr)(((unsigned char*)(transform)) + sizeof(xmlSecTransform)))
+#define xmlSecOpenSSLKWDes3Size \
+ (sizeof(xmlSecTransform) + sizeof(xmlSecBuffer))
+
+static int xmlSecOpenSSLKWDes3Initialize (xmlSecTransformPtr transform);
+static void xmlSecOpenSSLKWDes3Finalize (xmlSecTransformPtr transform);
+static int xmlSecOpenSSLKWDes3SetKeyReq (xmlSecTransformPtr transform,
+ xmlSecKeyInfoCtxPtr keyInfoCtx);
+static int xmlSecOpenSSLKWDes3SetKey (xmlSecTransformPtr transform,
+ xmlSecKeyPtr key);
+static int xmlSecOpenSSLKWDes3Execute (xmlSecTransformPtr transform,
+ int last,
+ xmlSecTransformCtxPtr transformCtx);
+static int xmlSecOpenSSLKWDes3Encode (const unsigned char *key,
+ size_t keySize,
+ const unsigned char *in,
+ size_t inSize,
+ unsigned char *out,
+ size_t outSize);
+static int xmlSecOpenSSLKWDes3Decode (const unsigned char *key,
+ size_t keySize,
+ const unsigned char *in,
+ size_t inSize,
+ unsigned char *out,
+ size_t outSize);
+static int xmlSecOpenSSLKWDes3Encrypt (const unsigned char *key,
+ size_t keySize,
+ const unsigned char *iv,
+ size_t ivSize,
+ const unsigned char *in,
+ size_t inSize,
+ unsigned char *out,
+ size_t outSize,
+ int enc);
+static int xmlSecOpenSSLKWDes3BufferReverse (unsigned char *buf,
+ size_t size);
+
+static xmlSecTransformKlass xmlSecOpenSSLKWDes3Klass = {
+ /* klass/object sizes */
+ sizeof(xmlSecTransformKlass), /* size_t klassSize */
+ xmlSecOpenSSLKWDes3Size, /* size_t objSize */
+
+ xmlSecNameKWDes3,
+ xmlSecTransformTypeBinary, /* xmlSecTransformType type; */
+ xmlSecTransformUsageEncryptionMethod, /* xmlSecAlgorithmUsage usage; */
+ xmlSecHrefKWDes3, /* const xmlChar href; */
+
+ xmlSecOpenSSLKWDes3Initialize, /* xmlSecTransformInitializeMethod initialize; */
+ xmlSecOpenSSLKWDes3Finalize, /* xmlSecTransformFinalizeMethod finalize; */
+ NULL, /* xmlSecTransformReadMethod read; */
+ xmlSecOpenSSLKWDes3SetKeyReq, /* xmlSecTransformSetKeyMethod setKeyReq; */
+ xmlSecOpenSSLKWDes3SetKey, /* xmlSecTransformSetKeyMethod setKey; */
+ NULL, /* xmlSecTransformValidateMethod validate; */
+ xmlSecTransformDefaultPushBin, /* xmlSecTransformPushBinMethod pushBin; */
+ xmlSecTransformDefaultPopBin, /* xmlSecTransformPopBinMethod popBin; */
+ NULL, /* xmlSecTransformPushXmlMethod pushXml; */
+ NULL, /* xmlSecTransformPopXmlMethod popXml; */
+ xmlSecOpenSSLKWDes3Execute, /* xmlSecTransformExecuteMethod execute; */
+
+ NULL, /* xmlSecTransformExecuteXmlMethod executeXml; */
+ NULL, /* xmlSecTransformExecuteC14NMethod executeC14N; */
+};
+
+
+xmlSecTransformId
+xmlSecOpenSSLTransformKWDes3GetKlass(void) {
+ return(&xmlSecOpenSSLKWDes3Klass);
+}
+
+static int
+xmlSecOpenSSLKWDes3Initialize(xmlSecTransformPtr transform) {
+ int ret;
+
+ xmlSecAssert2(xmlSecTransformCheckId(transform, xmlSecOpenSSLTransformKWDes3Id), -1);
+ xmlSecAssert2(xmlSecTransformCheckSize(transform, xmlSecOpenSSLKWDes3Size), -1);
+
+ ret = xmlSecBufferInitialize(xmlSecOpenSSLKWDes3GetKey(transform), 0);
+ if(ret < 0) {
+ xmlSecError(XMLSEC_ERRORS_HERE,
+ xmlSecErrorsSafeString(xmlSecTransformGetName(transform)),
+ "xmlSecBufferInitialize",
+ XMLSEC_ERRORS_R_XMLSEC_FAILED,
+ XMLSEC_ERRORS_NO_MESSAGE);
+ return(-1);
+ }
+
+ return(0);
+}
+
+static void
+xmlSecOpenSSLKWDes3Finalize(xmlSecTransformPtr transform) {
+ xmlSecAssert(xmlSecTransformCheckId(transform, xmlSecOpenSSLTransformKWDes3Id));
+ xmlSecAssert(xmlSecTransformCheckSize(transform, xmlSecOpenSSLKWDes3Size));
+
+ if(xmlSecOpenSSLKWDes3GetKey(transform) != NULL) {
+ xmlSecBufferFinalize(xmlSecOpenSSLKWDes3GetKey(transform));
+ }
+}
+
+static int
+xmlSecOpenSSLKWDes3SetKeyReq(xmlSecTransformPtr transform, xmlSecKeyInfoCtxPtr keyInfoCtx) {
+ xmlSecAssert2(xmlSecTransformCheckId(transform, xmlSecOpenSSLTransformKWDes3Id), -1);
+ xmlSecAssert2(xmlSecTransformCheckSize(transform, xmlSecOpenSSLKWDes3Size), -1);
+ xmlSecAssert2(keyInfoCtx != NULL, -1);
+
+ keyInfoCtx->keyId = xmlSecOpenSSLKeyDataDesId;
+ keyInfoCtx->keyType = xmlSecKeyDataTypeSymmetric;
+ if(transform->encode) {
+ keyInfoCtx->keyUsage = xmlSecKeyUsageEncrypt;
+ } else {
+ keyInfoCtx->keyUsage = xmlSecKeyUsageDecrypt;
+ }
+
+ return(0);
+}
+
+static int
+xmlSecOpenSSLKWDes3SetKey(xmlSecTransformPtr transform, xmlSecKeyPtr key) {
+ xmlSecBufferPtr buffer;
+ size_t keySize;
+ int ret;
+
+ xmlSecAssert2(xmlSecTransformCheckId(transform, xmlSecOpenSSLTransformKWDes3Id), -1);
+ xmlSecAssert2(xmlSecTransformCheckSize(transform, xmlSecOpenSSLKWDes3Size), -1);
+ xmlSecAssert2(xmlSecOpenSSLKWDes3GetKey(transform) != NULL, -1);
+ xmlSecAssert2(key != NULL, -1);
+ xmlSecAssert2(xmlSecKeyDataCheckId(xmlSecKeyGetValue(key), xmlSecOpenSSLKeyDataDesId), -1);
+
+ buffer = xmlSecKeyDataBinaryValueGetBuffer(xmlSecKeyGetValue(key));
+ xmlSecAssert2(buffer != NULL, -1);
+
+ keySize = xmlSecBufferGetSize(buffer);
+ if(keySize < XMLSEC_OPENSSL_DES3_KEY_LENGTH) {
+ xmlSecError(XMLSEC_ERRORS_HERE,
+ xmlSecErrorsSafeString(xmlSecTransformGetName(transform)),
+ NULL,
+ XMLSEC_ERRORS_R_INVALID_KEY_SIZE,
+ "key length %d is not enough (%d expected)",
+ keySize, XMLSEC_OPENSSL_DES3_KEY_LENGTH);
+ return(-1);
+ }
+
+ ret = xmlSecBufferSetData(xmlSecOpenSSLKWDes3GetKey(transform),
+ xmlSecBufferGetData(buffer),
+ XMLSEC_OPENSSL_DES3_KEY_LENGTH);
+ if(ret < 0) {
+ xmlSecError(XMLSEC_ERRORS_HERE,
+ xmlSecErrorsSafeString(xmlSecTransformGetName(transform)),
+ "xmlSecBufferSetData",
+ XMLSEC_ERRORS_R_XMLSEC_FAILED,
+ "%d", XMLSEC_OPENSSL_DES3_KEY_LENGTH);
+ return(-1);
+ }
+
+ return(0);
+}
+
+static int
+xmlSecOpenSSLKWDes3Execute(xmlSecTransformPtr transform, int last, xmlSecTransformCtxPtr transformCtx) {
+ xmlSecBufferPtr in, out, key;
+ size_t inSize, outSize, keySize;
+ int ret;
+
+ xmlSecAssert2(xmlSecTransformCheckId(transform, xmlSecOpenSSLTransformKWDes3Id), -1);
+ xmlSecAssert2(xmlSecTransformCheckSize(transform, xmlSecOpenSSLKWDes3Size), -1);
+ xmlSecAssert2(transformCtx != NULL, -1);
+
+ key = xmlSecOpenSSLKWDes3GetKey(transform);
+ xmlSecAssert2(key != NULL, -1);
+
+ keySize = xmlSecBufferGetSize(key);
+ xmlSecAssert2(keySize == XMLSEC_OPENSSL_DES3_KEY_LENGTH, -1);
+
+ in = &(transform->inBuf);
+ out = &(transform->outBuf);
+ inSize = xmlSecBufferGetSize(in);
+ outSize = xmlSecBufferGetSize(out);
+ xmlSecAssert2(outSize == 0, -1);
+
+ if(transform->status == xmlSecTransformStatusNone) {
+ transform->status = xmlSecTransformStatusWorking;
+ } else if((transform->status == xmlSecTransformStatusWorking) && (last == 0)) {
+ /* just do nothing */
+ } else if((transform->status == xmlSecTransformStatusWorking) && (last != 0)) {
+ if((inSize % XMLSEC_OPENSSL_DES3_BLOCK_LENGTH) != 0) {
+ xmlSecError(XMLSEC_ERRORS_HERE,
+ xmlSecErrorsSafeString(xmlSecTransformGetName(transform)),
+ NULL,
+ XMLSEC_ERRORS_R_INVALID_SIZE,
+ "%d bytes - not %d bytes aligned",
+ inSize, XMLSEC_OPENSSL_DES3_BLOCK_LENGTH);
+ return(-1);
+ }
+
+ if(transform->encode) {
+ /* the encoded key might be 16 bytes longer plus one block just in case */
+ outSize = inSize + XMLSEC_OPENSSL_DES3_IV_LENGTH +
+ XMLSEC_OPENSSL_DES3_BLOCK_LENGTH +
+ XMLSEC_OPENSSL_DES3_BLOCK_LENGTH;
+ } else {
+ outSize = inSize + XMLSEC_OPENSSL_DES3_BLOCK_LENGTH;
+ }
+
+ ret = xmlSecBufferSetMaxSize(out, outSize);
+ if(ret < 0) {
+ xmlSecError(XMLSEC_ERRORS_HERE,
+ xmlSecErrorsSafeString(xmlSecTransformGetName(transform)),
+ "xmlSecBufferSetMaxSize",
+ XMLSEC_ERRORS_R_XMLSEC_FAILED,
+ "%d", outSize);
+ return(-1);
+ }
+
+ if(transform->encode) {
+ ret = xmlSecOpenSSLKWDes3Encode(xmlSecBufferGetData(key), keySize,
+ xmlSecBufferGetData(in), inSize,
+ xmlSecBufferGetData(out), outSize);
+ if(ret < 0) {
+ xmlSecError(XMLSEC_ERRORS_HERE,
+ xmlSecErrorsSafeString(xmlSecTransformGetName(transform)),
+ "xmlSecOpenSSLKWDes3Encode",
+ XMLSEC_ERRORS_R_XMLSEC_FAILED,
+ "key=%d,in=%d,out=%d",
+ keySize, inSize, outSize);
+ return(-1);
+ }
+ outSize = ret;
+ } else {
+ ret = xmlSecOpenSSLKWDes3Decode(xmlSecBufferGetData(key), keySize,
+ xmlSecBufferGetData(in), inSize,
+ xmlSecBufferGetData(out), outSize);
+ if(ret < 0) {
+ xmlSecError(XMLSEC_ERRORS_HERE,
+ xmlSecErrorsSafeString(xmlSecTransformGetName(transform)),
+ "xmlSecOpenSSLKWDes3Decode",
+ XMLSEC_ERRORS_R_XMLSEC_FAILED,
+ "key=%d,in=%d,out=%d",
+ keySize, inSize, outSize);
+ return(-1);
+ }
+ outSize = ret;
+ }
+
+ ret = xmlSecBufferSetSize(out, outSize);
+ if(ret < 0) {
+ xmlSecError(XMLSEC_ERRORS_HERE,
+ xmlSecErrorsSafeString(xmlSecTransformGetName(transform)),
+ "xmlSecBufferSetSize",
+ XMLSEC_ERRORS_R_XMLSEC_FAILED,
+ "%d", outSize);
+ return(-1);
+ }
+
+ ret = xmlSecBufferRemoveHead(in, inSize);
+ if(ret < 0) {
+ xmlSecError(XMLSEC_ERRORS_HERE,
+ xmlSecErrorsSafeString(xmlSecTransformGetName(transform)),
+ "xmlSecBufferRemoveHead",
+ XMLSEC_ERRORS_R_XMLSEC_FAILED,
+ "%d", inSize);
+ 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(&(transform->inBuf)) == 0, -1);
+ } else {
+ xmlSecError(XMLSEC_ERRORS_HERE,
+ xmlSecErrorsSafeString(xmlSecTransformGetName(transform)),
+ NULL,
+ XMLSEC_ERRORS_R_INVALID_STATUS,
+ "%d", transform->status);
+ return(-1);
+ }
+ return(0);
+}
+
+static unsigned char xmlSecOpenSSLKWDes3Iv[XMLSEC_OPENSSL_DES3_IV_LENGTH] = {
+ 0x4a, 0xdd, 0xa2, 0x2c, 0x79, 0xe8, 0x21, 0x05
+};
+/**
+ * CMS Triple DES Key Wrap
+ *
+ * http://www.w3.org/TR/xmlenc-core/#sec-Alg-SymmetricKeyWrap
+ *
+ * The following algorithm wraps (encrypts) a key (the wrapped key, WK)
+ * under a TRIPLEDES key-encryption-key (KEK) as specified in [CMS-Algorithms]:
+ *
+ * 1. Represent the key being wrapped as an octet sequence. If it is a
+ * TRIPLEDES key, this is 24 octets (192 bits) with odd parity bit as
+ * the bottom bit of each octet.
+ * 2. Compute the CMS key checksum (section 5.6.1) call this CKS.
+ * 3. Let WKCKS = WK || CKS, where || is concatenation.
+ * 4. Generate 8 random octets [RANDOM] and call this IV.
+ * 5. Encrypt WKCKS in CBC mode using KEK as the key and IV as the
+ * initialization vector. Call the results TEMP1.
+ * 6. Left TEMP2 = IV || TEMP1.
+ * 7. Reverse the order of the octets in TEMP2 and call the result TEMP3.
+ * 8. Encrypt TEMP3 in CBC mode using the KEK and an initialization vector
+ * of 0x4adda22c79e82105. The resulting cipher text is the desired result.
+ * It is 40 octets long if a 168 bit key is being wrapped.
+ *
+ */
+static int
+xmlSecOpenSSLKWDes3Encode(const unsigned char *key, size_t keySize,
+ const unsigned char *in, size_t inSize,
+ unsigned char *out, size_t outSize) {
+ unsigned char sha1[SHA_DIGEST_LENGTH];
+ unsigned char iv[XMLSEC_OPENSSL_DES3_IV_LENGTH];
+ size_t s;
+ int ret;
+
+ xmlSecAssert2(key != NULL, -1);
+ xmlSecAssert2(keySize == XMLSEC_OPENSSL_DES3_KEY_LENGTH, -1);
+ xmlSecAssert2(in != NULL, -1);
+ xmlSecAssert2(inSize > 0, -1);
+ xmlSecAssert2(out != NULL, -1);
+ xmlSecAssert2(outSize >= inSize + 16, -1);
+
+ /* step 2: calculate sha1 and CMS */
+ if(SHA1(in, inSize, sha1) == NULL) {
+ xmlSecError(XMLSEC_ERRORS_HERE,
+ NULL,
+ "SHA1",
+ XMLSEC_ERRORS_R_CRYPTO_FAILED,
+ XMLSEC_ERRORS_NO_MESSAGE);
+ return(-1);
+ }
+
+ /* step 3: construct WKCKS */
+ memcpy(out, in, inSize);
+ memcpy(out + inSize, sha1, XMLSEC_OPENSSL_DES3_BLOCK_LENGTH);
+
+ /* step 4: generate random iv */
+ ret = RAND_bytes(iv, XMLSEC_OPENSSL_DES3_IV_LENGTH);
+ if(ret != 1) {
+ xmlSecError(XMLSEC_ERRORS_HERE,
+ NULL,
+ "RAND_bytes",
+ XMLSEC_ERRORS_R_CRYPTO_FAILED,
+ "%d", ret);
+ return(-1);
+ }
+
+ /* step 5: first encryption, result is TEMP1 */
+ ret = xmlSecOpenSSLKWDes3Encrypt(key, keySize,
+ iv, XMLSEC_OPENSSL_DES3_IV_LENGTH,
+ out, inSize + XMLSEC_OPENSSL_DES3_BLOCK_LENGTH,
+ out, outSize, 1);
+ if(ret < 0) {
+ xmlSecError(XMLSEC_ERRORS_HERE,
+ NULL,
+ "xmlSecOpenSSLKWDes3Encrypt",
+ XMLSEC_ERRORS_R_XMLSEC_FAILED,
+ XMLSEC_ERRORS_NO_MESSAGE);
+ return(-1);
+ }
+
+ /* step 6: construct TEMP2=IV || TEMP1 */
+ memmove(out + XMLSEC_OPENSSL_DES3_IV_LENGTH, out,
+ inSize + XMLSEC_OPENSSL_DES3_IV_LENGTH);
+ memcpy(out, iv, XMLSEC_OPENSSL_DES3_IV_LENGTH);
+ s = ret + XMLSEC_OPENSSL_DES3_IV_LENGTH;
+
+ /* step 7: reverse octets order, result is TEMP3 */
+ ret = xmlSecOpenSSLKWDes3BufferReverse(out, s);
+ if(ret < 0) {
+ xmlSecError(XMLSEC_ERRORS_HERE,
+ NULL,
+ "xmlSecOpenSSLKWDes3BufferReverse",
+ XMLSEC_ERRORS_R_XMLSEC_FAILED,
+ XMLSEC_ERRORS_NO_MESSAGE);
+ return(-1);
+ }
+
+ /* step 8: second encryption with static IV */
+ ret = xmlSecOpenSSLKWDes3Encrypt(key, keySize,
+ xmlSecOpenSSLKWDes3Iv, XMLSEC_OPENSSL_DES3_IV_LENGTH,
+ out, s, out, outSize, 1);
+ if(ret < 0) {
+ xmlSecError(XMLSEC_ERRORS_HERE,
+ NULL,
+ "xmlSecOpenSSLKWDes3Encrypt",
+ XMLSEC_ERRORS_R_XMLSEC_FAILED,
+ XMLSEC_ERRORS_NO_MESSAGE);
+ return(-1);
+ }
+ s = ret;
+ return(s);
+}
+
+/**
+ * CMS Triple DES Key Wrap
+ *
+ * http://www.w3.org/TR/xmlenc-core/#sec-Alg-SymmetricKeyWrap
+ *
+ * The following algorithm unwraps (decrypts) a key as specified in
+ * [CMS-Algorithms]:
+ *
+ * 1. Check if the length of the cipher text is reasonable given the key type.
+ * It must be 40 bytes for a 168 bit key and either 32, 40, or 48 bytes for
+ * a 128, 192, or 256 bit key. If the length is not supported or inconsistent
+ * with the algorithm for which the key is intended, return error.
+ * 2. Decrypt the cipher text with TRIPLEDES in CBC mode using the KEK and
+ * an initialization vector (IV) of 0x4adda22c79e82105. Call the output TEMP3.
+ * 3. Reverse the order of the octets in TEMP3 and call the result TEMP2.
+ * 4. Decompose TEMP2 into IV, the first 8 octets, and TEMP1, the remaining
+ * octets.
+ * 5. Decrypt TEMP1 using TRIPLEDES in CBC mode using the KEK and the IV found
+ * in the previous step. Call the result WKCKS.
+ * 6. Decompose WKCKS. CKS is the last 8 octets and WK, the wrapped key, are
+ * those octets before the CKS.
+ * 7. Calculate a CMS key checksum (section 5.6.1) over the WK and compare
+ * with the CKS extracted in the above step. If they are not equal, return
+ * error.
+ * 8. WK is the wrapped key, now extracted for use in data decryption.
+ */
+static int
+xmlSecOpenSSLKWDes3Decode(const unsigned char *key, size_t keySize,
+ const unsigned char *in, size_t inSize,
+ unsigned char *out, size_t outSize) {
+ unsigned char sha1[SHA_DIGEST_LENGTH];
+ size_t s;
+ int ret;
+
+ xmlSecAssert2(key != NULL, -1);
+ xmlSecAssert2(keySize == XMLSEC_OPENSSL_DES3_KEY_LENGTH, -1);
+ xmlSecAssert2(in != NULL, -1);
+ xmlSecAssert2(inSize > 0, -1);
+ xmlSecAssert2(out != NULL, -1);
+ xmlSecAssert2(outSize >= inSize, -1);
+
+ /* step 2: first decryption with static IV, result is TEMP3 */
+ ret = xmlSecOpenSSLKWDes3Encrypt(key, keySize,
+ xmlSecOpenSSLKWDes3Iv, XMLSEC_OPENSSL_DES3_IV_LENGTH,
+ in, inSize, out, outSize, 0);
+ if((ret < 0) || (ret < XMLSEC_OPENSSL_DES3_IV_LENGTH)) {
+ xmlSecError(XMLSEC_ERRORS_HERE,
+ NULL,
+ "xmlSecOpenSSLKWDes3Encrypt",
+ XMLSEC_ERRORS_R_XMLSEC_FAILED,
+ XMLSEC_ERRORS_NO_MESSAGE);
+ return(-1);
+ }
+ s = ret;
+
+ /* step 3: reverse octets order in TEMP3, result is TEMP2 */
+ ret = xmlSecOpenSSLKWDes3BufferReverse(out, s);
+ if(ret < 0) {
+ xmlSecError(XMLSEC_ERRORS_HERE,
+ NULL,
+ "xmlSecOpenSSLKWDes3BufferReverse",
+ XMLSEC_ERRORS_R_XMLSEC_FAILED,
+ XMLSEC_ERRORS_NO_MESSAGE);
+ return(-1);
+ }
+
+ /* steps 4 and 5: get IV and decrypt second time, result is WKCKS */
+ ret = xmlSecOpenSSLKWDes3Encrypt(key, keySize,
+ out, XMLSEC_OPENSSL_DES3_IV_LENGTH,
+ out + XMLSEC_OPENSSL_DES3_IV_LENGTH,
+ s - XMLSEC_OPENSSL_DES3_IV_LENGTH,
+ out, outSize, 0);
+ if((ret < 0) || (ret < XMLSEC_OPENSSL_DES3_BLOCK_LENGTH)) {
+ xmlSecError(XMLSEC_ERRORS_HERE,
+ NULL,
+ "xmlSecOpenSSLKWDes3Encrypt",
+ XMLSEC_ERRORS_R_XMLSEC_FAILED,
+ XMLSEC_ERRORS_NO_MESSAGE);
+ return(-1);
+ }
+ s = ret - XMLSEC_OPENSSL_DES3_BLOCK_LENGTH;
+
+ /* steps 6 and 7: calculate SHA1 and validate it */
+ if(SHA1(out, s, sha1) == NULL) {
+ xmlSecError(XMLSEC_ERRORS_HERE,
+ NULL,
+ "SHA1",
+ XMLSEC_ERRORS_R_CRYPTO_FAILED,
+ XMLSEC_ERRORS_NO_MESSAGE);
+ return(-1);
+ }
+
+ if(memcmp(sha1, out + s, XMLSEC_OPENSSL_DES3_BLOCK_LENGTH) != 0) {
+ xmlSecError(XMLSEC_ERRORS_HERE,
+ NULL,
+ NULL,
+ XMLSEC_ERRORS_R_INVALID_DATA,
+ "SHA1 does not match");
+ return(-1);
+ }
+
+ return(s);
+}
+
+static int
+xmlSecOpenSSLKWDes3Encrypt(const unsigned char *key, size_t keySize,
+ const unsigned char *iv, size_t ivSize,
+ const unsigned char *in, size_t inSize,
+ unsigned char *out, size_t outSize, int enc) {
+ EVP_CIPHER_CTX cipherCtx;
+ int updateLen;
+ int finalLen;
+ int ret;
+
+ xmlSecAssert2(key != NULL, -1);
+ xmlSecAssert2(keySize == (size_t)EVP_CIPHER_key_length(EVP_des_ede3_cbc()), -1);
+ xmlSecAssert2(iv != NULL, -1);
+ xmlSecAssert2(ivSize == (size_t)EVP_CIPHER_iv_length(EVP_des_ede3_cbc()), -1);
+ xmlSecAssert2(in != NULL, -1);
+ xmlSecAssert2(inSize > 0, -1);
+ xmlSecAssert2(out != NULL, -1);
+ xmlSecAssert2(outSize >= inSize, -1);
+
+ EVP_CIPHER_CTX_init(&cipherCtx);
+ ret = EVP_CipherInit(&cipherCtx, EVP_des_ede3_cbc(), key, iv, enc);
+ if(ret != 1) {
+ xmlSecError(XMLSEC_ERRORS_HERE,
+ NULL,
+ "EVP_CipherInit",
+ XMLSEC_ERRORS_R_CRYPTO_FAILED,
+ XMLSEC_ERRORS_NO_MESSAGE);
+ return(-1);
+ }
+
+#ifndef XMLSEC_OPENSSL_096
+ EVP_CIPHER_CTX_set_padding(&cipherCtx, 0);
+#endif /* XMLSEC_OPENSSL_096 */
+
+ ret = EVP_CipherUpdate(&cipherCtx, out, &updateLen, in, inSize);
+ if(ret != 1) {
+ xmlSecError(XMLSEC_ERRORS_HERE,
+ NULL,
+ "EVP_CipherUpdate",
+ XMLSEC_ERRORS_R_CRYPTO_FAILED,
+ XMLSEC_ERRORS_NO_MESSAGE);
+ return(-1);
+ }
+
+ ret = EVP_CipherFinal(&cipherCtx, out + updateLen, &finalLen);
+ if(ret != 1) {
+ xmlSecError(XMLSEC_ERRORS_HERE,
+ NULL,
+ "EVP_CipherFinal",
+ XMLSEC_ERRORS_R_CRYPTO_FAILED,
+ XMLSEC_ERRORS_NO_MESSAGE);
+ return(-1);
+ }
+ EVP_CIPHER_CTX_cleanup(&cipherCtx);
+
+ return(updateLen + finalLen);
+}
+
+static int
+xmlSecOpenSSLKWDes3BufferReverse(unsigned char *buf, size_t size) {
+ size_t s;
+ size_t i;
+ unsigned char c;
+
+ xmlSecAssert2(buf != NULL, -1);
+
+ s = size / 2;
+ --size;
+ for(i = 0; i < s; ++i) {
+ c = buf[i];
+ buf[i] = buf[size - i];
+ buf[size - i] = c;
+ }
+ return(0);
+}
+
+#endif /* XMLSEC_NO_DES */
+