This is a quick follow up post to Data Masking that discussed how one might use the Fisher-Yates shuffle and a DRBG to mask shellcode. There’s a lot of ways to mask data that don’t involve using an XOR operation but despite being relatively simple to implement are rarely used. You can use involutions, a partial XOR, base encoding, simple arithmetic using addition and subtraction. In the past, I’ve found components of block and stream ciphers to be a good source of techniques because the operations need to be invertible. In this post we’ll look at how easy it is to use byte substitution.
Although substitution ciphers date back to ancient times, DES was first to use fixed s-box arrays for encrypting data. Since then, such non-linear operations have become a standard component of many block ciphers. To implement, we perform the following steps:
This S-Box can then be used for masking data and the inverse can be used for unmasking. The reason we use a random seed to shuffle the s-box is so that the masked data is always different. Here’s a snippet of C code to demonstrate…
// // simple byte substitution using fisher-yates shuffle and DBRG // 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/key 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; }
And here’s the output of the program.
You can simplify this further by just using the srand() and rand() functions instead of a DRBG. See the full example here.
This entry was posted in Uncategorized. Bookmark the permalink.