CommonSymmetricKeywrap.c [plain text]
#include <CommonCrypto/CommonSymmetricKeywrap.h>
#include <CommonCrypto/CommonCryptor.h>
#include "CommonCryptorPriv.h"
#include <AssertMacros.h>
#include "ccdebug.h"
static const uint8_t rfc3394_iv_data[] = { 0xA6, 0xA6, 0xA6, 0xA6, 0xA6, 0xA6,
0xA6, 0xA6 };
const uint8_t * const CCrfc3394_iv = rfc3394_iv_data;
const size_t CCrfc3394_ivLen = sizeof(rfc3394_iv_data);
static uint64_t
pack64(const uint8_t *iv, size_t __unused ivLen)
{
uint64_t retval;
int i;
for(i=0, retval=0; i<8; i++)
retval = (retval<<8) + iv[i];
return retval;
}
#if defined (_WIN32) //works for llvm
#define swap64(k) __builtin_bswap64(k);
#else
#define swap64(k) _OSSwapInt64(k)
#endif
int
CCSymmetricKeyWrap( CCWrappingAlgorithm __unused algorithm,
const uint8_t *iv, const size_t ivLen,
const uint8_t *kek, size_t kekLen,
const uint8_t *rawKey, size_t rawKeyLen,
uint8_t *wrappedKey, size_t *wrappedKeyLen)
{
size_t n = rawKeyLen / 8;
uint64_t (*R)[2];
int i, j, err = 0;
const struct ccmode_ecb *ccmode = getCipherMode(kCCAlgorithmAES128, kCCModeECB, kCCEncrypt).ecb;
CC_DEBUG_LOG("Entering\n");
ccecb_ctx_decl(ccmode->size, ctx);
R = calloc(n, sizeof(uint64_t[2]));
require_action(kekLen == 16 || kekLen == 24 || kekLen == 32, out, err = kCCParamError);
require_action(wrappedKeyLen && (*wrappedKeyLen >= rawKeyLen + 64/8), out, err = kCCParamError);
for (i = 0; i < (int) n; i++)
memcpy(&R[i][1], rawKey + (64/8) * i, (64/8));
uint64_t kek_iv = pack64(iv, ivLen);
R[0][0] = kek_iv;
ccmode->init(ccmode, ctx, kekLen, kek);
for (j = 0; j < 6; j++) {
for (i = 0; i < (int) n; i++)
{
ccmode->ecb(ctx, 1, (uint8_t*)&R[i][0], (uint8_t*)&R[i][0]);
R[(i + 1) % n][0] = R[i][0] ^ swap64((n*j)+i+1);
}
}
memcpy(wrappedKey, &R[0][0], 8);
for (i = 0; i < (int) n; i++)
memcpy(wrappedKey + 8 + i * 8, &R[i][1], 8);
for(i=0; i<(int) n; i++)
for(j=0; j<2; j++)
R[i][j] = 0;
out:
if (R) free(R);
return err;
}
int
CCSymmetricKeyUnwrap( CCWrappingAlgorithm __unused algorithm,
const uint8_t *iv, const size_t ivLen,
const uint8_t *kek, size_t kekLen,
const uint8_t *wrappedKey, size_t wrappedKeyLen,
uint8_t *rawKey, size_t * __unused rawKeyLen)
{
size_t n = wrappedKeyLen/8 - 1;
uint64_t (*R)[2] = NULL;
int j, err = 0;
const struct ccmode_ecb *ccmode = getCipherMode(kCCAlgorithmAES128, kCCModeECB, kCCDecrypt).ecb;
CC_DEBUG_LOG("Entering\n");
ccecb_ctx_decl(ccmode->size, ctx);
require_action(n>=1 && n<SIZE_MAX/sizeof(uint64_t[2]), out, err = kCCParamError);
R = calloc(n, sizeof(uint64_t[2]));
require_action(R!=NULL, out, err = kCCParamError);
require_action(kekLen == 16 || kekLen == 24 || kekLen == 32, out, err = kCCParamError);
memcpy(&R[0][0], wrappedKey, 64/8);
for (size_t i = 0; i < n; i++)
memcpy(&R[i][1], wrappedKey + (64/8) * (i+1), 64/8);
ccmode->init(ccmode, ctx, kekLen, kek);
for (j = 5; j >= 0; j--) {
for (size_t i = n; i > 0; i--) {
R[i-1][0] = R[(i) % n][0] ^ swap64((n*j)+i);
ccmode->ecb(ctx, 1, (uint8_t*)&R[i-1][0], (uint8_t*)&R[i-1][0]);
}
}
uint64_t kek_iv = pack64(iv, ivLen);
require_action(R[0][0] == kek_iv, out, err = kCCDecodeError);
for (size_t i = 0; i < n; i++)
memcpy(rawKey + i * 8, &R[i][1], 8);
cc_clear(n*sizeof(uint64_t[2]), R);
out:
free(R);
return err;
}
size_t
CCSymmetricWrappedSize( CCWrappingAlgorithm __unused algorithm, size_t rawKeyLen)
{
CC_DEBUG_LOG("Entering\n");
return (rawKeyLen + 8);
}
size_t
CCSymmetricUnwrappedSize( CCWrappingAlgorithm __unused algorithm, size_t wrappedKeyLen)
{
CC_DEBUG_LOG("Entering\n");
return (wrappedKeyLen - 8);
}