We'll need this to define the LRW2 tweakable block cipher used in CGO.
int evaluate_evp_for_aes(int force_value);
int evaluate_ctr_for_aes(void);
+#ifdef USE_AES_RAW
+typedef struct aes_raw_t aes_raw_t;
+
+aes_raw_t *aes_raw_new(const uint8_t *key, int key_bits, bool encrypt);
+void aes_raw_free_(aes_raw_t *cipher);
+#define aes_raw_free(cipher) \
+ FREE_AND_NULL(aes_raw_t, aes_raw_free_, (cipher))
+void aes_raw_encrypt(const aes_raw_t *cipher, uint8_t *block);
+void aes_raw_decrypt(const aes_raw_t *cipher, uint8_t *block);
+#endif
+
#endif /* !defined(TOR_AES_H) */
* \brief Use NSS to implement AES_CTR.
**/
+#define USE_AES_RAW
+
#include "orconfig.h"
#include "lib/crypt_ops/aes.h"
#include "lib/crypt_ops/crypto_nss_mgt.h"
{
return 0;
}
+
+aes_raw_t *
+aes_raw_new(const uint8_t *key, int key_bits, bool encrypt)
+{
+ const CK_MECHANISM_TYPE ckm = CKM_AES_ECB;
+ SECItem keyItem = { .type = siBuffer, // ????
+ .data = (unsigned char *)key,
+ .len = (key_bits / 8) };
+ SECItem ivItem = { .type = siBuffer,
+ .data = NULL,
+ .len = 0 };
+ PK11SlotInfo *slot = NULL;
+ PK11SymKey *keyObj = NULL;
+ SECItem *ivObj = NULL;
+ PK11Context *result = NULL;
+
+ slot = PK11_GetBestSlot(ckm, NULL);
+ if (!slot)
+ goto err;
+
+ CK_ATTRIBUTE_TYPE mode = encrypt ? CKA_ENCRYPT : CKA_DECRYPT;
+
+ keyObj = PK11_ImportSymKey(slot, ckm, PK11_OriginUnwrap,
+ mode, &keyItem, NULL);
+ if (!keyObj)
+ goto err;
+
+ ivObj = PK11_ParamFromIV(ckm, &ivItem);
+ if (!ivObj)
+ goto err;
+
+ PORT_SetError(SEC_ERROR_IO);
+ result = PK11_CreateContextBySymKey(ckm, mode, keyObj, ivObj);
+
+ err:
+
+ if (ivObj)
+ SECITEM_FreeItem(ivObj, PR_TRUE);
+ if (keyObj)
+ PK11_FreeSymKey(keyObj);
+ if (slot)
+ PK11_FreeSlot(slot);
+
+ tor_assert(result);
+ return (aes_raw_t *)result;
+}
+
+void
+aes_raw_free_(aes_raw_t *cipher_)
+{
+ if (!cipher_)
+ return;
+ PK11Context *ctx = (PK11Context*)cipher_;
+ PK11_DestroyContext(ctx, PR_TRUE);
+}
+void
+aes_raw_encrypt(const aes_raw_t *cipher, uint8_t *block)
+{
+ SECStatus s;
+ PK11Context *ctx = (PK11Context*)cipher;
+ int result_len = 0;
+ s = PK11_CipherOp(ctx, block, &result_len, 16, block, 16);
+ tor_assert(s == SECSuccess);
+ tor_assert(result_len == 16);
+}
+void
+aes_raw_decrypt(const aes_raw_t *cipher, uint8_t *block)
+{
+ /* This is the same function call for NSS. */
+ aes_raw_encrypt(cipher, block);
+}
* \brief Use OpenSSL to implement AES_CTR.
**/
+#define USE_AES_RAW
+
#include "orconfig.h"
#include "lib/crypt_ops/aes.h"
#include "lib/crypt_ops/crypto_util.h"
}
#endif /* defined(USE_EVP_AES_CTR) */
+
+/* ========
+ * Functions for "raw" (ECB) AES.
+ *
+ * I'm choosing the name "raw" here because ECB is not a mode;
+ * it's a disaster. The only way to use this safely is
+ * within a real construction.
+ */
+
+/**
+ * Create a new instance of AES using a key of length 'key_bits'
+ * for raw block encryption.
+ *
+ * This is even more low-level than counter-mode, and you should
+ * only use it with extreme caution.
+ */
+aes_raw_t *
+aes_raw_new(const uint8_t *key, int key_bits, bool encrypt)
+{
+ EVP_CIPHER_CTX *cipher = EVP_CIPHER_CTX_new();
+ tor_assert(cipher);
+ const EVP_CIPHER *c = NULL;
+ switch (key_bits) {
+ case 128: c = EVP_aes_128_ecb(); break;
+ case 192: c = EVP_aes_192_ecb(); break;
+ case 256: c = EVP_aes_256_ecb(); break;
+ default: tor_assert_unreached();
+ }
+
+ int r = EVP_CipherInit(cipher, c, key, NULL, encrypt);
+ tor_assert(r == 1);
+ EVP_CIPHER_CTX_set_padding(cipher, 0);
+ return (aes_raw_t *)cipher;
+}
+/**
+ * Release storage held by 'cipher'.
+ */
+void
+aes_raw_free_(aes_raw_t *cipher_)
+{
+ if (!cipher_)
+ return;
+ EVP_CIPHER_CTX *cipher = (EVP_CIPHER_CTX *)cipher_;
+#ifdef OPENSSL_1_1_API
+ EVP_CIPHER_CTX_reset(cipher);
+#else
+ EVP_CIPHER_CTX_cleanup(cipher);
+#endif
+ EVP_CIPHER_CTX_free(cipher);
+}
+#define aes_raw_free(cipher) \
+ FREE_AND_NULL(aes_raw_t, aes_raw_free_, (cipher))
+/**
+ * Encrypt a single 16-byte block with 'cipher',
+ * which must have been initialized for encryption.
+ */
+void
+aes_raw_encrypt(const aes_raw_t *cipher, uint8_t *block)
+{
+ int outl = 16;
+ int r = EVP_EncryptUpdate((EVP_CIPHER_CTX *)cipher, block, &outl, block, 16);
+ tor_assert(r == 1);
+ tor_assert(outl == 16);
+}
+/**
+ * Decrypt a single 16-byte block with 'cipher',
+ * which must have been initialized for decryption.
+ */
+void
+aes_raw_decrypt(const aes_raw_t *cipher, uint8_t *block)
+{
+ int outl = 16;
+ int r = EVP_DecryptUpdate((EVP_CIPHER_CTX *)cipher, block, &outl, block, 16);
+ tor_assert(r == 1);
+ tor_assert(outl == 16);
+}
#include "orconfig.h"
#define CRYPTO_CURVE25519_PRIVATE
#define CRYPTO_RAND_PRIVATE
+#define USE_AES_RAW
#include "core/or/or.h"
#include "test/test.h"
#include "lib/crypt_ops/aes.h"
tor_free(mem_op_hex_tmp);
}
+static void
+test_aes_raw_one(int keybits,
+ const char *key_hex,
+ const char *plaintext_hex,
+ const char *ciphertext_hex)
+{
+ aes_raw_t *enc = NULL;
+ aes_raw_t *dec = NULL;
+ uint8_t key[32]; // max key size.
+ uint8_t pt[16], ct[16], block[16];
+ tt_int_op(keybits, OP_EQ, strlen(key_hex) * 8 / 2);
+ base16_decode((char*)key, sizeof(key), key_hex, strlen(key_hex));
+ base16_decode((char*)pt, sizeof(pt), plaintext_hex, strlen(plaintext_hex));
+ base16_decode((char*)ct, sizeof(ct), ciphertext_hex, strlen(ciphertext_hex));
+
+ enc = aes_raw_new(key, keybits, true);
+ dec = aes_raw_new(key, keybits, false);
+ memcpy(block, pt, sizeof(pt));
+ aes_raw_encrypt(enc, block);
+ tt_mem_op(block, OP_EQ, ct, 16);
+ aes_raw_decrypt(dec, block);
+ tt_mem_op(block, OP_EQ, pt, 16);
+
+ done:
+ aes_raw_free(enc);
+ aes_raw_free(dec);
+}
+
+static void
+test_crypto_aes_raw(void *arg)
+{
+ (void)arg;
+
+#define T test_aes_raw_one
+
+ /* From https://csrc.nist.gov/CSRC/media/Projects/
+ Cryptographic-Algorithm-Validation-Program/documents/aes/AESAVS.pdf */
+ const char *z128 =
+ "00000000000000000000000000000000";
+ const char *z192 =
+ "00000000000000000000000000000000"
+ "0000000000000000";
+ const char *z256 =
+ "00000000000000000000000000000000"
+ "00000000000000000000000000000000";
+
+ T(128, z128,
+ "f34481ec3cc627bacd5dc3fb08f273e6",
+ "0336763e966d92595a567cc9ce537f5e");
+ T(192, z192,
+ "1b077a6af4b7f98229de786d7516b639",
+ "275cfc0413d8ccb70513c3859b1d0f72");
+ T(256, z256,
+ "014730f80ac625fe84f026c60bfd547d",
+ "5c9d844ed46f9885085e5d6a4f94c7d7");
+ T(128,
+ "10a58869d74be5a374cf867cfb473859", z128,
+ "6d251e6944b051e04eaa6fb4dbf78465");
+ T(192,
+ "e9f065d7c13573587f7875357dfbb16c53489f6a4bd0f7cd", z128,
+ "0956259c9cd5cfd0181cca53380cde06");
+ T(256,
+ "c47b0294dbbbee0fec4757f22ffeee35"
+ "87ca4730c3d33b691df38bab076bc558", z128,
+ "46f2fb342d6f0ab477476fc501242c5f");
+
+#undef T
+}
+
#ifndef COCCI
#define CRYPTO_LEGACY(name) \
{ #name, test_crypto_ ## name , 0, NULL, NULL }
{ "hashx", test_crypto_hashx, 0, NULL, NULL },
{ "failure_modes", test_crypto_failure_modes, TT_FORK, NULL, NULL },
{ "polyval", test_crypto_polyval, 0, NULL, NULL },
+ { "aes_raw", test_crypto_aes_raw, 0, NULL, NULL },
END_OF_TESTCASES
};