tor

The Tor anonymity network
git clone https://git.dasho.dev/tor.git
Log | Files | Refs | README | LICENSE

aes_nss.c (5852B)


      1 /* Copyright (c) 2001, Matej Pfajfar.
      2 * Copyright (c) 2001-2004, Roger Dingledine.
      3 * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
      4 * Copyright (c) 2007-2021, The Tor Project, Inc. */
      5 /* See LICENSE for licensing information */
      6 
      7 /**
      8 * \file aes_nss.c
      9 * \brief Use NSS to implement AES_CTR.
     10 **/
     11 
     12 #define USE_AES_RAW
     13 #define TOR_AES_PRIVATE
     14 
     15 #include "orconfig.h"
     16 #include "lib/crypt_ops/aes.h"
     17 #include "lib/crypt_ops/crypto_nss_mgt.h"
     18 #include "lib/crypt_ops/crypto_util.h"
     19 #include "lib/log/util_bug.h"
     20 
     21 DISABLE_GCC_WARNING("-Wstrict-prototypes")
     22 #include <pk11pub.h>
     23 #include <secerr.h>
     24 ENABLE_GCC_WARNING("-Wstrict-prototypes")
     25 
     26 struct aes_cnt_cipher_t {
     27  PK11Context *context;
     28  // We need to keep a copy of the key here since we can't set the IV only.
     29  // It would be nice to fix that, but NSS doesn't see a huge number of
     30  // users.
     31  uint8_t kbytes;
     32  uint8_t key[32];
     33 };
     34 
     35 static PK11Context *
     36 aes_new_cipher_internal(const uint8_t *key, const uint8_t *iv,
     37                        int key_bits)
     38 {
     39  const CK_MECHANISM_TYPE ckm = CKM_AES_CTR;
     40  SECItem keyItem = { .type = siBuffer,
     41                      .data = (unsigned char *)key,
     42                      .len = (key_bits / 8) };
     43  CK_AES_CTR_PARAMS params;
     44  params.ulCounterBits = 128;
     45  memcpy(params.cb, iv, 16);
     46  SECItem ivItem = { .type = siBuffer,
     47                     .data = (unsigned char *)&params,
     48                     .len = sizeof(params) };
     49  PK11SlotInfo *slot = NULL;
     50  PK11SymKey *keyObj = NULL;
     51  SECItem *ivObj = NULL;
     52  PK11Context *result = NULL;
     53 
     54  slot = PK11_GetBestSlot(ckm, NULL);
     55  if (!slot)
     56    goto err;
     57 
     58  keyObj = PK11_ImportSymKey(slot, ckm, PK11_OriginUnwrap,
     59                             CKA_ENCRYPT, &keyItem, NULL);
     60  if (!keyObj)
     61    goto err;
     62 
     63  ivObj = PK11_ParamFromIV(ckm, &ivItem);
     64  if (!ivObj)
     65    goto err;
     66 
     67  PORT_SetError(SEC_ERROR_IO);
     68  result = PK11_CreateContextBySymKey(ckm, CKA_ENCRYPT, keyObj, ivObj);
     69 
     70 err:
     71  memwipe(&params, 0, sizeof(params));
     72  if (ivObj)
     73    SECITEM_FreeItem(ivObj, PR_TRUE);
     74  if (keyObj)
     75    PK11_FreeSymKey(keyObj);
     76  if (slot)
     77    PK11_FreeSlot(slot);
     78 
     79  tor_assert(result);
     80  return result;
     81 }
     82 
     83 aes_cnt_cipher_t *
     84 aes_new_cipher(const uint8_t *key, const uint8_t *iv,
     85                        int key_bits)
     86 {
     87  aes_cnt_cipher_t *cipher = tor_malloc_zero(sizeof(*cipher));
     88  cipher->context = aes_new_cipher_internal(key, iv, key_bits);
     89  cipher->kbytes = key_bits / 8;
     90  memcpy(cipher->key, key, cipher->kbytes);
     91  return cipher;
     92 }
     93 
     94 void
     95 aes_cipher_free_(aes_cnt_cipher_t *cipher)
     96 {
     97  if (!cipher)
     98    return;
     99  PK11_DestroyContext(cipher->context, PR_TRUE);
    100  memwipe(cipher, 0, sizeof(*cipher));
    101  tor_free(cipher);
    102 }
    103 
    104 void
    105 aes_cipher_set_iv_aligned(aes_cnt_cipher_t *cipher, const uint8_t *iv)
    106 {
    107  // For NSS, I could not find a method to change the IV
    108  // of an existing context.  Maybe I missed one?
    109  PK11_DestroyContext(cipher->context, PR_TRUE);
    110  cipher->context = aes_new_cipher_internal(cipher->key, iv,
    111                                            8*(int)cipher->kbytes);
    112 }
    113 
    114 void
    115 aes_cipher_set_key(aes_cnt_cipher_t *cipher,
    116                   const uint8_t *key, int key_bits)
    117 {
    118  const uint8_t iv[16] = {0};
    119  // For NSS, I could not find a method to change the key
    120  // of an existing context. Maybe I missed one?
    121  PK11_DestroyContext(cipher->context, PR_TRUE);
    122  memwipe(cipher->key, 0, sizeof(cipher->key));
    123 
    124  cipher->context = aes_new_cipher_internal(key, iv, key_bits);
    125  cipher->kbytes = key_bits / 8;
    126  memcpy(cipher->key, key, cipher->kbytes);
    127 }
    128 
    129 void
    130 aes_crypt_inplace(aes_cnt_cipher_t *cipher, char *data_, size_t len_)
    131 {
    132  tor_assert(len_ <= INT_MAX);
    133 
    134  SECStatus s;
    135  unsigned char *data = (unsigned char *)data_;
    136  int len = (int) len_;
    137  int result_len = 0;
    138 
    139  s = PK11_CipherOp(cipher->context, data, &result_len, len, data, len);
    140  tor_assert(s == SECSuccess);
    141  tor_assert(result_len == len);
    142 }
    143 
    144 aes_raw_t *
    145 aes_raw_new(const uint8_t *key, int key_bits, bool encrypt)
    146 {
    147  const CK_MECHANISM_TYPE ckm = CKM_AES_ECB;
    148  SECItem keyItem = { .type = siBuffer, // ????
    149                      .data = (unsigned char *)key,
    150                      .len = (key_bits / 8) };
    151  SECItem ivItem = { .type = siBuffer,
    152                     .data = NULL,
    153                     .len = 0 };
    154  PK11SlotInfo *slot = NULL;
    155  PK11SymKey *keyObj = NULL;
    156  SECItem *ivObj = NULL;
    157  PK11Context *result = NULL;
    158 
    159  slot = PK11_GetBestSlot(ckm, NULL);
    160  if (!slot)
    161    goto err;
    162 
    163  CK_ATTRIBUTE_TYPE mode = encrypt ? CKA_ENCRYPT : CKA_DECRYPT;
    164 
    165  keyObj = PK11_ImportSymKey(slot, ckm, PK11_OriginUnwrap,
    166                             mode, &keyItem, NULL);
    167  if (!keyObj)
    168    goto err;
    169 
    170  ivObj = PK11_ParamFromIV(ckm, &ivItem);
    171  if (!ivObj)
    172    goto err;
    173 
    174  PORT_SetError(SEC_ERROR_IO);
    175  result = PK11_CreateContextBySymKey(ckm, mode, keyObj, ivObj);
    176 
    177 err:
    178 
    179  if (ivObj)
    180    SECITEM_FreeItem(ivObj, PR_TRUE);
    181  if (keyObj)
    182    PK11_FreeSymKey(keyObj);
    183  if (slot)
    184    PK11_FreeSlot(slot);
    185 
    186  tor_assert(result);
    187  return (aes_raw_t *)result;
    188 }
    189 void
    190 aes_raw_free_(aes_raw_t *cipher_)
    191 {
    192  if (!cipher_)
    193    return;
    194  PK11Context *ctx = (PK11Context*)cipher_;
    195  PK11_DestroyContext(ctx, PR_TRUE);
    196 }
    197 void
    198 aes_raw_set_key(aes_raw_t **cipher, const uint8_t *key,
    199                int key_bits, bool encrypt)
    200 {
    201  // For NSS, I could not find a method to change the key
    202  // of an existing context.
    203  aes_raw_free(*cipher);
    204  *cipher = aes_raw_new(key, key_bits, encrypt);
    205 }
    206 void
    207 aes_raw_encrypt(const aes_raw_t *cipher, uint8_t *block)
    208 {
    209  SECStatus s;
    210  PK11Context *ctx = (PK11Context*)cipher;
    211  int result_len = 0;
    212  s = PK11_CipherOp(ctx, block, &result_len, 16, block, 16);
    213  tor_assert(s == SECSuccess);
    214  tor_assert(result_len == 16);
    215 }
    216 void
    217 aes_raw_decrypt(const aes_raw_t *cipher, uint8_t *block)
    218 {
    219  /* This is the same function call for NSS. */
    220  aes_raw_encrypt(cipher, block);
    221 }