Inital import.
Initial fork from f2d678e6e89b6508147086610e985d4e8416e867 (1.0.2 beta).
(This change contains substantial changes from the original and
effectively starts a new history.)
diff --git a/crypto/cipher/CMakeLists.txt b/crypto/cipher/CMakeLists.txt
new file mode 100644
index 0000000..55a5f87
--- /dev/null
+++ b/crypto/cipher/CMakeLists.txt
@@ -0,0 +1,24 @@
+include_directories(. .. ../../include)
+
+add_library(
+ cipher
+
+ OBJECT
+
+ cipher.c
+ cipher_error.c
+ derive_key.c
+
+ e_null.c
+ e_rc4.c
+ e_des.c
+ e_aes.c
+)
+
+add_executable(
+ cipher_test
+
+ cipher_test.c
+)
+
+target_link_libraries(cipher_test crypto)
diff --git a/crypto/cipher/cipher.c b/crypto/cipher/cipher.c
new file mode 100644
index 0000000..bf5c559
--- /dev/null
+++ b/crypto/cipher/cipher.c
@@ -0,0 +1,596 @@
+/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
+ * All rights reserved.
+ *
+ * This package is an SSL implementation written
+ * by Eric Young (eay@cryptsoft.com).
+ * The implementation was written so as to conform with Netscapes SSL.
+ *
+ * This library is free for commercial and non-commercial use as long as
+ * the following conditions are aheared to. The following conditions
+ * apply to all code found in this distribution, be it the RC4, RSA,
+ * lhash, DES, etc., code; not just the SSL code. The SSL documentation
+ * included with this distribution is covered by the same copyright terms
+ * except that the holder is Tim Hudson (tjh@cryptsoft.com).
+ *
+ * Copyright remains Eric Young's, and as such any Copyright notices in
+ * the code are not to be removed.
+ * If this package is used in a product, Eric Young should be given attribution
+ * as the author of the parts of the library used.
+ * This can be in the form of a textual message at program startup or
+ * in documentation (online or textual) provided with the package.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * "This product includes cryptographic software written by
+ * Eric Young (eay@cryptsoft.com)"
+ * The word 'cryptographic' can be left out if the rouines from the library
+ * being used are not cryptographic related :-).
+ * 4. If you include any Windows specific code (or a derivative thereof) from
+ * the apps directory (application code) you must include an acknowledgement:
+ * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
+ *
+ * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * The licence and distribution terms for any publically available version or
+ * derivative of this code cannot be changed. i.e. this code cannot simply be
+ * copied and put under another distribution licence
+ * [including the GNU Public Licence.] */
+
+#include <openssl/cipher.h>
+
+#include <string.h>
+#include <assert.h>
+
+#include <openssl/err.h>
+#include <openssl/mem.h>
+#include <openssl/obj.h>
+
+#include "internal.h"
+
+
+const EVP_CIPHER *EVP_get_cipherbynid(int nid) {
+ switch (nid) {
+ case NID_des_ede3_cbc:
+ return EVP_des_ede3_cbc();
+ case NID_des_ede_cbc:
+ return EVP_des_cbc();
+ case NID_aes_128_cbc:
+ return EVP_aes_128_cbc();
+ case NID_aes_256_cbc:
+ return EVP_aes_256_cbc();
+ default:
+ return NULL;
+ }
+}
+
+void EVP_CIPHER_CTX_init(EVP_CIPHER_CTX *ctx) {
+ memset(ctx, 0, sizeof(EVP_CIPHER_CTX));
+}
+
+EVP_CIPHER_CTX *EVP_CIPHER_CTX_new(void) {
+ EVP_CIPHER_CTX *ctx = OPENSSL_malloc(sizeof(EVP_CIPHER_CTX));
+ if (ctx) {
+ EVP_CIPHER_CTX_init(ctx);
+ }
+ return ctx;
+}
+
+int EVP_CipherInit(EVP_CIPHER_CTX *ctx, const EVP_CIPHER *cipher,
+ const unsigned char *key, const unsigned char *iv, int enc) {
+ if (cipher) {
+ EVP_CIPHER_CTX_init(ctx);
+ }
+ return EVP_CipherInit_ex(ctx, cipher, NULL, key, iv, enc);
+}
+
+int EVP_CIPHER_CTX_cleanup(EVP_CIPHER_CTX *c) {
+ if (c->cipher != NULL && c->cipher->cleanup && !c->cipher->cleanup(c)) {
+ return 0;
+ }
+
+ if (c->cipher_data) {
+ OPENSSL_cleanse(c->cipher_data, c->cipher->ctx_size);
+ OPENSSL_free(c->cipher_data);
+ }
+
+ memset(c, 0, sizeof(EVP_CIPHER_CTX));
+ return 1;
+}
+
+void EVP_CIPHER_CTX_free(EVP_CIPHER_CTX *ctx) {
+ if (ctx) {
+ EVP_CIPHER_CTX_cleanup(ctx);
+ OPENSSL_free(ctx);
+ }
+}
+
+int EVP_CIPHER_CTX_copy(EVP_CIPHER_CTX *out, const EVP_CIPHER_CTX *in) {
+ if (in == NULL || in->cipher == NULL) {
+ OPENSSL_PUT_ERROR(CIPHER, EVP_CIPHER_CTX_copy, CIPHER_R_INPUT_NOT_INITIALIZED);
+ return 0;
+ }
+
+ EVP_CIPHER_CTX_cleanup(out);
+ memcpy(out, in, sizeof(EVP_CIPHER_CTX));
+
+ if (in->cipher_data && in->cipher->ctx_size) {
+ out->cipher_data = OPENSSL_malloc(in->cipher->ctx_size);
+ if (!out->cipher_data) {
+ OPENSSL_PUT_ERROR(CIPHER, EVP_CIPHER_CTX_copy, ERR_R_MALLOC_FAILURE);
+ return 0;
+ }
+ memcpy(out->cipher_data, in->cipher_data, in->cipher->ctx_size);
+ }
+
+ return 1;
+}
+
+int EVP_CipherInit_ex(EVP_CIPHER_CTX *ctx, const EVP_CIPHER *cipher,
+ ENGINE *engine, const uint8_t *key, const uint8_t *iv,
+ int enc) {
+ if (enc == -1) {
+ enc = ctx->encrypt;
+ } else {
+ if (enc) {
+ enc = 1;
+ }
+ ctx->encrypt = enc;
+ }
+
+ if (cipher) {
+ /* Ensure a context left from last time is cleared (the previous check
+ * attempted to avoid this if the same ENGINE and EVP_CIPHER could be
+ * used). */
+ if (ctx->cipher) {
+ EVP_CIPHER_CTX_cleanup(ctx);
+ /* Restore encrypt and flags */
+ ctx->encrypt = enc;
+ }
+
+ ctx->cipher = cipher;
+ if (ctx->cipher->ctx_size) {
+ ctx->cipher_data = OPENSSL_malloc(ctx->cipher->ctx_size);
+ if (!ctx->cipher_data) {
+ OPENSSL_PUT_ERROR(CIPHER, EVP_CipherInit_ex, ERR_R_MALLOC_FAILURE);
+ return 0;
+ }
+ } else {
+ ctx->cipher_data = NULL;
+ }
+
+ ctx->key_len = cipher->key_len;
+ ctx->flags = 0;
+
+ if (ctx->cipher->flags & EVP_CIPH_CTRL_INIT) {
+ if (!EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_INIT, 0, NULL)) {
+ OPENSSL_PUT_ERROR(CIPHER, EVP_CipherInit_ex, CIPHER_R_INITIALIZATION_ERROR);
+ return 0;
+ }
+ }
+ } else if (!ctx->cipher) {
+ OPENSSL_PUT_ERROR(CIPHER, EVP_CipherInit_ex, CIPHER_R_NO_CIPHER_SET);
+ return 0;
+ }
+
+ /* we assume block size is a power of 2 in *cryptUpdate */
+ assert(ctx->cipher->block_size == 1 || ctx->cipher->block_size == 8 ||
+ ctx->cipher->block_size == 16);
+
+ if (!(EVP_CIPHER_CTX_flags(ctx) & EVP_CIPH_CUSTOM_IV)) {
+ switch (EVP_CIPHER_CTX_mode(ctx)) {
+ case EVP_CIPH_STREAM_CIPHER:
+ case EVP_CIPH_ECB_MODE:
+ break;
+
+ case EVP_CIPH_CFB_MODE:
+ case EVP_CIPH_OFB_MODE:
+ ctx->num = 0;
+ /* fall-through */
+
+ case EVP_CIPH_CBC_MODE:
+ assert(EVP_CIPHER_CTX_iv_length(ctx) <= sizeof(ctx->iv));
+ if (iv) {
+ memcpy(ctx->oiv, iv, EVP_CIPHER_CTX_iv_length(ctx));
+ }
+ memcpy(ctx->iv, ctx->oiv, EVP_CIPHER_CTX_iv_length(ctx));
+ break;
+
+ case EVP_CIPH_CTR_MODE:
+ ctx->num = 0;
+ /* Don't reuse IV for CTR mode */
+ if (iv) {
+ memcpy(ctx->iv, iv, EVP_CIPHER_CTX_iv_length(ctx));
+ }
+ break;
+
+ default:
+ return 0;
+ }
+ }
+
+ if (key || (ctx->cipher->flags & EVP_CIPH_ALWAYS_CALL_INIT)) {
+ if (!ctx->cipher->init(ctx, key, iv, enc)) {
+ return 0;
+ }
+ }
+
+ ctx->buf_len = 0;
+ ctx->final_used = 0;
+ ctx->block_mask = ctx->cipher->block_size - 1;
+ return 1;
+}
+
+int EVP_EncryptInit_ex(EVP_CIPHER_CTX *ctx, const EVP_CIPHER *cipher,
+ ENGINE *impl, const uint8_t *key, const uint8_t *iv) {
+ return EVP_CipherInit_ex(ctx, cipher, impl, key, iv, 1);
+}
+
+int EVP_DecryptInit_ex(EVP_CIPHER_CTX *ctx, const EVP_CIPHER *cipher,
+ ENGINE *impl, const uint8_t *key, const uint8_t *iv) {
+ return EVP_CipherInit_ex(ctx, cipher, impl, key, iv, 0);
+}
+
+int EVP_EncryptUpdate(EVP_CIPHER_CTX *ctx, uint8_t *out, int *out_len,
+ const uint8_t *in, int in_len) {
+ int i, j, bl;
+
+ if (ctx->cipher->flags & EVP_CIPH_FLAG_CUSTOM_CIPHER) {
+ i = ctx->cipher->cipher(ctx, out, in, in_len);
+ if (i < 0) {
+ return 0;
+ } else {
+ *out_len = i;
+ }
+ return 1;
+ }
+
+ if (in_len <= 0) {
+ *out_len = 0;
+ return in_len == 0;
+ }
+
+ if (ctx->buf_len == 0 && (in_len & ctx->block_mask) == 0) {
+ if (ctx->cipher->cipher(ctx, out, in, in_len)) {
+ *out_len = in_len;
+ return 1;
+ } else {
+ *out_len = 0;
+ return 0;
+ }
+ }
+
+ i = ctx->buf_len;
+ bl = ctx->cipher->block_size;
+ assert(bl <= (int)sizeof(ctx->buf));
+ if (i != 0) {
+ if (i + in_len < bl) {
+ memcpy(&ctx->buf[i], in, in_len);
+ ctx->buf_len += in_len;
+ *out_len = 0;
+ return 1;
+ } else {
+ j = bl - i;
+ memcpy(&ctx->buf[i], in, j);
+ if (!ctx->cipher->cipher(ctx, out, ctx->buf, bl)) {
+ return 0;
+ }
+ in_len -= j;
+ in += j;
+ out += bl;
+ *out_len = bl;
+ }
+ } else {
+ *out_len = 0;
+ }
+
+ i = in_len & ctx->block_mask;
+ in_len -= i;
+ if (in_len > 0) {
+ if (!ctx->cipher->cipher(ctx, out, in, in_len)) {
+ return 0;
+ }
+ *out_len += in_len;
+ }
+
+ if (i != 0) {
+ memcpy(ctx->buf, &in[in_len], i);
+ }
+ ctx->buf_len = i;
+ return 1;
+}
+
+int EVP_EncryptFinal_ex(EVP_CIPHER_CTX *ctx, uint8_t *out, int *out_len) {
+ int n, ret;
+ unsigned int i, b, bl;
+
+ if (ctx->cipher->flags & EVP_CIPH_FLAG_CUSTOM_CIPHER) {
+ ret = ctx->cipher->cipher(ctx, out, NULL, 0);
+ if (ret < 0) {
+ return 0;
+ } else {
+ *out_len = ret;
+ }
+ return 1;
+ }
+
+ b = ctx->cipher->block_size;
+ assert(b <= sizeof(ctx->buf));
+ if (b == 1) {
+ *out_len = 0;
+ return 1;
+ }
+
+ bl = ctx->buf_len;
+ if (ctx->flags & EVP_CIPH_NO_PADDING) {
+ if (bl) {
+ OPENSSL_PUT_ERROR(CIPHER, EVP_EncryptFinal_ex,
+ CIPHER_R_DATA_NOT_MULTIPLE_OF_BLOCK_LENGTH);
+ return 0;
+ }
+ *out_len = 0;
+ return 1;
+ }
+
+ n = b - bl;
+ for (i = bl; i < b; i++) {
+ ctx->buf[i] = n;
+ }
+ ret = ctx->cipher->cipher(ctx, out, ctx->buf, b);
+
+ if (ret) {
+ *out_len = b;
+ }
+
+ return ret;
+}
+
+int EVP_DecryptUpdate(EVP_CIPHER_CTX *ctx, uint8_t *out, int *out_len,
+ const uint8_t *in, int in_len) {
+ int fix_len;
+ unsigned int b;
+
+ if (ctx->cipher->flags & EVP_CIPH_FLAG_CUSTOM_CIPHER) {
+ int r = ctx->cipher->cipher(ctx, out, in, in_len);
+ if (r < 0) {
+ *out_len = 0;
+ return 0;
+ } else {
+ *out_len = r;
+ }
+ return 1;
+ }
+
+ if (in_len <= 0) {
+ *out_len = 0;
+ return in_len == 0;
+ }
+
+ if (ctx->flags & EVP_CIPH_NO_PADDING) {
+ return EVP_EncryptUpdate(ctx, out, out_len, in, in_len);
+ }
+
+ b = ctx->cipher->block_size;
+ assert(b <= sizeof(ctx->final));
+
+ if (ctx->final_used) {
+ memcpy(out, ctx->final, b);
+ out += b;
+ fix_len = 1;
+ } else {
+ fix_len = 0;
+ }
+
+ if (!EVP_EncryptUpdate(ctx, out, out_len, in, in_len)) {
+ return 0;
+ }
+
+ /* if we have 'decrypted' a multiple of block size, make sure
+ * we have a copy of this last block */
+ if (b > 1 && !ctx->buf_len) {
+ *out_len -= b;
+ ctx->final_used = 1;
+ memcpy(ctx->final, &out[*out_len], b);
+ } else {
+ ctx->final_used = 0;
+ }
+
+ if (fix_len) {
+ *out_len += b;
+ }
+
+ return 1;
+}
+
+int EVP_DecryptFinal_ex(EVP_CIPHER_CTX *ctx, unsigned char *out, int *out_len) {
+ int i, n;
+ unsigned int b;
+ *out_len = 0;
+
+ if (ctx->cipher->flags & EVP_CIPH_FLAG_CUSTOM_CIPHER) {
+ i = ctx->cipher->cipher(ctx, out, NULL, 0);
+ if (i < 0) {
+ return 0;
+ } else {
+ *out_len = i;
+ }
+ return 1;
+ }
+
+ b = ctx->cipher->block_size;
+ if (ctx->flags & EVP_CIPH_NO_PADDING) {
+ if (ctx->buf_len) {
+ OPENSSL_PUT_ERROR(CIPHER, EVP_DecryptFinal_ex,
+ CIPHER_R_DATA_NOT_MULTIPLE_OF_BLOCK_LENGTH);
+ return 0;
+ }
+ *out_len = 0;
+ return 1;
+ }
+
+ if (b > 1) {
+ if (ctx->buf_len || !ctx->final_used) {
+ OPENSSL_PUT_ERROR(CIPHER, EVP_DecryptFinal_ex,
+ CIPHER_R_WRONG_FINAL_BLOCK_LENGTH);
+ return 0;
+ }
+ assert(b <= sizeof(ctx->final));
+
+ /* The following assumes that the ciphertext has been authenticated.
+ * Otherwise it provides a padding oracle. */
+ n = ctx->final[b - 1];
+ if (n == 0 || n > (int)b) {
+ OPENSSL_PUT_ERROR(CIPHER, EVP_DecryptFinal_ex, CIPHER_R_BAD_DECRYPT);
+ return 0;
+ }
+
+ for (i = 0; i < n; i++) {
+ if (ctx->final[--b] != n) {
+ OPENSSL_PUT_ERROR(CIPHER, EVP_DecryptFinal_ex, CIPHER_R_BAD_DECRYPT);
+ return 0;
+ }
+ }
+
+ n = ctx->cipher->block_size - n;
+ for (i = 0; i < n; i++) {
+ out[i] = ctx->final[i];
+ }
+ *out_len = n;
+ } else {
+ *out_len = 0;
+ }
+
+ return 1;
+}
+
+int EVP_Cipher(EVP_CIPHER_CTX *ctx, uint8_t *out, const uint8_t *in,
+ size_t in_len) {
+ return ctx->cipher->cipher(ctx, out, in, in_len);
+}
+
+int EVP_CipherUpdate(EVP_CIPHER_CTX *ctx, uint8_t *out, int *out_len,
+ const uint8_t *in, int in_len) {
+ if (ctx->encrypt) {
+ return EVP_EncryptUpdate(ctx, out, out_len, in, in_len);
+ } else {
+ return EVP_DecryptUpdate(ctx, out, out_len, in, in_len);
+ }
+}
+
+int EVP_CipherFinal_ex(EVP_CIPHER_CTX *ctx, uint8_t *out, int *out_len) {
+ if (ctx->encrypt) {
+ return EVP_EncryptFinal_ex(ctx, out, out_len);
+ } else {
+ return EVP_DecryptFinal_ex(ctx, out, out_len);
+ }
+}
+
+const EVP_CIPHER *EVP_CIPHER_CTX_cipher(const EVP_CIPHER_CTX *ctx) {
+ return ctx->cipher;
+}
+
+int EVP_CIPHER_CTX_nid(const EVP_CIPHER_CTX *ctx) {
+ return ctx->cipher->nid;
+}
+
+unsigned EVP_CIPHER_CTX_block_size(const EVP_CIPHER_CTX *ctx) {
+ return ctx->cipher->block_size;
+}
+
+unsigned EVP_CIPHER_CTX_key_length(const EVP_CIPHER_CTX *ctx) {
+ return ctx->key_len;
+}
+
+unsigned EVP_CIPHER_CTX_iv_length(const EVP_CIPHER_CTX *ctx) {
+ return ctx->cipher->iv_len;
+}
+
+void *EVP_CIPHER_CTX_get_app_data(const EVP_CIPHER_CTX *ctx) {
+ return ctx->app_data;
+}
+
+void EVP_CIPHER_CTX_set_app_data(EVP_CIPHER_CTX *ctx, void *data) {
+ ctx->app_data = data;
+}
+
+uint32_t EVP_CIPHER_CTX_flags(const EVP_CIPHER_CTX *ctx) {
+ return ctx->cipher->flags & ~EVP_CIPH_MODE_MASK;
+}
+
+uint32_t EVP_CIPHER_CTX_mode(const EVP_CIPHER_CTX *ctx) {
+ return ctx->cipher->flags & EVP_CIPH_MODE_MASK;
+}
+
+int EVP_CIPHER_CTX_ctrl(EVP_CIPHER_CTX *ctx, int command, int arg, void *ptr) {
+ int ret;
+ if (!ctx->cipher) {
+ OPENSSL_PUT_ERROR(CIPHER, EVP_CIPHER_CTX_ctrl, CIPHER_R_NO_CIPHER_SET);
+ return 0;
+ }
+
+ if (!ctx->cipher->ctrl) {
+ OPENSSL_PUT_ERROR(CIPHER, EVP_CIPHER_CTX_ctrl, CIPHER_R_CTRL_NOT_IMPLEMENTED);
+ return 0;
+ }
+
+ ret = ctx->cipher->ctrl(ctx, command, arg, ptr);
+ if (ret == -1) {
+ OPENSSL_PUT_ERROR(CIPHER, EVP_CIPHER_CTX_ctrl,
+ CIPHER_R_CTRL_OPERATION_NOT_IMPLEMENTED);
+ return 0;
+ }
+
+ return ret;
+}
+
+int EVP_CIPHER_CTX_set_padding(EVP_CIPHER_CTX *ctx, int pad) {
+ if (pad) {
+ ctx->flags &= ~EVP_CIPH_NO_PADDING;
+ } else {
+ ctx->flags |= EVP_CIPH_NO_PADDING;
+ }
+ return 1;
+}
+
+int EVP_CIPHER_nid(const EVP_CIPHER *cipher) { return cipher->nid; }
+
+const char *EVP_CIPHER_name(const EVP_CIPHER *cipher) {
+ return OBJ_nid2sn(cipher->nid);
+}
+
+unsigned EVP_CIPHER_block_size(const EVP_CIPHER *cipher) {
+ return cipher->block_size;
+}
+
+unsigned EVP_CIPHER_key_length(const EVP_CIPHER *cipher) {
+ return cipher->key_len;
+}
+
+unsigned EVP_CIPHER_iv_length(const EVP_CIPHER *cipher) {
+ return cipher->iv_len;
+}
+
+uint32_t EVP_CIPHER_flags(const EVP_CIPHER *cipher) {
+ return cipher->flags & ~EVP_CIPH_MODE_MASK;
+}
+
+uint32_t EVP_CIPHER_mode(const EVP_CIPHER *cipher) {
+ return cipher->flags & EVP_CIPH_MODE_MASK;
+}
diff --git a/crypto/cipher/cipher.h b/crypto/cipher/cipher.h
new file mode 100644
index 0000000..2d105d5
--- /dev/null
+++ b/crypto/cipher/cipher.h
@@ -0,0 +1,442 @@
+/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
+ * All rights reserved.
+ *
+ * This package is an SSL implementation written
+ * by Eric Young (eay@cryptsoft.com).
+ * The implementation was written so as to conform with Netscapes SSL.
+ *
+ * This library is free for commercial and non-commercial use as long as
+ * the following conditions are aheared to. The following conditions
+ * apply to all code found in this distribution, be it the RC4, RSA,
+ * lhash, DES, etc., code; not just the SSL code. The SSL documentation
+ * included with this distribution is covered by the same copyright terms
+ * except that the holder is Tim Hudson (tjh@cryptsoft.com).
+ *
+ * Copyright remains Eric Young's, and as such any Copyright notices in
+ * the code are not to be removed.
+ * If this package is used in a product, Eric Young should be given attribution
+ * as the author of the parts of the library used.
+ * This can be in the form of a textual message at program startup or
+ * in documentation (online or textual) provided with the package.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * "This product includes cryptographic software written by
+ * Eric Young (eay@cryptsoft.com)"
+ * The word 'cryptographic' can be left out if the rouines from the library
+ * being used are not cryptographic related :-).
+ * 4. If you include any Windows specific code (or a derivative thereof) from
+ * the apps directory (application code) you must include an acknowledgement:
+ * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
+ *
+ * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * The licence and distribution terms for any publically available version or
+ * derivative of this code cannot be changed. i.e. this code cannot simply be
+ * copied and put under another distribution licence
+ * [including the GNU Public Licence.] */
+
+#ifndef OPENSSL_HEADER_CIPHER_H
+#define OPENSSL_HEADER_CIPHER_H
+
+#include <openssl/base.h>
+
+#if defined(__cplusplus)
+extern "C" {
+#endif
+
+
+/* Ciphers. */
+
+
+/* Cipher primitives.
+ *
+ * The following functions return |EVP_CIPHER| objects that implement the named
+ * cipher algorithm. */
+
+const EVP_CIPHER *EVP_rc4(void);
+
+const EVP_CIPHER *EVP_des_cbc(void);
+const EVP_CIPHER *EVP_des_ede3_cbc(void);
+
+const EVP_CIPHER *EVP_aes_128_ecb(void);
+const EVP_CIPHER *EVP_aes_128_cbc(void);
+const EVP_CIPHER *EVP_aes_128_ctr(void);
+const EVP_CIPHER *EVP_aes_128_gcm(void);
+
+const EVP_CIPHER *EVP_aes_256_ecb(void);
+const EVP_CIPHER *EVP_aes_256_cbc(void);
+const EVP_CIPHER *EVP_aes_256_ctr(void);
+const EVP_CIPHER *EVP_aes_256_gcm(void);
+
+/* EVP_enc_null returns a 'cipher' that passes plaintext through as
+ * ciphertext. */
+const EVP_CIPHER *EVP_enc_null(void);
+
+/* EVP_get_cipherbynid returns the cipher corresponding to the given NID, or
+ * NULL if no such cipher is known. */
+const EVP_CIPHER *EVP_get_cipherbynid(int nid);
+
+
+/* Cipher context allocation.
+ *
+ * An |EVP_CIPHER_CTX| represents the state of an encryption or decryption in
+ * progress. */
+
+/* EVP_CIPHER_CTX_init initialises an, already allocated, |EVP_CIPHER_CTX|. */
+void EVP_CIPHER_CTX_init(EVP_CIPHER_CTX *ctx);
+
+/* EVP_CIPHER_CTX_new allocates a fresh |EVP_CIPHER_CTX|, calls
+ * |EVP_CIPHER_CTX_init| and returns it, or NULL on allocation failure. */
+EVP_CIPHER_CTX *EVP_CIPHER_CTX_new(void);
+
+/* EVP_CIPHER_CTX_cleanup frees any memory referenced by |ctx|. It returns one
+ * on success and zero otherwise. */
+int EVP_CIPHER_CTX_cleanup(EVP_CIPHER_CTX *ctx);
+
+/* EVP_CIPHER_CTX_free calls |EVP_CIPHER_CTX_cleanup| on |ctx| and then frees
+ * |ctx| itself. */
+void EVP_CIPHER_CTX_free(EVP_CIPHER_CTX *ctx);
+
+/* EVP_CIPHER_CTX_copy sets |out| to be a duplicate of the current state of
+ * |in|. The |out| argument must have been previously initialised. */
+int EVP_CIPHER_CTX_copy(EVP_CIPHER_CTX *out, const EVP_CIPHER_CTX *in);
+
+
+/* Cipher context configuration. */
+
+/* EVP_CipherInit_ex configures |ctx| for a fresh encryption (or decryption, if
+ * |enc| is zero) operation using |cipher|. If |ctx| has been previously
+ * configured with a cipher then |cipher|, |key| and |iv| may be |NULL| and
+ * |enc| may be -1 to reuse the previous values. The operation will use |key|
+ * as the key and |iv| as the IV (if any). These should have the correct
+ * lengths given by |EVP_CIPHER_key_length| and |EVP_CIPHER_iv_length|. It
+ * returns one on success and zero on error. */
+int EVP_CipherInit_ex(EVP_CIPHER_CTX *ctx, const EVP_CIPHER *cipher,
+ ENGINE *engine, const uint8_t *key, const uint8_t *iv,
+ int enc);
+
+/* EVP_EncryptInit_ex calls |EVP_CipherInit_ex| with |enc| equal to one. */
+int EVP_EncryptInit_ex(EVP_CIPHER_CTX *ctx, const EVP_CIPHER *cipher,
+ ENGINE *impl, const uint8_t *key, const uint8_t *iv);
+
+/* EVP_DecryptInit_ex calls |EVP_CipherInit_ex| with |enc| equal to zero. */
+int EVP_DecryptInit_ex(EVP_CIPHER_CTX *ctx, const EVP_CIPHER *cipher,
+ ENGINE *impl, const uint8_t *key, const uint8_t *iv);
+
+
+/* Cipher operations. */
+
+/* EVP_EncryptUpdate encrypts |in_len| bytes from |in| to |out|. The number
+ * of output bytes may be up to |in_len| plus the block length minus one and
+ * |out| must have sufficient space. The number of bytes actually output is
+ * written to |*out_len|. It returns one on success and zero otherwise. */
+int EVP_EncryptUpdate(EVP_CIPHER_CTX *ctx, uint8_t *out, int *out_len,
+ const uint8_t *in, int in_len);
+
+/* EVP_EncryptFinal_ex writes at most a block of ciphertext to |out| and sets
+ * |*out_len| to the number of bytes written. If padding is enabled (the
+ * default) then standard padding is applied to create the final block. If
+ * padding is disabled (with |EVP_CIPHER_CTX_set_padding|) then any partial
+ * block remaining will cause an error. The function returns one on success and
+ * zero otherwise. */
+int EVP_EncryptFinal_ex(EVP_CIPHER_CTX *ctx, uint8_t *out, int *out_len);
+
+/* EVP_DecryptUpdate decrypts |in_len| bytes from |in| to |out|. The number of
+ * output bytes may be up to |in_len| plus the block length minus one and |out|
+ * must have sufficient space. The number of bytes actually output is written
+ * to |*out_len|. It returns one on success and zero otherwise. */
+int EVP_DecryptUpdate(EVP_CIPHER_CTX *ctx, uint8_t *out, int *out_len,
+ const uint8_t *in, int in_len);
+
+/* EVP_DecryptFinal_ex writes at most a block of ciphertext to |out| and sets
+ * |*out_len| to the number of bytes written. If padding is enabled (the
+ * default) then padding is removed from the final block.
+ *
+ * WARNING: it is unsafe to call this function with unauthenticted
+ * ciphertext if padding is enabled. */
+int EVP_DecryptFinal_ex(EVP_CIPHER_CTX *ctx, unsigned char *out, int *out_len);
+
+/* EVP_Cipher performs a one-shot encryption/decryption operation. No partial
+ * blocks etc are maintained between calls. It returns the number of bytes
+ * written or -1 on error.
+ *
+ * WARNING: this differs from the usual return value convention. */
+int EVP_Cipher(EVP_CIPHER_CTX *ctx, uint8_t *out, const uint8_t *in,
+ size_t in_len);
+
+/* EVP_CipherUpdate calls either |EVP_EncryptUpdate| or |EVP_DecryptUpdate|
+ * depending on how |ctx| has been setup. */
+int EVP_CipherUpdate(EVP_CIPHER_CTX *ctx, uint8_t *out, int *out_len,
+ const uint8_t *in, int in_len);
+
+/* EVP_CipherFinal_ex calls either |EVP_EncryptFinal_ex| or
+ * |EVP_DecryptFinal_ex| depending on how |ctx| has been setup. */
+int EVP_CipherFinal_ex(EVP_CIPHER_CTX *ctx, uint8_t *out, int *out_len);
+
+
+/* Cipher context accessors. */
+
+/* EVP_CIPHER_CTX_cipher returns the |EVP_CIPHER| underlying |ctx|, or NULL if
+ * none has been set. */
+const EVP_CIPHER *EVP_CIPHER_CTX_cipher(const EVP_CIPHER_CTX *ctx);
+
+/* EVP_CIPHER_CTX_nid returns a NID identifying the |EVP_CIPHER| underlying
+ * |ctx| (e.g. |NID_rc4|). It will crash if no cipher has been configured. */
+int EVP_CIPHER_CTX_nid(const EVP_CIPHER_CTX *ctx);
+
+/* EVP_CIPHER_CTX_block_size returns the block size, in bytes, of the cipher
+ * underlying |ctx|, or one if the cipher is a stream cipher. It will crash if
+ * no cipher has been configured. */
+unsigned EVP_CIPHER_CTX_block_size(const EVP_CIPHER_CTX *ctx);
+
+/* EVP_CIPHER_CTX_key_length returns the key size, in bytes, of the cipher
+ * underlying |ctx| or zero if no cipher has been configured. */
+unsigned EVP_CIPHER_CTX_key_length(const EVP_CIPHER_CTX *ctx);
+
+/* EVP_CIPHER_CTX_iv_length returns the IV size, in bytes, of the cipher
+ * underlying |ctx|. It will crash if no cipher has been configured. */
+unsigned EVP_CIPHER_CTX_iv_length(const EVP_CIPHER_CTX *ctx);
+
+/* EVP_CIPHER_CTX_get_app_data returns the opaque, application data pointer for
+ * |ctx|, or NULL if none has been set. */
+void *EVP_CIPHER_CTX_get_app_data(const EVP_CIPHER_CTX *ctx);
+
+/* EVP_CIPHER_CTX_set_app_data sets the opaque, application data pointer for
+ * |ctx| to |data|. */
+void EVP_CIPHER_CTX_set_app_data(EVP_CIPHER_CTX *ctx, void *data);
+
+/* EVP_CIPHER_CTX_flags returns a value which is the OR of zero or more
+ * |EVP_CIPH_*| flags. It will crash if no cipher has been configured. */
+uint32_t EVP_CIPHER_CTX_flags(const EVP_CIPHER_CTX *ctx);
+
+/* EVP_CIPHER_CTX_mode returns one of the |EVP_CIPH_*| cipher mode values
+ * enumerated below. It will crash if no cipher has been configured. */
+uint32_t EVP_CIPHER_CTX_mode(const EVP_CIPHER_CTX *ctx);
+
+/* EVP_CIPHER_CTX_ctrl is an |ioctl| like function. The |command| argument
+ * should be one of the |EVP_CTRL_*| values. The |arg| and |ptr| arguments are
+ * specific to the command in question. */
+int EVP_CIPHER_CTX_ctrl(EVP_CIPHER_CTX *ctx, int command, int arg, void *ptr);
+
+/* EVP_CIPHER_CTX_set_padding sets whether padding is enabled for |ctx| and
+ * returns one. Pass a non-zero |pad| to enable padding (the default) or zero
+ * to disable. */
+int EVP_CIPHER_CTX_set_padding(EVP_CIPHER_CTX *ctx, int pad);
+
+
+/* Cipher accessors. */
+
+/* EVP_CIPHER_nid returns a NID identifing |cipher|. (For example,
+ * |NID_rc4|.) */
+int EVP_CIPHER_nid(const EVP_CIPHER *cipher);
+
+/* EVP_CIPHER_name returns the short name for |cipher| or NULL if no name is
+ * known. */
+const char *EVP_CIPHER_name(const EVP_CIPHER *cipher);
+
+/* EVP_CIPHER_block_size returns the block size, in bytes, for |cipher|, or one
+ * if |cipher| is a stream cipher. */
+unsigned EVP_CIPHER_block_size(const EVP_CIPHER *cipher);
+
+/* EVP_CIPHER_key_length returns the key size, in bytes, for |cipher|. If
+ * |cipher| can take a variable key length then this function returns the
+ * default key length and |EVP_CIPHER_flags| will return a value with
+ * |EVP_CIPH_VARIABLE_LENGTH| set. */
+unsigned EVP_CIPHER_key_length(const EVP_CIPHER *cipher);
+
+/* EVP_CIPHER_iv_length returns the IV size, in bytes, of |cipher|, or zero if
+ * |cipher| doesn't take an IV. */
+unsigned EVP_CIPHER_iv_length(const EVP_CIPHER *cipher);
+
+/* EVP_CIPHER_flags returns a value which is the OR of zero or more
+ * |EVP_CIPH_*| flags. */
+uint32_t EVP_CIPHER_flags(const EVP_CIPHER *cipher);
+
+/* EVP_CIPHER_mode returns one of the cipher mode values enumerated below. */
+uint32_t EVP_CIPHER_mode(const EVP_CIPHER *cipher);
+
+
+/* Key derivation. */
+
+/* EVP_BytesToKey generates a key and IV for the cipher |type| by iterating
+ * |md| |count| times using |data| and |salt|. On entry, the |key| and |iv|
+ * buffers must have enough space to hold a key and IV for |type|. It returns
+ * the length of the key on success or zero on error. */
+int EVP_BytesToKey(const EVP_CIPHER *type, const EVP_MD *md,
+ const uint8_t *salt, const uint8_t *data, size_t data_len,
+ unsigned count, uint8_t *key, uint8_t *iv);
+
+
+/* Cipher modes (for |EVP_CIPHER_mode|). */
+
+#define EVP_CIPH_STREAM_CIPHER 0x0
+#define EVP_CIPH_ECB_MODE 0x1
+#define EVP_CIPH_CBC_MODE 0x2
+#define EVP_CIPH_CFB_MODE 0x3
+#define EVP_CIPH_OFB_MODE 0x4
+#define EVP_CIPH_CTR_MODE 0x5
+#define EVP_CIPH_GCM_MODE 0x6
+
+
+/* Cipher flags (for |EVP_CIPHER_flags|). */
+
+/* EVP_CIPH_VARIABLE_LENGTH indicates that the cipher takes a variable length
+ * key. */
+#define EVP_CIPH_VARIABLE_LENGTH 0x40
+
+/* EVP_CIPH_ALWAYS_CALL_INIT indicates that the |init| function for the cipher
+ * should always be called when initialising a new operation, even if the key
+ * is NULL to indicate that the same key is being used. */
+#define EVP_CIPH_ALWAYS_CALL_INIT 0x80
+
+/* EVP_CIPH_CUSTOM_IV indicates that the cipher manages the IV itself rather
+ * than keeping it in the |iv| member of |EVP_CIPHER_CTX|. */
+#define EVP_CIPH_CUSTOM_IV 0x100
+
+/* EVP_CIPH_CTRL_INIT indicates that EVP_CTRL_INIT should be used when
+ * initialising an |EVP_CIPHER_CTX|. */
+#define EVP_CIPH_CTRL_INIT 0x200
+
+/* EVP_CIPH_FLAG_CUSTOM_CIPHER indicates that the cipher manages blocking
+ * itself. This causes EVP_(En|De)crypt_ex to be simple wrapper functions. */
+#define EVP_CIPH_FLAG_CUSTOM_CIPHER 0x400
+
+/* EVP_CIPH_FLAG_AEAD_CIPHER specifies that the cipher is an AEAD. This is an
+ * older version of the proper AEAD interface. See aead.h for the current
+ * one. */
+#define EVP_CIPH_FLAG_AEAD_CIPHER 0x800
+
+
+/* Private functions. */
+
+/* EVP_CIPH_NO_PADDING disables padding in block ciphers. */
+#define EVP_CIPH_NO_PADDING 0x800
+
+/* EVP_CIPHER_CTX_ctrl commands. */
+#define EVP_CTRL_INIT 0x0
+#define EVP_CTRL_SET_KEY_LENGTH 0x1
+#define EVP_CTRL_GET_RC2_KEY_BITS 0x2
+#define EVP_CTRL_SET_RC2_KEY_BITS 0x3
+#define EVP_CTRL_GET_RC5_ROUNDS 0x4
+#define EVP_CTRL_SET_RC5_ROUNDS 0x5
+#define EVP_CTRL_RAND_KEY 0x6
+#define EVP_CTRL_PBE_PRF_NID 0x7
+#define EVP_CTRL_COPY 0x8
+#define EVP_CTRL_GCM_SET_IVLEN 0x9
+#define EVP_CTRL_GCM_GET_TAG 0x10
+#define EVP_CTRL_GCM_SET_TAG 0x11
+#define EVP_CTRL_GCM_SET_IV_FIXED 0x12
+#define EVP_CTRL_GCM_IV_GEN 0x13
+#define EVP_CTRL_AEAD_TLS1_AAD 0x16
+#define EVP_CTRL_AEAD_SET_MAC_KEY 0x17
+/* Set the GCM invocation field, decrypt only */
+#define EVP_CTRL_GCM_SET_IV_INV 0x18
+
+/* GCM TLS constants */
+/* Length of fixed part of IV derived from PRF */
+#define EVP_GCM_TLS_FIXED_IV_LEN 4
+/* Length of explicit part of IV part of TLS records */
+#define EVP_GCM_TLS_EXPLICIT_IV_LEN 8
+/* Length of tag for TLS */
+#define EVP_GCM_TLS_TAG_LEN 16
+
+#define EVP_MAX_KEY_LENGTH 64
+#define EVP_MAX_IV_LENGTH 16
+#define EVP_MAX_BLOCK_LENGTH 32
+
+struct evp_cipher_ctx_st {
+ /* cipher contains the underlying cipher for this context. */
+ const EVP_CIPHER *cipher;
+
+ /* app_data is a pointer to opaque, user data. */
+ void *app_data; /* application stuff */
+
+ /* cipher_data points to the |cipher| specific state. */
+ void *cipher_data;
+
+ /* key_len contains the length of the key, which may differ from
+ * |cipher->key_len| if the cipher can take a variable key length. */
+ unsigned key_len;
+
+ /* encrypt is one if encrypting and zero if decrypting. */
+ int encrypt;
+
+ /* flags contains the OR of zero or more |EVP_CIPH_*| flags, above. */
+ uint32_t flags;
+
+ /* oiv contains the original IV value. */
+ uint8_t oiv[EVP_MAX_IV_LENGTH];
+
+ /* iv contains the current IV value, which may have been updated. */
+ uint8_t iv[EVP_MAX_IV_LENGTH];
+
+ /* buf contains a partial block which is used by, for example, CTR mode to
+ * store unused keystream bytes. */
+ uint8_t buf[EVP_MAX_BLOCK_LENGTH];
+
+ /* buf_len contains the number of bytes of a partial block contained in
+ * |buf|. */
+ int buf_len;
+
+ /* num contains the number of bytes of |iv| which are valid for modes that
+ * manage partial blocks themselves. */
+ int num;
+
+ /* final_used is non-zero if the |final| buffer contains plaintext. */
+ int final_used;
+
+ /* block_mask contains |cipher->block_size| minus one. (The block size
+ * assumed to be a power of two.) */
+ int block_mask;
+
+ uint8_t final[EVP_MAX_BLOCK_LENGTH]; /* possible final block */
+} /* EVP_CIPHER_CTX */;
+
+typedef struct evp_cipher_info_st {
+ const EVP_CIPHER *cipher;
+ unsigned char iv[EVP_MAX_IV_LENGTH];
+} EVP_CIPHER_INFO;
+
+
+#if defined(__cplusplus)
+} /* extern C */
+#endif
+
+#define CIPHER_F_EVP_CipherInit_ex 100
+#define CIPHER_F_EVP_EncryptFinal_ex 101
+#define CIPHER_F_EVP_DecryptFinal_ex 102
+#define CIPHER_F_EVP_CIPHER_CTX_ctrl 103
+#define CIPHER_F_aes_init_key 104
+#define CIPHER_F_aesni_init_key 105
+#define CIPHER_F_EVP_CIPHER_CTX_copy 106
+#define CIPHER_R_WRAP_MODE_NOT_ALLOWED 100
+#define CIPHER_R_AES_KEY_SETUP_FAILED 101
+#define CIPHER_R_INPUT_NOT_INITIALIZED 102
+#define CIPHER_R_DATA_NOT_MULTIPLE_OF_BLOCK_LENGTH 103
+#define CIPHER_R_INITIALIZATION_ERROR 104
+#define CIPHER_R_CTRL_NOT_IMPLEMENTED 105
+#define CIPHER_R_NO_CIPHER_SET 106
+#define CIPHER_R_BAD_DECRYPT 107
+#define CIPHER_R_WRONG_FINAL_BLOCK_LENGTH 108
+#define CIPHER_R_CTRL_OPERATION_NOT_IMPLEMENTED 109
+
+#endif /* OPENSSL_HEADER_CIPHER_H */
diff --git a/crypto/cipher/cipher_error.c b/crypto/cipher/cipher_error.c
new file mode 100644
index 0000000..bddecdd
--- /dev/null
+++ b/crypto/cipher/cipher_error.c
@@ -0,0 +1,38 @@
+/* Copyright (c) 2014, Google Inc.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
+ * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */
+
+#include <openssl/err.h>
+
+#include "cipher.h"
+
+const ERR_STRING_DATA CIPHER_error_string_data[] = {
+ {ERR_PACK(ERR_LIB_CIPHER, CIPHER_F_EVP_CIPHER_CTX_copy, 0), "EVP_CIPHER_CTX_copy"},
+ {ERR_PACK(ERR_LIB_CIPHER, CIPHER_F_EVP_CIPHER_CTX_ctrl, 0), "EVP_CIPHER_CTX_ctrl"},
+ {ERR_PACK(ERR_LIB_CIPHER, CIPHER_F_EVP_CipherInit_ex, 0), "EVP_CipherInit_ex"},
+ {ERR_PACK(ERR_LIB_CIPHER, CIPHER_F_EVP_DecryptFinal_ex, 0), "EVP_DecryptFinal_ex"},
+ {ERR_PACK(ERR_LIB_CIPHER, CIPHER_F_EVP_EncryptFinal_ex, 0), "EVP_EncryptFinal_ex"},
+ {ERR_PACK(ERR_LIB_CIPHER, CIPHER_F_aes_init_key, 0), "aes_init_key"},
+ {ERR_PACK(ERR_LIB_CIPHER, CIPHER_F_aesni_init_key, 0), "aesni_init_key"},
+ {ERR_PACK(ERR_LIB_CIPHER, 0, CIPHER_R_AES_KEY_SETUP_FAILED), "AES_KEY_SETUP_FAILED"},
+ {ERR_PACK(ERR_LIB_CIPHER, 0, CIPHER_R_BAD_DECRYPT), "BAD_DECRYPT"},
+ {ERR_PACK(ERR_LIB_CIPHER, 0, CIPHER_R_CTRL_NOT_IMPLEMENTED), "CTRL_NOT_IMPLEMENTED"},
+ {ERR_PACK(ERR_LIB_CIPHER, 0, CIPHER_R_CTRL_OPERATION_NOT_IMPLEMENTED), "CTRL_OPERATION_NOT_IMPLEMENTED"},
+ {ERR_PACK(ERR_LIB_CIPHER, 0, CIPHER_R_DATA_NOT_MULTIPLE_OF_BLOCK_LENGTH), "DATA_NOT_MULTIPLE_OF_BLOCK_LENGTH"},
+ {ERR_PACK(ERR_LIB_CIPHER, 0, CIPHER_R_INITIALIZATION_ERROR), "INITIALIZATION_ERROR"},
+ {ERR_PACK(ERR_LIB_CIPHER, 0, CIPHER_R_INPUT_NOT_INITIALIZED), "INPUT_NOT_INITIALIZED"},
+ {ERR_PACK(ERR_LIB_CIPHER, 0, CIPHER_R_NO_CIPHER_SET), "NO_CIPHER_SET"},
+ {ERR_PACK(ERR_LIB_CIPHER, 0, CIPHER_R_WRAP_MODE_NOT_ALLOWED), "WRAP_MODE_NOT_ALLOWED"},
+ {ERR_PACK(ERR_LIB_CIPHER, 0, CIPHER_R_WRONG_FINAL_BLOCK_LENGTH), "WRONG_FINAL_BLOCK_LENGTH"},
+ {0, NULL},
+};
diff --git a/crypto/cipher/cipher_test.c b/crypto/cipher/cipher_test.c
new file mode 100644
index 0000000..3dadb8a
--- /dev/null
+++ b/crypto/cipher/cipher_test.c
@@ -0,0 +1,409 @@
+/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
+ * All rights reserved.
+ *
+ * This package is an SSL implementation written
+ * by Eric Young (eay@cryptsoft.com).
+ * The implementation was written so as to conform with Netscapes SSL.
+ *
+ * This library is free for commercial and non-commercial use as long as
+ * the following conditions are aheared to. The following conditions
+ * apply to all code found in this distribution, be it the RC4, RSA,
+ * lhash, DES, etc., code; not just the SSL code. The SSL documentation
+ * included with this distribution is covered by the same copyright terms
+ * except that the holder is Tim Hudson (tjh@cryptsoft.com).
+ *
+ * Copyright remains Eric Young's, and as such any Copyright notices in
+ * the code are not to be removed.
+ * If this package is used in a product, Eric Young should be given attribution
+ * as the author of the parts of the library used.
+ * This can be in the form of a textual message at program startup or
+ * in documentation (online or textual) provided with the package.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * "This product includes cryptographic software written by
+ * Eric Young (eay@cryptsoft.com)"
+ * The word 'cryptographic' can be left out if the rouines from the library
+ * being used are not cryptographic related :-).
+ * 4. If you include any Windows specific code (or a derivative thereof) from
+ * the apps directory (application code) you must include an acknowledgement:
+ * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
+ *
+ * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * The licence and distribution terms for any publically available version or
+ * derivative of this code cannot be changed. i.e. this code cannot simply be
+ * copied and put under another distribution licence
+ * [including the GNU Public Licence.] */
+
+#include <stdio.h>
+
+#include <openssl/cipher.h>
+#include <openssl/err.h>
+#include <openssl/bio.h>
+
+
+static void hexdump(FILE *f, const char *title, const uint8_t *s, int l) {
+ int n = 0;
+
+ fprintf(f, "%s", title);
+ for (; n < l; ++n) {
+ if ((n % 16) == 0)
+ fprintf(f, "\n%04x", n);
+ fprintf(f, " %02x", s[n]);
+ }
+ fprintf(f, "\n");
+}
+
+static int convert(uint8_t *s) {
+ uint8_t *d;
+
+ for (d = s; *s; s += 2, ++d) {
+ unsigned int n;
+
+ if (!s[1]) {
+ fprintf(stderr, "Odd number of hex digits!");
+ exit(4);
+ }
+ sscanf((char *)s, "%2x", &n);
+ *d = (uint8_t)n;
+ }
+ return s - d;
+}
+
+static char *sstrsep(char **string, const char *delim) {
+ char isdelim[256];
+ char *token = *string;
+
+ if (**string == 0) {
+ return NULL;
+ }
+
+ memset(isdelim, 0, 256);
+ isdelim[0] = 1;
+
+ while (*delim) {
+ isdelim[(uint8_t)(*delim)] = 1;
+ delim++;
+ }
+
+ while (!isdelim[(uint8_t)(**string)]) {
+ (*string)++;
+ }
+
+ if (**string) {
+ **string = 0;
+ (*string)++;
+ }
+
+ return token;
+}
+
+static uint8_t *ustrsep(char **p, const char *sep) {
+ return (uint8_t *)sstrsep(p, sep);
+}
+
+static void test1(const EVP_CIPHER *c, const uint8_t *key, int kn,
+ const uint8_t *iv, int in, const uint8_t *plaintext, int pn,
+ const uint8_t *ciphertext, int cn, const uint8_t *aad, int an,
+ const uint8_t *tag, int tn, int encdec) {
+ EVP_CIPHER_CTX ctx;
+ uint8_t out[4096];
+ int outl, outl2, mode;
+
+ printf("Testing cipher %s%s\n", EVP_CIPHER_name(c),
+ (encdec == 1 ? "(encrypt)"
+ : (encdec == 0 ? "(decrypt)" : "(encrypt/decrypt)")));
+ hexdump(stdout, "Key", key, kn);
+ if (in) {
+ hexdump(stdout, "IV", iv, in);
+ }
+ hexdump(stdout, "Plaintext", plaintext, pn);
+ hexdump(stdout, "Ciphertext", ciphertext, cn);
+ if (an) {
+ hexdump(stdout, "AAD", aad, an);
+ }
+ if (tn) {
+ hexdump(stdout, "Tag", tag, tn);
+ }
+ mode = EVP_CIPHER_mode(c);
+ if (kn != EVP_CIPHER_key_length(c)) {
+ fprintf(stderr, "Key length doesn't match, got %d expected %lu\n", kn,
+ (unsigned long)EVP_CIPHER_key_length(c));
+ exit(5);
+ }
+ EVP_CIPHER_CTX_init(&ctx);
+ if (encdec != 0) {
+ if (mode == EVP_CIPH_GCM_MODE) {
+ if (!EVP_EncryptInit_ex(&ctx, c, NULL, NULL, NULL)) {
+ fprintf(stderr, "EncryptInit failed\n");
+ BIO_print_errors_fp(stderr);
+ exit(10);
+ }
+ if (!EVP_CIPHER_CTX_ctrl(&ctx, EVP_CTRL_GCM_SET_IVLEN, in, NULL)) {
+ fprintf(stderr, "IV length set failed\n");
+ BIO_print_errors_fp(stderr);
+ exit(11);
+ }
+ if (!EVP_EncryptInit_ex(&ctx, NULL, NULL, key, iv)) {
+ fprintf(stderr, "Key/IV set failed\n");
+ BIO_print_errors_fp(stderr);
+ exit(12);
+ }
+ if (an && !EVP_EncryptUpdate(&ctx, NULL, &outl, aad, an)) {
+ fprintf(stderr, "AAD set failed\n");
+ BIO_print_errors_fp(stderr);
+ exit(13);
+ }
+ } else if (!EVP_EncryptInit_ex(&ctx, c, NULL, key, iv)) {
+ fprintf(stderr, "EncryptInit failed\n");
+ BIO_print_errors_fp(stderr);
+ exit(10);
+ }
+ EVP_CIPHER_CTX_set_padding(&ctx, 0);
+
+ if (!EVP_EncryptUpdate(&ctx, out, &outl, plaintext, pn)) {
+ fprintf(stderr, "Encrypt failed\n");
+ BIO_print_errors_fp(stderr);
+ exit(6);
+ }
+ if (!EVP_EncryptFinal_ex(&ctx, out + outl, &outl2)) {
+ fprintf(stderr, "EncryptFinal failed\n");
+ BIO_print_errors_fp(stderr);
+ exit(7);
+ }
+
+ if (outl + outl2 != cn) {
+ fprintf(stderr, "Ciphertext length mismatch got %d expected %d\n",
+ outl + outl2, cn);
+ exit(8);
+ }
+
+ if (memcmp(out, ciphertext, cn)) {
+ fprintf(stderr, "Ciphertext mismatch\n");
+ hexdump(stderr, "Got", out, cn);
+ hexdump(stderr, "Expected", ciphertext, cn);
+ exit(9);
+ }
+ if (mode == EVP_CIPH_GCM_MODE) {
+ uint8_t rtag[16];
+ /* Note: EVP_CTRL_CCM_GET_TAG has same value as
+ * EVP_CTRL_GCM_GET_TAG
+ */
+ if (!EVP_CIPHER_CTX_ctrl(&ctx, EVP_CTRL_GCM_GET_TAG, tn, rtag)) {
+ fprintf(stderr, "Get tag failed\n");
+ BIO_print_errors_fp(stderr);
+ exit(14);
+ }
+ if (memcmp(rtag, tag, tn)) {
+ fprintf(stderr, "Tag mismatch\n");
+ hexdump(stderr, "Got", rtag, tn);
+ hexdump(stderr, "Expected", tag, tn);
+ exit(9);
+ }
+ }
+ }
+
+ if (encdec <= 0) {
+ if (mode == EVP_CIPH_GCM_MODE) {
+ if (!EVP_DecryptInit_ex(&ctx, c, NULL, NULL, NULL)) {
+ fprintf(stderr, "EncryptInit failed\n");
+ BIO_print_errors_fp(stderr);
+ exit(10);
+ }
+ if (!EVP_CIPHER_CTX_ctrl(&ctx, EVP_CTRL_GCM_SET_IVLEN, in, NULL)) {
+ fprintf(stderr, "IV length set failed\n");
+ BIO_print_errors_fp(stderr);
+ exit(11);
+ }
+ if (!EVP_DecryptInit_ex(&ctx, NULL, NULL, key, iv)) {
+ fprintf(stderr, "Key/IV set failed\n");
+ BIO_print_errors_fp(stderr);
+ exit(12);
+ }
+ if (!EVP_CIPHER_CTX_ctrl(&ctx, EVP_CTRL_GCM_SET_TAG, tn, (void *)tag)) {
+ fprintf(stderr, "Set tag failed\n");
+ BIO_print_errors_fp(stderr);
+ exit(14);
+ }
+ if (an && !EVP_DecryptUpdate(&ctx, NULL, &outl, aad, an)) {
+ fprintf(stderr, "AAD set failed\n");
+ BIO_print_errors_fp(stderr);
+ exit(13);
+ }
+ } else if (!EVP_DecryptInit_ex(&ctx, c, NULL, key, iv)) {
+ fprintf(stderr, "DecryptInit failed\n");
+ BIO_print_errors_fp(stderr);
+ exit(11);
+ }
+ EVP_CIPHER_CTX_set_padding(&ctx, 0);
+
+ if (!EVP_DecryptUpdate(&ctx, out, &outl, ciphertext, cn)) {
+ fprintf(stderr, "Decrypt failed\n");
+ BIO_print_errors_fp(stderr);
+ exit(6);
+ }
+ outl2 = 0;
+ if (!EVP_DecryptFinal_ex(&ctx, out + outl, &outl2)) {
+ fprintf(stderr, "DecryptFinal failed\n");
+ BIO_print_errors_fp(stderr);
+ exit(7);
+ }
+
+ if (outl + outl2 != pn) {
+ fprintf(stderr, "Plaintext length mismatch got %d expected %d\n",
+ outl + outl2, pn);
+ exit(8);
+ }
+
+ if (memcmp(out, plaintext, pn)) {
+ fprintf(stderr, "Plaintext mismatch\n");
+ hexdump(stderr, "Got", out, pn);
+ hexdump(stderr, "Expected", plaintext, pn);
+ exit(9);
+ }
+ }
+
+ EVP_CIPHER_CTX_cleanup(&ctx);
+
+ printf("\n");
+}
+
+static int test_cipher(const char *cipher, const uint8_t *key, int kn,
+ const uint8_t *iv, int in, const uint8_t *plaintext,
+ int pn, const uint8_t *ciphertext, int cn,
+ const uint8_t *aad, int an, const uint8_t *tag, int tn,
+ int encdec) {
+ const EVP_CIPHER *c;
+
+ if (strcmp(cipher, "DES-CBC") == 0) {
+ c = EVP_des_cbc();
+ } else if (strcmp(cipher, "DES-EDE3-CBC") == 0) {
+ c = EVP_des_ede3_cbc();
+ } else if (strcmp(cipher, "RC4") == 0) {
+ c = EVP_rc4();
+ } else if (strcmp(cipher, "AES-128-ECB") == 0) {
+ c = EVP_aes_128_ecb();
+ } else if (strcmp(cipher, "AES-256-ECB") == 0) {
+ c = EVP_aes_256_ecb();
+ } else if (strcmp(cipher, "AES-128-CBC") == 0) {
+ c = EVP_aes_128_cbc();
+ } else if (strcmp(cipher, "AES-128-GCM") == 0) {
+ c = EVP_aes_128_gcm();
+ } else if (strcmp(cipher, "AES-256-CBC") == 0) {
+ c = EVP_aes_256_cbc();
+ } else if (strcmp(cipher, "AES-128-CTR") == 0) {
+ c = EVP_aes_128_ctr();
+ } else if (strcmp(cipher, "AES-256-CTR") == 0) {
+ c = EVP_aes_256_ctr();
+ } else if (strcmp(cipher, "AES-256-GCM") == 0) {
+ c = EVP_aes_256_gcm();
+ } else {
+ fprintf(stderr, "Unknown cipher type %s\n", cipher);
+ return 0;
+ }
+
+ test1(c, key, kn, iv, in, plaintext, pn, ciphertext, cn, aad, an, tag, tn,
+ encdec);
+
+ return 1;
+}
+
+int main(int argc, char **argv) {
+ const char *input_file;
+ FILE *f;
+
+ if (argc != 2) {
+ fprintf(stderr, "%s <test file>\n", argv[0]);
+ return 1;
+ }
+
+ input_file = argv[1];
+
+ f = fopen(input_file, "r");
+ if (!f) {
+ perror(input_file);
+ return 2;
+ }
+
+ ERR_load_crypto_strings();
+
+ for (;;) {
+ char line[4096];
+ char *p;
+ char *cipher;
+ uint8_t *iv, *key, *plaintext, *ciphertext, *aad, *tag;
+ int encdec;
+ int kn, in, pn, cn;
+ int an = 0;
+ int tn = 0;
+
+ if (!fgets((char *)line, sizeof line, f)) {
+ break;
+ }
+ if (line[0] == '#' || line[0] == '\n') {
+ continue;
+ }
+ p = line;
+ cipher = sstrsep(&p, ":");
+ key = ustrsep(&p, ":");
+ iv = ustrsep(&p, ":");
+ plaintext = ustrsep(&p, ":");
+ ciphertext = ustrsep(&p, ":");
+ if (p[-1] == '\n') {
+ encdec = -1;
+ p[-1] = '\0';
+ tag = aad = NULL;
+ an = tn = 0;
+ } else {
+ aad = ustrsep(&p, ":");
+ tag = ustrsep(&p, ":");
+ if (tag == NULL) {
+ p = (char *)aad;
+ tag = aad = NULL;
+ an = tn = 0;
+ }
+ if (p[-1] == '\n') {
+ encdec = -1;
+ p[-1] = '\0';
+ } else
+ encdec = atoi(sstrsep(&p, "\n"));
+ }
+
+ kn = convert(key);
+ in = convert(iv);
+ pn = convert(plaintext);
+ cn = convert(ciphertext);
+ if (aad) {
+ an = convert(aad);
+ tn = convert(tag);
+ }
+
+ if (!test_cipher(cipher, key, kn, iv, in, plaintext, pn, ciphertext, cn,
+ aad, an, tag, tn, encdec)) {
+ return 3;
+ }
+ }
+ fclose(f);
+
+ printf("PASS\n");
+ return 0;
+}
diff --git a/crypto/cipher/cipher_test.txt b/crypto/cipher/cipher_test.txt
new file mode 100644
index 0000000..b250df3
--- /dev/null
+++ b/crypto/cipher/cipher_test.txt
@@ -0,0 +1,81 @@
+# RC4 tests (from rc4test)
+RC4:0123456789abcdef0123456789abcdef::0123456789abcdef:75b7878099e0c596
+RC4:0123456789abcdef0123456789abcdef::0000000000000000:7494c2e7104b0879
+RC4:00000000000000000000000000000000::0000000000000000:de188941a3375d3a
+RC4:ef012345ef012345ef012345ef012345::0000000000000000000000000000000000000000:d6a141a7ec3c38dfbd615a1162e1c7ba36b67858
+RC4:0123456789abcdef0123456789abcdef::123456789ABCDEF0123456789ABCDEF0123456789ABCDEF012345678:66a0949f8af7d6891f7f832ba833c00c892ebe30143ce28740011ecf
+RC4:ef012345ef012345ef012345ef012345::00000000000000000000:d6a141a7ec3c38dfbd61
+
+# DES EDE3 CBC tests (from destest)
+DES-EDE3-CBC:0123456789abcdeff1e0d3c2b5a49786fedcba9876543210:fedcba9876543210:37363534333231204E6F77206973207468652074696D6520666F722000000000:3FE301C962AC01D02213763C1CBD4CDC799657C064ECF5D41C673812CFDE9675
+
+# AES 128 ECB tests (from FIPS-197 test vectors, encrypt)
+AES-128-ECB:000102030405060708090A0B0C0D0E0F::00112233445566778899AABBCCDDEEFF:69C4E0D86A7B0430D8CDB78070B4C55A:1
+
+# AES 256 ECB tests (from FIPS-197 test vectors, encrypt)
+AES-256-ECB:000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F::00112233445566778899AABBCCDDEEFF:8EA2B7CA516745BFEAFC49904B496089:1
+
+# AES 128 CBC tests (from NIST test vectors, decrypt)
+
+# AES tests from NIST document SP800-38A
+# For all ECB encrypts and decrypts, the transformed sequence is
+# AES-bits-ECB:key::plaintext:ciphertext:encdec
+# ECB-AES128.Encrypt and ECB-AES128.Decrypt
+AES-128-ECB:2B7E151628AED2A6ABF7158809CF4F3C::6BC1BEE22E409F96E93D7E117393172A:3AD77BB40D7A3660A89ECAF32466EF97
+AES-128-ECB:2B7E151628AED2A6ABF7158809CF4F3C::AE2D8A571E03AC9C9EB76FAC45AF8E51:F5D3D58503B9699DE785895A96FDBAAF
+AES-128-ECB:2B7E151628AED2A6ABF7158809CF4F3C::30C81C46A35CE411E5FBC1191A0A52EF:43B1CD7F598ECE23881B00E3ED030688
+AES-128-ECB:2B7E151628AED2A6ABF7158809CF4F3C::F69F2445DF4F9B17AD2B417BE66C3710:7B0C785E27E8AD3F8223207104725DD4
+# ECB-AES256.Encrypt and ECB-AES256.Decrypt
+AES-256-ECB:603DEB1015CA71BE2B73AEF0857D77811F352C073B6108D72D9810A30914DFF4::6BC1BEE22E409F96E93D7E117393172A:F3EED1BDB5D2A03C064B5A7E3DB181F8
+AES-256-ECB:603DEB1015CA71BE2B73AEF0857D77811F352C073B6108D72D9810A30914DFF4::AE2D8A571E03AC9C9EB76FAC45AF8E51:591CCB10D410ED26DC5BA74A31362870
+AES-256-ECB:603DEB1015CA71BE2B73AEF0857D77811F352C073B6108D72D9810A30914DFF4::30C81C46A35CE411E5FBC1191A0A52EF:B6ED21B99CA6F4F9F153E7B1BEAFED1D
+AES-256-ECB:603DEB1015CA71BE2B73AEF0857D77811F352C073B6108D72D9810A30914DFF4::F69F2445DF4F9B17AD2B417BE66C3710:23304B7A39F9F3FF067D8D8F9E24ECC7
+# For all CBC encrypts and decrypts, the transformed sequence is
+# AES-bits-CBC:key:IV/ciphertext':plaintext:ciphertext:encdec
+# CBC-AES128.Encrypt and CBC-AES128.Decrypt
+AES-128-CBC:2B7E151628AED2A6ABF7158809CF4F3C:000102030405060708090A0B0C0D0E0F:6BC1BEE22E409F96E93D7E117393172A:7649ABAC8119B246CEE98E9B12E9197D
+AES-128-CBC:2B7E151628AED2A6ABF7158809CF4F3C:7649ABAC8119B246CEE98E9B12E9197D:AE2D8A571E03AC9C9EB76FAC45AF8E51:5086CB9B507219EE95DB113A917678B2
+AES-128-CBC:2B7E151628AED2A6ABF7158809CF4F3C:5086CB9B507219EE95DB113A917678B2:30C81C46A35CE411E5FBC1191A0A52EF:73BED6B8E3C1743B7116E69E22229516
+AES-128-CBC:2B7E151628AED2A6ABF7158809CF4F3C:73BED6B8E3C1743B7116E69E22229516:F69F2445DF4F9B17AD2B417BE66C3710:3FF1CAA1681FAC09120ECA307586E1A7
+# CBC-AES256.Encrypt and CBC-AES256.Decrypt
+AES-256-CBC:603DEB1015CA71BE2B73AEF0857D77811F352C073B6108D72D9810A30914DFF4:000102030405060708090A0B0C0D0E0F:6BC1BEE22E409F96E93D7E117393172A:F58C4C04D6E5F1BA779EABFB5F7BFBD6
+AES-256-CBC:603DEB1015CA71BE2B73AEF0857D77811F352C073B6108D72D9810A30914DFF4:F58C4C04D6E5F1BA779EABFB5F7BFBD6:AE2D8A571E03AC9C9EB76FAC45AF8E51:9CFC4E967EDB808D679F777BC6702C7D
+AES-256-CBC:603DEB1015CA71BE2B73AEF0857D77811F352C073B6108D72D9810A30914DFF4:9CFC4E967EDB808D679F777BC6702C7D:30C81C46A35CE411E5FBC1191A0A52EF:39F23369A9D9BACFA530E26304231461
+AES-256-CBC:603DEB1015CA71BE2B73AEF0857D77811F352C073B6108D72D9810A30914DFF4:39F23369A9D9BACFA530E26304231461:F69F2445DF4F9B17AD2B417BE66C3710:B2EB05E2C39BE9FCDA6C19078C6A9D1B
+
+# AES Counter test vectors from RFC3686
+AES-128-CTR:AE6852F8121067CC4BF7A5765577F39E:00000030000000000000000000000001:53696E676C6520626C6F636B206D7367:E4095D4FB7A7B3792D6175A3261311B8:1
+AES-128-CTR:7E24067817FAE0D743D6CE1F32539163:006CB6DBC0543B59DA48D90B00000001:000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F:5104A106168A72D9790D41EE8EDAD388EB2E1EFC46DA57C8FCE630DF9141BE28:1
+AES-128-CTR:7691BE035E5020A8AC6E618529F9A0DC:00E0017B27777F3F4A1786F000000001:000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F20212223:C1CF48A89F2FFDD9CF4652E9EFDB72D74540A42BDE6D7836D59A5CEAAEF3105325B2072F:1
+
+AES-256-CTR:776BEFF2851DB06F4C8A0542C8696F6C6A81AF1EEC96B4D37FC1D689E6C1C104:00000060DB5672C97AA8F0B200000001:53696E676C6520626C6F636B206D7367:145AD01DBF824EC7560863DC71E3E0C0:1
+AES-256-CTR:F6D66D6BD52D59BB0796365879EFF886C66DD51A5B6A99744B50590C87A23884:00FAAC24C1585EF15A43D87500000001:000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F:F05E231B3894612C49EE000B804EB2A9B8306B508F839D6A5530831D9344AF1C:1
+AES-256-CTR:FF7A617CE69148E4F1726E2F43581DE2AA62D9F805532EDFF1EED687FB54153D:001CC5B751A51D70A1C1114800000001:000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F20212223:EB6C52821D0BBBF7CE7594462ACA4FAAB407DF866569FD07F48CC0B583D6071F1EC0E6B8:1
+
+# AES GCM test vectors from http://csrc.nist.gov/groups/ST/toolkit/BCM/documents/proposedmodes/gcm/gcm-spec.pdf
+AES-128-GCM:00000000000000000000000000000000:000000000000000000000000::::58e2fccefa7e3061367f1d57a4e7455a
+AES-128-GCM:00000000000000000000000000000000:000000000000000000000000:00000000000000000000000000000000:0388dace60b6a392f328c2b971b2fe78::ab6e47d42cec13bdf53a67b21257bddf
+AES-128-GCM:feffe9928665731c6d6a8f9467308308:cafebabefacedbaddecaf888:d9313225f88406e5a55909c5aff5269a86a7a9531534f7da2e4c303d8a318a721c3c0c95956809532fcf0e2449a6b525b16aedf5aa0de657ba637b391aafd255:42831ec2217774244b7221b784d0d49ce3aa212f2c02a4e035c17e2329aca12e21d514b25466931c7d8f6a5aac84aa051ba30b396a0aac973d58e091473f5985::4d5c2af327cd64a62cf35abd2ba6fab4
+AES-128-GCM:feffe9928665731c6d6a8f9467308308:cafebabefacedbaddecaf888:d9313225f88406e5a55909c5aff5269a86a7a9531534f7da2e4c303d8a318a721c3c0c95956809532fcf0e2449a6b525b16aedf5aa0de657ba637b39:42831ec2217774244b7221b784d0d49ce3aa212f2c02a4e035c17e2329aca12e21d514b25466931c7d8f6a5aac84aa051ba30b396a0aac973d58e091:feedfacedeadbeeffeedfacedeadbeefabaddad2:5bc94fbc3221a5db94fae95ae7121a47
+AES-128-GCM:feffe9928665731c6d6a8f9467308308:cafebabefacedbad:d9313225f88406e5a55909c5aff5269a86a7a9531534f7da2e4c303d8a318a721c3c0c95956809532fcf0e2449a6b525b16aedf5aa0de657ba637b39:61353b4c2806934a777ff51fa22a4755699b2a714fcdc6f83766e5f97b6c742373806900e49f24b22b097544d4896b424989b5e1ebac0f07c23f4598:feedfacedeadbeeffeedfacedeadbeefabaddad2:3612d2e79e3b0785561be14aaca2fccb
+AES-128-GCM:feffe9928665731c6d6a8f9467308308:9313225df88406e555909c5aff5269aa6a7a9538534f7da1e4c303d2a318a728c3c0c95156809539fcf0e2429a6b525416aedbf5a0de6a57a637b39b:d9313225f88406e5a55909c5aff5269a86a7a9531534f7da2e4c303d8a318a721c3c0c95956809532fcf0e2449a6b525b16aedf5aa0de657ba637b39:8ce24998625615b603a033aca13fb894be9112a5c3a211a8ba262a3cca7e2ca701e4a9a4fba43c90ccdcb281d48c7c6fd62875d2aca417034c34aee5:feedfacedeadbeeffeedfacedeadbeefabaddad2:619cc5aefffe0bfa462af43c1699d050
+AES-256-GCM:0000000000000000000000000000000000000000000000000000000000000000:000000000000000000000000::::530f8afbc74536b9a963b4f1c4cb738b
+AES-256-GCM:0000000000000000000000000000000000000000000000000000000000000000:000000000000000000000000:00000000000000000000000000000000:cea7403d4d606b6e074ec5d3baf39d18::d0d1c8a799996bf0265b98b5d48ab919
+AES-256-GCM:feffe9928665731c6d6a8f9467308308feffe9928665731c6d6a8f9467308308:cafebabefacedbaddecaf888:d9313225f88406e5a55909c5aff5269a86a7a9531534f7da2e4c303d8a318a721c3c0c95956809532fcf0e2449a6b525b16aedf5aa0de657ba637b391aafd255:522dc1f099567d07f47f37a32a84427d643a8cdcbfe5c0c97598a2bd2555d1aa8cb08e48590dbb3da7b08b1056828838c5f61e6393ba7a0abcc9f662898015ad::b094dac5d93471bdec1a502270e3cc6c
+AES-256-GCM:feffe9928665731c6d6a8f9467308308feffe9928665731c6d6a8f9467308308:cafebabefacedbaddecaf888:d9313225f88406e5a55909c5aff5269a86a7a9531534f7da2e4c303d8a318a721c3c0c95956809532fcf0e2449a6b525b16aedf5aa0de657ba637b39:522dc1f099567d07f47f37a32a84427d643a8cdcbfe5c0c97598a2bd2555d1aa8cb08e48590dbb3da7b08b1056828838c5f61e6393ba7a0abcc9f662:feedfacedeadbeeffeedfacedeadbeefabaddad2:76fc6ece0f4e1768cddf8853bb2d551b
+AES-256-GCM:feffe9928665731c6d6a8f9467308308feffe9928665731c6d6a8f9467308308:cafebabefacedbad:d9313225f88406e5a55909c5aff5269a86a7a9531534f7da2e4c303d8a318a721c3c0c95956809532fcf0e2449a6b525b16aedf5aa0de657ba637b39:c3762df1ca787d32ae47c13bf19844cbaf1ae14d0b976afac52ff7d79bba9de0feb582d33934a4f0954cc2363bc73f7862ac430e64abe499f47c9b1f:feedfacedeadbeeffeedfacedeadbeefabaddad2:3a337dbf46a792c45e454913fe2ea8f2
+AES-256-GCM:feffe9928665731c6d6a8f9467308308feffe9928665731c6d6a8f9467308308:9313225df88406e555909c5aff5269aa6a7a9538534f7da1e4c303d2a318a728c3c0c95156809539fcf0e2429a6b525416aedbf5a0de6a57a637b39b:d9313225f88406e5a55909c5aff5269a86a7a9531534f7da2e4c303d8a318a721c3c0c95956809532fcf0e2449a6b525b16aedf5aa0de657ba637b39:5a8def2f0c9e53f1f75d7853659e2a20eeb2b22aafde6419a058ab4f6f746bf40fc0c3b780f244452da3ebf1c5d82cdea2418997200ef82e44ae7e3f:feedfacedeadbeeffeedfacedeadbeefabaddad2:a44a8266ee1c8eb0c8b5d4cf5ae9f19a
+# local add-ons, primarily streaming ghash tests
+# 128 bytes aad
+AES-128-GCM:00000000000000000000000000000000:000000000000000000000000:::d9313225f88406e5a55909c5aff5269a86a7a9531534f7da2e4c303d8a318a721c3c0c95956809532fcf0e2449a6b525b16aedf5aa0de657ba637b391aafd255522dc1f099567d07f47f37a32a84427d643a8cdcbfe5c0c97598a2bd2555d1aa8cb08e48590dbb3da7b08b1056828838c5f61e6393ba7a0abcc9f662898015ad:5fea793a2d6f974d37e68e0cb8ff9492
+# 48 bytes plaintext
+AES-128-GCM:00000000000000000000000000000000:000000000000000000000000:000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000:0388dace60b6a392f328c2b971b2fe78f795aaab494b5923f7fd89ff948bc1e0200211214e7394da2089b6acd093abe0::9dd0a376b08e40eb00c35f29f9ea61a4
+# 80 bytes plaintext
+AES-128-GCM:00000000000000000000000000000000:000000000000000000000000:0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000:0388dace60b6a392f328c2b971b2fe78f795aaab494b5923f7fd89ff948bc1e0200211214e7394da2089b6acd093abe0c94da219118e297d7b7ebcbcc9c388f28ade7d85a8ee35616f7124a9d5270291::98885a3a22bd4742fe7b72172193b163
+# 128 bytes plaintext
+AES-128-GCM:00000000000000000000000000000000:000000000000000000000000:0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000:0388dace60b6a392f328c2b971b2fe78f795aaab494b5923f7fd89ff948bc1e0200211214e7394da2089b6acd093abe0c94da219118e297d7b7ebcbcc9c388f28ade7d85a8ee35616f7124a9d527029195b84d1b96c690ff2f2de30bf2ec89e00253786e126504f0dab90c48a30321de3345e6b0461e7c9e6c6b7afedde83f40::cac45f60e31efd3b5a43b98a22ce1aa1
+# 192 bytes plaintext, iv is chosen so that initial counter LSB is 0xFF
+AES-128-GCM:00000000000000000000000000000000:ffffffff000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000:000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000:56b3373ca9ef6e4a2b64fe1e9a17b61425f10d47a75a5fce13efc6bc784af24f4141bdd48cf7c770887afd573cca5418a9aeffcd7c5ceddfc6a78397b9a85b499da558257267caab2ad0b23ca476a53cb17fb41c4b8b475cb4f3f7165094c229c9e8c4dc0a2a5ff1903e501511221376a1cdb8364c5061a20cae74bc4acd76ceb0abc9fd3217ef9f8c90be402ddf6d8697f4f880dff15bfb7a6b28241ec8fe183c2d59e3f9dfff653c7126f0acb9e64211f42bae12af462b1070bef1ab5e3606::566f8ef683078bfdeeffa869d751a017
+# 80 bytes plaintext, submitted by Intel
+AES-128-GCM:843ffcf5d2b72694d19ed01d01249412:dbcca32ebf9b804617c3aa9e:000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f:6268c6fa2a80b2d137467f092f657ac04d89be2beaa623d61b5a868c8f03ff95d3dcee23ad2f1ab3a6c80eaf4b140eb05de3457f0fbc111a6b43d0763aa422a3013cf1dc37fe417d1fbfc449b75d4cc5:00000000000000000000000000000000101112131415161718191a1b1c1d1e1f:3b629ccfbc1119b7319e1dce2cd6fd6d
+
diff --git a/crypto/cipher/derive_key.c b/crypto/cipher/derive_key.c
new file mode 100644
index 0000000..9e1634a
--- /dev/null
+++ b/crypto/cipher/derive_key.c
@@ -0,0 +1,154 @@
+/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
+ * All rights reserved.
+ *
+ * This package is an SSL implementation written
+ * by Eric Young (eay@cryptsoft.com).
+ * The implementation was written so as to conform with Netscapes SSL.
+ *
+ * This library is free for commercial and non-commercial use as long as
+ * the following conditions are aheared to. The following conditions
+ * apply to all code found in this distribution, be it the RC4, RSA,
+ * lhash, DES, etc., code; not just the SSL code. The SSL documentation
+ * included with this distribution is covered by the same copyright terms
+ * except that the holder is Tim Hudson (tjh@cryptsoft.com).
+ *
+ * Copyright remains Eric Young's, and as such any Copyright notices in
+ * the code are not to be removed.
+ * If this package is used in a product, Eric Young should be given attribution
+ * as the author of the parts of the library used.
+ * This can be in the form of a textual message at program startup or
+ * in documentation (online or textual) provided with the package.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * "This product includes cryptographic software written by
+ * Eric Young (eay@cryptsoft.com)"
+ * The word 'cryptographic' can be left out if the rouines from the library
+ * being used are not cryptographic related :-).
+ * 4. If you include any Windows specific code (or a derivative thereof) from
+ * the apps directory (application code) you must include an acknowledgement:
+ * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
+ *
+ * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * The licence and distribution terms for any publically available version or
+ * derivative of this code cannot be changed. i.e. this code cannot simply be
+ * copied and put under another distribution licence
+ * [including the GNU Public Licence.] */
+
+#include <openssl/cipher.h>
+
+#include <assert.h>
+
+#include <openssl/digest.h>
+#include <openssl/mem.h>
+
+#include "internal.h"
+
+
+#define PKCS5_SALT_LEN 8
+
+int EVP_BytesToKey(const EVP_CIPHER *type, const EVP_MD *md,
+ const uint8_t *salt, const uint8_t *data, size_t data_len,
+ unsigned count, uint8_t *key, uint8_t *iv) {
+ EVP_MD_CTX c;
+ uint8_t md_buf[EVP_MAX_MD_SIZE];
+ unsigned niv, nkey, addmd = 0;
+ unsigned mds = 0, i;
+ int rv = 0;
+
+ nkey = type->key_len;
+ niv = type->iv_len;
+
+ assert(nkey <= EVP_MAX_KEY_LENGTH);
+ assert(niv <= EVP_MAX_IV_LENGTH);
+
+ if (data == NULL) {
+ return nkey;
+ }
+
+ EVP_MD_CTX_init(&c);
+ for (;;) {
+ if (!EVP_DigestInit_ex(&c, md, NULL)) {
+ return 0;
+ }
+ if (addmd++) {
+ if (!EVP_DigestUpdate(&c, md_buf, mds)) {
+ goto err;
+ }
+ }
+ if (!EVP_DigestUpdate(&c, data, data_len)) {
+ goto err;
+ }
+ if (salt != NULL) {
+ if (!EVP_DigestUpdate(&c, salt, PKCS5_SALT_LEN)) {
+ goto err;
+ }
+ }
+ if (!EVP_DigestFinal_ex(&c, md_buf, &mds)) {
+ goto err;
+ }
+
+ for (i = 1; i < count; i++) {
+ if (!EVP_DigestInit_ex(&c, md, NULL) ||
+ !EVP_DigestUpdate(&c, md_buf, mds) ||
+ !EVP_DigestFinal_ex(&c, md_buf, &mds)) {
+ goto err;
+ }
+ }
+
+ i = 0;
+ if (nkey) {
+ for (;;) {
+ if (nkey == 0 || i == mds) {
+ break;
+ }
+ if (key != NULL) {
+ *(key++) = md_buf[i];
+ }
+ nkey--;
+ i++;
+ }
+ }
+
+ if (niv && i != mds) {
+ for (;;) {
+ if (niv == 0 || i == mds) {
+ break;
+ }
+ if (iv != NULL) {
+ *(iv++) = md_buf[i];
+ }
+ niv--;
+ i++;
+ }
+ }
+ if (nkey == 0 && niv == 0) {
+ break;
+ }
+ }
+ rv = type->key_len;
+
+err:
+ EVP_MD_CTX_cleanup(&c);
+ OPENSSL_cleanse(md_buf, EVP_MAX_MD_SIZE);
+ return rv;
+}
diff --git a/crypto/cipher/e_aes.c b/crypto/cipher/e_aes.c
new file mode 100644
index 0000000..c22e306
--- /dev/null
+++ b/crypto/cipher/e_aes.c
@@ -0,0 +1,915 @@
+/* ====================================================================
+ * Copyright (c) 2001-2011 The OpenSSL Project. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * 3. All advertising materials mentioning features or use of this
+ * software must display the following acknowledgment:
+ * "This product includes software developed by the OpenSSL Project
+ * for use in the OpenSSL Toolkit. (http://www.openssl.org/)"
+ *
+ * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
+ * endorse or promote products derived from this software without
+ * prior written permission. For written permission, please contact
+ * openssl-core@openssl.org.
+ *
+ * 5. Products derived from this software may not be called "OpenSSL"
+ * nor may "OpenSSL" appear in their names without prior written
+ * permission of the OpenSSL Project.
+ *
+ * 6. Redistributions of any form whatsoever must retain the following
+ * acknowledgment:
+ * "This product includes software developed by the OpenSSL Project
+ * for use in the OpenSSL Toolkit (http://www.openssl.org/)"
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
+ * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR
+ * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ * ==================================================================== */
+
+#include <openssl/aes.h>
+#include <openssl/cipher.h>
+#include <openssl/cpu.h>
+#include <openssl/err.h>
+#include <openssl/mem.h>
+#include <openssl/modes.h>
+#include <openssl/rand.h>
+#include <openssl/obj.h>
+
+#include "internal.h"
+#include "../modes/internal.h"
+
+
+typedef struct {
+ union {
+ double align;
+ AES_KEY ks;
+ } ks;
+ block128_f block;
+ union {
+ cbc128_f cbc;
+ ctr128_f ctr;
+ } stream;
+} EVP_AES_KEY;
+
+typedef struct {
+ union {
+ double align;
+ AES_KEY ks;
+ } ks; /* AES key schedule to use */
+ int key_set; /* Set if key initialised */
+ int iv_set; /* Set if an iv is set */
+ GCM128_CONTEXT gcm;
+ uint8_t *iv; /* Temporary IV store */
+ int ivlen; /* IV length */
+ int taglen;
+ int iv_gen; /* It is OK to generate IVs */
+ int tls_aad_len; /* TLS AAD length */
+ ctr128_f ctr;
+} EVP_AES_GCM_CTX;
+
+
+void AES_ctr32_encrypt(const uint8_t *in, uint8_t *out, size_t blocks,
+ const AES_KEY *key, const uint8_t ivec[AES_BLOCK_SIZE]);
+
+
+#if !defined(OPENSSL_NO_ASM) && \
+ (defined(OPENSSL_X86_64) || defined(OPENSSL_X86))
+#define VPAES
+extern unsigned int OPENSSL_ia32cap_P[];
+
+static char vpaes_capable() {
+ return (OPENSSL_ia32cap_P[1] & (1 << (41 - 32))) != 0;
+}
+
+#if defined(OPENSSL_X86_64)
+#define BSAES
+static char bsaes_capable() {
+ return vpaes_capable();
+}
+#endif
+
+#elif !defined(OPENSSL_NO_ASM) && defined(OPENSSL_ARM)
+#include "../arm_arch.h"
+#if __ARM_ARCH__ >= 7
+#define BSAES
+static char bsaes_capable() {
+ return CRYPTO_is_NEON_capable();
+}
+#endif /* __ARM_ARCH__ >= 7 */
+#endif /* OPENSSL_ARM */
+
+#if defined(BSAES)
+/* On platforms where BSAES gets defined (just above), then these functions are
+ * provided by asm. */
+void bsaes_cbc_encrypt(const uint8_t *in, uint8_t *out, size_t length,
+ const AES_KEY *key, uint8_t ivec[16], int enc);
+void bsaes_ctr32_encrypt_blocks(const uint8_t *in, uint8_t *out, size_t len,
+ const AES_KEY *key, const uint8_t ivec[16]);
+#else
+static char bsaes_capable() {
+ return 0;
+}
+
+/* On other platforms, bsaes_capable() will always return false and so the
+ * following will never be called. */
+void bsaes_cbc_encrypt(const uint8_t *in, uint8_t *out, size_t length,
+ const AES_KEY *key, uint8_t ivec[16], int enc) {
+ abort();
+}
+
+void bsaes_ctr32_encrypt_blocks(const uint8_t *in, uint8_t *out, size_t len,
+ const AES_KEY *key, const uint8_t ivec[16]) {
+ abort();
+}
+#endif
+
+#if defined(VPAES)
+/* On platforms where BSAES gets defined (just above), then these functions are
+ * provided by asm. */
+int vpaes_set_encrypt_key(const uint8_t *userKey, int bits, AES_KEY *key);
+int vpaes_set_decrypt_key(const uint8_t *userKey, int bits, AES_KEY *key);
+
+void vpaes_encrypt(const uint8_t *in, uint8_t *out, const AES_KEY *key);
+void vpaes_decrypt(const uint8_t *in, uint8_t *out, const AES_KEY *key);
+
+void vpaes_cbc_encrypt(const uint8_t *in, uint8_t *out, size_t length,
+ const AES_KEY *key, uint8_t *ivec, int enc);
+#else
+static char vpaes_capable() {
+ return 0;
+}
+
+/* On other platforms, vpaes_capable() will always return false and so the
+ * following will never be called. */
+int vpaes_set_encrypt_key(const uint8_t *userKey, int bits, AES_KEY *key) {
+ abort();
+}
+int vpaes_set_decrypt_key(const uint8_t *userKey, int bits, AES_KEY *key) {
+ abort();
+}
+void vpaes_encrypt(const uint8_t *in, uint8_t *out, const AES_KEY *key) {
+ abort();
+}
+void vpaes_decrypt(const uint8_t *in, uint8_t *out, const AES_KEY *key) {
+ abort();
+}
+void vpaes_cbc_encrypt(const uint8_t *in, uint8_t *out, size_t length,
+ const AES_KEY *key, uint8_t *ivec, int enc) {
+ abort();
+}
+#endif
+
+#if !defined(OPENSSL_NO_ASM) && \
+ (defined(OPENSSL_X86_64) || defined(OPENSSL_X86))
+int aesni_set_encrypt_key(const uint8_t *userKey, int bits, AES_KEY *key);
+int aesni_set_decrypt_key(const uint8_t *userKey, int bits, AES_KEY *key);
+
+void aesni_encrypt(const uint8_t *in, uint8_t *out, const AES_KEY *key);
+void aesni_decrypt(const uint8_t *in, uint8_t *out, const AES_KEY *key);
+
+void aesni_ecb_encrypt(const uint8_t *in, uint8_t *out, size_t length,
+ const AES_KEY *key, int enc);
+void aesni_cbc_encrypt(const uint8_t *in, uint8_t *out, size_t length,
+ const AES_KEY *key, uint8_t *ivec, int enc);
+
+void aesni_ctr32_encrypt_blocks(const uint8_t *in, uint8_t *out, size_t blocks,
+ const void *key, const uint8_t *ivec);
+
+#if defined(OPENSSL_X86_64)
+size_t aesni_gcm_encrypt(const uint8_t *in, uint8_t *out, size_t len,
+ const void *key, uint8_t ivec[16], uint64_t *Xi);
+#define AES_gcm_encrypt aesni_gcm_encrypt
+size_t aesni_gcm_decrypt(const uint8_t *in, uint8_t *out, size_t len,
+ const void *key, uint8_t ivec[16], uint64_t *Xi);
+#define AES_gcm_decrypt aesni_gcm_decrypt
+void gcm_ghash_avx(uint64_t Xi[2], const u128 Htable[16], const uint8_t *in,
+ size_t len);
+#define AES_GCM_ASM(gctx) \
+ (gctx->ctr == aesni_ctr32_encrypt_blocks && gctx->gcm.ghash == gcm_ghash_avx)
+#endif
+
+#else
+
+/* On other platforms, aesni_capable() will always return false and so the
+ * following will never be called. */
+void aesni_encrypt(const uint8_t *in, uint8_t *out, const AES_KEY *key) {
+ abort();
+}
+int aesni_set_encrypt_key(const uint8_t *userKey, int bits, AES_KEY *key) {
+ abort();
+}
+void aesni_ctr32_encrypt_blocks(const uint8_t *in, uint8_t *out, size_t blocks,
+ const void *key, const uint8_t *ivec) {
+ abort();
+}
+
+#endif
+
+static int aes_init_key(EVP_CIPHER_CTX *ctx, const uint8_t *key,
+ const uint8_t *iv, int enc) {
+ int ret, mode;
+ EVP_AES_KEY *dat = (EVP_AES_KEY *)ctx->cipher_data;
+
+ mode = ctx->cipher->flags & EVP_CIPH_MODE_MASK;
+ if ((mode == EVP_CIPH_ECB_MODE || mode == EVP_CIPH_CBC_MODE) && !enc) {
+ if (bsaes_capable() && mode == EVP_CIPH_CBC_MODE) {
+ ret = AES_set_decrypt_key(key, ctx->key_len * 8, &dat->ks.ks);
+ dat->block = (block128_f)AES_decrypt;
+ dat->stream.cbc = (cbc128_f)bsaes_cbc_encrypt;
+ } else if (vpaes_capable()) {
+ ret = vpaes_set_decrypt_key(key, ctx->key_len * 8, &dat->ks.ks);
+ dat->block = (block128_f)vpaes_decrypt;
+ dat->stream.cbc =
+ mode == EVP_CIPH_CBC_MODE ? (cbc128_f)vpaes_cbc_encrypt : NULL;
+ } else {
+ ret = AES_set_decrypt_key(key, ctx->key_len * 8, &dat->ks.ks);
+ dat->block = (block128_f)AES_decrypt;
+ dat->stream.cbc =
+ mode == EVP_CIPH_CBC_MODE ? (cbc128_f)AES_cbc_encrypt : NULL;
+ }
+ } else if (bsaes_capable() && mode == EVP_CIPH_CTR_MODE) {
+ ret = AES_set_encrypt_key(key, ctx->key_len * 8, &dat->ks.ks);
+ dat->block = (block128_f)AES_encrypt;
+ dat->stream.ctr = (ctr128_f)bsaes_ctr32_encrypt_blocks;
+ } else if (vpaes_capable()) {
+ ret = vpaes_set_encrypt_key(key, ctx->key_len * 8, &dat->ks.ks);
+ dat->block = (block128_f)vpaes_encrypt;
+ dat->stream.cbc =
+ mode == EVP_CIPH_CBC_MODE ? (cbc128_f)vpaes_cbc_encrypt : NULL;
+ } else {
+ ret = AES_set_encrypt_key(key, ctx->key_len * 8, &dat->ks.ks);
+ dat->block = (block128_f)AES_encrypt;
+ dat->stream.cbc =
+ mode == EVP_CIPH_CBC_MODE ? (cbc128_f)AES_cbc_encrypt : NULL;
+ }
+
+ if (ret < 0) {
+ OPENSSL_PUT_ERROR(CIPHER, aes_init_key, CIPHER_R_AES_KEY_SETUP_FAILED);
+ return 0;
+ }
+
+ return 1;
+}
+
+static int aes_cbc_cipher(EVP_CIPHER_CTX *ctx, unsigned char *out,
+ const unsigned char *in, size_t len) {
+ EVP_AES_KEY *dat = (EVP_AES_KEY *)ctx->cipher_data;
+
+ if (dat->stream.cbc) {
+ (*dat->stream.cbc)(in, out, len, &dat->ks, ctx->iv, ctx->encrypt);
+ } else if (ctx->encrypt) {
+ CRYPTO_cbc128_encrypt(in, out, len, &dat->ks, ctx->iv, dat->block);
+ } else {
+ CRYPTO_cbc128_decrypt(in, out, len, &dat->ks, ctx->iv, dat->block);
+ }
+
+ return 1;
+}
+
+static int aes_ecb_cipher(EVP_CIPHER_CTX *ctx, unsigned char *out,
+ const unsigned char *in, size_t len) {
+ size_t bl = ctx->cipher->block_size;
+ size_t i;
+ EVP_AES_KEY *dat = (EVP_AES_KEY *)ctx->cipher_data;
+
+ if (len < bl) {
+ return 1;
+ }
+
+ for (i = 0, len -= bl; i <= len; i += bl) {
+ (*dat->block)(in + i, out + i, &dat->ks);
+ }
+
+ return 1;
+}
+
+static int aes_ctr_cipher(EVP_CIPHER_CTX *ctx, unsigned char *out,
+ const unsigned char *in, size_t len) {
+ unsigned int num = ctx->num;
+ EVP_AES_KEY *dat = (EVP_AES_KEY *)ctx->cipher_data;
+
+ if (dat->stream.ctr) {
+ CRYPTO_ctr128_encrypt_ctr32(in, out, len, &dat->ks, ctx->iv, ctx->buf, &num,
+ dat->stream.ctr);
+ } else {
+ CRYPTO_ctr128_encrypt(in, out, len, &dat->ks, ctx->iv, ctx->buf, &num,
+ dat->block);
+ }
+ ctx->num = (size_t)num;
+ return 1;
+}
+
+static int aes_gcm_init_key(EVP_CIPHER_CTX *ctx, const uint8_t *key,
+ const uint8_t *iv, int enc) {
+ EVP_AES_GCM_CTX *gctx = ctx->cipher_data;
+ if (!iv && !key) {
+ return 1;
+ }
+
+ if (key) {
+ if (bsaes_capable()) {
+ AES_set_encrypt_key(key, ctx->key_len * 8, &gctx->ks.ks);
+ CRYPTO_gcm128_init(&gctx->gcm, &gctx->ks, (block128_f)AES_encrypt);
+ gctx->ctr = (ctr128_f)bsaes_ctr32_encrypt_blocks;
+ } else if (vpaes_capable()) {
+ vpaes_set_encrypt_key(key, ctx->key_len * 8, &gctx->ks.ks);
+ CRYPTO_gcm128_init(&gctx->gcm, &gctx->ks, (block128_f)vpaes_encrypt);
+ gctx->ctr = NULL;
+ } else {
+ AES_set_encrypt_key(key, ctx->key_len * 8, &gctx->ks.ks);
+ CRYPTO_gcm128_init(&gctx->gcm, &gctx->ks, (block128_f)AES_encrypt);
+ gctx->ctr = NULL;
+ }
+
+ /* If we have an iv can set it directly, otherwise use
+ * saved IV. */
+ if (iv == NULL && gctx->iv_set) {
+ iv = gctx->iv;
+ }
+ if (iv) {
+ CRYPTO_gcm128_setiv(&gctx->gcm, iv, gctx->ivlen);
+ gctx->iv_set = 1;
+ }
+ gctx->key_set = 1;
+ } else {
+ /* If key set use IV, otherwise copy */
+ if (gctx->key_set) {
+ CRYPTO_gcm128_setiv(&gctx->gcm, iv, gctx->ivlen);
+ } else {
+ memcpy(gctx->iv, iv, gctx->ivlen);
+ }
+ gctx->iv_set = 1;
+ gctx->iv_gen = 0;
+ }
+ return 1;
+}
+
+static int aes_gcm_cleanup(EVP_CIPHER_CTX *c) {
+ EVP_AES_GCM_CTX *gctx = c->cipher_data;
+ OPENSSL_cleanse(&gctx->gcm, sizeof(gctx->gcm));
+ if (gctx->iv != c->iv) {
+ OPENSSL_free(gctx->iv);
+ }
+ return 1;
+}
+
+/* increment counter (64-bit int) by 1 */
+static void ctr64_inc(uint8_t *counter) {
+ int n = 8;
+ uint8_t c;
+
+ do {
+ --n;
+ c = counter[n];
+ ++c;
+ counter[n] = c;
+ if (c) {
+ return;
+ }
+ } while (n);
+}
+
+static int aes_gcm_ctrl(EVP_CIPHER_CTX *c, int type, int arg, void *ptr) {
+ EVP_AES_GCM_CTX *gctx = c->cipher_data;
+ switch (type) {
+ case EVP_CTRL_INIT:
+ gctx->key_set = 0;
+ gctx->iv_set = 0;
+ gctx->ivlen = c->cipher->iv_len;
+ gctx->iv = c->iv;
+ gctx->taglen = -1;
+ gctx->iv_gen = 0;
+ gctx->tls_aad_len = -1;
+ return 1;
+
+ case EVP_CTRL_GCM_SET_IVLEN:
+ if (arg <= 0) {
+ return 0;
+ }
+
+ /* Allocate memory for IV if needed */
+ if (arg > EVP_MAX_IV_LENGTH && arg > gctx->ivlen) {
+ if (gctx->iv != c->iv) {
+ OPENSSL_free(gctx->iv);
+ }
+ gctx->iv = OPENSSL_malloc(arg);
+ if (!gctx->iv) {
+ return 0;
+ }
+ }
+ gctx->ivlen = arg;
+ return 1;
+
+ case EVP_CTRL_GCM_SET_TAG:
+ if (arg <= 0 || arg > 16 || c->encrypt) {
+ return 0;
+ }
+ memcpy(c->buf, ptr, arg);
+ gctx->taglen = arg;
+ return 1;
+
+ case EVP_CTRL_GCM_GET_TAG:
+ if (arg <= 0 || arg > 16 || !c->encrypt || gctx->taglen < 0) {
+ return 0;
+ }
+ memcpy(ptr, c->buf, arg);
+ return 1;
+
+ case EVP_CTRL_GCM_SET_IV_FIXED:
+ /* Special case: -1 length restores whole IV */
+ if (arg == -1) {
+ memcpy(gctx->iv, ptr, gctx->ivlen);
+ gctx->iv_gen = 1;
+ return 1;
+ }
+ /* Fixed field must be at least 4 bytes and invocation field
+ * at least 8. */
+ if (arg < 4 || (gctx->ivlen - arg) < 8) {
+ return 0;
+ }
+ if (arg) {
+ memcpy(gctx->iv, ptr, arg);
+ }
+ if (c->encrypt &&
+ RAND_pseudo_bytes(gctx->iv + arg, gctx->ivlen - arg) <= 0) {
+ return 0;
+ }
+ gctx->iv_gen = 1;
+ return 1;
+
+ case EVP_CTRL_GCM_IV_GEN:
+ if (gctx->iv_gen == 0 || gctx->key_set == 0) {
+ return 0;
+ }
+ CRYPTO_gcm128_setiv(&gctx->gcm, gctx->iv, gctx->ivlen);
+ if (arg <= 0 || arg > gctx->ivlen) {
+ arg = gctx->ivlen;
+ }
+ memcpy(ptr, gctx->iv + gctx->ivlen - arg, arg);
+ /* Invocation field will be at least 8 bytes in size and
+ * so no need to check wrap around or increment more than
+ * last 8 bytes. */
+ ctr64_inc(gctx->iv + gctx->ivlen - 8);
+ gctx->iv_set = 1;
+ return 1;
+
+ case EVP_CTRL_GCM_SET_IV_INV:
+ if (gctx->iv_gen == 0 || gctx->key_set == 0 || c->encrypt) {
+ return 0;
+ }
+ memcpy(gctx->iv + gctx->ivlen - arg, ptr, arg);
+ CRYPTO_gcm128_setiv(&gctx->gcm, gctx->iv, gctx->ivlen);
+ gctx->iv_set = 1;
+ return 1;
+
+ case EVP_CTRL_AEAD_TLS1_AAD:
+ /* Save the AAD for later use */
+ if (arg != 13) {
+ return 0;
+ }
+ memcpy(c->buf, ptr, arg);
+ gctx->tls_aad_len = arg;
+ {
+ unsigned int len = c->buf[arg - 2] << 8 | c->buf[arg - 1];
+ /* Correct length for explicit IV */
+ len -= EVP_GCM_TLS_EXPLICIT_IV_LEN;
+ /* If decrypting correct for tag too */
+ if (!c->encrypt)
+ len -= EVP_GCM_TLS_TAG_LEN;
+ c->buf[arg - 2] = len >> 8;
+ c->buf[arg - 1] = len & 0xff;
+ }
+
+ /* Extra padding: tag appended to record */
+ return EVP_GCM_TLS_TAG_LEN;
+
+ default:
+ return -1;
+ }
+}
+
+/* Handle TLS GCM packet format. This consists of the last portion of the IV
+ * followed by the payload and finally the tag. On encrypt generate IV, encrypt
+ * payload and write the tag. On verify retrieve IV, decrypt payload and verify
+ * tag. */
+
+static int aes_gcm_tls_cipher(EVP_CIPHER_CTX *ctx, uint8_t *out,
+ const uint8_t *in, size_t len) {
+ EVP_AES_GCM_CTX *gctx = ctx->cipher_data;
+ int rv = -1;
+ /* Encrypt/decrypt must be performed in place */
+ if (out != in || len < (EVP_GCM_TLS_EXPLICIT_IV_LEN + EVP_GCM_TLS_TAG_LEN)) {
+ return -1;
+ }
+ /* Set IV from start of buffer or generate IV and write to start
+ * of buffer.
+ */
+ if (EVP_CIPHER_CTX_ctrl(
+ ctx, ctx->encrypt ? EVP_CTRL_GCM_IV_GEN : EVP_CTRL_GCM_SET_IV_INV,
+ EVP_GCM_TLS_EXPLICIT_IV_LEN, out) <= 0)
+ goto err;
+ /* Use saved AAD */
+ if (!CRYPTO_gcm128_aad(&gctx->gcm, ctx->buf, gctx->tls_aad_len))
+ goto err;
+ /* Fix buffer and length to point to payload */
+ in += EVP_GCM_TLS_EXPLICIT_IV_LEN;
+ out += EVP_GCM_TLS_EXPLICIT_IV_LEN;
+ len -= EVP_GCM_TLS_EXPLICIT_IV_LEN + EVP_GCM_TLS_TAG_LEN;
+ if (ctx->encrypt) {
+ /* Encrypt payload */
+ if (gctx->ctr) {
+ size_t bulk = 0;
+#if defined(AES_GCM_ASM)
+ if (len >= 32 && AES_GCM_ASM(gctx)) {
+ if (!CRYPTO_gcm128_encrypt(&gctx->gcm, NULL, NULL, 0))
+ return -1;
+
+ bulk = AES_gcm_encrypt(in, out, len, gctx->gcm.key, gctx->gcm.Yi.c,
+ gctx->gcm.Xi.u);
+ gctx->gcm.len.u[1] += bulk;
+ }
+#endif
+ if (!CRYPTO_gcm128_encrypt_ctr32(&gctx->gcm, in + bulk, out + bulk,
+ len - bulk, gctx->ctr))
+ goto err;
+ } else {
+ size_t bulk = 0;
+ if (!CRYPTO_gcm128_encrypt(&gctx->gcm, in + bulk, out + bulk, len - bulk))
+ goto err;
+ }
+ out += len;
+ /* Finally write tag */
+ CRYPTO_gcm128_tag(&gctx->gcm, out, EVP_GCM_TLS_TAG_LEN);
+ rv = len + EVP_GCM_TLS_EXPLICIT_IV_LEN + EVP_GCM_TLS_TAG_LEN;
+ } else {
+ /* Decrypt */
+ if (gctx->ctr) {
+ size_t bulk = 0;
+#if defined(AES_GCM_ASM)
+ if (len >= 16 && AES_GCM_ASM(gctx)) {
+ if (!CRYPTO_gcm128_decrypt(&gctx->gcm, NULL, NULL, 0))
+ return -1;
+
+ bulk = AES_gcm_decrypt(in, out, len, gctx->gcm.key, gctx->gcm.Yi.c,
+ gctx->gcm.Xi.u);
+ gctx->gcm.len.u[1] += bulk;
+ }
+#endif
+ if (!CRYPTO_gcm128_decrypt_ctr32(&gctx->gcm, in + bulk, out + bulk,
+ len - bulk, gctx->ctr))
+ goto err;
+ } else {
+ size_t bulk = 0;
+ if (!CRYPTO_gcm128_decrypt(&gctx->gcm, in + bulk, out + bulk, len - bulk))
+ goto err;
+ }
+ /* Retrieve tag */
+ CRYPTO_gcm128_tag(&gctx->gcm, ctx->buf, EVP_GCM_TLS_TAG_LEN);
+ /* If tag mismatch wipe buffer */
+ if (memcmp(ctx->buf, in + len, EVP_GCM_TLS_TAG_LEN)) {
+ OPENSSL_cleanse(out, len);
+ goto err;
+ }
+ rv = len;
+ }
+
+err:
+ gctx->iv_set = 0;
+ gctx->tls_aad_len = -1;
+ return rv;
+}
+
+static int aes_gcm_cipher(EVP_CIPHER_CTX *ctx, uint8_t *out, const uint8_t *in,
+ size_t len) {
+ EVP_AES_GCM_CTX *gctx = ctx->cipher_data;
+ /* If not set up, return error */
+ if (!gctx->key_set)
+ return -1;
+
+ if (gctx->tls_aad_len >= 0)
+ return aes_gcm_tls_cipher(ctx, out, in, len);
+
+ if (!gctx->iv_set)
+ return -1;
+ if (in) {
+ if (out == NULL) {
+ if (!CRYPTO_gcm128_aad(&gctx->gcm, in, len))
+ return -1;
+ } else if (ctx->encrypt) {
+ if (gctx->ctr) {
+ size_t bulk = 0;
+#if defined(AES_GCM_ASM)
+ if (len >= 32 && AES_GCM_ASM(gctx)) {
+ size_t res = (16 - gctx->gcm.mres) % 16;
+
+ if (!CRYPTO_gcm128_encrypt(&gctx->gcm, in, out, res))
+ return -1;
+
+ bulk = AES_gcm_encrypt(in + res, out + res, len - res, gctx->gcm.key,
+ gctx->gcm.Yi.c, gctx->gcm.Xi.u);
+ gctx->gcm.len.u[1] += bulk;
+ bulk += res;
+ }
+#endif
+ if (!CRYPTO_gcm128_encrypt_ctr32(&gctx->gcm, in + bulk, out + bulk,
+ len - bulk, gctx->ctr))
+ return -1;
+ } else {
+ size_t bulk = 0;
+ if (!CRYPTO_gcm128_encrypt(&gctx->gcm, in + bulk, out + bulk,
+ len - bulk))
+ return -1;
+ }
+ } else {
+ if (gctx->ctr) {
+ size_t bulk = 0;
+#if defined(AES_GCM_ASM)
+ if (len >= 16 && AES_GCM_ASM(gctx)) {
+ size_t res = (16 - gctx->gcm.mres) % 16;
+
+ if (!CRYPTO_gcm128_decrypt(&gctx->gcm, in, out, res))
+ return -1;
+
+ bulk = AES_gcm_decrypt(in + res, out + res, len - res, gctx->gcm.key,
+ gctx->gcm.Yi.c, gctx->gcm.Xi.u);
+ gctx->gcm.len.u[1] += bulk;
+ bulk += res;
+ }
+#endif
+ if (!CRYPTO_gcm128_decrypt_ctr32(&gctx->gcm, in + bulk, out + bulk,
+ len - bulk, gctx->ctr))
+ return -1;
+ } else {
+ size_t bulk = 0;
+ if (!CRYPTO_gcm128_decrypt(&gctx->gcm, in + bulk, out + bulk,
+ len - bulk))
+ return -1;
+ }
+ }
+ return len;
+ } else {
+ if (!ctx->encrypt) {
+ if (gctx->taglen < 0)
+ return -1;
+ if (!CRYPTO_gcm128_finish(&gctx->gcm, ctx->buf, gctx->taglen) != 0)
+ return -1;
+ gctx->iv_set = 0;
+ return 0;
+ }
+ CRYPTO_gcm128_tag(&gctx->gcm, ctx->buf, 16);
+ gctx->taglen = 16;
+ /* Don't reuse the IV */
+ gctx->iv_set = 0;
+ return 0;
+ }
+}
+
+static const EVP_CIPHER aes_128_cbc = {
+ NID_aes_128_cbc, 16 /* block_size */, 16 /* key_size */,
+ 16 /* iv_len */, sizeof(EVP_AES_KEY), EVP_CIPH_CBC_MODE,
+ NULL /* app_data */, aes_init_key, aes_cbc_cipher,
+ NULL /* cleanup */, NULL /* ctrl */};
+
+static const EVP_CIPHER aes_128_ctr = {
+ NID_aes_128_ctr, 1 /* block_size */, 16 /* key_size */,
+ 16 /* iv_len */, sizeof(EVP_AES_KEY), EVP_CIPH_CTR_MODE,
+ NULL /* app_data */, aes_init_key, aes_ctr_cipher,
+ NULL /* cleanup */, NULL /* ctrl */};
+
+static const EVP_CIPHER aes_128_ecb = {
+ NID_aes_128_ecb, 16 /* block_size */, 16 /* key_size */,
+ 16 /* iv_len */, sizeof(EVP_AES_KEY), EVP_CIPH_ECB_MODE,
+ NULL /* app_data */, aes_init_key, aes_ecb_cipher,
+ NULL /* cleanup */, NULL /* ctrl */};
+
+static const EVP_CIPHER aes_128_gcm = {
+ NID_aes_128_gcm, 1 /* block_size */, 16 /* key_size */, 12 /* iv_len */,
+ sizeof(EVP_AES_GCM_CTX),
+ EVP_CIPH_GCM_MODE | EVP_CIPH_CUSTOM_IV | EVP_CIPH_FLAG_CUSTOM_CIPHER |
+ EVP_CIPH_ALWAYS_CALL_INIT | EVP_CIPH_CTRL_INIT |
+ EVP_CIPH_FLAG_AEAD_CIPHER,
+ NULL /* app_data */, aes_gcm_init_key, aes_gcm_cipher, aes_gcm_cleanup,
+ aes_gcm_ctrl};
+
+
+static const EVP_CIPHER aes_256_cbc = {
+ NID_aes_128_cbc, 16 /* block_size */, 32 /* key_size */,
+ 16 /* iv_len */, sizeof(EVP_AES_KEY), EVP_CIPH_CBC_MODE,
+ NULL /* app_data */, aes_init_key, aes_cbc_cipher,
+ NULL /* cleanup */, NULL /* ctrl */};
+
+static const EVP_CIPHER aes_256_ctr = {
+ NID_aes_128_ctr, 1 /* block_size */, 32 /* key_size */,
+ 16 /* iv_len */, sizeof(EVP_AES_KEY), EVP_CIPH_CTR_MODE,
+ NULL /* app_data */, aes_init_key, aes_ctr_cipher,
+ NULL /* cleanup */, NULL /* ctrl */};
+
+static const EVP_CIPHER aes_256_ecb = {
+ NID_aes_128_ecb, 16 /* block_size */, 32 /* key_size */,
+ 16 /* iv_len */, sizeof(EVP_AES_KEY), EVP_CIPH_ECB_MODE,
+ NULL /* app_data */, aes_init_key, aes_ecb_cipher,
+ NULL /* cleanup */, NULL /* ctrl */};
+
+static const EVP_CIPHER aes_256_gcm = {
+ NID_aes_128_gcm, 1 /* block_size */, 32 /* key_size */, 12 /* iv_len */,
+ sizeof(EVP_AES_GCM_CTX),
+ EVP_CIPH_GCM_MODE | EVP_CIPH_CUSTOM_IV | EVP_CIPH_FLAG_CUSTOM_CIPHER |
+ EVP_CIPH_ALWAYS_CALL_INIT | EVP_CIPH_CTRL_INIT |
+ EVP_CIPH_FLAG_AEAD_CIPHER,
+ NULL /* app_data */, aes_gcm_init_key, aes_gcm_cipher, aes_gcm_cleanup,
+ aes_gcm_ctrl};
+
+#if !defined(OPENSSL_NO_ASM) && \
+ (defined(OPENSSL_X86_64) || defined(OPENSSL_X86))
+
+/* AES-NI section. */
+
+static char aesni_capable() {
+ return (OPENSSL_ia32cap_P[1] & (1 << (57 - 32))) != 0;
+}
+
+static int aesni_init_key(EVP_CIPHER_CTX *ctx, const uint8_t *key,
+ const uint8_t *iv, int enc) {
+ int ret, mode;
+ EVP_AES_KEY *dat = (EVP_AES_KEY *)ctx->cipher_data;
+
+ mode = ctx->cipher->flags & EVP_CIPH_MODE_MASK;
+ if ((mode == EVP_CIPH_ECB_MODE || mode == EVP_CIPH_CBC_MODE) && !enc) {
+ ret = aesni_set_decrypt_key(key, ctx->key_len * 8, ctx->cipher_data);
+ dat->block = (block128_f)aesni_decrypt;
+ dat->stream.cbc =
+ mode == EVP_CIPH_CBC_MODE ? (cbc128_f)aesni_cbc_encrypt : NULL;
+ } else {
+ ret = aesni_set_encrypt_key(key, ctx->key_len * 8, ctx->cipher_data);
+ dat->block = (block128_f)aesni_encrypt;
+ if (mode == EVP_CIPH_CBC_MODE) {
+ dat->stream.cbc = (cbc128_f)aesni_cbc_encrypt;
+ } else if (mode == EVP_CIPH_CTR_MODE) {
+ dat->stream.ctr = (ctr128_f)aesni_ctr32_encrypt_blocks;
+ } else {
+ dat->stream.cbc = NULL;
+ }
+ }
+
+ if (ret < 0) {
+ OPENSSL_PUT_ERROR(CIPHER, aesni_init_key, CIPHER_R_AES_KEY_SETUP_FAILED);
+ return 0;
+ }
+
+ return 1;
+}
+
+static int aesni_cbc_cipher(EVP_CIPHER_CTX *ctx, uint8_t *out,
+ const uint8_t *in, size_t len) {
+ aesni_cbc_encrypt(in, out, len, ctx->cipher_data, ctx->iv, ctx->encrypt);
+
+ return 1;
+}
+
+static int aesni_ecb_cipher(EVP_CIPHER_CTX *ctx, uint8_t *out,
+ const uint8_t *in, size_t len) {
+ size_t bl = ctx->cipher->block_size;
+
+ if (len < bl) {
+ return 1;
+ }
+
+ aesni_ecb_encrypt(in, out, len, ctx->cipher_data, ctx->encrypt);
+
+ return 1;
+}
+
+static int aesni_gcm_init_key(EVP_CIPHER_CTX *ctx, const uint8_t *key,
+ const uint8_t *iv, int enc) {
+ EVP_AES_GCM_CTX *gctx = ctx->cipher_data;
+ if (!iv && !key)
+ return 1;
+ if (key) {
+ aesni_set_encrypt_key(key, ctx->key_len * 8, &gctx->ks.ks);
+ CRYPTO_gcm128_init(&gctx->gcm, &gctx->ks, (block128_f)aesni_encrypt);
+ gctx->ctr = (ctr128_f)aesni_ctr32_encrypt_blocks;
+ /* If we have an iv can set it directly, otherwise use
+ * saved IV. */
+ if (iv == NULL && gctx->iv_set) {
+ iv = gctx->iv;
+ }
+ if (iv) {
+ CRYPTO_gcm128_setiv(&gctx->gcm, iv, gctx->ivlen);
+ gctx->iv_set = 1;
+ }
+ gctx->key_set = 1;
+ } else {
+ /* If key set use IV, otherwise copy */
+ if (gctx->key_set) {
+ CRYPTO_gcm128_setiv(&gctx->gcm, iv, gctx->ivlen);
+ } else {
+ memcpy(gctx->iv, iv, gctx->ivlen);
+ }
+ gctx->iv_set = 1;
+ gctx->iv_gen = 0;
+ }
+ return 1;
+}
+
+static const EVP_CIPHER aesni_128_cbc = {
+ NID_aes_128_cbc, 16 /* block_size */, 16 /* key_size */,
+ 16 /* iv_len */, sizeof(EVP_AES_KEY), EVP_CIPH_CBC_MODE,
+ NULL /* app_data */, aesni_init_key, aesni_cbc_cipher,
+ NULL /* cleanup */, NULL /* ctrl */};
+
+static const EVP_CIPHER aesni_128_ctr = {
+ NID_aes_128_ctr, 1 /* block_size */, 16 /* key_size */,
+ 16 /* iv_len */, sizeof(EVP_AES_KEY), EVP_CIPH_CTR_MODE,
+ NULL /* app_data */, aesni_init_key, aes_ctr_cipher,
+ NULL /* cleanup */, NULL /* ctrl */};
+
+static const EVP_CIPHER aesni_128_ecb = {
+ NID_aes_128_ecb, 16 /* block_size */, 16 /* key_size */,
+ 16 /* iv_len */, sizeof(EVP_AES_KEY), EVP_CIPH_ECB_MODE,
+ NULL /* app_data */, aesni_init_key, aesni_ecb_cipher,
+ NULL /* cleanup */, NULL /* ctrl */};
+
+static const EVP_CIPHER aesni_128_gcm = {
+ NID_aes_128_gcm, 1 /* block_size */, 16 /* key_size */, 12 /* iv_len */,
+ sizeof(EVP_AES_GCM_CTX),
+ EVP_CIPH_GCM_MODE | EVP_CIPH_CUSTOM_IV | EVP_CIPH_FLAG_CUSTOM_CIPHER |
+ EVP_CIPH_ALWAYS_CALL_INIT | EVP_CIPH_CTRL_INIT |
+ EVP_CIPH_FLAG_AEAD_CIPHER,
+ NULL /* app_data */, aesni_gcm_init_key, aes_gcm_cipher, aes_gcm_cleanup,
+ aes_gcm_ctrl};
+
+
+static const EVP_CIPHER aesni_256_cbc = {
+ NID_aes_128_cbc, 16 /* block_size */, 32 /* key_size */,
+ 16 /* iv_len */, sizeof(EVP_AES_KEY), EVP_CIPH_CBC_MODE,
+ NULL /* app_data */, aesni_init_key, aesni_cbc_cipher,
+ NULL /* cleanup */, NULL /* ctrl */};
+
+static const EVP_CIPHER aesni_256_ctr = {
+ NID_aes_128_ctr, 1 /* block_size */, 32 /* key_size */,
+ 16 /* iv_len */, sizeof(EVP_AES_KEY), EVP_CIPH_CTR_MODE,
+ NULL /* app_data */, aesni_init_key, aes_ctr_cipher,
+ NULL /* cleanup */, NULL /* ctrl */};
+
+static const EVP_CIPHER aesni_256_ecb = {
+ NID_aes_128_ecb, 16 /* block_size */, 32 /* key_size */,
+ 16 /* iv_len */, sizeof(EVP_AES_KEY), EVP_CIPH_ECB_MODE,
+ NULL /* app_data */, aesni_init_key, aesni_ecb_cipher,
+ NULL /* cleanup */, NULL /* ctrl */};
+
+static const EVP_CIPHER aesni_256_gcm = {
+ NID_aes_256_gcm, 1 /* block_size */, 32 /* key_size */, 12 /* iv_len */,
+ sizeof(EVP_AES_GCM_CTX),
+ EVP_CIPH_GCM_MODE | EVP_CIPH_CUSTOM_IV | EVP_CIPH_FLAG_CUSTOM_CIPHER |
+ EVP_CIPH_ALWAYS_CALL_INIT | EVP_CIPH_CTRL_INIT |
+ EVP_CIPH_FLAG_AEAD_CIPHER,
+ NULL /* app_data */, aesni_gcm_init_key, aes_gcm_cipher, aes_gcm_cleanup,
+ aes_gcm_ctrl};
+
+#define EVP_CIPHER_FUNCTION(keybits, mode) \
+ const EVP_CIPHER *EVP_aes_##keybits##_##mode(void) { \
+ if (aesni_capable()) { \
+ return &aesni_##keybits##_##mode; \
+ } else { \
+ return &aes_##keybits##_##mode; \
+ } \
+ }
+
+#else /* ^^^ OPENSSL_X86_64 || OPENSSL_X86 */
+
+#define EVP_CIPHER_FUNCTION(keybits, mode) \
+ const EVP_CIPHER *EVP_aes_##keybits##_##mode(void) { \
+ return &aes_##keybits##_##mode; \
+ }
+
+#endif
+
+EVP_CIPHER_FUNCTION(128, cbc)
+EVP_CIPHER_FUNCTION(128, ctr)
+EVP_CIPHER_FUNCTION(128, ecb)
+EVP_CIPHER_FUNCTION(128, gcm)
+
+EVP_CIPHER_FUNCTION(256, cbc)
+EVP_CIPHER_FUNCTION(256, ctr)
+EVP_CIPHER_FUNCTION(256, ecb)
+EVP_CIPHER_FUNCTION(256, gcm)
diff --git a/crypto/cipher/e_des.c b/crypto/cipher/e_des.c
new file mode 100644
index 0000000..d4b04f4
--- /dev/null
+++ b/crypto/cipher/e_des.c
@@ -0,0 +1,157 @@
+/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
+ * All rights reserved.
+ *
+ * This package is an SSL implementation written
+ * by Eric Young (eay@cryptsoft.com).
+ * The implementation was written so as to conform with Netscapes SSL.
+ *
+ * This library is free for commercial and non-commercial use as long as
+ * the following conditions are aheared to. The following conditions
+ * apply to all code found in this distribution, be it the RC4, RSA,
+ * lhash, DES, etc., code; not just the SSL code. The SSL documentation
+ * included with this distribution is covered by the same copyright terms
+ * except that the holder is Tim Hudson (tjh@cryptsoft.com).
+ *
+ * Copyright remains Eric Young's, and as such any Copyright notices in
+ * the code are not to be removed.
+ * If this package is used in a product, Eric Young should be given attribution
+ * as the author of the parts of the library used.
+ * This can be in the form of a textual message at program startup or
+ * in documentation (online or textual) provided with the package.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * "This product includes cryptographic software written by
+ * Eric Young (eay@cryptsoft.com)"
+ * The word 'cryptographic' can be left out if the rouines from the library
+ * being used are not cryptographic related :-).
+ * 4. If you include any Windows specific code (or a derivative thereof) from
+ * the apps directory (application code) you must include an acknowledgement:
+ * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
+ *
+ * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * The licence and distribution terms for any publically available version or
+ * derivative of this code cannot be changed. i.e. this code cannot simply be
+ * copied and put under another distribution licence
+ * [including the GNU Public Licence.] */
+
+#include <openssl/cipher.h>
+#include <openssl/des.h>
+#include <openssl/obj.h>
+
+#include "internal.h"
+
+
+#define EVP_MAXCHUNK (1<<30)
+
+typedef struct {
+ union {
+ double align;
+ DES_key_schedule ks;
+ } ks;
+} EVP_DES_KEY;
+
+static int des_init_key(EVP_CIPHER_CTX *ctx, const uint8_t *key,
+ const uint8_t *iv, int enc) {
+ DES_cblock *deskey = (DES_cblock *)key;
+ EVP_DES_KEY *dat = (EVP_DES_KEY *)ctx->cipher_data;
+
+ DES_set_key(deskey, &dat->ks.ks);
+ return 1;
+}
+
+static int des_cbc_cipher(EVP_CIPHER_CTX *ctx, uint8_t *out, const uint8_t *in,
+ size_t in_len) {
+ EVP_DES_KEY *dat = (EVP_DES_KEY *)ctx->cipher_data;
+
+ while (in_len >= EVP_MAXCHUNK) {
+ DES_ncbc_encrypt(in, out, EVP_MAXCHUNK, &dat->ks.ks, (DES_cblock *)ctx->iv,
+ ctx->encrypt);
+ in_len -= EVP_MAXCHUNK;
+ in += EVP_MAXCHUNK;
+ out += EVP_MAXCHUNK;
+ }
+
+ if (in_len) {
+ DES_ncbc_encrypt(in, out, (long)in_len, &dat->ks.ks,
+ (DES_cblock *)ctx->iv, ctx->encrypt);
+ }
+
+ return 1;
+}
+
+static const EVP_CIPHER des_cbc = {
+ NID_des_cbc, 8 /* block_size */, 8 /* key_size */,
+ 8 /* iv_len */, sizeof(EVP_DES_KEY), EVP_CIPH_CBC_MODE,
+ NULL /* app_data */, des_init_key, des_cbc_cipher,
+ NULL /* cleanup */, NULL /* ctrl */, };
+
+const EVP_CIPHER *EVP_des_cbc(void) { return &des_cbc; }
+
+
+typedef struct {
+ union {
+ double align;
+ DES_key_schedule ks[3];
+ } ks;
+} DES_EDE_KEY;
+
+
+static int des_ede3_init_key(EVP_CIPHER_CTX *ctx, const uint8_t *key,
+ const uint8_t *iv, int enc) {
+ DES_cblock *deskey = (DES_cblock *)key;
+ DES_EDE_KEY *dat = (DES_EDE_KEY*) ctx->cipher_data;
+
+ DES_set_key(&deskey[0], &dat->ks.ks[0]);
+ DES_set_key(&deskey[1], &dat->ks.ks[1]);
+ DES_set_key(&deskey[2], &dat->ks.ks[2]);
+
+ return 1;
+}
+
+static int des_ede3_cbc_cipher(EVP_CIPHER_CTX *ctx, uint8_t *out,
+ const uint8_t *in, size_t in_len) {
+ DES_EDE_KEY *dat = (DES_EDE_KEY*) ctx->cipher_data;
+
+ while (in_len >= EVP_MAXCHUNK) {
+ DES_ede3_cbc_encrypt(in, out, EVP_MAXCHUNK, &dat->ks.ks[0], &dat->ks.ks[1],
+ &dat->ks.ks[2], (DES_cblock *)ctx->iv, ctx->encrypt);
+ in_len -= EVP_MAXCHUNK;
+ in += EVP_MAXCHUNK;
+ out += EVP_MAXCHUNK;
+ }
+
+ if (in_len) {
+ DES_ede3_cbc_encrypt(in, out, in_len, &dat->ks.ks[0], &dat->ks.ks[1],
+ &dat->ks.ks[2], (DES_cblock *)ctx->iv, ctx->encrypt);
+ }
+
+ return 1;
+}
+
+static const EVP_CIPHER des3_cbc = {
+ NID_des_cbc, 8 /* block_size */, 24 /* key_size */,
+ 8 /* iv_len */, sizeof(DES_EDE_KEY), EVP_CIPH_CBC_MODE,
+ NULL /* app_data */, des_ede3_init_key, des_ede3_cbc_cipher,
+ NULL /* cleanup */, NULL /* ctrl */, };
+
+const EVP_CIPHER *EVP_des_ede3_cbc(void) { return &des3_cbc; }
diff --git a/crypto/cipher/e_null.c b/crypto/cipher/e_null.c
new file mode 100644
index 0000000..196520d
--- /dev/null
+++ b/crypto/cipher/e_null.c
@@ -0,0 +1,83 @@
+/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
+ * All rights reserved.
+ *
+ * This package is an SSL implementation written
+ * by Eric Young (eay@cryptsoft.com).
+ * The implementation was written so as to conform with Netscapes SSL.
+ *
+ * This library is free for commercial and non-commercial use as long as
+ * the following conditions are aheared to. The following conditions
+ * apply to all code found in this distribution, be it the RC4, RSA,
+ * lhash, DES, etc., code; not just the SSL code. The SSL documentation
+ * included with this distribution is covered by the same copyright terms
+ * except that the holder is Tim Hudson (tjh@cryptsoft.com).
+ *
+ * Copyright remains Eric Young's, and as such any Copyright notices in
+ * the code are not to be removed.
+ * If this package is used in a product, Eric Young should be given attribution
+ * as the author of the parts of the library used.
+ * This can be in the form of a textual message at program startup or
+ * in documentation (online or textual) provided with the package.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * "This product includes cryptographic software written by
+ * Eric Young (eay@cryptsoft.com)"
+ * The word 'cryptographic' can be left out if the rouines from the library
+ * being used are not cryptographic related :-).
+ * 4. If you include any Windows specific code (or a derivative thereof) from
+ * the apps directory (application code) you must include an acknowledgement:
+ * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
+ *
+ * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * The licence and distribution terms for any publically available version or
+ * derivative of this code cannot be changed. i.e. this code cannot simply be
+ * copied and put under another distribution licence
+ * [including the GNU Public Licence.] */
+
+#include <openssl/cipher.h>
+
+#include <openssl/obj.h>
+
+#include "internal.h"
+
+
+static int null_init_key(EVP_CIPHER_CTX *ctx, const uint8_t *key,
+ const uint8_t *iv, int enc) {
+ return 1;
+}
+
+static int null_cipher(EVP_CIPHER_CTX *ctx, uint8_t *out,
+ const uint8_t *in, size_t in_len) {
+ if (in != out) {
+ memcpy(out, in, in_len);
+ }
+ return 1;
+}
+
+static const EVP_CIPHER n_cipher = {
+ NID_undef, 1 /* block size */, 0 /* key_len */, 0 /* iv_len */,
+ 0 /* ctx_size */, 0 /* flags */, NULL /* app_data */, null_init_key,
+ null_cipher, NULL /* cleanup */, NULL /* ctrl */,
+};
+
+const EVP_CIPHER *EVP_enc_null(void) { return &n_cipher; }
diff --git a/crypto/cipher/e_rc4.c b/crypto/cipher/e_rc4.c
new file mode 100644
index 0000000..840855a
--- /dev/null
+++ b/crypto/cipher/e_rc4.c
@@ -0,0 +1,87 @@
+/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
+ * All rights reserved.
+ *
+ * This package is an SSL implementation written
+ * by Eric Young (eay@cryptsoft.com).
+ * The implementation was written so as to conform with Netscapes SSL.
+ *
+ * This library is free for commercial and non-commercial use as long as
+ * the following conditions are aheared to. The following conditions
+ * apply to all code found in this distribution, be it the RC4, RSA,
+ * lhash, DES, etc., code; not just the SSL code. The SSL documentation
+ * included with this distribution is covered by the same copyright terms
+ * except that the holder is Tim Hudson (tjh@cryptsoft.com).
+ *
+ * Copyright remains Eric Young's, and as such any Copyright notices in
+ * the code are not to be removed.
+ * If this package is used in a product, Eric Young should be given attribution
+ * as the author of the parts of the library used.
+ * This can be in the form of a textual message at program startup or
+ * in documentation (online or textual) provided with the package.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * "This product includes cryptographic software written by
+ * Eric Young (eay@cryptsoft.com)"
+ * The word 'cryptographic' can be left out if the rouines from the library
+ * being used are not cryptographic related :-).
+ * 4. If you include any Windows specific code (or a derivative thereof) from
+ * the apps directory (application code) you must include an acknowledgement:
+ * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
+ *
+ * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * The licence and distribution terms for any publically available version or
+ * derivative of this code cannot be changed. i.e. this code cannot simply be
+ * copied and put under another distribution licence
+ * [including the GNU Public Licence.] */
+
+#include <openssl/cipher.h>
+#include <openssl/md5.h>
+#include <openssl/obj.h>
+#include <openssl/rc4.h>
+
+#include "internal.h"
+
+
+static int rc4_init_key(EVP_CIPHER_CTX *ctx, const uint8_t *key,
+ const uint8_t *iv, int enc) {
+ RC4_KEY *rc4key = (RC4_KEY *)ctx->cipher_data;
+
+ RC4_set_key(rc4key, EVP_CIPHER_CTX_key_length(ctx), key);
+ return 1;
+}
+
+static int rc4_cipher(EVP_CIPHER_CTX *ctx, uint8_t *out, const uint8_t *in,
+ size_t in_len) {
+ RC4_KEY *rc4key = (RC4_KEY *)ctx->cipher_data;
+
+ RC4(rc4key, in_len, in, out);
+ return 1;
+}
+
+static const EVP_CIPHER rc4 = {
+ NID_rc4, 1 /* block_size */, 16 /* key_size */,
+ 0 /* iv_len */, sizeof(RC4_KEY), EVP_CIPH_VARIABLE_LENGTH,
+ NULL /* app_data */, rc4_init_key, rc4_cipher,
+ NULL /* cleanup */, NULL /* ctrl */, };
+
+const EVP_CIPHER *EVP_rc4(void) { return &rc4; }
diff --git a/crypto/cipher/internal.h b/crypto/cipher/internal.h
new file mode 100644
index 0000000..1edc059
--- /dev/null
+++ b/crypto/cipher/internal.h
@@ -0,0 +1,113 @@
+/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
+ * All rights reserved.
+ *
+ * This package is an SSL implementation written
+ * by Eric Young (eay@cryptsoft.com).
+ * The implementation was written so as to conform with Netscapes SSL.
+ *
+ * This library is free for commercial and non-commercial use as long as
+ * the following conditions are aheared to. The following conditions
+ * apply to all code found in this distribution, be it the RC4, RSA,
+ * lhash, DES, etc., code; not just the SSL code. The SSL documentation
+ * included with this distribution is covered by the same copyright terms
+ * except that the holder is Tim Hudson (tjh@cryptsoft.com).
+ *
+ * Copyright remains Eric Young's, and as such any Copyright notices in
+ * the code are not to be removed.
+ * If this package is used in a product, Eric Young should be given attribution
+ * as the author of the parts of the library used.
+ * This can be in the form of a textual message at program startup or
+ * in documentation (online or textual) provided with the package.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * "This product includes cryptographic software written by
+ * Eric Young (eay@cryptsoft.com)"
+ * The word 'cryptographic' can be left out if the rouines from the library
+ * being used are not cryptographic related :-).
+ * 4. If you include any Windows specific code (or a derivative thereof) from
+ * the apps directory (application code) you must include an acknowledgement:
+ * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
+ *
+ * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * The licence and distribution terms for any publically available version or
+ * derivative of this code cannot be changed. i.e. this code cannot simply be
+ * copied and put under another distribution licence
+ * [including the GNU Public Licence.] */
+
+#ifndef OPENSSL_HEADER_CIPHER_INTERNAL_H
+#define OPENSSL_HEADER_CIPHER_INTERNAL_H
+
+#include <openssl/base.h>
+
+#include <openssl/asn1t.h>
+
+#if defined(__cplusplus)
+extern "C" {
+#endif
+
+
+struct evp_cipher_st {
+ /* type contains a NID identifing the cipher. (For example, NID_rc4.) */
+ int nid;
+
+ /* block_size contains the block size, in bytes, of the cipher, or 1 for a
+ * stream cipher. */
+ unsigned block_size;
+
+ /* key_len contains the key size, in bytes, for the cipher. If the cipher
+ * takes a variable key size then this contains the default size. */
+ unsigned key_len;
+
+ /* iv_len contains the IV size, in bytes, or zero if inapplicable. */
+ unsigned iv_len;
+
+ /* ctx_size contains the size, in bytes, of the per-key context for this
+ * cipher. */
+ unsigned ctx_size;
+
+ /* flags contains the OR of a number of flags. See |EVP_CIPH_*|. */
+ uint32_t flags;
+
+ /* app_data is a pointer to opaque, user data. */
+ void *app_data;
+
+ int (*init)(EVP_CIPHER_CTX *ctx, const uint8_t *key, const uint8_t *iv,
+ int enc);
+
+ int (*cipher)(EVP_CIPHER_CTX *ctx, uint8_t *out, const uint8_t *in,
+ size_t inl);
+
+ int (*cleanup)(EVP_CIPHER_CTX *);
+
+ int (*ctrl)(EVP_CIPHER_CTX *, int type, int arg, void *ptr);
+};
+
+/* EVP_CIPH_MODE_MASK contains the bits of |flags| that represent the mode. */
+#define EVP_CIPH_MODE_MASK 0x3f
+
+
+#if defined(__cplusplus)
+} /* extern C */
+#endif
+
+#endif /* OPENSSL_HEADER_CIPHER_INTERNAL_H */