Browse Source

Add fixed hex/base32 encode and decode routines

tags/1.2.0
Vsevolod Stakhov 8 years ago
parent
commit
aed148fd30
2 changed files with 211 additions and 56 deletions
  1. 167
    56
      src/libutil/str_util.c
  2. 44
    0
      src/libutil/str_util.h

+ 167
- 56
src/libutil/str_util.c View File

@@ -463,49 +463,51 @@ rspamd_str_pool_copy (gconstpointer data, gpointer ud)
* http://philzimmermann.com/docs/human-oriented-base-32-encoding.txt
*/

gchar *
rspamd_encode_base32 (const guchar *in, gsize inlen)
gint
rspamd_encode_base32_buf (const guchar *in, gsize inlen, gchar *out,
gsize outlen)
{
gint remain = -1, x;
gsize i, r;
gsize allocated_len = inlen * 8 / 5 + 2;
gchar *out;
static const char b32[]="ybndrfg8ejkmcpqxot1uwisza345h769";
gchar *o, *end;
gsize i, r;
gint remain = -1, x;

out = g_malloc (allocated_len);
for (i = 0, r = 0; i < inlen; i++) {
end = out + outlen;
o = out;

for (i = 0, r = 0; i < inlen && o < end - 1; i++) {
switch (i % 5) {
case 0:
/* 8 bits of input and 3 to remain */
x = in[i];
remain = in[i] >> 5;
out[r++] = b32[x & 0x1F];
*o++ = b32[x & 0x1F];
break;
case 1:
/* 11 bits of input, 1 to remain */
x = remain | in[i] << 3;
out[r++] = b32[x & 0x1F];
out[r++] = b32[x >> 5 & 0x1F];
*o++ = b32[x & 0x1F];
*o++ = b32[x >> 5 & 0x1F];
remain = x >> 10;
break;
case 2:
/* 9 bits of input, 4 to remain */
x = remain | in[i] << 1;
out[r++] = b32[x & 0x1F];
*o++ = b32[x & 0x1F];
remain = x >> 5;
break;
case 3:
/* 12 bits of input, 2 to remain */
x = remain | in[i] << 4;
out[r++] = b32[x & 0x1F];
out[r++] = b32[x >> 5 & 0x1F];
*o++ = b32[x & 0x1F];
*o++ = b32[x >> 5 & 0x1F];
remain = x >> 10 & 0x3;
break;
case 4:
/* 10 bits of output, nothing to remain */
x = remain | in[i] << 2;
out[r++] = b32[x & 0x1F];
out[r++] = b32[x >> 5 & 0x1F];
*o++ = b32[x & 0x1F];
*o++ = b32[x >> 5 & 0x1F];
remain = -1;
break;
default:
@@ -514,14 +516,36 @@ rspamd_encode_base32 (const guchar *in, gsize inlen)
}

}
if (remain >= 0) {
out[r++] = b32[remain];
if (remain >= 0 && o < end) {
*o++ = b32[remain];
}

out[r] = 0;
g_assert (r < allocated_len);
if (o <= end) {
return (o - out);
}

return out;
return -1;
}

gchar *
rspamd_encode_base32 (const guchar *in, gsize inlen)
{
gsize allocated_len = inlen * 8 / 5 + 2;
gchar *out;
gint outlen;

out = g_malloc (allocated_len);
outlen = rspamd_encode_base32_buf (in, inlen, out, allocated_len - 1);

if (outlen >= 0) {
out[outlen] = 0;

return out;
}

g_free (out);

return NULL;
}

static const guchar b32_dec[] = {
@@ -559,48 +583,86 @@ static const guchar b32_dec[] = {
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff
};

guchar*
rspamd_decode_base32 (const gchar *in, gsize inlen, gsize *outlen)
gint
rspamd_decode_base32_buf (const gchar *in, gsize inlen,
guchar *out, gsize outlen)
{
guchar *res, decoded;
guchar *o, *end, decoded;
guchar c;
guint acc = 0U;
guint processed_bits = 0;
gsize olen = 0, i, allocated_len = inlen * 5 / 8 + 2;
gsize i;

res = g_malloc (allocated_len);
end = out + outlen;
o = out;

for (i = 0; i < inlen; i ++) {
c = (guchar)in[i];

if (processed_bits >= 8) {
processed_bits -= 8;
res[olen++] = acc & 0xFF;
*o++ = acc & 0xFF;
acc >>= 8;
}

decoded = b32_dec[c];
if (decoded == 0xff) {
g_free (res);
return NULL;
if (decoded == 0xff || o >= end) {
return -1;
}

acc = (decoded << processed_bits) | acc;
processed_bits += 5;
}

if (processed_bits > 0) {
res[olen++] = (acc & 0xFF);
if (processed_bits > 0 && o < end) {
*o++ = (acc & 0xFF);
}
else if (o > end) {
return -1;
}

return (o - out);
}

guchar*
rspamd_decode_base32 (const gchar *in, gsize inlen, gsize *outlen)
{
guchar *res;

gsize olen = 0, i, allocated_len = inlen * 5 / 8 + 2;

res = g_malloc (allocated_len);

olen = rspamd_decode_base32_buf (in, inlen, res, allocated_len - 1);

if (olen >= 0) {
res[olen] = '\0';
}
else {
g_free (res);

g_assert (olen <= allocated_len);
return NULL;
}

*outlen = olen;
if (outlen) {
*outlen = olen;
}

return res;
}



/**
* Decode string using base32 encoding
* @param in input
* @param inlen input length
* @param out output buf (may overlap with `in`)
* @param outlen output buf len
* @return TRUE if in is valid base32 and `outlen` is enough to encode `inlen`
*/


static gchar *
rspamd_encode_base64_common (const guchar *in, gsize inlen, gint str_len,
gsize *outlen, gboolean fold)
@@ -1264,54 +1326,74 @@ rspamd_string_find_eoh (GString *input)
return -1;
}

gchar *
rspamd_encode_hex (const guchar *in, gsize inlen)
gint
rspamd_encode_hex_buf (const guchar *in, gsize inlen, gchar *out,
gsize outlen)
{
gchar *out, *o;
gchar *o, *end;
const guchar *p;
gsize outlen = inlen * 2 + 1;
static const gchar hexdigests[16] = "0123456789abcdef";

if (in == NULL) {
return NULL;
}

out = g_malloc (outlen);
end = out + end;
o = out;
p = in;

while (inlen > 0) {

while (inlen > 0 && o < end - 1) {
*o++ = hexdigests[((*p >> 4) & 0xF)];
*o++ = hexdigests[((*p++) & 0xF)];
inlen --;
}

*o = '\0';
if (o <= end) {
return (o - end);
}

return out;
return -1;
}


guchar*
rspamd_decode_hex (const gchar *in, gsize inlen)
gchar *
rspamd_encode_hex (const guchar *in, gsize inlen)
{
guchar *out, *o, ret;
const gchar *p;
gchar c;
gsize outlen = (inlen / 2 + inlen % 2) + 1;
gchar *out;
gsize outlen = inlen * 2 + 1;
gint olen;

if (in == NULL) {
return NULL;
}

out = g_malloc (outlen);
olen = rspamd_encode_hex_buf (in, inlen, out, outlen - 1);

if (olen >= 0) {
out[olen] = '\0';
}
else {
g_free (out);

return NULL;
}

return out;
}

gint
rspamd_decode_hex_buf (const gchar *in, gsize inlen, gsize inlen,
guchar *out, gsize outlen)
{
guchar *o, *end, ret;
const gchar *p;
gchar c;

end = out + outlen;
o = out;
p = in;

/* We ignore trailing chars if we have not even input */
inlen = inlen - inlen % 2;

while (inlen > 0) {
while (inlen > 1 && o < end) {
c = *p++;

if (c >= '0' && c <= '9') ret = c - '0';
@@ -1330,11 +1412,40 @@ rspamd_decode_hex (const gchar *in, gsize inlen)
inlen -= 2;
}

*o = '\0';
if (o <= end) {
return (o - end);
}

return out;
return -1;
}

guchar*
rspamd_decode_hex (const gchar *in, gsize inlen)
{
guchar *out;
gsize outlen = (inlen / 2 + inlen % 2) + 1;
gint olen;

if (in == NULL) {
return NULL;
}

out = g_malloc (outlen);

olen = rspamd_decode_hex_buf (in, inlen, out, outlen - 1);

if (olen >= 0) {
out[olen] = '\0';

return out;
}

g_free (out);

return NULL;
}


/*
* GString ucl emitting functions
*/

+ 44
- 0
src/libutil/str_util.h View File

@@ -131,6 +131,50 @@ gchar * rspamd_encode_hex (const guchar *in, gsize inlen);
*/
guchar* rspamd_decode_hex (const gchar *in, gsize inlen);

/**
* Encode string using base32 encoding
* @param in input
* @param inlen input length
* @param out output buf
* @param outlen output buf len
* @return encoded len if `outlen` is enough to encode `inlen`
*/
gint rspamd_encode_base32_buf (const guchar *in, gsize inlen, gchar *out,
gsize outlen);

/**
* Decode string using base32 encoding
* @param in input
* @param inlen input length
* @param out output buf (may overlap with `in`)
* @param outlen output buf len
* @return decoded len if in is valid base32 and `outlen` is enough to encode `inlen`
*/
gint rspamd_decode_base32_buf (const gchar *in, gsize inlen,
guchar *out, gsize outlen);

/**
* Encode string using hex encoding
* @param in input
* @param inlen input length
* @param out output buf
* @param outlen output buf len
* @return encoded len if `outlen` is enough to encode `inlen`
*/
gint rspamd_encode_hex_buf (const guchar *in, gsize inlen, gchar *out,
gsize outlen);

/**
* Decode string using hex encoding
* @param in input
* @param inlen input length
* @param out output buf (may overlap with `in`)
* @param outlen output buf len
* @return decoded len if in is valid hex and `outlen` is enough to encode `inlen`
*/
gint rspamd_decode_hex_buf (const gchar *in, gsize inlen,
guchar *out, gsize outlen);

/**
* Encode string using base64 encoding
* @param in input

Loading…
Cancel
Save