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 *)¶ms, 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(¶ms, 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 }