Last active
April 29, 2024 09:03
-
-
Save odzhan/209275e08bf6b770de8b553d759d5d5c to your computer and use it in GitHub Desktop.
Data Masking with Byte Substitution
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
// | |
// @modexpblog | |
// | |
#include <cstdio> | |
#include <cstdlib> | |
#include <cstring> | |
#include <cstdint> | |
#include <ctime> | |
#include <cmath> | |
#include <fcntl.h> | |
#if defined(_WIN32) || defined(_WIN64) | |
#define WINDOWS | |
#include <windows.h> | |
#if defined(_MSC_VER) | |
#pragma comment(lib, "advapi32") | |
#endif | |
#else | |
#define LINUX | |
#include <unistd.h> | |
#include <sys/types.h> | |
#endif | |
#if defined(USE64) | |
// | |
// SPECK128-256 | |
// | |
#define WORDLEN 64 | |
#define PRNG_MAX_INT (INT64_MAX + 1) | |
#define ENCRYPT_KEY_LEN 32 | |
#define ENCRYPT_BLOCK_LEN 16 | |
#define R(v,n)(((v)>>(n))|((v)<<(64-(n)))) | |
typedef unsigned long long W; | |
void | |
encrypt(void*mk,void*p){ | |
W k[4],*x=(W*)p,i,t; | |
for (i=0; i<4; i++) k[i] = ((W*)mk)[i]; | |
for (i=0; i<34; i++) { | |
x[1] = (R(x[1], 8) + x[0]) ^ k[0], | |
x[0] = R(x[0], 61) ^ x[1], | |
k[1] = (R(k[1], 8) + k[0]) ^ i, | |
k[0] = R(k[0], 61) ^ k[1]; | |
t = k[1], k[1] = k[2], k[2] = k[3], k[3] = t; | |
} | |
} | |
#else | |
// | |
// SPECK64-128 | |
// | |
#define WORDLEN 32 | |
#define PRNG_MAX_INT (INT32_MAX + 1) | |
#define ENCRYPT_KEY_LEN 16 | |
#define ENCRYPT_BLOCK_LEN 8 | |
#define R(v,n)(((v)>>(n))|((v)<<(32-(n)))) | |
typedef unsigned int W; | |
void | |
encrypt(void* mk, void* p) { | |
W k[4],*x=(W*)p,i,t; | |
for (i=0; i<4; i++) k[i] = ((W*)mk)[i]; | |
for (i=0; i<27; i++) { | |
x[0] = (R(x[0], 8) + x[1]) ^ k[0], | |
x[1] = R(x[1], 29) ^ x[0], | |
t = k[3], | |
k[3] = (R(k[1], 8) + k[0]) ^ i, | |
k[0] = R(k[0], 29) ^ k[3], | |
k[1] = k[2], k[2]=t; | |
} | |
} | |
#endif | |
W | |
prng_word(void *key, W max) { | |
W r, x[2], ctr = 1, d = ((-max) / max) + 1; | |
if (d == 0) return 0; | |
for (;;) { | |
x[0] = max; | |
x[1] = ctr++; | |
encrypt(key, x); | |
r = x[0] / d; | |
if (r < max) return r; | |
} | |
} | |
void | |
shuffle(void *seed, void *inbuf, size_t inlen) { | |
uint8_t *in = (uint8_t*)inbuf; | |
for (size_t i = inlen - 1; i > 0; i--) { | |
uint32_t j = prng_word(seed, (i + 1)); | |
uint8_t t = in[i]; | |
in[i] = in[j]; | |
in[j] = t; | |
} | |
} | |
void | |
unshuffle(void *seed, void *inbuf, size_t inlen) { | |
uint8_t *in = (uint8_t*)inbuf; | |
for (size_t i = 0; i < inlen; i++) { | |
uint32_t j = prng_word(seed, (i + 1)); | |
uint8_t t = in[i]; | |
in[i] = in[j]; | |
in[j] = t; | |
} | |
} | |
int | |
random(void *buf, uint64_t len) { | |
#if defined(_WIN32) | |
HCRYPTPROV prov; | |
int ok; | |
// 1. acquire crypto context | |
if(!CryptAcquireContext( | |
&prov, NULL, NULL, | |
PROV_RSA_FULL, | |
CRYPT_VERIFYCONTEXT | CRYPT_SILENT)) return 0; | |
ok = (int)CryptGenRandom(prov, (DWORD)len, (PBYTE)buf); | |
CryptReleaseContext(prov, 0); | |
return ok; | |
#else | |
int fd; | |
uint64_t r=0; | |
uint8_t *p=(uint8_t*)buf; | |
fd = open("/dev/urandom", O_RDONLY); | |
if(fd > 0) { | |
for(r=0; r<len; r++, p++) { | |
if(read(fd, p, 1) != 1) break; | |
} | |
close(fd); | |
} | |
return r == len; | |
#endif | |
} | |
// | |
// simple byte substitution using fisher-yates shuffle and DRBG | |
// | |
typedef struct _mask_ctx { | |
uint8_t sbox[256], sbox_inv[256]; | |
} mask_ctx; | |
void | |
init_mask(mask_ctx *c) { | |
uint8_t seed[ENCRYPT_KEY_LEN]; | |
// initialise sbox | |
for (int i=0; i<256; i++) { | |
c->sbox[i] = (uint8_t)i; | |
} | |
// initialise seed | |
random(seed, ENCRYPT_KEY_LEN); | |
// shuffle sbox using random seed. | |
shuffle(seed, c->sbox, 256); | |
// create inverse | |
for (int i=0; i<256; i++) { | |
c->sbox_inv[c->sbox[i]] = i; | |
} | |
} | |
// mask buf | |
void | |
encode(mask_ctx *c, void *buf, size_t len) { | |
uint8_t *x = (uint8_t*)buf; | |
for (size_t i=0; i<len; i++) { | |
x[i] = c->sbox[x[i]]; | |
} | |
} | |
// unmask buf | |
void | |
decode(mask_ctx *c, void *buf, size_t len) { | |
uint8_t *x = (uint8_t*)buf; | |
for (size_t i=0; i<len; i++) { | |
x[i] = c->sbox_inv[x[i]]; | |
} | |
} | |
void | |
dump(const char *str, void *buf, size_t len) { | |
uint8_t *x = (uint8_t*)buf; | |
printf("\n%s:\n", str); | |
for (size_t i=0; i<len; i++) { | |
printf(" %02X", x[i]); | |
} | |
} | |
int | |
main(int argc, char *argv[]) { | |
mask_ctx c; | |
uint8_t buf[32]; | |
// using random bytes here for testing.. | |
random(buf, sizeof(buf)); | |
init_mask(&c); | |
dump("raw", buf, sizeof(buf)); | |
encode(&c, buf, sizeof(buf)); | |
dump("encoded", buf, sizeof(buf)); | |
decode(&c, buf, sizeof(buf)); | |
dump("decoded", buf, sizeof(buf)); | |
return 0; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment