Previous: 05-SubstitutionFrequency.html

Meet Alice and Bob (and sometimes evil Eve)!

http://cryptocouple.com/ (show in class)

https://en.wikipedia.org/wiki/Alice_and_Bob

- Password for the Vimeo videos is in Zulip chat.
- SP21: https://vimeo.com/510344865
- FS20: https://vimeo.com/458219783
- Tip: If anyone wants to speed up the lecture videos a little,
inspect the page, go to the browser console, and paste this in:
`document.querySelector('video').playbackRate = 1.2`

http://inventwithpython.com/cracking/ Chapter 21

Our first **modern** encryption algorithm.

It’s also **primitive**.

The only **timeless** encryption algorithm!

https://en.wikipedia.org/wiki/One-time_pad

http://users.telenet.be/d.rijmenants/en/onetimepad.htm

One Time Pad (OTP) is **not** the same thing as a One
Time Password (OTP):

https://en.wikipedia.org/wiki/One-time_password

is **not** what we’re talking about today.

**What defines a “one time pad”?**

The key is at least as long as the message or data that must be
encrypted.

The key is **truly random.**

It is not generated by a deterministic pseudo-random software
function.

Key and plain-text are calculated mod the encoding base,

for example:

modulo 10 (digits),

modulo 26 (letters), or

modulo 2 (binary)

mod also works as you would expect in binary (or any base).

Example mod 26:

Communication partners **must** securely pre-share their
secret keys!

Information-theoretic security of the correctly implemented OTP is
truly **perfect**,

since the message contains absolutely no “information”.

Given a ciphertext from a correctly implemented OTP,

all plaintext messages are equally likely.

The following are equally likely:

+++++++++++++++++++++

**Cahoot-06.1**

Re-using a OTP key is the Vigenere cipher!

**Cryptographically secure** pseudo-random number
generator (CSPRNG)

or cryptographic pseudo-random number generator (CPRNG)

is a pseudo-random number generator (PRNG),

with properties that make it suitable for use in cryptography.

**Pseudorandom** number generators (PRNG)

also known as a deterministic random bit generator (DRBG),

is an algorithm for generating a sequence of numbers,

whose properties approximate the properties of sequences of random
numbers.

The PRNG-generated sequence is not truly random,

because it is completely determined by an initial value,

called the PRNG’s seed (which may include truly random values).

**There are two primary methods used to generate random
numbers.**

**Physical**

The first method measures some**physical phenomenon**that is expected to be random,

and then compensates for possible biases in the measurement process.

Example sources include measuring atmospheric noise,

thermal noise, and other external electromagnetic or quantum phenomena.

For example, cosmic background radiation or radioactive decay,

as measured over short timescales represent sources of**natural entropy**.

In Linux distributions, the pseudo device file`/dev/random`

will block,

until sufficient entropy is harvested from the environment for retrieval.**Computational**

The second method uses deterministic**computational algorithms,**

that can produce long sequences of apparently random results,

which are completely determined by a short initial seed value,

known as a seed value, key, or nonce.

As a result, the entire seemingly random sequence can be reproduced,

if the seed value is known.

This type is often called a**pseudorandom**number generator,

and typically does not continually rely on sources of naturally occurring entropy,

though it may be periodically seeded by natural sources to compensate or start.

+++++++++++++++++++++

**Cahoot-06.2**

**The module random (random.random, etc.) and numpy.random are
not “truly” random:**

https://docs.python.org/3/library/random.html

**Use the module called secrets instead:**

https://docs.python.org/3/library/secrets.html

The secrets module is used for generating cryptographically strong
random numbers.

It is suitable for managing data such as:

passwords, account authentication, security tokens, and related
secrets.

Secrets should be used in preference to the random module,

which is designed for modeling and simulation,

not for security or cryptography.

To generate a 55-long OTP key, for a 55-long message:

06-OneTimePad/secrets_demo.py

```
#!/usr/bin/python3
# -*- coding: utf-8 -*-
import secrets
otp: str = ""
for _ in range(55):
otp += secrets.choice("ABCDEFGHIJKLMNOPQRSTUVWXYZ .")
print(otp)
# or more concisely
otp = "".join([secrets.choice("ABCDEFGHIJKLMNOPQRSTUVWXYZ .") for _ in range(55)])
print(otp)
```

or from /dev/random for a big integer:

06-OneTimePad/urandom_demo.py

```
#!/usr/bin/python3
# -*- coding: utf-8 -*-
import os
print(os.urandom(10))
# or
with open("/dev/random", "rb") as f:
print(int.from_bytes(f.read(10), "big"))
```

You could post-process this into random characters.

See this for more detail on (`/dev/urandom`

vs /dev/random|`/dev/random`

.html.html):

https://www.2uo.de/myths-about-urandom/

../../DataStructuresLab/Content/01-02-LinuxBash.html

Section # Generate random strings

**Discussion Question:**

Can you think of any practical issues with actually using the OTP?

Requires **physical delivery** for certainty of perfect
security.

Is this practical?

Do other algorithms have a similar constraint?

End-points are vulnerable.

As they are generally, in most security systems.

What else is like this?

Each key is used only once.

Is this practical?

How?

There should only be n copies of the key(s) for n parties,

one for each sender and one for each receiver.

The key material must be securely destroyed after use,

to ensure the key material is never reused,

and to protect the messages sent.

How?

Because the key material must be transported from one endpoint to
another,

and persists until the message is sent or received,

it can be more vulnerable to forensic recovery,

compared to the transient plaintext it protects.

How, when?

A simple hack/conversion of some code from our previous
algorithms:

06-OneTimePad/otp.py

```
#!/usr/bin/python3
# -*- coding: utf-8 -*-
"""
How could this code be improved?
@author: taylor@mst.edu
"""
import secrets
LETTERS = "ABCDEFGHIJKLMNOPQRSTUVWXYZ ."
def keygen(keylen: int) -> str:
return "".join([secrets.choice(LETTERS) for _ in range(keylen)])
def main() -> None:
myMessage = (
"The generation of random numbers is too important to be left to chance."
)
myMode = "encrypt" # Set to either 'encrypt' or 'decrypt'.
if myMode == "encrypt":
myKey = keygen(len(myMessage))
print("Your ONE-TIME use key is:\n", myKey, "\n")
translated = translateMessage(myKey, myMessage, "encrypt")
elif myMode == "decrypt":
myKey = input("What was the ONE-TIME use key you securily pre-shared?")
translated = translateMessage(myKey, myMessage, "decrypt")
print("Your " + myMode + "ed message was:", translated)
def translateMessage(key: str, message: str, mode: str) -> str:
translated = [] # Stores the encrypted/decrypted message string.
keyIndex = 0
key = key.upper()
for symbol in message: # Loop through each symbol in message.
num = LETTERS.find(symbol.upper())
if num != -1: # -1 means symbol.upper() was not found in LETTERS.
if mode == "encrypt":
num += LETTERS.find(key[keyIndex]) # Add if encrypting.
elif mode == "decrypt":
num -= LETTERS.find(key[keyIndex]) # Subtract if decrypting.
num %= len(LETTERS) # Handle any wraparound.
# Add the encrypted/decrypted symbol to the end of translated:
if symbol.isupper():
translated.append(LETTERS[num])
elif symbol.islower():
translated.append(LETTERS[num].lower())
keyIndex += 1 # Move to the next letter in the key.
else:
# Append the symbol without encrypting/decrypting.
translated.append(symbol)
return "".join(translated)
if _name_ == "_main_":
main()
```

**Ask**:

Taken from which cipher in the book?

Could this be simplified?

Discuss:

This is a base-26 (or symbol-set size base) otp.

One could compute the OTP in any base.

Does the number of symbols impact strength?

Would it be weaker if there were only two symbols?

+++++++++++++++++++++

**Cahoot-06.3**

General symbol is \(\oplus\).

Subset of the bitwise operators in Python:

In interpreting the below code,

remember that the ints 1 and 0 are the same as the binary numbers 0 and
1.

The `^`

operator operates on the binary representation of
int,

or directly on a binary string number,

e.g., 0b11111

06-OneTimePad/xor.py

```
#!/usr/bin/python3
# -*- coding: utf-8 -*-
import operator
print(1 ^ 0)
print(0 ^ 1)
print(1 ^ 1)
print(0 ^ 0)
# or where the operator lives
print(operator.xor(1, 0))
print(operator.xor(0, 1))
print(operator.xor(1, 1))
print(operator.xor(0, 0))
# Example on binary strings:
print(31 ^ 30)
print(bin(0b1111 ^ 0b1110))
```

A clean, simple, and general OTP implementation:

- Plaintext
- Encrypted message / Ciphertext

- Length of message
- Key

P = {0, 1}^{n}

C = {0, 1}^{n}

P = {0, 1}^{n}

E(p, k) = p \(\oplus\) k

D(c, k) = c \(\oplus\) k

Does it even matter what the key-space, plaintext, or ciphertext
space is?

What about in the lower limit of message length, 0 or 1 bit?

Encrypt by xor’ing input with key:

How to decrypt?

Just repeat to go backwards!

n = 5 the length of the data

p = 01011 which is 11

k = 10111 which is 23

c = p \(\oplus\) k

11100 = 01011 \(\oplus\) 10111

```
Also written as:
~~~
c = p ^ k
11100 = 01011 ^ 10111
~~~
```

p = c \(\oplus\) k

01011 = 11100 \(\oplus\) 10111

```
Also written as:
~~~
p = c ^ k
01011 = 11100 ^ 10111
~~~
```

```
#!/usr/bin/python3
# -*- coding: utf-8 -*-
n = 5
p = 0b01011
k = 0b10111
print("plaintext is:", p, bin(p))
print("key is:", k, bin(k))
c = p ^ k
print("ciphertext is:", c, bin(c))
p = c ^ k
print("recovered plaintext is:", p, bin(p))
```

Original message is unambiguously recoverable with XOR,

but not other bit-wise operators, why?

https://www.devdungeon.com/content/working-binary-data-python

06-OneTimePad/numeric_bases_encoding.py (review in class)

These two are for you to ponder when doing this in python:

06-OneTimePad/ascii_newline.py

06-OneTimePad/ascii_nonewline.py

https://docs.python.org/3.7/howto/unicode.html

https://git-classes.mst.edu/taylorpat/python-otp

The permissions on this project are institutional.

You just have to be logged into git-classes to see it.

For personal text-based communications?

Has key-storage changed since this algorithm was used more widely?

For watching videos?

For video-chatting?

http://pidgin-paranoia.sourceforge.net/

There are many variants of the OTP, hardware, quantum, light,
etc.,

but they’re all just the OTP.

The next time you hear about some new exciting **perfect**
cryptography,

you’ll know it’s just the same old OTP!

Next: 07-CryptoMath.html