1

I'm writing the code for the one time pad in python, and I've run into an issue.

I randomly choose a key from the ascii table (meaning it doesn't have to be a letter) And after I xor it with the plaintext message (which is only alphabet letters)-- I get a ciphertext that is nonsense. The xor is fine, I get that the answer should be that nonsensical ascii character, but my question is- can I get the code to return back an alphabet letter?

I was trying to work this out and my pseudo code so far was:

for i in msglen: c[i]=msg[i] ^ key[i] if c[i]<65: c=(c+65)%26 #add 65 to bring up to alphabet, mod 26 in case it goes over c+=65 #add another 65 to make up for the modular reduction. 

But obviously I got stuck in the decryption part.

1
  • 2
    Instead of pseudocode, please post actual code with examples of input and expected output. Commented Mar 18, 2017 at 17:34

3 Answers 3

3

The second part of your code is unnecessary and ruining your calculations.

One time pad is simple because it requires the same code for encryption and decryption, and that code is one line -

result = ''.join(chr(ord(s) ^ ord(k)) for s, k in zip(message, key)) 

Working with byte arrays will make that even simpler as

result = [s ^ k for s, k in zip(message, key)] 

Since x ^ x = 0 and x ^ 0 = x, we can resolve that s ^ k ^ k = s, so running this line will both encrypt a plaintext with the key and decrypt an encrypted text with that key (note that, weather it encrypts or decrypts depends on your view - a computer would not recognize that hj67si#s$jv38sok?g6e73 is probably not a plaintext).

Sign up to request clarification or add additional context in comments.

3 Comments

But the resulting ciphertext is something like: a bunch of rectangles and weird symbols ('):D\x0b\x1eH\x04\n\x01\x1fX\n\x05B\x1d\x0c\x03\x16\r'e) which is my main issue. I want the ciphertext to also be some sort of alphabetic output as well
@maree that's the point of cipher text - you are not supposed to be able to understand it. if you want a nice visualization, try hexadecimal representation with binascii.hexlify.
Thanks Uriel! Saw your update a bit after choosing the answer, but hexlify was what I was looking for. Works like a charm
0

You cannot just XOR (ASCII encoded) characters together, as they will usually not result in valid characters - even when implemented right.

There are two main ways of dealing with this. It is possible to XOR together the binary encoding of the characters and then encode it to hexadecimals or base 64. This will of course expand your ciphertext compared to your plaintext. To reverse, first decode, perform the XOR again and you'll have your binary encoded plaintext.

The other way is to encode the printable characters - the alphabet you choose to use - to a range [0, m) and then use modular addition instead of XOR with a key k to perform the one time pad. You can then convert back to the printable characters to have your ciphertext. To reverse this you do the same thing but you subtract (or add the negative key value: -k).

One problem is that to keep using a one time pad your key values within the key stream must also be in this range, and this can be tricky if you don't have a routine available to generate keys in a range [0, m) given some random bit string. See my answer here if you want to generate unbiased numbers from a random bit generator (RBG).

3 Comments

In the reverse, when you say : first decode, then preform xor again- could you clarify? Do you want me to xor the ciphertext and the key twice by itself? Or are you implying- convert the hex back to binary then xor?
nevermind, I figured it out! Thanks- the hex thing really helped. That was my main issue!
Glad it helped you create a final solution. If this was a learning experience it could be an idea to look at the solution in the link as well.
0

What you have is almost certainly not a One Time Pad. For a true OTP the key must be:

  • randomly chosen.
  • as long as the plaintext.
  • used only once.

If your key (which I suspect you use to seed some RNG somewhere) is shorter than your plaintext then what you have is a Stream Cipher, not an OTP.

Stream Ciphers are perfectly respectable, but it is a common amateur mistake to think that a Stream Cipher is an OTP. Look at RC4 for a simple, though obsolescent, Stream Cipher.

4 Comments

The key might be longer than the plaintext, choosing from a table is considered random and although generating random sequences for OTP is much better practice, this is not the cause for OPs problem. This is good as a comment though.
How are you "choosing from a table"? If you are using a computer-based RNG then the choosing is deterministic, not random. If you have a quantum-based TRNG card counting radioactive decays or whatever, then you have a randomly generated ket and hence an OTP. Then you have the problem of transferring the key (which is as long as the message) to the receiver.
en.m.wikipedia.org/wiki/Lavarand is a good enough randomness. And the key transfer is the main reason against OTP, which is why we have RSA. But I believe OP is just experimenting crypto, so these are no concern.
Lavarand is not secure once the bits get on to the Internet. The OTP key is as long as the message. If you have a secure way to send the key then you don't need to send it, just send the message itself. A true OTP is only useful in very restricted circumstances. Otherwise a block cipher or stream cipher with RSA to send the short key is the way to go.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.