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;
+}