Skip to content

Commit

Permalink
SCP11: Major code optimization
Browse files Browse the repository at this point in the history
  • Loading branch information
aveenismail committed Dec 15, 2024
1 parent 18c684a commit a79141a
Show file tree
Hide file tree
Showing 18 changed files with 1,054 additions and 908 deletions.
481 changes: 481 additions & 0 deletions aes_cmac/aes.c

Large diffs are not rendered by default.

97 changes: 97 additions & 0 deletions aes_cmac/aes.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
/*
* Copyright (c) 2024 Yubico AB
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following
* disclaimer in the documentation and/or other materials provided
* with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/

#ifndef YUBICO_PIV_TOOL_AES_H
#define YUBICO_PIV_TOOL_AES_H

#include <stdint.h>

#ifdef _WIN32
#include <windows.h>
#include <bcrypt.h>
#include <ntstatus.h>
#else
#include <openssl/evp.h>
#endif

#ifndef AES_BLOCK_SIZE // Defined in openssl/aes.h
#define AES_BLOCK_SIZE 16
#endif

#ifdef __cplusplus
extern "C" {
#endif

typedef struct {
#ifdef _WIN32
BCRYPT_ALG_HANDLE hAlgCBC;
BCRYPT_ALG_HANDLE hAlgECB;
BCRYPT_KEY_HANDLE hKeyCBC;
BCRYPT_KEY_HANDLE hKeyECB;
PBYTE pbKeyCBCObj;
PBYTE pbKeyECBObj;
size_t cbKeyObj;
#else
EVP_CIPHER_CTX *ctx;
unsigned char key_algo;
uint8_t key[EVP_MAX_KEY_LENGTH];
#endif
} aes_context;

#ifndef _WIN32
#define YH_INTERNAL __attribute__((visibility("hidden")))
#else
#define YH_INTERNAL
#endif

int YH_INTERNAL aes_set_key(const uint8_t *key, uint16_t key_len, unsigned char key_algo,
aes_context *ctx);

int YH_INTERNAL
aes_encrypt(const uint8_t *in, uint32_t in_len, uint8_t *out, uint32_t *out_len, aes_context *ctx);
int YH_INTERNAL
aes_decrypt(const uint8_t *in, uint32_t in_len, uint8_t *out, uint32_t *out_len, aes_context *ctx);

int YH_INTERNAL aes_cbc_encrypt(const uint8_t *in, uint32_t in_len, uint8_t *out, uint32_t *out_len,
const uint8_t *iv, uint32_t iv_len, aes_context *ctx);
int YH_INTERNAL aes_cbc_decrypt(const uint8_t *in, uint32_t in_len, uint8_t *out, uint32_t *out_len,
const uint8_t *iv, uint32_t iv_len, aes_context *ctx);

uint32_t YH_INTERNAL aes_blocksize(aes_context *key);
int YH_INTERNAL aes_add_padding(uint8_t *in, uint16_t max_len, uint16_t *len);
void YH_INTERNAL aes_remove_padding(uint8_t *in, uint16_t *len);

int YH_INTERNAL aes_destroy(aes_context *ctx);

#ifdef __cplusplus
}
#endif

#endif //YUBICO_PIV_TOOL_AES_H
140 changes: 140 additions & 0 deletions aes_cmac/aes_cmac.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,140 @@
/*
* Copyright (c) 2024 Yubico AB
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following
* disclaimer in the documentation and/or other materials provided
* with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/

// AES-CMAC implementation as defined in SP-800-38B
// AES key length can be one of 128, 192, 256
// Output length is one full block (16 bytes)

#include <string.h>

#include "aes_cmac.h"
#include "insecure_memzero.h"

static const uint8_t zero[AES_BLOCK_SIZE] = {0};

static void do_pad(uint8_t *data, uint8_t len) {

for (uint8_t i = len; i < AES_BLOCK_SIZE; i++)
if (i == len)
data[i] = 0x80;
else
data[i] = 0x00;
}

static void do_xor(const uint8_t *a, uint8_t *b) {

for (uint8_t i = 0; i < AES_BLOCK_SIZE; i++) {
b[i] ^= a[i];
}
}

static void do_shift_one_bit_left(const uint8_t *a, uint8_t *b,
uint8_t *carry) {
for (int8_t i = AES_BLOCK_SIZE - 1; i >= 0; i--) {
b[i] = (a[i] << 1) | *carry;

*carry = a[i] >> 7;
}
}

static void cmac_generate_subkey(const uint8_t *key, uint8_t *subkey) {

uint8_t carry = 0;

do_shift_one_bit_left(key, subkey, &carry);

subkey[AES_BLOCK_SIZE - 1] ^= 0x87 >> (8 - (carry * 8));
}

int aes_cmac_encrypt(aes_cmac_context_t *ctx, const uint8_t *message,
const uint16_t message_len, uint8_t *mac) {

uint8_t M[AES_BLOCK_SIZE] = {0};
const uint8_t *ptr = message;

memcpy(mac, zero, AES_BLOCK_SIZE);

uint8_t n_blocks;
if (message_len == 0)
n_blocks = 0;
else
n_blocks = (message_len + (AES_BLOCK_SIZE - 1)) / AES_BLOCK_SIZE - 1;

int out_len = AES_BLOCK_SIZE;
for (uint8_t i = 0; i < n_blocks; i++) {
int rc = aes_cbc_encrypt(ptr, AES_BLOCK_SIZE, mac, &out_len, mac, AES_BLOCK_SIZE, ctx->aes_ctx);
if (rc) {
return rc;
}
ptr += AES_BLOCK_SIZE;
}

uint8_t remaining_bytes = (message_len % AES_BLOCK_SIZE);

if (remaining_bytes == 0) {
if (message != NULL && message_len != 0) {
memcpy(M, ptr, AES_BLOCK_SIZE);
do_xor(ctx->k1, M);
} else {
do_pad(M, 0);
do_xor(ctx->k2, M);
}
} else {
memcpy(M, ptr, remaining_bytes);
do_pad(M, remaining_bytes);
do_xor(ctx->k2, M);
}

return aes_cbc_encrypt(M, AES_BLOCK_SIZE, mac, &out_len, mac, AES_BLOCK_SIZE, ctx->aes_ctx);
}

int aes_cmac_init(aes_context *aes_ctx, aes_cmac_context_t *ctx) {

uint8_t L[AES_BLOCK_SIZE] = {0};

ctx->aes_ctx = aes_ctx;

int out_len = AES_BLOCK_SIZE;
int rc = aes_encrypt(zero, AES_BLOCK_SIZE, L, &out_len, ctx->aes_ctx);
if (rc) {
return rc;
}

cmac_generate_subkey(L, ctx->k1);
cmac_generate_subkey(ctx->k1, ctx->k2);

return 0;
}

void aes_cmac_destroy(aes_cmac_context_t *ctx) {
if (ctx) {
insecure_memzero(ctx, sizeof(aes_cmac_context_t));
}
}
54 changes: 54 additions & 0 deletions aes_cmac/aes_cmac.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
/*
* Copyright (c) 2024 Yubico AB
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following
* disclaimer in the documentation and/or other materials provided
* with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/

#ifndef YUBICO_PIV_TOOL_AES_CMAC_H
#define YUBICO_PIV_TOOL_AES_CMAC_H

#include "aes.h"

typedef struct {
aes_context *aes_ctx;
uint8_t k1[AES_BLOCK_SIZE];
uint8_t k2[AES_BLOCK_SIZE];
} aes_cmac_context_t;

#ifndef _WIN32
#define YH_INTERNAL __attribute__((visibility("hidden")))
#else
#define YH_INTERNAL
#endif

int YH_INTERNAL aes_cmac_init(aes_context *aes_ctx, aes_cmac_context_t *ctx);
int YH_INTERNAL aes_cmac_encrypt(aes_cmac_context_t *ctx,
const uint8_t *message,
const uint16_t message_len, uint8_t *mac);
void YH_INTERNAL aes_cmac_destroy(aes_cmac_context_t *ctx);

#endif //YUBICO_PIV_TOOL_AES_CMAC_H
48 changes: 48 additions & 0 deletions aes_cmac/insecure_memzero.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
/*
* Copyright (c) 2024 Yubico AB
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following
* disclaimer in the documentation and/or other materials provided
* with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/

#ifndef YUBICO_PIV_TOOL_INSECURE_MEMZERO_H
#define YUBICO_PIV_TOOL_INSECURE_MEMZERO_H

#ifdef _WIN32
#include <windows.h>
#define insecure_memzero(buf, len) SecureZeroMemory(buf, len)
#elif HAVE_MEMSET_S
#include <string.h>
#define insecure_memzero(buf, len) memset_s(buf, len, 0, len)
#elif HAVE_EXPLICIT_BZERO
#include <string.h>
#define insecure_memzero(buf, len) explicit_bzero(buf, len)
#else
#include <openssl/crypto.h>
#define insecure_memzero(buf, len) OPENSSL_cleanse(buf, len)
#endif

#endif //YUBICO_PIV_TOOL_INSECURE_MEMZERO_H
5 changes: 3 additions & 2 deletions lib/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -40,9 +40,10 @@ set(SOURCE
version.c
error.c
internal.c
aes_util.c
cmac_util.c
ecdh.c
scp11_util.c
../aes_cmac/aes.c
../aes_cmac/aes_cmac.c
../common/openssl-compat.c
../common/util.c)

Expand Down
Loading

0 comments on commit a79141a

Please sign in to comment.