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