diff options
author | Aleksey Sanin <aleksey@src.gnome.org> | 2003-02-28 05:59:55 +0000 |
---|---|---|
committer | Aleksey Sanin <aleksey@src.gnome.org> | 2003-02-28 05:59:55 +0000 |
commit | 1c20c86d98f034af13cf90f44336b0469abcfb7d (patch) | |
tree | 12eb0644e6018b85931d62bb0e626602f97fd054 | |
parent | 160d7b3f59bcf9286dbe7c31b3024e5a55ddac05 (diff) | |
download | xmlsec1-1c20c86d98f034af13cf90f44336b0469abcfb7d.tar.gz xmlsec1-1c20c86d98f034af13cf90f44336b0469abcfb7d.tar.bz2 xmlsec1-1c20c86d98f034af13cf90f44336b0469abcfb7d.zip |
*** empty log message ***
-rw-r--r-- | src/openssl/kwaes.c | 593 | ||||
-rw-r--r-- | src/openssl/kwdes.c | 616 |
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 */ + |