Hi. I was searching for a working implementation of the one time pad encryption method in C++, but wasn't able to find one, so I wrote it myself. Wanted to share this in case someone needs it. Feel free to use, distribute, sell or modify the code as you see fit: https://github.com/DDomjosa/One-time-pad-encryption
Everything is explained in the program itself, so I won't go over it again. If you want to add (remove) legal characters, all you have to do is add (remove) them to (from) the tempAlphabetChars array on line 225 and increase (decrease) the alphabetSize on line 10 accordingly (that's the size of the array) and you're done.
If you have any suggestions or observations to share, please do. Thanks!
Mersenne Twister is not a cryptographically secure PRNG. Extreme care should be taken when generating a pad, since the security of OTP relies entirely on the quality of the random numbers. Ideally, a true randomness source should be used.
The encryption and decryption algorithms are too complex. They should not be more complex than
1 2 3 4 5 6 7
void otp_crypto(void *_data, constvoid *_pad, size_t n){
auto data = (unsignedchar *)_data;
auto pad = (constunsignedchar *)_pad;
while (n--){
data[n] ^= pad[n];
}
}
Note that otp_crypto() is self-inverse when the second and third parameters are maintained.
I don't see any reason why the program needs to be aware of an alphabet. Just process byte values.
I tried using random_device to seed the Mersenne Twister, but apparently there's a bug in MinGW that prevents me from doing that, so I just stuck to using the time (I know it's a horrible idea!). It's not like I'll be encrypting top secret documents anyway (or will I?)...
At first I was going to just XOR the bits, but soon I found out that that would result in encrypted text containing a ton of unreadable characters, such as NULLs, hearts, etc., so I just resorted to letting the user only use characters that have been given integer values to prevent that sort of thing.
For example, XORing the chars 'a' and 'b' gives a binary value of 00000011, that's the end of text character, console interprets it as a heart, notepad as a superscript L and notepad++ as an ETX character and I don't want to deal with that.
I tried using random_device to seed the Mersenne Twister, but apparently there's a bug in MinGW that prevents me from doing that, so I just stuck to using the time (I know it's a horrible idea!).
You would still be using MT to generate the numbers, so it doesn't matter much. It'd be better to use std::random_device instead, which is supposed to be as close as the system can get to a true randomness source.
It's not like I'll be encrypting top secret documents anyway (or will I?)
Then the implementation is pointless. The only people who use OTP use it because they need a mathematical guarantee of uncrackability.
I found out that that would result in encrypted text containing a ton of unreadable characters, such as NULLs, hearts, etc.
And?
If you want "human readable" output then just encode the ciphertext in Base64 or even hex. That complexity doesn't belong in the encryption functions.
Like I said, I can't use random_device due to a bug (for the record, I'm using the Code::Blocks IDE). On the note of output, thank you for opening my eyes. I will rewrite the program to just XOR it. Could you please explain a few things though? What do these notations mean:
void *_data, constvoid *_pad, auto data = (unsignedchar *)_data;, auto pad = (constunsignedchar *)_pad;
Also, how would you go about encoding (and then decoding) the ciphertext in Base64? How would you go about generating the key? A random sequence of 1s and 0s? How can you convert that into chars? char a = (char)01100001; doesn't seem to work. Thank you a lot!
EDIT:
Found a way to generate 8 random bits and convert them into a char:
Like I said, I can't use random_device due to a bug
You said you couldn't use it to seed Mersenne Twister. I'm saying don't use Mersenne Twister at all. Just get your numbers from std::random_device. An OTP implementation that gets its pads from Mersenne Twister is simply broken. It doesn't matter if you get your numbers as bits or as multibit integers.
What do these notations mean:
The first one is simply a function parameter list. The other two are casts.
terminate called after throwing an instance of 'std::runtime_error'
what(): random_device::random_device(const std::string&)
This application has requested the Runtime to terminate it in an unusual way.
Please contact the application's support team for more information.
As for the function parameters, what I meant to say is why are you passing something in as void? Doesn't that just result in it being nothing or am I thinking completely wrong? Thanks!
Ok, I rewrote the whole program ( https://github.com/DDomjosa/One-time-pad-encryption ) and it works up until a point. It can encrypt/decrypt small pieces of text easily, but when it comes to a wall of text ( http://uncyclopedia.wikia.com/wiki/Wall_of_Text for example) it outputs a key and ciphertext files that are both different sizes from each other and the original text (???) and when decrypting it only decrypts like a few first words. Where did I go wrong? Also, on line 11 it doesn't let me change the type of input to unsigned char (maybe that's the problem?)...
Oh, and I created my own file extension just to feel cool (and to lower the risk of people messing with the files manually).
I will look into that, now I just want it to work fully. I figured out why it decrypts only a few words. When it encounters a SUB character (decimal 26), it thinks that's the end of the file. How can this be handled? This doesn't work:
1 2 3 4 5 6 7
while (read.get(input))
{
if (input == '\x1A')
chars.push_back('\x1A');
else
chars.push_back(input);
}
https://github.com/DDomjosa/One-time-pad-encryption I figured it out!!! It works fully, implementing base64 encoding fixed the SUB character issue too! Thank you so much for helping and not telling me the answers directly, helios!