Skip to content

Commit bc8baa5

Browse files
committed
process xor/rol optimised and fully implemented (thanks @webbnh)
1 parent 14b9bd8 commit bc8baa5

File tree

2 files changed

+87
-13
lines changed

2 files changed

+87
-13
lines changed

kaitai/kaitaistream.cpp

Lines changed: 79 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -432,41 +432,108 @@ std::string kaitai::kstream::bytes_terminate(std::string src, char term, bool in
432432
// ========================================================================
433433

434434
std::string kaitai::kstream::process_xor_one(std::string data, uint8_t key) {
435+
if (key == 0)
436+
return data;
437+
435438
size_t len = data.length();
436439
std::string result(len, ' ');
437440

438-
for (size_t i = 0; i < len; i++)
441+
for (size_t i = 0; i < len; i++) {
439442
result[i] = data[i] ^ key;
443+
}
440444

441445
return result;
442446
}
443447

444448
std::string kaitai::kstream::process_xor_many(std::string data, std::string key) {
445449
size_t len = data.length();
446-
size_t kl = key.length();
450+
if (len == 1)
451+
return process_xor_one(data, key[0]);
452+
447453
std::string result(len, ' ');
448454

449-
size_t ki = 0;
455+
size_t k = 0;
456+
size_t keylen = key.length();
450457
for (size_t i = 0; i < len; i++) {
451-
result[i] = data[i] ^ key[ki];
452-
ki++;
453-
if (ki >= kl)
454-
ki = 0;
458+
result[i] = data[i] ^ key[k];
459+
k++;
460+
if (k == keylen)
461+
k = 0;
455462
}
456463

457464
return result;
458465
}
459466

460-
std::string kaitai::kstream::process_rotate_left(std::string data, int amount) {
467+
uint8_t precomputedSingleRotations[8][256];
468+
469+
// NOTE: static block of code, https://stackoverflow.com/a/34321324/2375119
470+
computeSingleRotations {
471+
for (int amount = 1; amount < 8; amount++) {
472+
int anti_amount = 8 - amount;
473+
for (uint8_t i = 0; i < 256; i++) {
474+
precomputedSingleRotations[amount][i] = (uint8_t)((i << amount) | (i >> anti_amount));
475+
}
476+
}
477+
}
478+
479+
std::string kaitai::kstream::process_rotate_left(std::string data, int amount, int groupSize = 1) {
480+
if (groupSize < 1)
481+
throw std::runtime_error("process_rotate_left: groupSize must be at least 1");
482+
483+
amount = mod(amount, groupSize * 8);
484+
if (amount == 0)
485+
return data;
486+
487+
int amount_bytes = amount / 8;
461488
size_t len = data.length();
462489
std::string result(len, ' ');
463490

464-
for (size_t i = 0; i < len; i++) {
465-
uint8_t bits = data[i];
466-
result[i] = (bits << amount) | (bits >> (8 - amount));
491+
if (groupSize == 1) {
492+
uint8_t *translate = &precomputedSingleRotations[amount][0];
493+
494+
for (size_t i = 0; i < len; i++) {
495+
result[i] = translate[data[i]];
496+
}
497+
498+
return result;
467499
}
468500

469-
return result;
501+
if (len % groupSize != 0)
502+
throw std::runtime_error("process_rotate_left: data length must be a multiple of group size");
503+
504+
if (amount % 8 == 0) {
505+
size_t indices[groupSize];
506+
for (size_t i = 0; i < groupSize; i++) {
507+
indices[i] = (size_t)((i + amount_bytes) % groupSize);
508+
}
509+
510+
for (size_t i = 0; i < len; i += groupSize) {
511+
for (size_t k = 0; k < groupSize; k++) {
512+
result[i+k] = data[i + indices[k]];
513+
}
514+
}
515+
516+
return result;
517+
}
518+
519+
{
520+
int amount1 = amount % 8;
521+
int amount2 = 8 - amount1;
522+
size_t indices1[groupSize];
523+
size_t indices2[groupSize];
524+
for (size_t i = 0; i < groupSize; i++) {
525+
indices1[i] = (size_t)((i + amount_bytes) % groupSize);
526+
indices2[i] = (size_t)((i + 1 + amount_bytes) % groupSize);
527+
}
528+
529+
for (size_t i = 0; i < len; i += groupSize) {
530+
for (size_t k = 0; k < groupSize; k++) {
531+
result[i+k] = (uint8_t)((data[i + indices1[k]] << amount1) | (data[i + indices2[k]] >> amount2));
532+
}
533+
}
534+
535+
return result;
536+
}
470537
}
471538

472539
#ifdef KS_ZLIB

kaitai/kaitaistream.h

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -172,6 +172,8 @@ class kstream {
172172
/**
173173
* Performs a XOR processing with given data, XORing every byte of input with a single
174174
* given value.
175+
* WARNING: May return same byte array if key is zero.
176+
*
175177
* @param data data to process
176178
* @param key value to XOR with
177179
* @return processed data
@@ -182,6 +184,8 @@ class kstream {
182184
* Performs a XOR processing with given data, XORing every byte of input with a key
183185
* array, repeating key array many times, if necessary (i.e. if data array is longer
184186
* than key array).
187+
* WARNING: May return same byte array if key is zero.
188+
*
185189
* @param data data to process
186190
* @param key array of bytes to XOR with
187191
* @return processed data
@@ -192,11 +196,14 @@ class kstream {
192196
* Performs a circular left rotation shift for a given buffer by a given amount of bits,
193197
* using groups of 1 bytes each time. Right circular rotation should be performed
194198
* using this procedure with corrected amount.
199+
* WARNING: May return same byte array if amount is zero (modulo-wise).
200+
*
195201
* @param data source data to process
196202
* @param amount number of bits to shift by
203+
* @param groupSize number of bytes that make a group
197204
* @return copy of source array with requested shift applied
198205
*/
199-
static std::string process_rotate_left(std::string data, int amount);
206+
static std::string process_rotate_left(std::string data, int amount, int groupSize = 1);
200207

201208
#ifdef KS_ZLIB
202209
/**

0 commit comments

Comments
 (0)