2006-12-16 02:12:06 +02:00
|
|
|
/*
|
2008-09-09 22:07:09 +03:00
|
|
|
* Copyright (c) 2006-2008 Bjorn Andersson <flex@kryo.se>, Erik Ekman <yarrick@kryo.se>
|
2006-12-16 02:12:06 +02:00
|
|
|
*
|
|
|
|
* Permission to use, copy, modify, and 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 <stdio.h>
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <string.h>
|
|
|
|
|
2007-06-09 19:18:59 +03:00
|
|
|
#include "encoding.h"
|
2006-12-16 02:12:06 +02:00
|
|
|
#include "base32.h"
|
|
|
|
|
2008-12-06 17:31:28 +02:00
|
|
|
#define BLKSIZE_RAW 5
|
|
|
|
#define BLKSIZE_ENC 8
|
|
|
|
|
2006-12-16 02:12:06 +02:00
|
|
|
static const char cb32[] =
|
2008-12-06 17:31:28 +02:00
|
|
|
"abcdefghijklmnopqrstuvwxyz012345";
|
2007-06-09 19:18:59 +03:00
|
|
|
static unsigned char rev32[128];
|
|
|
|
static int reverse_init = 0;
|
|
|
|
|
2008-12-06 17:31:28 +02:00
|
|
|
static int base32_decode(void *, size_t *, const char *, size_t);
|
|
|
|
static int base32_encode(char *, size_t *, const void *, size_t);
|
|
|
|
static int base32_handles_dots();
|
|
|
|
static int base32_blksize_raw();
|
|
|
|
static int base32_blksize_enc();
|
|
|
|
|
2007-06-09 19:18:59 +03:00
|
|
|
static struct encoder base32_encoder =
|
|
|
|
{
|
2008-09-14 15:05:55 +03:00
|
|
|
"Base32",
|
2007-06-09 19:18:59 +03:00
|
|
|
base32_encode,
|
|
|
|
base32_decode,
|
|
|
|
base32_handles_dots,
|
2008-12-06 17:31:28 +02:00
|
|
|
base32_handles_dots,
|
|
|
|
base32_blksize_raw,
|
|
|
|
base32_blksize_enc
|
2007-06-09 19:18:59 +03:00
|
|
|
};
|
|
|
|
|
|
|
|
struct encoder
|
|
|
|
*get_base32_encoder()
|
|
|
|
{
|
|
|
|
return &base32_encoder;
|
|
|
|
}
|
|
|
|
|
2008-12-06 17:31:28 +02:00
|
|
|
static int
|
2007-06-09 19:18:59 +03:00
|
|
|
base32_handles_dots()
|
|
|
|
{
|
|
|
|
return 0;
|
|
|
|
}
|
2006-12-16 02:12:06 +02:00
|
|
|
|
2008-12-06 17:31:28 +02:00
|
|
|
static int
|
|
|
|
base32_blksize_raw()
|
|
|
|
{
|
|
|
|
return BLKSIZE_RAW;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
|
|
|
base32_blksize_enc()
|
|
|
|
{
|
|
|
|
return BLKSIZE_ENC;
|
|
|
|
}
|
|
|
|
|
2008-12-11 21:26:11 +02:00
|
|
|
int
|
|
|
|
b32_5to8(int in)
|
|
|
|
{
|
|
|
|
return cb32[in & 31];
|
|
|
|
}
|
|
|
|
|
|
|
|
int
|
|
|
|
b32_8to5(int in)
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
int c;
|
|
|
|
if (!reverse_init) {
|
|
|
|
for (i = 0; i < 32; i++) {
|
|
|
|
c = cb32[i];
|
|
|
|
rev32[(int) c] = i;
|
|
|
|
}
|
|
|
|
reverse_init = 1;
|
|
|
|
}
|
|
|
|
return rev32[in];
|
|
|
|
}
|
|
|
|
|
2008-12-06 17:31:28 +02:00
|
|
|
static int
|
2007-06-09 19:18:59 +03:00
|
|
|
base32_encode(char *buf, size_t *buflen, const void *data, size_t size)
|
2006-12-16 02:12:06 +02:00
|
|
|
{
|
|
|
|
size_t newsize;
|
2007-06-09 19:18:59 +03:00
|
|
|
size_t maxsize;
|
|
|
|
unsigned char *p;
|
|
|
|
unsigned char *q;
|
2006-12-16 02:12:06 +02:00
|
|
|
int i;
|
|
|
|
|
2007-06-09 19:18:59 +03:00
|
|
|
memset(buf, 0, *buflen);
|
2006-12-16 02:12:06 +02:00
|
|
|
|
2007-06-09 19:18:59 +03:00
|
|
|
/* how many chars can we encode within the buf */
|
2008-12-06 17:31:28 +02:00
|
|
|
maxsize = BLKSIZE_RAW * (*buflen / BLKSIZE_ENC - 1) - 1;
|
2007-06-09 19:18:59 +03:00
|
|
|
/* how big will the encoded data be */
|
2008-12-06 17:31:28 +02:00
|
|
|
newsize = BLKSIZE_ENC * (size / BLKSIZE_RAW + 1) + 1;
|
2007-06-09 19:18:59 +03:00
|
|
|
/* if the buffer is too small, eat some of the data */
|
|
|
|
if (*buflen < newsize) {
|
|
|
|
size = maxsize;
|
2006-12-16 02:12:06 +02:00
|
|
|
}
|
|
|
|
|
2008-12-06 17:31:28 +02:00
|
|
|
p = (unsigned char *) buf;
|
2007-06-09 19:18:59 +03:00
|
|
|
q = (unsigned char *)data;
|
2006-12-16 02:12:06 +02:00
|
|
|
|
2008-12-06 17:31:28 +02:00
|
|
|
for(i=0;i<size;i+=BLKSIZE_RAW) {
|
2007-06-09 19:18:59 +03:00
|
|
|
p[0] = cb32[((q[0] & 0xf8) >> 3)];
|
|
|
|
p[1] = cb32[(((q[0] & 0x07) << 2) | ((q[1] & 0xc0) >> 6))];
|
2006-12-16 02:12:06 +02:00
|
|
|
p[2] = (i+1 < size) ? cb32[((q[1] & 0x3e) >> 1)] : '\0';
|
|
|
|
p[3] = (i+1 < size) ? cb32[((q[1] & 0x01) << 4) | ((q[2] & 0xf0) >> 4)] : '\0';
|
|
|
|
p[4] = (i+2 < size) ? cb32[((q[2] & 0x0f) << 1) | ((q[3] & 0x80) >> 7)] : '\0';
|
2007-06-09 19:18:59 +03:00
|
|
|
p[5] = (i+3 < size) ? cb32[((q[3] & 0x7c) >> 2)] : '\0';
|
|
|
|
p[6] = (i+3 < size) ? cb32[((q[3] & 0x03) << 3) | ((q[4] & 0xe0) >> 5)] : '\0';
|
2006-12-16 02:12:06 +02:00
|
|
|
p[7] = (i+4 < size) ? cb32[((q[4] & 0x1f))] : '\0';
|
|
|
|
|
2008-12-06 17:31:28 +02:00
|
|
|
q += BLKSIZE_RAW;
|
|
|
|
p += BLKSIZE_ENC;
|
2006-12-16 02:12:06 +02:00
|
|
|
}
|
|
|
|
*p = 0;
|
|
|
|
|
2007-06-09 19:18:59 +03:00
|
|
|
/* store number of bytes from data that was used */
|
|
|
|
*buflen = size;
|
2006-12-16 02:12:06 +02:00
|
|
|
|
2007-06-09 19:18:59 +03:00
|
|
|
return strlen(buf) - 1;
|
2006-12-16 02:12:06 +02:00
|
|
|
}
|
|
|
|
|
2007-06-09 19:18:59 +03:00
|
|
|
#define DECODE_ERROR 0xffffffff
|
|
|
|
#define REV32(x) rev32[(int) (x)]
|
|
|
|
|
2006-12-16 02:12:06 +02:00
|
|
|
static int
|
2007-06-09 19:18:59 +03:00
|
|
|
decode_token(const unsigned char *t, unsigned char *data, size_t len)
|
2006-12-16 02:12:06 +02:00
|
|
|
{
|
2007-01-28 03:07:51 +02:00
|
|
|
if (len < 2)
|
|
|
|
return 0;
|
|
|
|
|
2007-06-09 19:18:59 +03:00
|
|
|
data[0] = ((REV32(t[0]) & 0x1f) << 3) |
|
|
|
|
((REV32(t[1]) & 0x1c) >> 2);
|
2007-01-28 03:07:51 +02:00
|
|
|
|
|
|
|
if (len < 4)
|
|
|
|
return 1;
|
|
|
|
|
2007-06-09 19:18:59 +03:00
|
|
|
data[1] = ((REV32(t[1]) & 0x03) << 6) |
|
|
|
|
((REV32(t[2]) & 0x1f) << 1) |
|
|
|
|
((REV32(t[3]) & 0x10) >> 4);
|
2007-01-28 03:07:51 +02:00
|
|
|
|
|
|
|
if (len < 5)
|
|
|
|
return 2;
|
|
|
|
|
2007-06-09 19:18:59 +03:00
|
|
|
data[2] = ((REV32(t[3]) & 0x0f) << 4) |
|
|
|
|
((REV32(t[4]) & 0x1e) >> 1);
|
2007-01-28 03:07:51 +02:00
|
|
|
|
|
|
|
if (len < 7)
|
|
|
|
return 3;
|
|
|
|
|
2007-06-09 19:18:59 +03:00
|
|
|
data[3] = ((REV32(t[4]) & 0x01) << 7) |
|
|
|
|
((REV32(t[5]) & 0x1f) << 2) |
|
|
|
|
((REV32(t[6]) & 0x18) >> 3);
|
2007-01-28 03:07:51 +02:00
|
|
|
|
|
|
|
if (len < 8)
|
|
|
|
return 4;
|
|
|
|
|
2007-06-09 19:18:59 +03:00
|
|
|
data[4] = ((REV32(t[6]) & 0x07) << 5) |
|
|
|
|
((REV32(t[7]) & 0x1f));
|
2007-01-28 03:07:51 +02:00
|
|
|
|
|
|
|
return 5;
|
2006-12-16 02:12:06 +02:00
|
|
|
}
|
|
|
|
|
2008-12-06 17:31:28 +02:00
|
|
|
static int
|
2007-06-09 19:18:59 +03:00
|
|
|
base32_decode(void *buf, size_t *buflen, const char *str, size_t slen)
|
2006-12-16 02:12:06 +02:00
|
|
|
{
|
|
|
|
unsigned char *q;
|
|
|
|
size_t newsize;
|
2007-06-09 19:18:59 +03:00
|
|
|
size_t maxsize;
|
2006-12-16 02:12:06 +02:00
|
|
|
const char *p;
|
2007-06-09 19:18:59 +03:00
|
|
|
unsigned char c;
|
2006-12-16 02:12:06 +02:00
|
|
|
int len;
|
2007-06-09 19:18:59 +03:00
|
|
|
int i;
|
2006-12-16 02:12:06 +02:00
|
|
|
|
2007-06-09 19:18:59 +03:00
|
|
|
if (!reverse_init) {
|
|
|
|
for (i = 0; i < 32; i++) {
|
|
|
|
c = cb32[i];
|
|
|
|
rev32[(int) c] = i;
|
|
|
|
}
|
|
|
|
reverse_init = 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* chars needed to decode slen */
|
2008-12-06 17:31:28 +02:00
|
|
|
newsize = BLKSIZE_RAW * (slen / BLKSIZE_ENC + 1) + 1;
|
2007-06-09 19:18:59 +03:00
|
|
|
/* encoded chars that fit in buf */
|
2008-12-06 17:31:28 +02:00
|
|
|
maxsize = BLKSIZE_ENC * (*buflen / BLKSIZE_RAW + 1) + 1;
|
2007-06-09 19:18:59 +03:00
|
|
|
/* if the buffer is too small, eat some of the data */
|
|
|
|
if (*buflen < newsize) {
|
|
|
|
slen = maxsize;
|
2006-12-16 02:12:06 +02:00
|
|
|
}
|
|
|
|
|
2007-06-09 19:18:59 +03:00
|
|
|
q = buf;
|
2008-12-06 17:31:28 +02:00
|
|
|
for (p = str; *p && strchr(cb32, *p); p += BLKSIZE_ENC) {
|
2007-06-09 19:18:59 +03:00
|
|
|
len = decode_token((unsigned char *) p, (unsigned char *) q, slen);
|
2006-12-16 02:12:06 +02:00
|
|
|
q += len;
|
2008-12-06 17:31:28 +02:00
|
|
|
slen -= BLKSIZE_ENC;
|
2007-01-28 03:07:51 +02:00
|
|
|
|
2008-12-06 17:31:28 +02:00
|
|
|
if (len < BLKSIZE_RAW)
|
2007-01-28 03:07:51 +02:00
|
|
|
break;
|
2006-12-16 02:12:06 +02:00
|
|
|
}
|
|
|
|
*q = '\0';
|
|
|
|
|
2007-06-09 19:18:59 +03:00
|
|
|
return q - (unsigned char *) buf;
|
2006-12-16 02:12:06 +02:00
|
|
|
}
|
|
|
|
|