Skip to content

Instantly share code, notes, and snippets.

@funny-falcon
Last active July 19, 2016 11:29
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save funny-falcon/d47232c0ae20122be2056700d4e85934 to your computer and use it in GitHub Desktop.
Save funny-falcon/d47232c0ae20122be2056700d4e85934 to your computer and use it in GitHub Desktop.
Encrypt 32bit value + 2*32bit seed + 128bit key into 48bit cipher text
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <assert.h>
#include <sys/stat.h>
#include <unistd.h>
#include <inttypes.h>
#include <string.h>
// Minimum recommended values are DOUBLEROUND=3 and MIX=2.
// I believe, it could be compromized in theory, but should be safe in practice.
// DOUBLEROUND=3 and MIX=3 should be safe for any purpose.
#define QUADROUND 3
#define MIX 2
#define rotl(v,n) ((v)<<(n)|(v)>>(32-(n)))
#define rotr(v,n) ((v)>>(n)|(v)<<(32-(n)))
static inline void
mix48(uint16_t *v2, uint32_t *v, int i)
{
for(;i;i--) {
*v = rotl(*v, 6);
*v2 -= (*v>>16)+(*v);
*v = rotl(*v, 7);
*v ^= *v2;
}
}
static inline void
demix48(uint16_t *v2, uint32_t *v, int i)
{
for(;i;i--) {
*v ^= *v2;
*v = rotr(*v, 7);
*v2 += (*v>>16)+(*v);
*v = rotr(*v, 6);
}
}
static inline void
schedule_key(uint32_t s[4])
{
/* Chaskey round */
s[0] += s[1];
s[2] += s[3];
s[1]=rotl(s[1], 5);
s[3]=rotl(s[3], 8);
s[1] ^= s[0];
s[3] ^= s[2];
s[0]=rotl(s[0],16);
s[0] += s[3];
s[2] += s[1];
s[3]=rotl(s[3],13);
s[1]=rotl(s[1], 7);
s[3] ^= s[0];
s[1] ^= s[2];
s[2]=rotl(s[2],16);
}
static void
derive_secret(uint8_t secret[16], uint32_t s[8], uint32_t seed1, uint32_t seed2)
{
int i;
uint8_t *p = secret;
for (i=0; i<4; i++) {
s[i] = p[i*4] | p[i*4+1]<<8 |
p[i*4+2]<<16 | p[i*4+3]<<24;
}
for (i=0; i<4; i++) s[4+i] = s[i];
s[1] += seed1; s[3] += seed2;
for (i=0; i<3; i++) schedule_key(s);
for (i=0; i<4; i++) s[4+i] ^= s[i];
}
void __attribute__((__noinline__))
encode48(uint32_t vb, uint32_t seed1, uint32_t seed2, uint8_t secret[16], uint8_t out[6])
{
int i,j;
uint16_t va = 0;
uint32_t s[8];
derive_secret(secret, s, seed1, seed2);
va = (uint16_t)s[3]^s[3]>>16;
for (i=1; i<=QUADROUND*4; i++) {
va ^= 0xdef*i;
vb ^= s[i&7];
mix48(&va, &vb, MIX);
}
va ^= (uint16_t)s[3]^s[3]>>16;
vb ^= s[0]^s[1]^s[2];
out[0] = (uint8_t)va;
out[1] = (uint8_t)(va>>8);
out[2] = (uint8_t)vb;
out[3] = (uint8_t)(vb>>8);
out[4] = (uint8_t)(vb>>16);
out[5] = (uint8_t)(vb>>24);
}
uint32_t __attribute__((__noinline__))
decode48(uint32_t seed1, uint32_t seed2, uint8_t secret[12], uint8_t in[6], int *ok)
{
int i,j;
uint16_t va;
uint32_t vb;
uint32_t s[8];
derive_secret(secret, s, seed1, seed2);
va = in[0] | in[1]<<8;
vb = in[2]|in[3]<<8|in[4]<<16|in[5]<<24;
va ^= (uint16_t)s[3]^s[3]>>16;
vb ^= s[0]^s[1]^s[2];
for (i=QUADROUND*4; i; i--) {
demix48(&va, &vb, MIX);
va ^= 0xdef*i;
vb ^= s[i&7];
}
*ok = va == (uint16_t)s[3]^s[3]>>16;
return vb;
}
/* There is a stuff code below */
char map[64] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ" \
"abcdefghijklmnopqrstuvwxyz" \
"0123456789-_";
uint8_t remap[256] = {};
void tobase64(uint8_t ciph[6], char base[8]) {
uint32_t v;
v = ciph[0]<<16|ciph[1]<<8|ciph[2];
base[0] = map[(v>>18)&0x3f];
base[1] = map[(v>>12)&0x3f];
base[2] = map[(v>>6)&0x3f];
base[3] = map[v&0x3f];
v = ciph[3]<<16|ciph[4]<<8|ciph[5];
base[4] = map[(v>>18)&0x3f];
base[5] = map[(v>>12)&0x3f];
base[6] = map[(v>>6)&0x3f];
base[7] = map[v&0x3f];
}
void makeremap() {
int j;
for (j=0; j<256; j++) remap[j] = 255;
for (j=0; j<64; j++) remap[(uint8_t)map[j]] = j;
}
void frombase64(uint8_t ciph[6], char base[8]) {
uint8_t *b = (uint8_t*)base;
uint8_t *c = ciph;
int j;
for (j=2; j; j--, b+=4, c+=3) {
int i;
uint32_t v = 0;
for(i=0; i<4; i++) {
uint32_t ch = remap[b[i]];
/*
b[i] >= 'A' && b[i] <= 'Z' ? b[i]-'A' :
b[i] >= 'a' && b[i] <= 'z' ? b[i] - 'a'+26 :
b[i] >= '0' && b[i] <= '9' ? b[i] - '0'+52 :
b[i] == '-' ? 62 : b[i] == '_' ? 63 : -1;
*/
v <<= 6;
v |= ch;
}
c[0] = (uint8_t)(v>>16);
c[1] = (uint8_t)(v>>8);
c[2] = (uint8_t)(v);
}
}
int main(int argc, char** argv) {
uint32_t val = 0;
uint32_t seed1, seed2;
uint8_t secret[16] = {0};
uint8_t ciph[6];
char base[8];
int r, repeat = 1;
int mode = 0;
if (argc < 5) goto help;
seed1 = atoi(argv[3]);
seed2 = atoi(argv[4]);
if (strcmp(argv[1], "demo") == 0) {
mode = 1;
val = atoi(argv[2]);
if (argc == 6) {
repeat = atoi(argv[5]);
}
} else if (strcmp(argv[1], "encode") == 0) {
mode = 2;
val = atoi(argv[2]);
} else if (strcmp(argv[1], "decode") == 0) {
if (strlen(argv[2]) != 8) goto help;
mode = 3;
memcpy(base, argv[2], 8);
}
r = read(0, secret, sizeof(secret));
if (r <= 0) {
goto help;
}
makeremap();
r = 1;
for (; repeat > 1 && r; repeat--) {
encode48(val, seed1, seed2, secret, ciph);
val = decode48(seed1, seed2, secret, ciph, &r);
}
if (!r) {
printf("mismatch during demo\n");
goto error;
}
if (mode == 1 || mode == 2)
encode48(val, seed1, seed2, secret, ciph);
if (mode == 1) {
printf("hex:\t%02x%02x%02x%02x%02x%02x\n",
ciph[0], ciph[1], ciph[2],
ciph[3], ciph[4], ciph[5]);
}
if (mode == 1 || mode == 2) {
tobase64(ciph, base);
printf("%s%.8s\n", mode==1?"base64:\t":"", base);
}
if (mode == 1 || mode == 3) {
frombase64(ciph, base);
val = decode48(seed1, seed2, secret, ciph, &r);
if (mode == 1)
printf("%d - %s\n", val, r ? "ok" : "fail");
else if (r)
printf("%d\n", val);
}
error:
return !r;
help:
printf("usage:\n");
printf("%s demo VAL SEED1 SEED2 [REPEAT] < secret\n", argv[0]);
printf("%s encode VAL SEED1 SEED2 < secret\n", argv[0]);
printf("%s decode BASE64 SEED1 SEED2 < secret\n", argv[0]);
printf("\tVAL - value to encrypt\n");
printf("\tBASE64 - encoded 8character encrypted value to decrypt\n");
printf("\tSEED1, SEED2 - seed to encrypt\n");
printf("\tsecret - 12-24byte encryption key\n");
exit(1);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment