Squashed 'third_party/rawrtc/re/' content from commit f3163ce8b
Change-Id: I6a235e6ac0f03269d951026f9d195da05c40fdab
git-subtree-dir: third_party/rawrtc/re
git-subtree-split: f3163ce8b526a13b35ef71ce4dd6f43585064d8a
diff --git a/src/aes/apple/aes.c b/src/aes/apple/aes.c
new file mode 100644
index 0000000..8f5809e
--- /dev/null
+++ b/src/aes/apple/aes.c
@@ -0,0 +1,145 @@
+/**
+ * @file apple/aes.c AES using Apple CommonCrypto API
+ *
+ * Copyright (C) 2010 Creytiv.com
+ */
+
+#include <string.h>
+#include <re_types.h>
+#include <re_mem.h>
+#include <re_fmt.h>
+#include <re_aes.h>
+#include <CommonCrypto/CommonCryptor.h>
+
+
+struct aes {
+ CCCryptorRef cryptor;
+ uint8_t key[64];
+ size_t key_bytes;
+};
+
+
+static void destructor(void *arg)
+{
+ struct aes *st = arg;
+
+ if (st->cryptor)
+ CCCryptorRelease(st->cryptor);
+}
+
+
+int aes_alloc(struct aes **stp, enum aes_mode mode,
+ const uint8_t *key, size_t key_bits,
+ const uint8_t *iv)
+{
+ struct aes *st;
+ size_t key_bytes = key_bits / 8;
+ CCCryptorStatus status;
+ int err = 0;
+
+ if (!stp || !key)
+ return EINVAL;
+
+ if (mode != AES_MODE_CTR)
+ return ENOTSUP;
+
+ st = mem_zalloc(sizeof(*st), destructor);
+ if (!st)
+ return ENOMEM;
+
+ if (key_bytes > sizeof(st->key)) {
+ err = EINVAL;
+ goto out;
+ }
+
+ st->key_bytes = key_bytes;
+ memcpy(st->key, key, st->key_bytes);
+
+ /* used for both encryption and decryption because CTR is symmetric */
+ status = CCCryptorCreateWithMode(kCCEncrypt, kCCModeCTR,
+ kCCAlgorithmAES, ccNoPadding,
+ iv, key, key_bytes, NULL, 0, 0,
+ kCCModeOptionCTR_BE, &st->cryptor);
+ if (status != kCCSuccess) {
+ err = EPROTO;
+ goto out;
+ }
+
+ out:
+ if (err)
+ mem_deref(st);
+ else
+ *stp = st;
+
+ return err;
+}
+
+
+void aes_set_iv(struct aes *st, const uint8_t *iv)
+{
+ CCCryptorStatus status;
+
+ if (!st)
+ return;
+
+ /* we must reset the state when updating IV */
+ if (st->cryptor) {
+ CCCryptorRelease(st->cryptor);
+ st->cryptor = NULL;
+ }
+
+ status = CCCryptorCreateWithMode(kCCEncrypt, kCCModeCTR,
+ kCCAlgorithmAES, ccNoPadding,
+ iv, st->key, st->key_bytes,
+ NULL, 0, 0, kCCModeOptionCTR_BE,
+ &st->cryptor);
+ if (status != kCCSuccess) {
+ re_fprintf(stderr, "aes: CCCryptorCreateWithMode error (%d)\n",
+ status);
+ }
+}
+
+
+int aes_encr(struct aes *st, uint8_t *out, const uint8_t *in, size_t len)
+{
+ CCCryptorStatus status;
+ size_t moved;
+
+ if (!st || !out || !in)
+ return EINVAL;
+
+ status = CCCryptorUpdate(st->cryptor, in, len, out, len, &moved);
+ if (status != kCCSuccess) {
+ re_fprintf(stderr, "aes: CCCryptorUpdate error (%d)\n",
+ status);
+ return EPROTO;
+ }
+
+ return 0;
+}
+
+
+int aes_decr(struct aes *st, uint8_t *out, const uint8_t *in, size_t len)
+{
+ return aes_encr(st, out, in, len);
+}
+
+
+int aes_get_authtag(struct aes *aes, uint8_t *tag, size_t taglen)
+{
+ (void)aes;
+ (void)tag;
+ (void)taglen;
+
+ return ENOSYS;
+}
+
+
+int aes_authenticate(struct aes *aes, const uint8_t *tag, size_t taglen)
+{
+ (void)aes;
+ (void)tag;
+ (void)taglen;
+
+ return ENOSYS;
+}
diff --git a/src/aes/mod.mk b/src/aes/mod.mk
new file mode 100644
index 0000000..c522149
--- /dev/null
+++ b/src/aes/mod.mk
@@ -0,0 +1,13 @@
+#
+# mod.mk
+#
+# Copyright (C) 2010 Creytiv.com
+#
+
+ifneq ($(USE_OPENSSL_AES),)
+SRCS += aes/openssl/aes.c
+else ifneq ($(USE_APPLE_COMMONCRYPTO),)
+SRCS += aes/apple/aes.c
+else
+SRCS += aes/stub.c
+endif
diff --git a/src/aes/openssl/aes.c b/src/aes/openssl/aes.c
new file mode 100644
index 0000000..4d710f2
--- /dev/null
+++ b/src/aes/openssl/aes.c
@@ -0,0 +1,267 @@
+/**
+ * @file openssl/aes.c AES (Advanced Encryption Standard) using OpenSSL
+ *
+ * Copyright (C) 2010 Creytiv.com
+ */
+#include <string.h>
+#include <openssl/aes.h>
+#include <openssl/evp.h>
+#include <openssl/err.h>
+#include <re_types.h>
+#include <re_fmt.h>
+#include <re_mem.h>
+#include <re_aes.h>
+
+
+struct aes {
+ EVP_CIPHER_CTX *ctx;
+ enum aes_mode mode;
+ bool encr;
+};
+
+
+static const EVP_CIPHER *aes_cipher(enum aes_mode mode, size_t key_bits)
+{
+ if (mode == AES_MODE_CTR) {
+
+ switch (key_bits) {
+
+ case 128: return EVP_aes_128_ctr();
+ case 192: return EVP_aes_192_ctr();
+ case 256: return EVP_aes_256_ctr();
+ default:
+ return NULL;
+ }
+ }
+ else if (mode == AES_MODE_GCM) {
+
+ switch (key_bits) {
+
+ case 128: return EVP_aes_128_gcm();
+ case 256: return EVP_aes_256_gcm();
+ default:
+ return NULL;
+ }
+ }
+ else {
+ return NULL;
+ }
+}
+
+
+static inline bool set_crypt_dir(struct aes *aes, bool encr)
+{
+ if (aes->encr != encr) {
+
+ /* update the encrypt/decrypt direction */
+ if (!EVP_CipherInit_ex(aes->ctx, NULL, NULL,
+ NULL, NULL, encr)) {
+ ERR_clear_error();
+ return false;
+ }
+
+ aes->encr = encr;
+ }
+
+ return true;
+}
+
+
+static void destructor(void *arg)
+{
+ struct aes *st = arg;
+
+#if OPENSSL_VERSION_NUMBER >= 0x10100000L
+ if (st->ctx)
+ EVP_CIPHER_CTX_free(st->ctx);
+#else
+ if (st->ctx)
+ EVP_CIPHER_CTX_cleanup(st->ctx);
+ mem_deref(st->ctx);
+#endif
+}
+
+
+int aes_alloc(struct aes **aesp, enum aes_mode mode,
+ const uint8_t *key, size_t key_bits,
+ const uint8_t *iv)
+{
+ const EVP_CIPHER *cipher;
+ struct aes *st;
+ int err = 0, r;
+
+ if (!aesp || !key)
+ return EINVAL;
+
+ cipher = aes_cipher(mode, key_bits);
+ if (!cipher)
+ return ENOTSUP;
+
+ st = mem_zalloc(sizeof(*st), destructor);
+ if (!st)
+ return ENOMEM;
+
+ st->mode = mode;
+ st->encr = true;
+
+#if OPENSSL_VERSION_NUMBER >= 0x10100000L
+ st->ctx = EVP_CIPHER_CTX_new();
+ if (!st->ctx) {
+ ERR_clear_error();
+ err = ENOMEM;
+ goto out;
+ }
+
+#else
+ st->ctx = mem_zalloc(sizeof(*st->ctx), NULL);
+ if (!st->ctx) {
+ err = ENOMEM;
+ goto out;
+ }
+
+ EVP_CIPHER_CTX_init(st->ctx);
+#endif
+
+ r = EVP_EncryptInit_ex(st->ctx, cipher, NULL, key, iv);
+ if (!r) {
+ ERR_clear_error();
+ err = EPROTO;
+ }
+
+ out:
+ if (err)
+ mem_deref(st);
+ else
+ *aesp = st;
+
+ return err;
+}
+
+
+void aes_set_iv(struct aes *aes, const uint8_t *iv)
+{
+ int r;
+
+ if (!aes || !iv)
+ return;
+
+ r = EVP_CipherInit_ex(aes->ctx, NULL, NULL, NULL, iv, -1);
+ if (!r)
+ ERR_clear_error();
+}
+
+
+int aes_encr(struct aes *aes, uint8_t *out, const uint8_t *in, size_t len)
+{
+ int c_len = (int)len;
+
+ if (!aes || !in)
+ return EINVAL;
+
+ if (!set_crypt_dir(aes, true))
+ return EPROTO;
+
+ if (!EVP_EncryptUpdate(aes->ctx, out, &c_len, in, (int)len)) {
+ ERR_clear_error();
+ return EPROTO;
+ }
+
+ return 0;
+}
+
+
+int aes_decr(struct aes *aes, uint8_t *out, const uint8_t *in, size_t len)
+{
+ int c_len = (int)len;
+
+ if (!aes || !in)
+ return EINVAL;
+
+ if (!set_crypt_dir(aes, false))
+ return EPROTO;
+
+ if (!EVP_DecryptUpdate(aes->ctx, out, &c_len, in, (int)len)) {
+ ERR_clear_error();
+ return EPROTO;
+ }
+
+ return 0;
+}
+
+
+/**
+ * Get the authentication tag for an AEAD cipher (e.g. GCM)
+ *
+ * @param aes AES Context
+ * @param tag Authentication tag
+ * @param taglen Length of Authentication tag
+ *
+ * @return 0 if success, otherwise errorcode
+ */
+int aes_get_authtag(struct aes *aes, uint8_t *tag, size_t taglen)
+{
+ int tmplen;
+
+ if (!aes || !tag || !taglen)
+ return EINVAL;
+
+ switch (aes->mode) {
+
+ case AES_MODE_GCM:
+ if (!EVP_EncryptFinal_ex(aes->ctx, NULL, &tmplen)) {
+ ERR_clear_error();
+ return EPROTO;
+ }
+
+ if (!EVP_CIPHER_CTX_ctrl(aes->ctx, EVP_CTRL_GCM_GET_TAG,
+ (int)taglen, tag)) {
+ ERR_clear_error();
+ return EPROTO;
+ }
+
+ return 0;
+
+ default:
+ return ENOTSUP;
+ }
+}
+
+
+/**
+ * Authenticate a decryption tag for an AEAD cipher (e.g. GCM)
+ *
+ * @param aes AES Context
+ * @param tag Authentication tag
+ * @param taglen Length of Authentication tag
+ *
+ * @return 0 if success, otherwise errorcode
+ *
+ * @retval EAUTH if authentication failed
+ */
+int aes_authenticate(struct aes *aes, const uint8_t *tag, size_t taglen)
+{
+ int tmplen;
+
+ if (!aes || !tag || !taglen)
+ return EINVAL;
+
+ switch (aes->mode) {
+
+ case AES_MODE_GCM:
+ if (!EVP_CIPHER_CTX_ctrl(aes->ctx, EVP_CTRL_GCM_SET_TAG,
+ (int)taglen, (void *)tag)) {
+ ERR_clear_error();
+ return EPROTO;
+ }
+
+ if (EVP_DecryptFinal_ex(aes->ctx, NULL, &tmplen) <= 0) {
+ ERR_clear_error();
+ return EAUTH;
+ }
+
+ return 0;
+
+ default:
+ return ENOTSUP;
+ }
+}
diff --git a/src/aes/stub.c b/src/aes/stub.c
new file mode 100644
index 0000000..32506d9
--- /dev/null
+++ b/src/aes/stub.c
@@ -0,0 +1,67 @@
+/**
+ * @file aes/stub.c AES stub
+ *
+ * Copyright (C) 2010 Creytiv.com
+ */
+#include <re_types.h>
+#include <re_aes.h>
+
+
+int aes_alloc(struct aes **stp, enum aes_mode mode,
+ const uint8_t *key, size_t key_bits,
+ const uint8_t iv[AES_BLOCK_SIZE])
+{
+ (void)stp;
+ (void)mode;
+ (void)key;
+ (void)key_bits;
+ (void)iv;
+ return ENOSYS;
+}
+
+
+void aes_set_iv(struct aes *st, const uint8_t iv[AES_BLOCK_SIZE])
+{
+ (void)st;
+ (void)iv;
+}
+
+
+int aes_encr(struct aes *st, uint8_t *out, const uint8_t *in, size_t len)
+{
+ (void)st;
+ (void)out;
+ (void)in;
+ (void)len;
+ return ENOSYS;
+}
+
+
+int aes_decr(struct aes *st, uint8_t *out, const uint8_t *in, size_t len)
+{
+ (void)st;
+ (void)out;
+ (void)in;
+ (void)len;
+ return ENOSYS;
+}
+
+
+int aes_get_authtag(struct aes *aes, uint8_t *tag, size_t taglen)
+{
+ (void)aes;
+ (void)tag;
+ (void)taglen;
+
+ return ENOSYS;
+}
+
+
+int aes_authenticate(struct aes *aes, const uint8_t *tag, size_t taglen)
+{
+ (void)aes;
+ (void)tag;
+ (void)taglen;
+
+ return ENOSYS;
+}