HiveBrain v1.2.0
Get Started
← Back to all entries
patterncppMinor

Citadel's VisualEncrypt and VisualDecrypt

Submitted by: @import:stackexchange-codereview··
0
Viewed 0 times
andcitadelvisualencryptvisualdecrypt

Problem

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  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 
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 
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 
Iterator VisualEncrypt (Iterator begin, Iterator end)
{
    return VisualEncrypt (begin, end, begin) ;
}

template 
Iterator VisualDecrypt (Iterator begin, Iterator end)
{
    return VisualDecrypt (begin, end, begin) ;
}


Here are two sample cases of it being used:

```
#include
#include
#include

int main ()
{
// Test char
std::string plaintext = "Please encrypt me!" ;

std::vector 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,

Solution

The way you handle the first element as a special case is cumbersome: you're basically unrolling the first iteration of the loop. You could just initialize value = 0 so that the first XOR just copies the input to the output.

template 
OutputIterator VisualEncrypt (InputIterator begin, InputIterator end, OutputIterator destination)
{
    typedef typename std::iterator_traits::value_type T;
    T value = 0;
    while (begin != end) {
        value ^= *begin++;
        *destination++ = value ;
    }

    return destination ;
}

template 
OutputIterator VisualDecrypt (InputIterator begin, InputIterator end, OutputIterator destination)
{
    typedef typename std::iterator_traits::value_type T;
    T value = 0;

    while (begin != end) {
        T temp = *begin++;
        *destination++ = value ^ temp ;
        value = temp ;
    }

    return destination ;
}


Alternatively, use a for-loop, which results in slightly more compact code and gets the pesky side-effect ++ operators out of the way.

template 
OutputIterator VisualEncrypt(InputIterator begin, InputIterator end, OutputIterator destination)
{
    typedef typename std::iterator_traits::value_type T;
    for (T value = 0; begin != end; ++begin, ++destination) {
        *destination = (value ^= *begin);    // 
OutputIterator VisualDecrypt(InputIterator begin, InputIterator end, OutputIterator destination)
{
    typedef typename std::iterator_traits::value_type T;
    for (T value = 0; begin != end; ++begin, ++destination) {
        T temp = *begin;
        *destination = value ^ temp;
        value = temp;
    }

    return destination;
}

Code Snippets

template <class InputIterator, class OutputIterator>
OutputIterator VisualEncrypt (InputIterator begin, InputIterator end, OutputIterator destination)
{
    typedef typename std::iterator_traits<InputIterator>::value_type T;
    T value = 0;
    while (begin != end) {
        value ^= *begin++;
        *destination++ = value ;
    }

    return destination ;
}

template <class InputIterator, class OutputIterator>
OutputIterator VisualDecrypt (InputIterator begin, InputIterator end, OutputIterator destination)
{
    typedef typename std::iterator_traits<InputIterator>::value_type T;
    T value = 0;

    while (begin != end) {
        T temp = *begin++;
        *destination++ = value ^ temp ;
        value = temp ;
    }

    return destination ;
}
template <class InputIterator, class OutputIterator>
OutputIterator VisualEncrypt(InputIterator begin, InputIterator end, OutputIterator destination)
{
    typedef typename std::iterator_traits<InputIterator>::value_type T;
    for (T value = 0; begin != end; ++begin, ++destination) {
        *destination = (value ^= *begin);    // <-- Probably controversial one-liner
    }

    return destination;
}

template <class InputIterator, class OutputIterator>
OutputIterator VisualDecrypt(InputIterator begin, InputIterator end, OutputIterator destination)
{
    typedef typename std::iterator_traits<InputIterator>::value_type T;
    for (T value = 0; begin != end; ++begin, ++destination) {
        T temp = *begin;
        *destination = value ^ temp;
        value = temp;
    }

    return destination;
}

Context

StackExchange Code Review Q#57420, answer score: 7

Revisions (0)

No revisions yet.