Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 7c5465a3 authored by Jakub Pawlowski's avatar Jakub Pawlowski
Browse files

crypto_toolbox

This is copy of the crypto_toolbox for GD usage.
Only necessary changes were made:
* removed dependency on bt_types.h
* removed dependency on libbase
* reformatted code
* added namespace

Further improvements will be stacked on top of this patch.

Test: CryptoToolboxTest
Bug: 132863815
Change-Id: I639ba42705b23218a14085abcf431d744f87b913
parent 9d19ea64
Loading
Loading
Loading
Loading
+2 −0
Original line number Diff line number Diff line
@@ -104,6 +104,7 @@ cc_library {
        "stack_manager.cc",
        "module.cc",
        ":BluetoothCommonSources",
        ":BluetoothCryptoToolboxSources",
        ":BluetoothHalSources",
        ":BluetoothHciSources",
        ":BluetoothPacketSources",
@@ -232,6 +233,7 @@ cc_test {
    srcs: [
        "module_unittest.cc",
        ":BluetoothCommonTestSources",
        ":BluetoothCryptoToolboxTestSources",
        ":BluetoothHciTestSources",
        ":BluetoothL2capTestSources",
        ":BluetoothPacketTestSources",
+15 −0
Original line number Diff line number Diff line
filegroup {
    name: "BluetoothCryptoToolboxSources",
    srcs: [
        "aes.cc",
        "aes_cmac.cc",
        "crypto_toolbox.cc",
    ]
}

filegroup {
    name: "BluetoothCryptoToolboxTestSources",
    srcs: [
        "crypto_toolbox_test.cc",
    ]
}
 No newline at end of file
+950 −0

File added.

Preview size limit exceeded, changes collapsed.

+154 −0
Original line number Diff line number Diff line
/*
 ---------------------------------------------------------------------------
 Copyright (c) 1998-2008, Brian Gladman, Worcester, UK. All rights reserved.

 LICENSE TERMS

 The redistribution and use of this software (with or without changes)
 is allowed without the payment of fees or royalties provided that:

  1. source code distributions include the above copyright notice, this
     list of conditions and the following disclaimer;

  2. binary distributions include the above copyright notice, this list
     of conditions and the following disclaimer in their documentation;

  3. the name of the copyright holder is not used to endorse products
     built using this software without specific written permission.

 DISCLAIMER

 This software is provided 'as is' with no explicit or implied warranties
 in respect of its properties, including, but not limited to, correctness
 and/or fitness for purpose.
 ---------------------------------------------------------------------------
 Issue 09/09/2006

 This is an AES implementation that uses only 8-bit byte operations on the
 cipher state.
 */

#ifndef AES_H
#define AES_H

#if 1
#define AES_ENC_PREKEYED /* AES encryption with a precomputed key schedule  */
#endif
#if 1
#define AES_DEC_PREKEYED /* AES decryption with a precomputed key schedule  */
#endif
#if 1
#define AES_ENC_128_OTFK /* AES encryption with 'on the fly' 128 bit keying */
#endif
#if 1
#define AES_DEC_128_OTFK /* AES decryption with 'on the fly' 128 bit keying */
#endif
#if 1
#define AES_ENC_256_OTFK /* AES encryption with 'on the fly' 256 bit keying */
#endif
#if 1
#define AES_DEC_256_OTFK /* AES decryption with 'on the fly' 256 bit keying */
#endif

#define N_ROW 4
#define N_COL 4
#define N_BLOCK (N_ROW * N_COL)
#define N_MAX_ROUNDS 14

typedef unsigned char uint_8t;

typedef uint_8t return_type;

/*  Warning: The key length for 256 bit keys overflows a byte
    (see comment below)
*/

typedef uint_8t length_type;

typedef struct {
  uint_8t ksch[(N_MAX_ROUNDS + 1) * N_BLOCK];
  uint_8t rnd;
} aes_context;

/*  The following calls are for a precomputed key schedule

    NOTE: If the length_type used for the key length is an
    unsigned 8-bit character, a key length of 256 bits must
    be entered as a length in bytes (valid inputs are hence
    128, 192, 16, 24 and 32).
*/

#if defined(AES_ENC_PREKEYED) || defined(AES_DEC_PREKEYED)

return_type aes_set_key(const unsigned char key[], length_type keylen,
                        aes_context ctx[1]);
#endif

#if defined(AES_ENC_PREKEYED)

return_type aes_encrypt(const unsigned char in[N_BLOCK],
                        unsigned char out[N_BLOCK], const aes_context ctx[1]);

return_type aes_cbc_encrypt(const unsigned char* in, unsigned char* out,
                            int n_block, unsigned char iv[N_BLOCK],
                            const aes_context ctx[1]);
#endif

#if defined(AES_DEC_PREKEYED)

return_type aes_decrypt(const unsigned char in[N_BLOCK],
                        unsigned char out[N_BLOCK], const aes_context ctx[1]);

return_type aes_cbc_decrypt(const unsigned char* in, unsigned char* out,
                            int n_block, unsigned char iv[N_BLOCK],
                            const aes_context ctx[1]);
#endif

/*  The following calls are for 'on the fly' keying.  In this case the
    encryption and decryption keys are different.

    The encryption subroutines take a key in an array of bytes in
    key[L] where L is 16, 24 or 32 bytes for key lengths of 128,
    192, and 256 bits respectively.  They then encrypts the input
    data, in[] with this key and put the reult in the output array
    out[].  In addition, the second key array, o_key[L], is used
    to output the key that is needed by the decryption subroutine
    to reverse the encryption operation.  The two key arrays can
    be the same array but in this case the original key will be
    overwritten.

    In the same way, the decryption subroutines output keys that
    can be used to reverse their effect when used for encryption.

    Only 128 and 256 bit keys are supported in these 'on the fly'
    modes.
*/

#if defined(AES_ENC_128_OTFK)
void aes_encrypt_128(const unsigned char in[N_BLOCK],
                     unsigned char out[N_BLOCK],
                     const unsigned char key[N_BLOCK], uint_8t o_key[N_BLOCK]);
#endif

#if defined(AES_DEC_128_OTFK)
void aes_decrypt_128(const unsigned char in[N_BLOCK],
                     unsigned char out[N_BLOCK],
                     const unsigned char key[N_BLOCK],
                     unsigned char o_key[N_BLOCK]);
#endif

#if defined(AES_ENC_256_OTFK)
void aes_encrypt_256(const unsigned char in[N_BLOCK],
                     unsigned char out[N_BLOCK],
                     const unsigned char key[2 * N_BLOCK],
                     unsigned char o_key[2 * N_BLOCK]);
#endif

#if defined(AES_DEC_256_OTFK)
void aes_decrypt_256(const unsigned char in[N_BLOCK],
                     unsigned char out[N_BLOCK],
                     const unsigned char key[2 * N_BLOCK],
                     unsigned char o_key[2 * N_BLOCK]);
#endif

#endif
+202 −0
Original line number Diff line number Diff line
/******************************************************************************
 *
 *  Copyright 2008-2012 Broadcom Corporation
 *
 *  Licensed under the Apache License, Version 2.0 (the "License");
 *  you may not use this file except in compliance with the License.
 *  You may obtain a copy of the License at:
 *
 *  http://www.apache.org/licenses/LICENSE-2.0
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 *
 ******************************************************************************/

/******************************************************************************
 *
 *  This file contains the implementation of the AES128 and AES CMAC algorithm.
 *
 ******************************************************************************/

#include "crypto_toolbox/aes.h"
#include "crypto_toolbox/crypto_toolbox.h"

namespace bluetooth {
namespace crypto_toolbox {

namespace {

typedef struct {
  uint8_t* text;
  uint16_t len;
  uint16_t round;
} tCMAC_CB;

thread_local tCMAC_CB cmac_cb;

/* Rb for AES-128 as block cipher, LSB as [0] */
Octet16 const_Rb{0x87, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};

/** utility function to do an biteise exclusive-OR of two bit strings of the
 * length of OCTET16_LEN. Result is stored in first argument.
 */
static void xor_128(Octet16* a, const Octet16& b) {
  // CHECK(a);
  uint8_t i, *aa = a->data();
  const uint8_t* bb = b.data();

  for (i = 0; i < OCTET16_LEN; i++) {
    aa[i] = aa[i] ^ bb[i];
  }
}
}  // namespace

/* This function computes AES_128(key, message) */
Octet16 aes_128(const Octet16& key, const Octet16& message) {
  Octet16 key_reversed;
  Octet16 message_reversed;
  Octet16 output;

  std::reverse_copy(key.begin(), key.end(), key_reversed.begin());
  std::reverse_copy(message.begin(), message.end(), message_reversed.begin());

  aes_context ctx;
  aes_set_key(key_reversed.data(), key_reversed.size(), &ctx);
  aes_encrypt(message_reversed.data(), output.data(), &ctx);

  std::reverse(output.begin(), output.end());
  return output;
}

/** utility function to padding the given text to be a 128 bits data. The
 * parameter dest is input and output parameter, it must point to a
 * OCTET16_LEN memory space; where include length bytes valid data. */
static void padding(Octet16* dest, uint8_t length) {
  uint8_t i, *p = dest->data();
  /* original last block */
  for (i = length; i < OCTET16_LEN; i++) p[OCTET16_LEN - i - 1] = (i == length) ? 0x80 : 0;
}

/** utility function to left shift one bit for a 128 bits value. */
static void leftshift_onebit(uint8_t* input, uint8_t* output) {
  uint8_t i, overflow = 0, next_overflow = 0;
  /* input[0] is LSB */
  for (i = 0; i < OCTET16_LEN; i++) {
    next_overflow = (input[i] & 0x80) ? 1 : 0;
    output[i] = (input[i] << 1) | overflow;
    overflow = next_overflow;
  }
  return;
}

/** This function is the calculation of block cipher using AES-128. */
static Octet16 cmac_aes_k_calculate(const Octet16& key) {
  Octet16 output;
  Octet16 x{0};  // zero initialized

  uint8_t i = 1;
  while (i <= cmac_cb.round) {
    /* Mi' := Mi (+) X  */
    xor_128((Octet16*)&cmac_cb.text[(cmac_cb.round - i) * OCTET16_LEN], x);

    output = aes_128(key, &cmac_cb.text[(cmac_cb.round - i) * OCTET16_LEN], OCTET16_LEN);
    x = output;
    i++;
  }

  return output;
}

/** This function proceeed to prepare the last block of message Mn depending on
 * the size of the message.
 */
static void cmac_prepare_last_block(const Octet16& k1, const Octet16& k2) {
  //    uint8_t     x[16] = {0};
  bool flag;

  /* last block is a complete block set flag to 1 */
  flag = ((cmac_cb.len % OCTET16_LEN) == 0 && cmac_cb.len != 0) ? true : false;

  if (flag) { /* last block is complete block */
    xor_128((Octet16*)&cmac_cb.text[0], k1);
  } else /* padding then xor with k2 */
  {
    padding((Octet16*)&cmac_cb.text[0], (uint8_t)(cmac_cb.len % 16));

    xor_128((Octet16*)&cmac_cb.text[0], k2);
  }
}

/** This is the function to generate the two subkeys.
 * |key| is CMAC key, expect SRK when used by SMP.
 */
static void cmac_generate_subkey(const Octet16& key) {
  Octet16 zero{};
  Octet16 p = aes_128(key, zero.data(), OCTET16_LEN);

  Octet16 k1, k2;
  uint8_t* pp = p.data();

  /* If MSB(L) = 0, then K1 = L << 1 */
  if ((pp[OCTET16_LEN - 1] & 0x80) != 0) {
    /* Else K1 = ( L << 1 ) (+) Rb */
    leftshift_onebit(pp, k1.data());
    xor_128(&k1, const_Rb);
  } else {
    leftshift_onebit(pp, k1.data());
  }

  if ((k1[OCTET16_LEN - 1] & 0x80) != 0) {
    /* K2 =  (K1 << 1) (+) Rb */
    leftshift_onebit(k1.data(), k2.data());
    xor_128(&k2, const_Rb);
  } else {
    /* If MSB(K1) = 0, then K2 = K1 << 1 */
    leftshift_onebit(k1.data(), k2.data());
  }

  cmac_prepare_last_block(k1, k2);
}

/** key - CMAC key in little endian order
 *  input - text to be signed in little endian byte order.
 *  length - length of the input in byte.
 */
Octet16 aes_cmac(const Octet16& key, const uint8_t* input, uint16_t length) {
  uint16_t len, diff;
  /* n is number of rounds */
  uint16_t n = (length + OCTET16_LEN - 1) / OCTET16_LEN;

  if (n == 0) n = 1;
  len = n * OCTET16_LEN;

  /* allocate a memory space of multiple of 16 bytes to hold text  */
  cmac_cb.text = (uint8_t*)alloca(len);
  cmac_cb.round = n;
  diff = len - length;

  if (input != NULL && length > 0) {
    memcpy(&cmac_cb.text[diff], input, (int)length);
    cmac_cb.len = length;
  } else {
    cmac_cb.len = 0;
  }

  /* prepare calculation for subkey s and last block of data */
  cmac_generate_subkey(key);
  /* start calculation */
  Octet16 signature = cmac_aes_k_calculate(key);

  /* clean up */
  memset(&cmac_cb, 0, sizeof(tCMAC_CB));
  // cmac_cb.text is auto-freed by alloca

  return signature;
}

}  // namespace crypto_toolbox
}  // namespace bluetooth
Loading