Skip to content

Add support for changing IV and reading key / IV from nginx variables. #24

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 3 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 11 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -38,15 +38,24 @@ Synopsis
========

```nginx
set $key "abcdefghijklmnopqrstuvwxyz123456";
set $iv "1234567812345678";
set $ses_expires "3600";

# key must be of 32 bytes long
encrypted_session_key $key;

encrypted_session_key "abcdefghijklmnopqrstuvwxyz123456";

# iv must not be longer than 16 bytes
# default: "deadbeefdeadbeef" (w/o quotes)
encrypted_session_iv "1234567812345678";
encrypted_session_iv $iv;

encrypted_session_iv_in_content; # enable this only if you rotate IV for each encryption
encrypted_session_mode gcm; # cbc is the default mode.

# default: 1d (1 day)
encrypted_session_expires 3600; # in sec
encrypted_session_expires $ses_expires; # in sec

location /encrypt {
set $raw 'text to encrypted'; # from the ngx_rewrite module
Expand Down
69 changes: 64 additions & 5 deletions src/ngx_http_encrypted_session_cipher.c
Original file line number Diff line number Diff line change
Expand Up @@ -12,20 +12,36 @@

#include "ngx_http_encrypted_session_cipher.h"
#include <openssl/evp.h>
#include <openssl/hmac.h>
#include <openssl/md5.h>
#include <stdint.h>


static uint64_t ngx_http_encrypted_session_ntohll(uint64_t n);
static uint64_t ngx_http_encrypted_session_htonll(uint64_t n);

const EVP_CIPHER*
ngx_http_encrypted_session_get_cipher(enum ngx_http_encrypted_session_mode mode)
{
if (mode == ngx_http_encrypted_session_mode_cbc)
{
return EVP_aes_256_cbc();
}
else if (mode == ngx_http_encrypted_session_mode_gcm)
{
return EVP_aes_256_gcm();
}

return NULL;
}

ngx_int_t
ngx_http_encrypted_session_aes_mac_encrypt(
ngx_http_encrypted_session_main_conf_t *emcf, ngx_pool_t *pool,
ngx_log_t *log, const u_char *iv, size_t iv_len, const u_char *key,
size_t key_len, const u_char *in, size_t in_len, ngx_uint_t expires,
u_char **dst, size_t *dst_len)
enum ngx_http_encrypted_session_mode mode,
u_char **dst, size_t *dst_len, u_char **tag)
{
const EVP_CIPHER *cipher;
u_char *p, *data;
Expand All @@ -49,7 +65,10 @@ ngx_http_encrypted_session_aes_mac_encrypt(
}
}

cipher = EVP_aes_256_cbc();
cipher = ngx_http_encrypted_session_get_cipher(mode);
if (!cipher) {
goto evp_error;
}

block_size = EVP_CIPHER_block_size(cipher);

Expand Down Expand Up @@ -106,6 +125,15 @@ ngx_http_encrypted_session_aes_mac_encrypt(
p += len;

ret = EVP_EncryptFinal(emcf->session_ctx, p, &len);
if (!ret) {
goto evp_error;
}

if (mode == ngx_http_encrypted_session_mode_gcm) {
*tag = (u_char*)ngx_pcalloc(pool, ngx_http_encrypted_session_aes_tag_size);
ret = EVP_CIPHER_CTX_ctrl(emcf->session_ctx, EVP_CTRL_GCM_GET_TAG,
ngx_http_encrypted_session_aes_tag_size, *tag);
}

emcf->reset_cipher_ctx(emcf->session_ctx);

Expand Down Expand Up @@ -138,8 +166,10 @@ ngx_int_t
ngx_http_encrypted_session_aes_mac_decrypt(
ngx_http_encrypted_session_main_conf_t *emcf, ngx_pool_t *pool,
ngx_log_t *log, const u_char *iv, size_t iv_len, const u_char *key,
size_t key_len, const u_char *in, size_t in_len, u_char **dst,
size_t *dst_len)
size_t key_len, const u_char *in, size_t in_len,
enum ngx_http_encrypted_session_mode mode,
u_char *tag,
u_char **dst, size_t *dst_len)
{
const EVP_CIPHER *cipher;
int ret;
Expand Down Expand Up @@ -170,7 +200,10 @@ ngx_http_encrypted_session_aes_mac_decrypt(
}
}

cipher = EVP_aes_256_cbc();
cipher = ngx_http_encrypted_session_get_cipher(mode);
if (!cipher) {
goto evp_error;
}

ret = EVP_DecryptInit(emcf->session_ctx, cipher, key, iv);
if (!ret) {
Expand Down Expand Up @@ -199,6 +232,14 @@ ngx_http_encrypted_session_aes_mac_decrypt(

p += len;

if (mode == ngx_http_encrypted_session_mode_gcm) {
ret = EVP_CIPHER_CTX_ctrl(emcf->session_ctx, EVP_CTRL_GCM_SET_TAG,
ngx_http_encrypted_session_aes_tag_size, tag);
if (!ret) {
goto evp_error;
}
}

ret = EVP_DecryptFinal(emcf->session_ctx, p, &len);

emcf->reset_cipher_ctx(emcf->session_ctx);
Expand Down Expand Up @@ -291,3 +332,21 @@ ngx_http_encrypted_session_htonll(uint64_t n)
+ htonl((unsigned long) (n >> 32));
#endif
}

unsigned char*
ngx_http_encrypted_session_hmac(ngx_pool_t *pool,
const u_char *key, size_t key_len,
const u_char *data, size_t data_len, u_char **dst, size_t *dst_len)
{
u_char *result = NULL;
u_char *input = ngx_pcalloc(pool, data_len + 1);
ngx_memcpy(input, data, data_len);

unsigned int len;
result = HMAC(EVP_sha256(), key, key_len, input, data_len, result, &len);
*dst_len = len;
*dst = (u_char*)ngx_pcalloc(pool, len + 1);
ngx_memcpy(*dst, result, len);

return *dst;
}
24 changes: 19 additions & 5 deletions src/ngx_http_encrypted_session_cipher.h
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
#include <ngx_core.h>
#include <ngx_http.h>
#include <openssl/evp.h>
#include <openssl/hmac.h>


typedef int (*cipher_ctx_reset_handle) (EVP_CIPHER_CTX *ctx);
Expand All @@ -18,22 +19,35 @@ typedef struct {

enum {
ngx_http_encrypted_session_key_length = 256 / 8,
ngx_http_encrypted_session_iv_length = EVP_MAX_IV_LENGTH
ngx_http_encrypted_session_iv_length = EVP_MAX_IV_LENGTH,
ngx_http_encrypted_session_aes_tag_size = 16
};

enum ngx_http_encrypted_session_mode {
ngx_http_encrypted_session_mode_unknown = 0, // unknown / unset value.
ngx_http_encrypted_session_mode_cbc = 1, // equivalent of setting cbc string in config or nothing at all.
ngx_http_encrypted_session_mode_gcm = 2 // equivalent of explicitly setting gcm in nginx config.
};

ngx_int_t ngx_http_encrypted_session_aes_mac_encrypt(
ngx_http_encrypted_session_main_conf_t *emcf, ngx_pool_t *pool,
ngx_log_t *log, const u_char *iv, size_t iv_len, const u_char *key,
size_t key_len, const u_char *in, size_t in_len,
ngx_uint_t expires, u_char **dst, size_t *dst_len);
ngx_uint_t expires, enum ngx_http_encrypted_session_mode mode,
u_char **dst, size_t *dst_len, u_char **tag);

ngx_int_t ngx_http_encrypted_session_aes_mac_decrypt(
ngx_http_encrypted_session_main_conf_t *emcf, ngx_pool_t *pool,
ngx_log_t *log, const u_char *iv, size_t iv_len, const u_char *key,
size_t key_len, const u_char *in, size_t in_len, u_char **dst,
size_t *dst_len);

size_t key_len, const u_char *in, size_t in_len,
enum ngx_http_encrypted_session_mode mode,
u_char *tag,
u_char **dst, size_t *dst_len);

unsigned char* ngx_http_encrypted_session_hmac(
ngx_pool_t *pool,
const u_char *key, size_t key_len,
const u_char *data, size_t data_len, u_char **dst, size_t *dst_len);

#endif /* NGX_HTTP_ENCRYPTED_SESSION_CIPHER_H */

Loading