#include <stdlib.h>
#include <stdint.h>
#include <string.h>
typedef unsigned char uchar;
typedef unsigned int uint;
#define Nb 4 // number of columns in the state & expanded key
#define Nr 10 // number of rounds in encryption
void ExpandKey(uchar *key, uchar *expkey);
void Encrypt (uchar *in, uchar *expkey, uchar *out);
void Decrypt (uchar *in, uchar *expkey, uchar *out);
void get_hash(uint *out, uchar *in, uint len)
{
uint32_t hash = 0;
for (; len--; ++in) {
hash = (hash >> 1) + ((hash & 1) << 31);
hash += *in;
}
*out = hash;
}
/* http://base64.sourceforge.net/b64.c. LICENCE: Copyright (c) 2001
* Bob Trower, Trantor Standard Systems Inc. */
static const char cb64[]="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
void base64_enc(char *out, uchar *in, uint len)
{
while (len) {
uchar buffin[3];
buffin[0] = *(in++);
if (--len) {
buffin[1] = *(in++);
if (--len) {
buffin[2] = *(in++);
--len;
} else {
buffin[2] = 0;
}
} else {
buffin[1] = 0;
buffin[2] = 0;
}
*(out++) = cb64[buffin[0] >> 2];
*(out++) = cb64[ (buffin[0] & 0x03) << 4
| (buffin[1] & 0xf0) >> 4];
*(out++) = cb64[ (buffin[1] & 0x0f) << 2
| (buffin[2] & 0xc0) >> 6];
*(out++) = cb64[buffin[2] & 0x3f];
}
}
int parse_char(uchar *out, char in)
{
if ('A' <= in && in <= 'Z') {
*out = in - 'A';
} else if ('a' <= in && in <= 'z') {
*out = in - 'a' + 26;
} else if ('0' <= in && in <= '9') {
*out = in - '0' + 52;
} else if (in == '+') {
*out = 62;
} else if (in == '/') {
*out = 63;
} else {
return 0;
}
return 1;
}
int base64_dec(uchar *out, char *in, uint len)
{
for (; len; in += 4, out += 3, len -= 4) {
uchar tmp[4];
int i = 0;
for (i = 0; i < 4; ++i) {
if (! parse_char(tmp + i, in[i])) return 0;
}
out[0] = tmp[0] << 2 | tmp[1] >> 4;
out[1] = tmp[1] << 4 | tmp[2] >> 2;
out[2] = ((tmp[2] << 6) & 0xc0) | tmp[3];
}
return 1;
}
char * encrypt(uint32_t len, uchar *in, uchar *key, uint *outlen)
{
uchar expkey[4 * Nb * (Nr + 1)];
uchar *out;
uint i;
uint totlen, encoded_len;
uchar *tmp;
uchar buff[16];
/* 4 bytes for the hash, 4 bytes for the length, then the string.
* Need to align to 16 bytes.
*/
totlen = len + 8;
totlen += 16 - (totlen % 16);
tmp = alloca(totlen);
bzero(tmp, totlen);
get_hash((uint*) tmp, in, len);
memcpy(tmp + 4, &len, 4);
memcpy(tmp + 8, in, len);
ExpandKey(key, expkey);
for (i = 0; i < totlen; i += 16) {
//Encrypt(tmp + i, expkey, buff);
//memcpy(tmp + 1, buff, 16);
}
encoded_len = (totlen + 2 - ((totlen + 2) % 3)) / 3 * 4;
out = malloc(encoded_len + 1);
out[encoded_len] = 0;
base64_enc(out, tmp, totlen);
*outlen = encoded_len;
return out;
}
uchar * decrypt(uint len, char *in, uchar *key, uint *out_len)
{
uchar expkey[4 * Nb * (Nr + 1)];
uchar *out;
uint i;
uchar buff[16];
uint outlen;
uint hash, orig_hash;
uint orig_len;
if (! len % 4) return 0;
outlen = len / 4 * 3;
out = alloca(outlen);
if (! base64_dec(out, in, len)) {
return 0;
}
ExpandKey(key, expkey);
for (i = 0; i < len; i += 16) {
//Decrypt(out + i, expkey, buff);
//memcpy(out + i, buff, 16);
}
orig_hash = *((uint*) out);
orig_len = *(out + 4);
get_hash(&hash, out + 8, orig_len);
if (orig_hash != hash) {
return 0;
}
uchar *realout = malloc(orig_len + 1);
realout[orig_len] = 0;
memcpy(realout, out + 8, orig_len);
*out_len = orig_len;
return realout;
}