Add base32 decoder
This commit is contained in:
parent
3e8b900464
commit
15bcd35557
2
Makefile
2
Makefile
@ -17,7 +17,7 @@
|
||||
P = otpcli
|
||||
V = 0.0
|
||||
|
||||
HDR = err.h strtonum.h otp.h
|
||||
HDR = base32.h err.h strtonum.h otp.h
|
||||
OBJ = cli.o ${HDR:.h=.o}
|
||||
SRC = ${OBJ:.o=.c}
|
||||
|
||||
|
101
base32.c
Normal file
101
base32.c
Normal file
@ -0,0 +1,101 @@
|
||||
/*
|
||||
* otpcli - CLI utility for generating OTPs
|
||||
*
|
||||
* Written in 2021 by Lucas
|
||||
*
|
||||
* To the extent possible under law, the author(s) have dedicated all
|
||||
* copyright and related and neighboring rights to this software to the
|
||||
* public domain worldwide. This software is distributed without any
|
||||
* warranty.
|
||||
*
|
||||
* You should have received a copy of the CC0 Public Domain Dedication
|
||||
* along with this software. If not, see
|
||||
* <http://creativecommons.org/publicdomain/zero/1.0/>.
|
||||
*/
|
||||
|
||||
#include <limits.h>
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "base32.h"
|
||||
|
||||
#define B32_VALID(a) (('A' <= (a) && (a) <= 'Z') || ('2' <= (a) && (a) <= '7'))
|
||||
#define B32_DECODE_CHAR(a) ((a) <= '7' ? (a) - '2' + 26 : (a) - 'A')
|
||||
|
||||
static int b32_last_chunk_length[] = { 0, -1, 1, -1, 2, 3, -1, 4 };
|
||||
|
||||
static void
|
||||
b32_decode_chunk(unsigned char out[5], const char in[8])
|
||||
{
|
||||
uint64_t x = 0;
|
||||
|
||||
x |= (uint64_t)B32_DECODE_CHAR(in[0]) << 35;
|
||||
x |= (uint64_t)B32_DECODE_CHAR(in[1]) << 30;
|
||||
x |= (uint64_t)B32_DECODE_CHAR(in[2]) << 25;
|
||||
x |= (uint64_t)B32_DECODE_CHAR(in[3]) << 20;
|
||||
x |= (uint64_t)B32_DECODE_CHAR(in[4]) << 15;
|
||||
x |= (uint64_t)B32_DECODE_CHAR(in[5]) << 10;
|
||||
x |= (uint64_t)B32_DECODE_CHAR(in[6]) << 5;
|
||||
x |= (uint64_t)B32_DECODE_CHAR(in[7]);
|
||||
|
||||
out[0] = (x >> 32) & 0xff;
|
||||
out[1] = (x >> 24) & 0xff;
|
||||
out[2] = (x >> 16) & 0xff;
|
||||
out[3] = (x >> 8) & 0xff;
|
||||
out[4] = x & 0xff;
|
||||
}
|
||||
|
||||
int
|
||||
b32_decoded_len(const char *s, size_t n)
|
||||
{
|
||||
const char *it, *t;
|
||||
size_t r, eqc;
|
||||
|
||||
for (it = s; *it != '\0' && B32_VALID(*it); it++)
|
||||
continue;
|
||||
if (*it != '\0' && *it != '=')
|
||||
return -1;
|
||||
|
||||
for (t = it; *t == '=' && t - it < 8; t++)
|
||||
continue;
|
||||
eqc = t - it;
|
||||
if (*t != '\0' || t - it == 8 || b32_last_chunk_length[eqc] == -1)
|
||||
return -1;
|
||||
|
||||
r = n / 8 * 5 + b32_last_chunk_length[eqc == 0 ? n % 8 : eqc];
|
||||
return r > INT_MAX ? -1 : r;
|
||||
}
|
||||
|
||||
int
|
||||
b32_decode(unsigned char *out, size_t outlen, const char *in, size_t inlen)
|
||||
{
|
||||
unsigned char tout[5];
|
||||
char tin[8];
|
||||
size_t i, t, eqc, last_chunk;
|
||||
|
||||
t = inlen;
|
||||
while (in[inlen - 1] == '=')
|
||||
inlen--;
|
||||
eqc = t - inlen;
|
||||
last_chunk = b32_last_chunk_length[eqc == 0 ? inlen % 8 : eqc];
|
||||
|
||||
while (inlen >= 8 && outlen >= 5) {
|
||||
b32_decode_chunk(out, in);
|
||||
in += 8;
|
||||
inlen -= 8;
|
||||
out += 5;
|
||||
outlen -= 5;
|
||||
}
|
||||
|
||||
if (inlen > 0) {
|
||||
if (outlen == 0)
|
||||
return 0;
|
||||
|
||||
memcpy(tin, in, inlen);
|
||||
memset(tin + inlen, 'A', sizeof(tin) - inlen);
|
||||
b32_decode_chunk(tout, tin);
|
||||
memcpy(out, tout, outlen);
|
||||
}
|
||||
|
||||
return outlen >= last_chunk;
|
||||
}
|
Loading…
Reference in New Issue
Block a user