# Crypto Algs (Part 3.0): XOR

Hello again. I know Fust3rCluck covered this, but I had something different in mind…

XOR, or Exclusive XOR, is a Boolean Logic Gate. Like most of the other logic gates, XOR takes two parameters. Thus, it is a binary logic gate.

XOR is a computationally easy form of encryption. However, it certainly is breakable. What follows is my take on it.

# Proof

``````Given: n XOR n = 0
and: n XOR 0 = n
Plaintext: p
Ciphertext: p XOR n = c
Decrypted: c XOR n = p

p XOR n = c
c XOR n = p

(p XOR n) XOR n = p
p XOR (n XOR n) = p
n XOR n = 0
p XOR (0) = p
p = p
``````

# Implementation

encrypt.cpp

``````#include <iostream>
#include <string>
#include <vector>
#include <algorithm>

namespace XOR {
std::vector<unsigned char>
encrypt(const std::vector<unsigned char> str, const std::string& key)
{
std::vector<unsigned char> res(str.begin(), str.end());

for (int i = 0, n = str.size(), m = key.length(); i < n; i++) {
res[i] ^= key[i % m];
}

return res;
}

std::vector<unsigned char>
decrypt(const std::vector<unsigned char>& str, const std::string& key)
{
return encrypt(str,key);
}
};
``````

The above code is pretty straightforward. I am using the `std::vector` container in place of `std::string` to avoid any awkward null-terminators, which could be present when copying an encrypted message into a new `std::string`. Essentially, a `std::vector<unsigned char>` is a string.

Notice that the `decrypt(...)` function simply calls the above `encrypt(...)` function. Unlike in the Vigenere Cipher code, there is no need to complement the key before decryption. This is because of the above proof.

``````#include "./encrypt.cpp"
#include <iomanip>

void hex_print(const std::vector<unsigned char>& s) {
std::cout << std::hex;
for (auto& c : s) {
std::cout << int(c) << " ";
}
std::cout << std::hex << std::endl;
}

int main() {
std::string s,k;
std::getline(std::cin, s);
std::getline(std::cin, k);

std::vector<unsigned char> v(s.begin(),s.end());
v = XOR::encrypt(v,k);

hex_print(v);

v = XOR::decrypt(v, k);

for(auto& c : v) {
std::cout << c;
}
std::cout << std::endl;

return 0;
}
``````

The above code interfaces with that mini library I wrote (encrypt.cpp). We `hex_print(...)` the ciphertext because some of the characters could be unreadable ASCII characters. We don’t have to worry about this when we decrypt the ciphertext – as long as our encryption scheme is implemented correctly, that is…

# Conclusion

You may see a few similarities between the Vigenere program I wrote and the above code. The program outlined here allows for a variable-length key, rather than a one-byte key or a statically defined key. This is both convenient and more secure.

Feel free to play around with the code. It’s all there.

Later…
@oaktree

8 Likes

Loved it mate! Keep it up! Love the series as a whole!

1 Like

This topic was automatically closed after 30 days. New replies are no longer allowed.