I was skimming through this paper out of boredom. On pages 5 and 6, the paper shows a simple encryption/decryption scheme that Citadel uses to obfuscate data. The algorithm basically XORs the next character with the previous character. The code is roughly this (ugly, I know):
void VisualEncrypt (void *buffer, unsigned size) { for (unsigned i = 1; i < size; ++i) { ((unsigned char *) buffer) [i] ^= ((unsigned char *) buffer) [i - 1] ; } } void VisualDecrypt (void *buffer, unsigned size) { if (!size) { return ; } for (unsigned i = size - 1; i > 0; --i) { ((unsigned char *) buffer) [i] ^= ((unsigned char *) buffer) [i - 1] ; } }
I decided to make a more generic version of this code so that it could work on different containers and values:
template <class InputIterator, class OutputIterator>
OutputIterator VisualEncrypt (InputIterator begin, InputIterator end, OutputIterator destination)
{
if (begin == end) {
return destination ;
}
auto value = *begin ;
*destination++ = value ;
while (++begin != end) {
value ^= *begin ;
*destination++ = value ;
}
return destination ;
}
template <class InputIterator, class OutputIterator>
OutputIterator VisualDecrypt (InputIterator begin, InputIterator end, OutputIterator destination)
{
if (begin == end) {
return destination ;
}
auto value = *begin ;
*destination++ = value ;
while (++begin != end) {
auto temp = *begin ;
*destination++ = value ^ temp ;
value = temp ;
}
return destination ;
}
template <class Iterator>
Iterator VisualEncrypt (Iterator begin, Iterator end)
{
return VisualEncrypt (begin, end, begin) ;
}
template <class Iterator>
Iterator VisualDecrypt (Iterator begin, Iterator end)
{
return VisualDecrypt (begin, end, begin) ;
}
Here are two sample cases of it being used:
#include <iterator>
#include <string>
#include <vector>
int main ()
{
// Test char
std::string plaintext = "Please encrypt me!" ;
std::vector <unsigned char> cyphertext ;
VisualEncrypt (plaintext.cbegin (), plaintext.cend (), std::back_inserter (cyphertext)) ;
std::string decrypttext ;
VisualDecrypt (cyphertext.cbegin (), cyphertext.cend (), std::back_inserter (decrypttext)) ;
// Test long
long arr [] = {1, 2, 3, 4, 5} ;
const auto size = sizeof (arr) / sizeof (arr [0]) ;
VisualEncrypt (arr, arr + size) ;
VisualDecrypt (arr, arr + size) ;
return 0 ;
}
The code seems to work fine. I want to make sure I'm not misusing the iterators and invoking undefined behavior. I couldn't find a clean way to simplify any of this with the <algorithm>
library. Any tips on that would be great too.
std::transform
with a simple callable (a struct with a single data member like yourvalue
and anoperator()
) would do the job. \$\endgroup\$