Last active
July 19, 2016 11:29
-
-
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
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#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