#ifndef DDEBUG #define DDEBUG 0 #endif #include "ddebug.h" #include #include "ngx_http_set_base32.h" #include "ngx_http_set_misc_module.h" #define base32_encoded_length(len) ((((len)+4)/5)*8) #define base32_decoded_length(len) ((((len)+7)/8)*5) static void encode_base32(size_t slen, u_char *src, size_t *dlen, u_char *dst, ngx_flag_t padding, ngx_str_t *alphabet); static int decode_base32(size_t slen, u_char *src, size_t *dlen, u_char *dst, u_char *basis32); ngx_int_t ngx_http_set_misc_encode_base32(ngx_http_request_t *r, ngx_str_t *res, ngx_http_variable_value_t *v) { size_t len; u_char *p; u_char *src, *dst; ngx_http_set_misc_loc_conf_t *conf; conf = ngx_http_get_module_loc_conf(r, ngx_http_set_misc_module); len = base32_encoded_length(v->len); dd("estimated dst len: %d", (int) len); p = ngx_palloc(r->pool, len); if (p == NULL) { return NGX_ERROR; } src = v->data; dst = p; encode_base32(v->len, src, &len, dst, conf->base32_padding, &conf->base32_alphabet); res->data = p; res->len = len; dd("res (len %d): %.*s", (int) res->len, (int) res->len, res->data); return NGX_OK; } ngx_int_t ngx_http_set_misc_decode_base32(ngx_http_request_t *r, ngx_str_t *res, ngx_http_variable_value_t *v) { size_t len; u_char *p; u_char *src, *dst; int ret; ngx_http_set_misc_loc_conf_t *conf; conf = ngx_http_get_module_loc_conf(r, ngx_http_set_misc_module); len = base32_decoded_length(v->len); dd("estimated dst len: %d", (int) len); p = ngx_palloc(r->pool, len); if (p == NULL) { return NGX_ERROR; } src = v->data; dst = p; ret = decode_base32(v->len, src, &len, dst, conf->basis32); if (ret == 0 /* OK */) { res->data = p; res->len = len; return NGX_OK; } /* failed to decode */ res->data = NULL; res->len = 0; return NGX_OK; } /* See the implementation in src/core/ngx_string.c's * ngx_(encode|decode)_base64() for details. */ static void encode_base32(size_t slen, u_char *src, size_t *dlen, u_char *dst, ngx_flag_t padding, ngx_str_t *alphabet) { unsigned char *basis32 = alphabet->data; size_t len; u_char *s; u_char *d; len = slen; s = src; d = dst; while (len > 4) { *d++ = basis32[s[0] >> 3]; *d++ = basis32[((s[0] & 0x07) << 2) | (s[1] >> 6)]; *d++ = basis32[(s[1] >> 1) & 0x1f]; *d++ = basis32[((s[1] & 1) << 4) | (s[2] >> 4)]; *d++ = basis32[((s[2] & 0x0f) << 1) | (s[3] >> 7)]; *d++ = basis32[(s[3] >> 2) & 0x1f]; *d++ = basis32[((s[3] & 0x03) << 3) | (s[4] >> 5)]; *d++ = basis32[s[4] & 0x1f]; s += 5; len -= 5; } if (len) { *d++ = basis32[s[0] >> 3]; if (len == 1) { /* 1 byte left */ *d++ = basis32[(s[0] & 0x07) << 2]; /* pad six '='s to the end */ if (padding) { *d++ = '='; *d++ = '='; *d++ = '='; *d++ = '='; *d++ = '='; } } else { *d++ = basis32[((s[0] & 0x07) << 2) | (s[1] >> 6)]; *d++ = basis32[(s[1] >> 1) & 0x1f]; if (len == 2) { /* 2 bytes left */ *d++ = basis32[(s[1] & 1) << 4]; /* pad four '='s to the end */ if (padding) { *d++ = '='; *d++ = '='; *d++ = '='; } } else { *d++ = basis32[((s[1] & 1) << 4) | (s[2] >> 4)]; if (len == 3) { /* 3 bytes left */ *d++ = basis32[(s[2] & 0x0f) << 1]; if (padding) { /* pad three '='s to the end */ *d++ = '='; *d++ = '='; } } else { /* 4 bytes left */ *d++ = basis32[((s[2] & 0x0f) << 1) | (s[3] >> 7)]; *d++ = basis32[(s[3] >> 2) & 0x1f]; *d++ = basis32[(s[3] & 0x03) << 3]; /* pad one '=' to the end */ } } } if (padding) { *d++ = '='; } } *dlen = (size_t) (d - dst); } static int decode_base32(size_t slen, u_char *src, size_t *dlen, u_char *dst, u_char *basis32) { size_t len, mod; u_char *s = src; u_char *d = dst; for (len = 0; len < slen; len++) { if (s[len] == '=') { break; } if (basis32[s[len]] == 77) { return -1; } } mod = len % 8; if (mod == 1 || mod == 3 || mod == 6) { /* bad Base32 digest length */ return -1; } while (len > 7) { *d++ = (basis32[s[0]] << 3) | ((basis32[s[1]] >> 2) & 0x07); *d++ = ((basis32[s[1]] & 0x03) << 6) | (basis32[s[2]] << 1) | ((basis32[s[3]] >> 4) & 1); *d++ = ((basis32[s[3]] & 0x0f) << 4) | ((basis32[s[4]] >> 1) & 0x0f); *d++ = ((basis32[s[4]] & 1) << 7) | ((basis32[s[5]] & 0x1f) << 2) | ((basis32[s[6]] >> 3) & 0x03); *d++ = ((basis32[s[6]] & 0x07) << 5) | (basis32[s[7]] & 0x1f); s += 8; len -= 8; } if (len) { /* 2 bytes left */ *d++ = (basis32[s[0]] << 3) | ((basis32[s[1]] >> 2) & 0x07); if (len > 2) { /* 4 bytes left */ *d++ = ((basis32[s[1]] & 0x03) << 6) | ((basis32[s[2]] & 0x1f) << 1) | ((basis32[s[3]] >> 4) & 1); if (len > 4) { /* 5 bytes left */ *d++ = ((basis32[s[3]] & 0x0f) << 4) | ((basis32[s[4]] >> 1) & 0x0f); if (len > 5) { /* 7 bytes left */ *d++ = ((basis32[s[4]] & 1) << 7) | ((basis32[s[5]] & 0x1f) << 2) | ((basis32[s[6]] >> 3) & 0x03); } } } } *dlen = (size_t) (d - dst); return 0; }