Skip to content

Commit 109e2bc

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

File tree

2 files changed

+82
-12
lines changed

2 files changed

+82
-12
lines changed

kaitai/kaitaistream.cpp

Lines changed: 74 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -432,41 +432,104 @@ 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();
446450
size_t kl = key.length();
451+
if (len == 1)
452+
return process_xor_one(data, key[0]);
453+
447454
std::string result(len, ' ');
448455

449-
size_t ki = 0;
450456
for (size_t i = 0; i < len; i++) {
451-
result[i] = data[i] ^ key[ki];
452-
ki++;
453-
if (ki >= kl)
454-
ki = 0;
457+
result[i] = data[i] ^ key[i % kl];
455458
}
456459

457460
return result;
458461
}
459462

460-
std::string kaitai::kstream::process_rotate_left(std::string data, int amount) {
463+
uint8_t precomputedSingleRotations[8][256];
464+
465+
// NOTE: code based on StackOverflow answer at https://stackoverflow.com/a/34321324/2375119
466+
computeSingleRotations {
467+
for (int amount = 1; amount < 8; amount++) {
468+
int anti_amount = 8 - amount;
469+
for (uint8_t i = 0; i < 256; i++) {
470+
precomputedSingleRotations[amount][i] = (uint8_t)((i << amount) | (i >> anti_amount));
471+
}
472+
}
473+
}
474+
475+
std::string kaitai::kstream::process_rotate_left(std::string data, int amount, int groupSize = 1) {
476+
if (groupSize < 1)
477+
throw std::runtime_error("process_rotate_left: groupSize must be at least 1");
478+
479+
amount = mod(amount, groupSize * 8);
480+
if (amount == 0)
481+
return data;
482+
483+
int amount_bytes = amount / 8;
461484
size_t len = data.length();
462485
std::string result(len, ' ');
463486

464-
for (size_t i = 0; i < len; i++) {
465-
uint8_t bits = data[i];
466-
result[i] = (bits << amount) | (bits >> (8 - amount));
487+
if (groupSize == 1) {
488+
uint8_t *translate = &precomputedSingleRotations[amount][0];
489+
490+
for (size_t i = 0; i < len; i++) {
491+
result[i] = translate[data[i]];
492+
}
493+
494+
return result;
467495
}
468496

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

472535
#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)