All Downloads are FREE. Search and download functionalities are using the official Maven repository.

native.intel.ccm.ccm.c Maven / Gradle / Ivy

Go to download

The Long Term Stable (LTS) Bouncy Castle Crypto package is a Java implementation of cryptographic algorithms. This jar contains the JCA/JCE provider and low-level API for the BC LTS version 2.73.7 for Java 8 and later.

There is a newer version: 2.73.7
Show newest version
//
//


#include 
#include "ccm.h"
#include 
#include 
#include "../common.h"


ccm_err *make_ccm_error(const char *msg, int type) {
    ccm_err *err = calloc(1, sizeof(ccm_err));
    assert(err != NULL);
    err->msg = msg;
    err->type = type;
    return err;
}

void ccm_err_free(ccm_err *err) {
    if (err != NULL) {
        free(err);
    }
}


ccm_ctx *ccm_create_ctx() {
    ccm_ctx *ctx = calloc(1, sizeof(ccm_ctx));
    ctx->encryption = true; // to make get output size return the longest array if init not called first.
    assert(ctx != NULL);
    return ctx;
}

void ccm_free(ccm_ctx *ctx) {
    if (ctx == NULL) {
        return;
    }
    //     Free if we have initial AD.
    if (ctx->initAD != NULL) {
        memzero(ctx->initAD, ctx->initADLen);
        free(ctx->initAD);
    }

//     Zero context
    memzero(ctx, sizeof(ccm_ctx));
    free(ctx);
}

void ccm_reset(ccm_ctx *ctx, bool keepMac) {

    memzero(ctx->buf, BLOCK_SIZE);
    ctx->buf_ptr = 0;
    ctx->chainblock = ctx->initialChainblock;
    ctx->partialBlock = _mm_setzero_si128();
    ctx->buf_pos = 0;
    ctx->ctr = ctx->initialCTR;
    ctx->ctrAtEnd = false;
    if (!keepMac) {
        // Zero out mac block
        memzero(ctx->macBlock, MAC_BLOCK_LEN);
    }
}

/**
 *
 * @param encryption
 * @param key
 * @param keyLen
 * @param nonce
 * @param nonceLen
 * @return NULL if no error, other ptr to struct CALLER NEEDS TO FREE
 */
ccm_err *ccm_init(
        ccm_ctx *ctx,
        bool encryption,
        uint8_t *key,
        size_t keyLen,
        uint8_t *nonce,
        size_t nonceLen,
        uint8_t *initialText,
        size_t initialTextLen,
        uint32_t macBlockLenBytes) {
    //
    // All assertions of correctness need to be done by this call.
    //
    ctx->encryption = encryption;
    ctx->nonceLen = nonceLen;
    memzero(ctx->nonce, BLOCK_SIZE);
    memcpy(ctx->nonce, nonce, nonceLen);
    ctx->macBlockLenInBytes = macBlockLenBytes;
    ctx->q = 15 - nonceLen;

    memzero(ctx->roundKeys, sizeof(__m128i) * 15);
    switch (keyLen) {
        case 16:
            ctx->num_rounds = ROUNDS_128;
            init_128(ctx->roundKeys, key, true);
            break;
        case 24:
            ctx->num_rounds = ROUNDS_192;
            init_192(ctx->roundKeys, key, true);
            break;
        case 32:
            ctx->num_rounds = ROUNDS_256;
            init_256(ctx->roundKeys, key, true);
            break;
        default:
            assert(0);
    }
    ctx->initialChainblock = _mm_setzero_si128();//_mm_loadu_si128((__m128i *) ctx->macBlock);
    ctx->chainblock = ctx->initialChainblock;

    memzero(ctx->buf, BLOCK_SIZE);

    ctx->buf_ptr = 0;
    ctx->macLen = macBlockLenBytes;
    memzero(ctx->macBlock, MAC_BLOCK_LEN);
    ctx->macBlock[0] = (ctx->q - 1) & 0x7;
    memcpy(ctx->macBlock + 1, ctx->nonce, ctx->nonceLen);
    ctx->ctrMask = 0xFFFFFFFFFFFFFFFF;
    ctx->IV_le = _mm_loadu_si128((__m128i *) ctx->macBlock);
    ctx->IV_le = _mm_shuffle_epi8(ctx->IV_le, *SWAP_ENDIAN_128);
    ctx->ctr = (uint64_t) _mm_extract_epi64(ctx->IV_le, 0);
    ctx->initialCTR = ctx->ctr;
    ctx->IV_le = _mm_and_si128(ctx->IV_le, _mm_set_epi64x(-1, 0));
    // We had old initial text drop it here.
    if (ctx->initAD != NULL) {
        memzero(ctx->initAD, ctx->initADLen);
        free(ctx->initAD);
        ctx->initAD = NULL;
        ctx->initADLen = 0;
    }

    if (initialText != NULL) {
        //
        // We keep a copy as it is needed to calculate the mac
        // the same state it was before the first data is processed.
        //
        ctx->initAD = malloc(initialTextLen * sizeof(uint8_t));
        assert(ctx->initAD != NULL);
        ctx->initADLen = initialTextLen;
        memcpy(ctx->initAD, initialText, initialTextLen);
    }
    // Zero out mac block
    memzero(ctx->macBlock, MAC_BLOCK_LEN);
    return NULL;// All good
}


size_t ccm_get_output_size(ccm_ctx *ctx, size_t len) {
    if (ctx->encryption) {
        return len + ctx->macBlockLenInBytes;
    }
    return len < ctx->macBlockLenInBytes ? 0 : len - ctx->macBlockLenInBytes;
}

ccm_err *ccm_process_packet(
        ccm_ctx *ref,
        uint8_t *in,
        size_t to_process,
        uint8_t *out,
        size_t *output_len,
        uint8_t *aad,
        size_t aad_len) {

    if (ref->q < 4) {
        int limitLen = 1 << (ref->q << 3);
        if (to_process >= limitLen) {
            return make_ccm_error("CCM packet too large for choice of q", ILLEGAL_STATE);
        }
    }
    size_t written = 0;

    if (ref->encryption) {
        calculateMac(ref, in, to_process, aad, aad_len);
        ccm_ctr_process_bytes(ref, ref->macBlock, BLOCK_SIZE, ref->macBlock, &written);
        ccm_ctr_process_bytes(ref, in, to_process, out, &written);
        memcpy(out + written, ref->macBlock, ref->macBlockLenInBytes);
        *output_len = to_process + ref->macBlockLenInBytes;

    } else {
        if (to_process < ref->macBlockLenInBytes) {
            return make_ccm_error("ciphertext too short", ILLEGAL_CIPHER_TEXT);
        }
        size_t outputLen = to_process - ref->macBlockLenInBytes;

        uint8_t tmp[BLOCK_SIZE] = {
                0, 0, 0, 0, 0, 0, 0, 0,
                0, 0, 0, 0, 0, 0, 0, 0};
        memcpy(ref->macBlock, in + outputLen, ref->macBlockLenInBytes);
        memzero(ref->macBlock + ref->macBlockLenInBytes, (BLOCK_SIZE - ref->macBlockLenInBytes));
        ccm_ctr_process_bytes(ref, ref->macBlock, BLOCK_SIZE, tmp, &written);
        ccm_ctr_process_bytes(ref, in, outputLen, out, &written);
        calculateMac(ref, out, outputLen, aad, aad_len);
        uint8_t nonEqual = 0;
        for (int i = 0; i < ref->macBlockLenInBytes; i++) {
            nonEqual |= (ref->macBlock[i] ^ tmp[i]);
        }
        memzero(tmp, BLOCK_SIZE);
        //"mac check in CCM failed"
        if (nonEqual) {
            return make_ccm_error("mac check in CCM failed", ILLEGAL_CIPHER_TEXT);
        }
        *output_len = outputLen;
    }
    return NULL;
}


void calculateMac(ccm_ctx *ctx, uint8_t *input, size_t len, uint8_t *aad, size_t aad_len) {
    size_t textLength = ctx->initADLen + aad_len;
    if (textLength) {
        ctx->buf[0] |= 0x40;
    }
    ctx->buf[0] |= ((((ctx->macBlockLenInBytes - 2) >> 1) & 0x7) << 3) | (((15 - ctx->nonceLen) - 1) & 0x7);
    memcpy(ctx->buf + 1, ctx->nonce, ctx->nonceLen); // nonceLen is <=13, buf is 16
    size_t count = 1;
    size_t q = len;
    while (q > 0) {
        ctx->buf[BLOCK_SIZE - count++] = (uint8_t) (q & 0xFF);
        q >>= 8;
    }
    cbcencrypt(ctx, ctx->buf, 1, ctx->macBlock);
    if (textLength) {
        if (textLength < TEXT_LENGTH_UPPER_BOUND) {
            ctx->buf[0] = (uint8_t) (textLength >> 8);
            ctx->buf[1] = (uint8_t) (textLength);
            ctx->buf_ptr = 2;
        } else {
            ctx->buf[0] = 0xff;
            ctx->buf[1] = 0xfe;
            ctx->buf[2] = (uint8_t) (textLength >> 24);
            ctx->buf[3] = (uint8_t) (textLength >> 16);
            ctx->buf[4] = (uint8_t) (textLength >> 8);
            ctx->buf[5] = (uint8_t) (textLength);
            ctx->buf_ptr = 6;
        }
        if (ctx->initAD != NULL) {
            cbcmac_update(ctx, ctx->initAD, ctx->initADLen);
        }
        if (aad != NULL) {
            cbcmac_update(ctx, aad, aad_len);
        }
        memzero(ctx->buf + ctx->buf_ptr, (BLOCK_SIZE - ctx->buf_ptr));
        cbcencrypt(ctx, ctx->buf, 1, ctx->macBlock);
        ctx->buf_ptr = 0;
    }
    cbcmac_update(ctx, input, len);
    if (ctx->buf_ptr) {
        memzero(ctx->buf + ctx->buf_ptr, BLOCK_SIZE - ctx->buf_ptr);
        cbcencrypt(ctx, ctx->buf, 1, ctx->macBlock);
    }
    memzero(ctx->macBlock + ctx->macBlockLenInBytes, MAC_BLOCK_LEN - ctx->macBlockLenInBytes);
}

size_t ccm_getMac(ccm_ctx *ctx, uint8_t *destination) {
    memcpy(destination, ctx->macBlock, ctx->macBlockLenInBytes);
    return ctx->macBlockLenInBytes;
}


static inline void encrypt(__m128i *d0, const __m128i chainblock, __m128i *roundKeys, const uint32_t num_rounds) {
    *d0 = _mm_xor_si128(*d0, chainblock);
    *d0 = _mm_xor_si128(*d0, roundKeys[0]);
    *d0 = _mm_aesenc_si128(*d0, roundKeys[1]);
    *d0 = _mm_aesenc_si128(*d0, roundKeys[2]);
    *d0 = _mm_aesenc_si128(*d0, roundKeys[3]);
    *d0 = _mm_aesenc_si128(*d0, roundKeys[4]);
    *d0 = _mm_aesenc_si128(*d0, roundKeys[5]);
    *d0 = _mm_aesenc_si128(*d0, roundKeys[6]);
    *d0 = _mm_aesenc_si128(*d0, roundKeys[7]);
    *d0 = _mm_aesenc_si128(*d0, roundKeys[8]);
    *d0 = _mm_aesenc_si128(*d0, roundKeys[9]);
    if (num_rounds == ROUNDS_128) {
        *d0 = _mm_aesenclast_si128(*d0, roundKeys[10]);
    } else if (num_rounds == ROUNDS_192) {
        *d0 = _mm_aesenc_si128(*d0, roundKeys[10]);
        *d0 = _mm_aesenc_si128(*d0, roundKeys[11]);
        *d0 = _mm_aesenclast_si128(*d0, roundKeys[12]);
    } else if (num_rounds == ROUNDS_256) {
        *d0 = _mm_aesenc_si128(*d0, roundKeys[10]);
        *d0 = _mm_aesenc_si128(*d0, roundKeys[11]);
        *d0 = _mm_aesenc_si128(*d0, roundKeys[12]);
        *d0 = _mm_aesenc_si128(*d0, roundKeys[13]);
        *d0 = _mm_aesenclast_si128(*d0, roundKeys[14]);
    } else {
        assert(0);
    }
}


size_t cbcencrypt(ccm_ctx *ctx, unsigned char *src, uint32_t blocks, unsigned char *dest) {

    unsigned char *destStart = dest;
    __m128i d0;
    __m128i tmpCb = ctx->chainblock;
    while (blocks > 0) {
        d0 = _mm_loadu_si128((__m128i *) src);
        encrypt(&d0, tmpCb, ctx->roundKeys, ctx->num_rounds);
        _mm_storeu_si128((__m128i *) dest, d0);
        blocks--;
        src += BLOCK_SIZE;
        dest += BLOCK_SIZE;
        tmpCb = d0;
    }
    ctx->chainblock = tmpCb;
    return (size_t) (dest - destStart);
}

void cbcmac_update(ccm_ctx *ctx, uint8_t *src, size_t len) {
    size_t gapLen = BLOCK_SIZE - ctx->buf_ptr;
    if (len > gapLen) {
        memcpy(ctx->buf + ctx->buf_ptr, src, gapLen);
        cbcencrypt(ctx, ctx->buf, 1, ctx->macBlock);
        ctx->buf_ptr = 0;
        len -= gapLen;
        src += gapLen;
        while (len > BLOCK_SIZE) {
            cbcencrypt(ctx, src, 1, ctx->macBlock);
            len -= BLOCK_SIZE;
            src += BLOCK_SIZE;
        }
    }
    if (len) {
        memcpy(ctx->buf + ctx->buf_ptr, src, len);
        ctx->buf_ptr += len;
    }
}

void ccm_generate_partial_block(ccm_ctx *pCtr) {
    __m128i c = _mm_xor_si128(pCtr->IV_le, _mm_set_epi64x(0, (long long) pCtr->ctr));
    __m128i j = _mm_shuffle_epi8(c, *SWAP_ENDIAN_128);
    c = _mm_xor_si128(j, pCtr->roundKeys[0]);
    int r;
    for (r = 1; r < pCtr->num_rounds; r++) {
        c = _mm_aesenc_si128(c, pCtr->roundKeys[r]);
    }
    pCtr->partialBlock = _mm_aesenclast_si128(c, pCtr->roundKeys[r]);
}

bool ccm_incCtr(ccm_ctx *pCtr, uint64_t magnitude) {
    uint64_t blockIndex = (pCtr->ctr - pCtr->initialCTR) & pCtr->ctrMask;
    uint64_t lastBlockIndex = pCtr->ctrMask;
    if (pCtr->ctrAtEnd || magnitude - 1 > lastBlockIndex - blockIndex) {
        return false;
    }
    pCtr->ctrAtEnd = magnitude > lastBlockIndex - blockIndex;
    pCtr->ctr += magnitude;
    pCtr->ctr &= pCtr->ctrMask;
    return true;
}

bool ccm_ctr_process_byte(ccm_ctx *ctx, unsigned char *io) {
    if (ctx->buf_pos == 0) {
        if (ctx->ctrAtEnd) {
            return false;
        }
        ccm_generate_partial_block(ctx);
        *io = ((unsigned char *) &ctx->partialBlock)[ctx->buf_pos++] ^ *io;
        return true;
    }
    *io = ((unsigned char *) &ctx->partialBlock)[ctx->buf_pos++] ^ *io;
    if (ctx->buf_pos == CTR_BLOCK_SIZE) {
        ctx->buf_pos = 0;
        return ccm_incCtr(ctx, 1);
    }
    return true;
}






© 2015 - 2024 Weber Informatics LLC | Privacy Policy