Module otp_emoji
Used to generate ๐ one-time pads ๐ค exclusively in emojis.
Also has functions for ๐'ing and ๐'ing text with the one time pads. The module exposes both an API and entrypoint. API documentation begins after the entrypoint usage information.
๐ฅ๏ธScript Usage
The usage POSIX string for the otp_emoji script:
Usage
-----
otp_emoji [-h] [-v]
otp_emoji encrypt <text> [-s] [-o OUTPUT_PATH] [-p PAD_PATH]
otp_emoji decrypt <ciphertext> <pad> [-s] [-o OUTPUT_PATH]
Options:
-h, --help show this help message and exit
-v, --version show program's version number and exit
-o OUTPUT_PATH, --output OUTPUT_PATH
custom directory of where to write
pad/plaintext/ciphertext output
-p PAD_PATH, --pad PAD_PATH
allows you to specify a pre-created one time pad
-s, --stream print result to output stream (stdout)
So for example you could run otp_emoji encrypt secret_text.txt
which will create
a ciphertext and pad of the contents of secret_text.txt and output them to the current
directory as pad.txt
and ciphertext.txt
respectively. You could then run
otp_emoji decrypt ciphertext.txt pad.txt
which would decrypt the message and send the
output to the current directory as plaintext.txt
.
๐ฆVariables
chipher_chars : (list) The list of emojis useable for creating one time pads
usage : (str)
The POSIX usage string that drives docopt for the otp_emoji
script
๐Notes
-
๐ซ DON'T USE THIS IN PRODUCTION ๐ซ I created this project to help better understand my security course in ๐ซ.
-
Note that because of the mapping necessary to make the project more secure in case someone does actually use this only ASCII characters can be used.
-
No I will not put this on PyPi, again I put minimal effort into this and it's better for it to remain a dissapointment to me than the python community as a whole.
-
When opening a text file with the api make sure to pass the encoding parameter to open() as 'UTF-8' otherwise there will be an error when the charmaps are read. i.e.
with open('pad.txt', encoding='utf-8') as pad_file:
pad = pad_file.read()
๐ฉโ๐ซReferences
One Time Pad explanations:
- <https://searchsecurity.techtarget.com/definition/one-time-pad>
- <http://users.telenet.be/d.rijmenants/en/onetimepad.htm>
- <https://www.cryptomuseum.com/crypto/otp/index.htm>
- <https://medium.com/blockgeeks-blog/cryptography-for-dummies-part-4-the-one-time-pad-7711438c9b8a>
ASCII chart for supported characters: - https://www.commfront.com/pages/ascii-chart
๐คทExamples
Encrypting 'Do not go gentle into that good night' by Dylan Thomas
from otp_emoji import encrypt, decrypt
text = '''Do not go gentle into that good night,
Old age should burn and rave at close of day;
Rage, rage against the dying of the light.
Though wise men at their end know dark is right,
Because their words had forked no lightning they
Do not go gentle into that good night.
Good men, the last wave by, crying how bright
Their frail deeds might have danced in a green bay,
Rage, rage against the dying of the light.
Wild men who caught and sang the sun in flight,
And learn, too late, they grieved it on its way,
Do not go gentle into that good night.
Grave men, near death, who see with blinding sight
Blind eyes could blaze like meteors and be gay,
Rage, rage against the dying of the light.
And you, my father, there on the sad height,
Curse, bless, me now with your fierce tears, I pray.
Do not go gentle into that good night.
Rage, rage against the dying of the light.'''
ciphertext, pad = encrypt(text, pad_path='./pad.txt', ciphertext_path='./ciphertext.txt')
decrypt(ciphertext, pad, text_path='./decrypted_text.txt')
TODO
- Get emoji map up to 255
- Change generate OTP to use emoji map and secrets hex generation
- Write ciphertext as emoji's
Expand source code
"""Used to generate ๐ one-time pads ๐ค exclusively in emojis.
Also has functions for ๐'ing and ๐'ing text with the one time pads. The
module exposes both an API and entrypoint. API documentation begins after the
entrypoint usage information.
๐ฅ๏ธScript Usage
--------------
The usage POSIX string for the otp_emoji script:
```
Usage:
otp_emoji [-h] [-v]
otp_emoji encrypt <text> [-s] [-o OUTPUT_PATH] [-p PAD_PATH]
otp_emoji decrypt <ciphertext> <pad> [-s] [-o OUTPUT_PATH]
Options:
-h, --help show this help message and exit
-v, --version show program's version number and exit
-o OUTPUT_PATH, --output OUTPUT_PATH
custom directory of where to write
pad/plaintext/ciphertext output
-p PAD_PATH, --pad PAD_PATH
allows you to specify a pre-created one time pad
-s, --stream print result to output stream (stdout)
```
So for example you could run ```otp_emoji encrypt secret_text.txt``` which will create
a ciphertext and pad of the contents of secret_text.txt and output them to the current
directory as ```pad.txt``` and ```ciphertext.txt``` respectively. You could then run
```otp_emoji decrypt ciphertext.txt pad.txt``` which would decrypt the message and send the
output to the current directory as ```plaintext.txt```.
๐ฆVariables
------------
chipher_chars : (list)
The list of emojis useable for creating one time pads
usage : (str)
The POSIX usage string that drives docopt for the ``otp_emoji`` script
๐Notes
--------
- ๐ซ DON'T USE THIS IN PRODUCTION ๐ซ I created this project to help better
understand my security course in ๐ซ.
- Note that because of the mapping necessary to make the project more secure in case someone
does actually use this only ASCII characters can be used.
- No I will not put this on PyPi, again I put minimal effort into this and it's
better for it to remain a dissapointment to me than the python community as a whole.
- When opening a text file with the api make sure to pass the encoding parameter to open()
as 'UTF-8' otherwise there will be an error when the charmaps are read. i.e.
```
with open('pad.txt', encoding='utf-8') as pad_file:
pad = pad_file.read()
```
๐ฉโ๐ซReferences
-------------
One Time Pad explanations:
- https://searchsecurity.techtarget.com/definition/one-time-pad
- http://users.telenet.be/d.rijmenants/en/onetimepad.htm
- https://www.cryptomuseum.com/crypto/otp/index.htm
- https://medium.com/blockgeeks-blog/cryptography-for-dummies-part-4-the-one-time-pad-7711438c9b8a
ASCII chart for supported characters:
- https://www.commfront.com/pages/ascii-chart
๐คทExamples
-----------
Encrypting 'Do not go gentle into that good night' by Dylan Thomas
```
from otp_emoji import encrypt, decrypt
text = '''Do not go gentle into that good night,
Old age should burn and rave at close of day;
Rage, rage against the dying of the light.
Though wise men at their end know dark is right,
Because their words had forked no lightning they
Do not go gentle into that good night.
Good men, the last wave by, crying how bright
Their frail deeds might have danced in a green bay,
Rage, rage against the dying of the light.
Wild men who caught and sang the sun in flight,
And learn, too late, they grieved it on its way,
Do not go gentle into that good night.
Grave men, near death, who see with blinding sight
Blind eyes could blaze like meteors and be gay,
Rage, rage against the dying of the light.
And you, my father, there on the sad height,
Curse, bless, me now with your fierce tears, I pray.
Do not go gentle into that good night.
Rage, rage against the dying of the light.'''
ciphertext, pad = encrypt(text, pad_path='./pad.txt', ciphertext_path='./ciphertext.txt')
decrypt(ciphertext, pad, text_path='./decrypted_text.txt')
```
TODO
----
* Get emoji map up to 255
* Change generate OTP to use emoji map and secrets hex generation
* Write ciphertext as emoji's
"""
# Standard lib dependencies
import os # Used to validate filepaths
import sys # Used to fix arglengths of 0 for CLI
import logging # Used to log (obviously)
from copy import deepcopy
from typing import Generator # Used to typehint generator returns
from secrets import token_hex # Used to produce reliably random hex values
# External Dependencies
from docopt import docopt # Used to handle argument parsing from the entrypoint
usage = """Used to generate one-time pads ๐ค, by default in emojis.
Usage:
otp_emoji [-h] [-v]
otp_emoji encrypt <text> [-s] [-o OUTPUT_PATH] [-p PAD_PATH]
otp_emoji decrypt <ciphertext> <pad> [-s] [-o OUTPUT_PATH]
Options:
-h, --help show this help message and exit
-v, --version show program's version number and exit
-o OUTPUT_PATH, --output OUTPUT_PATH
a directory of where to write pad/plaintext/ciphertext
output
-p PAD_PATH, --pad PAD_PATH
allows you to specify a pre-created one time pad
-s, --stream print result to output stream (stdout)
"""
cipher_chars = [
"๐ค", "๐", "๐คฎ", "๐คง", "๐ฅต", "๐", "๐
", "๐", "๐", "๐", "๐", "๐", "๐ต", "๐", "๐",
"๐จโ๐ป", "๐จโ๐ค", "๐ง", "๐งโโ๏ธ", "๐งโโ๏ธ", "๐ง", "๐จโ๐ฆผ", "๐ง", "โท", "๐ถ", "๐ฆ", "๐ฆ", "๐", "๐ข", "๐ฆ", "๐ฆ",
"๐", "๐ณ", "๐", "๐ฆ", "๐ฆ", "๐ฅ", "๐ฅจ", "๐ฅฏ", "๐ฅ", "๐", "๐", "๐ง", "๐", "๐ฆ", "๐ฆ", "๐ฆ",
"๐บ", "๐", "๐", "๐ฆผ", "๐", "๐ธ", "๐", "โ", "๐", "๐ฅ", "โ", "๐ฆบ", "๐ฉ", "๐ท", "๐ป", "๐พ",
"๐ค", "๐ค", "๐ค", "๐ค", "๐", "๐", "๐ค", "๐", "๐", "๐คณ", "๐ช", "๐", "๐", "๐จโ๐ฆฐ", "๐จโ๐ฆฑ", "๐ง", "๐ฉโ๐ฆณ",
"๐ฉ", "๐ฉโ๐ฆฒ", "๐ด", "๐
", "๐", "๐โโ๏ธ", "๐โโ๏ธ", "๐งโโ๏ธ", "๐", "๐คฆ", "๐คฆโโ๏ธ", "๐คฆโโ๏ธ", "๐คท", "๐คทโโ๏ธ", "๐คทโโ๏ธ", "๐จโ๐", "๐จโ๐ซ",
"๐จโ๐พ", "๐จโ๐ง", "๐ฉโ๐ญ", "๐ฉโ๐ผ", "๐จโ๐ฌ", "๐ฉโ๐ป", "๐จโ๐จ", "๐ฉโโ๏ธ", "๐ฎ", "๐ต", "๐", "๐ท", "๐
", "๐ฆธ", "๐ง", "๐ง", "๐", "๐จโ๐ฆฏ",
"๐ฏ", "๐คบ", "๐", "๐", "โน", "๐", "๐ด", "๐คธ", "๐คฝ", "๐คผ", "๐คน", "๐ง", "๐", "๐จโ๐ฉโ๐ฆโ๐ฆ", "๐จโ๐ฉโ๐งโ๐ง", "๐จโ๐จโ๐งโ๐ฆ", "๐ฉโ๐ฉโ๐งโ๐ฆ", "๐ฉโ๐ฉโ๐งโ๐ง",
"๐ค", "๐ค", "๐", "๐", "๐", "๐", "๐งก", "๐ฏ", "๐ฅ", "๐ฆ", "๐ฃ", "๐จ", "๐ค", "๐", "๐", "๐", "๐", "๐ฃ",
"๐", "๐ฟ", "๐น", "๐", "๐ฆ", "๐ฆฅ", "๐ฆฆ", "๐ฆจ", "๐ฆ", "๐ฆ", "๐", "๐ฅ", "๐ง", "๐", "๐ฆ
", "๐ฆ", "๐ฆข", "๐",
"๐ฆ", "๐", "๐", "๐", "๐ฆ", "๐", "๐ท", "๐ฎ", "๐ต", "๐ท", "๐ฑ", "๐ฟ", "๐", "๐ฅ", "๐ถ", "๐ฅ", "๐ณ", "๐ฅ", "๐ฟ",
"๐บ", "๐ป", "๐ฅ", "๐ฝ", "๐", "๐", "๐", "๐ฐ", "๐ฝ", "๐ผ", "โฉ", "๐", "๐", "โฒ", "๐", "โจ", "๐", "๐ก", "๐ค", "โฝ",
"โต", "๐ค", "โ", "๐", "๐", "๐งณ", "๐", "๐", "๐", "๐", "๐", "๐", "๐", "๐ช", "โญ", "๐", "๐", "๐ช", "๐", "โฑ",
"โก", "โ", "๐ฅ", "๐ง", "๐", "๐", "๐", "๐งง", "๐ฅ", "๐ฅ
", "๐ฃ", "๐คฟ", "๐ฟ", "๐ฅ", "๐ฑ", "๐ฎ", "๐ฐ", "๐ฒ", "โ ", "โ",
"๐ด", "๐งต", "๐ฅผ", "๐", "๐งฅ", "๐ฅพ", "๐จ", "๐"
]
emoji_map = {
"๐ค" : 0,"๐" : 1,"๐คฎ" : 2,"๐คง" : 3,"๐ฅต" : 4,"๐" : 5,"๐
" : 6,"๐" : 7,"๐" : 8,"๐" : 9,"๐" : 10,
"๐" : 11,"๐ต" : 12,"๐" : 13,"๐" : 14,"๐จโ๐ป" : 15,"๐จโ๐ค" : 16,"๐ง" : 17,"๐งโโ๏ธ" : 18,"๐งโโ๏ธ" : 19,"๐ง" : 20,
"๐จโ๐ฆผ" : 21,"๐ง" : 22,"โท" : 23,"๐ถ" : 24,"๐ฆ" : 25,"๐ฆ" : 26,"๐" : 27,"๐ข" : 28,"๐ฆ" : 29,"๐ฆ" : 30,
"๐" : 31,"๐ณ" : 32,"๐" : 33,"๐ฆ" : 34,"๐ฆ" : 35,"๐ฅ" : 36,"๐ฅจ" : 37,"๐ฅฏ" : 38,"๐ฅ" : 39,"๐" : 40,
"๐" : 41,"๐ง" : 42,"๐" : 43,"๐ฆ" : 44,"๐ฆ" : 45,"๐ฆ" : 46,"๐บ" : 47,"๐" : 48,"๐" : 49,"๐ฆผ" : 50,
"๐" : 51,"๐ธ" : 52,"๐" : 53,"โ" : 54,"๐" : 232,"๐ฅ" : 241,"โ" : 247,"๐ฆบ" : 58,"๐ฉ" : 59,"๐ท" : 60,
"๐ป" : 61,"๐พ" : 62,"๐ค" : 63,"๐ค" : 64,"๐ค" : 65,"๐ค" : 66,"๐" : 67,"๐" : 68,"๐ค" : 69,"๐" : 70,
"๐" : 71,"๐คณ" : 72,"๐ช" : 73,"๐" : 74,"๐" : 75,"๐จโ๐ฆฐ" : 76,"๐จโ๐ฆฑ" : 77,"๐ง" : 78,"๐ฉโ๐ฆณ" : 79,"๐ฉ" : 80,
"๐ฉโ๐ฆฒ" : 81,"๐ด" : 82,"๐
" : 83,"๐" : 84,"๐โโ๏ธ" : 85,"๐โโ๏ธ" : 86,"๐งโโ๏ธ" : 87,"๐" : 88,"๐คฆ" : 89,"๐คฆโโ๏ธ" : 90,
"๐คฆโโ๏ธ" : 91,"๐คท" : 92,"๐คทโโ๏ธ" : 93,"๐คทโโ๏ธ" : 94,"๐จโ๐" : 95,"๐จโ๐ซ" : 96,"๐จโ๐พ" : 97,"๐จโ๐ง" : 98,"๐ฉโ๐ญ" : 99,"๐ฉโ๐ผ" : 100,
"๐จโ๐ฌ" : 101,"๐ฉโ๐ป" : 102,"๐จโ๐จ" : 103,"๐ฉโโ๏ธ" : 104,"๐ฎ" : 105,"๐ต" : 106,"๐" : 107,"๐ท" : 108,"๐
" : 109,"๐ฆธ" : 110,
"๐ง" : 111,"๐ง" : 112,"๐" : 113,"๐จโ๐ฆฏ" : 114,"๐ฏ" : 115,"๐คบ" : 116,"๐" : 117,"๐" : 118,"โน" : 119,"๐" : 120,
"๐ด" : 121,"๐คธ" : 122,"๐คฝ" : 123,"๐คผ" : 124,"๐คน" : 125,"๐ง" : 126,"๐" : 127,"๐จโ๐ฉโ๐ฆโ๐ฆ" : 128,"๐จโ๐ฉโ๐งโ๐ง" : 129,"๐จโ๐จโ๐งโ๐ฆ" : 130,
"๐ฉโ๐ฉโ๐งโ๐ฆ" : 131,"๐ฉโ๐ฉโ๐งโ๐ง" : 132,"๐ค" : 133,"๐ค" : 134,"๐" : 135,"๐" : 136,"๐" : 137,"๐" : 138,"๐งก" : 139,"๐ฏ" : 140,
"๐ฅ" : 141,"๐ฆ" : 142,"๐ฃ" : 143,"๐จ" : 144,"๐ค" : 145,"๐" : 146,"๐" : 147,"๐" : 148,"๐" : 149,"๐ฃ" : 150,
"๐" : 151,"๐ฟ" : 152,"๐น" : 153,"๐" : 154,"๐ฆ" : 155,"๐ฆฅ" : 156,"๐ฆฆ" : 157,"๐ฆจ" : 158,"๐ฆ" : 159,"๐ฆ" : 160,
"๐" : 161,"๐ฅ" : 162,"๐ง" : 163,"๐" : 164,"๐ฆ
" : 165,"๐ฆ" : 166,"๐ฆข" : 167,"๐" : 168,"๐ฆ" : 169,"๐" : 170,
"๐" : 171,"๐" : 172,"๐ฆ" : 173,"๐" : 174,"๐ท" : 175,"๐ฎ" : 176,"๐ต" : 177,"๐ท" : 178,"๐ฑ" : 179,"๐ฟ" : 180,
"๐" : 181,"๐ฅ" : 182,"๐ถ" : 183,"๐ฅ" : 184,"๐ณ" : 185,"๐ฅ" : 186,"๐ฟ" : 187,"๐บ" : 188,"๐ป" : 189,"๐ฅ" : 190,
"๐ฝ" : 191,"๐" : 192,"๐" : 193,"๐" : 194,"๐ฐ" : 195,"๐ฝ" : 196,"๐ผ" : 197,"โฉ" : 198,"๐" : 199,"๐" : 200,
"โฒ" : 201,"๐" : 202,"โจ" : 203,"๐" : 204,"๐ก" : 205,"๐ค" : 206,"โฝ" : 207,"โต" : 208,"๐ค" : 209,"โ" : 210,
"๐" : 211,"๐" : 212,"๐งณ" : 213,"๐" : 214,"๐" : 215,"๐" : 216,"๐" : 217,"๐" : 218,"๐" : 219,"๐" : 220,
"๐ช" : 221,"โญ" : 222,"๐" : 223,"๐" : 224,"๐ช" : 225,"๐" : 226,"โฑ" : 227,"โก" : 228,"โ" : 229,"๐ฅ" : 230,
"๐ง" : 231,"๐" : 233,"๐" : 234,"๐งง" : 235,"๐ฅ" : 236,"๐ฅ
" : 237,"๐ฃ" : 238,"๐คฟ" : 239,"๐ฟ" : 240,"๐ฑ" : 242,
"๐ฎ" : 243,"๐ฐ" : 244,"๐ฒ" : 245,"โ " : 246,"๐ด" : 248,"๐งต" : 249,"๐ฅผ" : 250,"๐" : 251,"๐งฅ" : 252,"๐ฅพ" : 253,
"๐จ" : 254,"๐" : 255
}
def generate_otp(length:int) -> Generator:
"""Generates a one time pad of emojis based on input length.
Parameters
----------
length:(int)
The amount of random emoji's to generate.
Yields
------
str:
The next character in the one time pad
Examples
--------
Generating a 10 character otp
```
from otp_emoji import generate_otp
otp = generate_otp(10)
for character in otp: # Iterate through resulting generator
print(character) # Prints: ๐๐ง๐ง๐จโ๐ค๐ฉ๐ฅฏ๐ง๐๐บ๐ง
```
"""
for digit in range(length):
hex_value = int(token_hex(1), 16)
yield cipher_chars[hex_value] + "|"
def encrypt(input_text:str, pad:bool=False, pad_path:str = False, ciphertext_path:str = False) -> tuple:
"""Encrypts ๐ text using provided pad, or generates one of the same length.
Parameters
----------
input_text:(str)
The text you would like to encrypt.
pad:(bool|str)
If pad is specified it will be used to encrypt
if left False it will be generated for you.
pad_path:(bool|str)
If specified then it will be the path the pad is
written to.
ciphertext_path:(bool|str)
If specified then it will be the path the ciphertext
is written to.
Returns
------
tuple[str,str]:
The ciphertext, and the onetime pad
Examples
--------
Encrypting a 1984 (George Orwell) quote and saving
the resulting ciphertext and path to files.
```
from otp_emoji import encrypt
text = 'Who controls the past controls the future. Who controls the present controls the past.'
# Creates ciphertext and pad and saves them in current directory as pad.txt and ciphertext.txt respectively
ciphertext, pad = encrypt(text, pad_path='./pad.txt', ciphertext_path='./ciphertext.txt')
```
"""
print("๐ Encrypting Text ๐")
logging.debug(f"input_text = {input_text}")
logging.debug(f"pad={pad}")
logging.debug(f"pad_path={pad_path}")
logging.debug(f"ciphertext_path={ciphertext_path}")
ciphertext = ""
if not pad:
pad = ""
for count, character in enumerate(generate_otp(len(input_text))):
logging.debug(character)
pad += character
shifted_value = ""
character = character[0:-1] # remove | delimiter from pad character
logging.debug(f"{input_text[count]} ^ {character}({emoji_map[character]})")
shifted_value += cipher_chars[(ord(input_text[count]) ^ emoji_map[character])]
ciphertext += (shifted_value) + "|" # Delimit ciphertext by pipes and append
logging.debug(f"pad={pad}")
else: # If custom pad is provided
pad = deepcopy(pad)
pad = pad.split("|")
for character in zip(input_text, pad):
print(f"Character= {character[0]} {character[1]}")
shifted_value = ""
logging.debug(f"{input_text[count]} ^ {character}({emoji_map[character]})")
shifted_value += cipher_chars[(ord(input_text[count]) ^ emoji_map[character])]
ciphertext += (shifted_value) + "|" # Delimit ciphertext by pipes and append
ciphertext = ciphertext[0:-1]
if pad_path:
with open(pad_path, "wb") as otp_file:
otp_file.write(pad.encode("utf-8"))
logging.info(f"One-time-pad text written to: {pad_path}")
if ciphertext_path:
with open(ciphertext_path, "wb") as encrypted_message:
encrypted_message.write(ciphertext.encode("utf-8"))
logging.info(f"Encrypted text written to: {ciphertext_path}")
return ciphertext, pad
def decrypt(cipher_text:str, pad:str, text_path:str = False) -> str:
"""Decrypts ๐ text using provided pad.
Parameters
----------
cipher_text:(str)
The text you would like to decrypt.
pad:(str)
The pad that corresponds with the ciphertext.
text_path:(bool|str)
If specified then it will be the path the decrypted
text is written to.
Returns
------
str:
The decrypted text
Examples
--------
Encrypting some text from files found in the encrypt() example.
```
from otp_emoji import decrypt
pad = ''
ciphertext = ''
with open('pad.txt') as pad_file:
pad = pad_file.read()
with open('ciphertext.txt') as ciphertext_file:
ciphertext = ciphertext_file.read()
print( decrypt(ciphertext, pad) ) # Prints: 'Who controls the past controls the future. Who controls the present controls the past.'
```
"""
cipher_text = cipher_text.split("|") # Split ciphertext by pipes
pad = pad.split("|") # Split pad by pipes
print("๐ Decrypting text ๐")
plaintext = ""
logging.debug(f"cipher_text={cipher_text}")
logging.debug(f"pad={pad}")
for character in zip(cipher_text, pad): # Use pad to decrypt each character
logging.debug(f"Character= {character[0]} {character[1]}")
decrypted_value = ""
logging.debug(f"{character[0]} ^ {character[1]}")
decrypted_value += chr(emoji_map[character[0]] ^ emoji_map[character[1]])
plaintext += decrypted_value
if text_path:
with open(os.path.abspath(text_path), "wb") as encrypted_message:
encrypted_message.write(plaintext.encode("utf-8"))
logging.info(f"Decrypted text written to: {text_path}")
return plaintext
def main() -> None:
"""otp_emoji script entrypoint; handles logic for the otp_emoji command"""
if len(sys.argv) == 1: # If no arguments are provided
print(usage) # Print helptext
exit() # Exit program
args = docopt(usage, version="otp_emoji V 1.3.0")
# ================== Encrypt Argument Parsing ==================
if args["encrypt"]:
if os.path.isfile(args["<text>"]):
with open(args["<text>"], encoding="utf-8") as text_file:
args["<text>"] = text_file.read()
if args["--output"]:
if not os.path.isdir(args["--output"]): # If no valid output directory specified
args["--output"] = os.curdir
else:
args["--output"] = os.curdir
ciphertext, pad = encrypt(args["<text>"], args["--pad"], pad_path=f"{args['--output']}{os.sep}pad.txt", ciphertext_path=f"{args['--output']}{os.sep}ciphertext.txt")
if args["--stream"]:
print(f"Ciphertext: {ciphertext}")
print(f"Pad: {pad}")
# ================== Decrypt Argument Parsing ==================
if args["decrypt"]:
with open(args["<ciphertext>"], encoding="utf-8") as ciphertext_file:
args["<ciphertext>"] = ciphertext_file.read()
with open(args["<pad>"], encoding="utf-8") as pad_file:
args["<pad>"] = pad_file.read()
if args["--output"]:
if not os.path.isdir(args["--output"]): # If no valid output directory specified
args["--output"] = os.curdir
print(f"Provided output path was not valid using {os.curdir} instead")
else:
args["--output"] = os.curdir
plaintext = decrypt(args["<ciphertext>"], args["<pad>"], text_path=f"{args['--output']}{os.sep}plaintext.txt")
if args["--stream"]:
print(plaintext)
if __name__ == "__main__":
main() # Runs the otp_emoji command
Functions
def decrypt(cipher_text, pad, text_path=False)
-
Decrypts ๐ text using provided pad.
Parameters
cipher_text:(str) The text you would like to decrypt.
pad:(str) The pad that corresponds with the ciphertext.
text_path:(bool|str) If specified then it will be the path the decrypted text is written to.
Returns
str
:- The decrypted text
Examples
Encrypting some text from files found in the encrypt() example.
from otp_emoji import decrypt pad = '' ciphertext = '' with open('pad.txt') as pad_file: pad = pad_file.read() with open('ciphertext.txt') as ciphertext_file: ciphertext = ciphertext_file.read() print( decrypt(ciphertext, pad) ) # Prints: 'Who controls the past controls the future. Who controls the present controls the past.'
Expand source code
def decrypt(cipher_text:str, pad:str, text_path:str = False) -> str: """Decrypts ๐ text using provided pad. Parameters ---------- cipher_text:(str) The text you would like to decrypt. pad:(str) The pad that corresponds with the ciphertext. text_path:(bool|str) If specified then it will be the path the decrypted text is written to. Returns ------ str: The decrypted text Examples -------- Encrypting some text from files found in the encrypt() example. ``` from otp_emoji import decrypt pad = '' ciphertext = '' with open('pad.txt') as pad_file: pad = pad_file.read() with open('ciphertext.txt') as ciphertext_file: ciphertext = ciphertext_file.read() print( decrypt(ciphertext, pad) ) # Prints: 'Who controls the past controls the future. Who controls the present controls the past.' ``` """ cipher_text = cipher_text.split("|") # Split ciphertext by pipes pad = pad.split("|") # Split pad by pipes print("๐ Decrypting text ๐") plaintext = "" logging.debug(f"cipher_text={cipher_text}") logging.debug(f"pad={pad}") for character in zip(cipher_text, pad): # Use pad to decrypt each character logging.debug(f"Character= {character[0]} {character[1]}") decrypted_value = "" logging.debug(f"{character[0]} ^ {character[1]}") decrypted_value += chr(emoji_map[character[0]] ^ emoji_map[character[1]]) plaintext += decrypted_value if text_path: with open(os.path.abspath(text_path), "wb") as encrypted_message: encrypted_message.write(plaintext.encode("utf-8")) logging.info(f"Decrypted text written to: {text_path}") return plaintext
def encrypt(input_text, pad=False, pad_path=False, ciphertext_path=False)
-
Encrypts ๐ text using provided pad, or generates one of the same length.
Parameters
input_text:(str) The text you would like to encrypt.
pad:(bool|str) If pad is specified it will be used to encrypt if left False it will be generated for you.
pad_path:(bool|str) If specified then it will be the path the pad is written to.
ciphertext_path:(bool|str) If specified then it will be the path the ciphertext is written to.
Returns
tuple
[str
,str
]:- The ciphertext, and the onetime pad
Examples
Encrypting a 1984 (George Orwell) quote and saving the resulting ciphertext and path to files.
from otp_emoji import encrypt text = 'Who controls the past controls the future. Who controls the present controls the past.' # Creates ciphertext and pad and saves them in current directory as pad.txt and ciphertext.txt respectively ciphertext, pad = encrypt(text, pad_path='./pad.txt', ciphertext_path='./ciphertext.txt')
Expand source code
def encrypt(input_text:str, pad:bool=False, pad_path:str = False, ciphertext_path:str = False) -> tuple: """Encrypts ๐ text using provided pad, or generates one of the same length. Parameters ---------- input_text:(str) The text you would like to encrypt. pad:(bool|str) If pad is specified it will be used to encrypt if left False it will be generated for you. pad_path:(bool|str) If specified then it will be the path the pad is written to. ciphertext_path:(bool|str) If specified then it will be the path the ciphertext is written to. Returns ------ tuple[str,str]: The ciphertext, and the onetime pad Examples -------- Encrypting a 1984 (George Orwell) quote and saving the resulting ciphertext and path to files. ``` from otp_emoji import encrypt text = 'Who controls the past controls the future. Who controls the present controls the past.' # Creates ciphertext and pad and saves them in current directory as pad.txt and ciphertext.txt respectively ciphertext, pad = encrypt(text, pad_path='./pad.txt', ciphertext_path='./ciphertext.txt') ``` """ print("๐ Encrypting Text ๐") logging.debug(f"input_text = {input_text}") logging.debug(f"pad={pad}") logging.debug(f"pad_path={pad_path}") logging.debug(f"ciphertext_path={ciphertext_path}") ciphertext = "" if not pad: pad = "" for count, character in enumerate(generate_otp(len(input_text))): logging.debug(character) pad += character shifted_value = "" character = character[0:-1] # remove | delimiter from pad character logging.debug(f"{input_text[count]} ^ {character}({emoji_map[character]})") shifted_value += cipher_chars[(ord(input_text[count]) ^ emoji_map[character])] ciphertext += (shifted_value) + "|" # Delimit ciphertext by pipes and append logging.debug(f"pad={pad}") else: # If custom pad is provided pad = deepcopy(pad) pad = pad.split("|") for character in zip(input_text, pad): print(f"Character= {character[0]} {character[1]}") shifted_value = "" logging.debug(f"{input_text[count]} ^ {character}({emoji_map[character]})") shifted_value += cipher_chars[(ord(input_text[count]) ^ emoji_map[character])] ciphertext += (shifted_value) + "|" # Delimit ciphertext by pipes and append ciphertext = ciphertext[0:-1] if pad_path: with open(pad_path, "wb") as otp_file: otp_file.write(pad.encode("utf-8")) logging.info(f"One-time-pad text written to: {pad_path}") if ciphertext_path: with open(ciphertext_path, "wb") as encrypted_message: encrypted_message.write(ciphertext.encode("utf-8")) logging.info(f"Encrypted text written to: {ciphertext_path}") return ciphertext, pad
def generate_otp(length)
-
Generates a one time pad of emojis based on input length.
Parameters
length:(int) The amount of random emoji's to generate.
Yields
str
:- The next character in the one time pad
Examples
Generating a 10 character otp
from otp_emoji import generate_otp otp = generate_otp(10) for character in otp: # Iterate through resulting generator print(character) # Prints: ๐๐ง๐ง๐จโ๐ค๐ฉ๐ฅฏ๐ง๐๐บ๐ง
Expand source code
def generate_otp(length:int) -> Generator: """Generates a one time pad of emojis based on input length. Parameters ---------- length:(int) The amount of random emoji's to generate. Yields ------ str: The next character in the one time pad Examples -------- Generating a 10 character otp ``` from otp_emoji import generate_otp otp = generate_otp(10) for character in otp: # Iterate through resulting generator print(character) # Prints: ๐๐ง๐ง๐จโ๐ค๐ฉ๐ฅฏ๐ง๐๐บ๐ง ``` """ for digit in range(length): hex_value = int(token_hex(1), 16) yield cipher_chars[hex_value] + "|"
def main()
-
otp_emoji script entrypoint; handles logic for the otp_emoji command
Expand source code
def main() -> None: """otp_emoji script entrypoint; handles logic for the otp_emoji command""" if len(sys.argv) == 1: # If no arguments are provided print(usage) # Print helptext exit() # Exit program args = docopt(usage, version="otp_emoji V 1.3.0") # ================== Encrypt Argument Parsing ================== if args["encrypt"]: if os.path.isfile(args["<text>"]): with open(args["<text>"], encoding="utf-8") as text_file: args["<text>"] = text_file.read() if args["--output"]: if not os.path.isdir(args["--output"]): # If no valid output directory specified args["--output"] = os.curdir else: args["--output"] = os.curdir ciphertext, pad = encrypt(args["<text>"], args["--pad"], pad_path=f"{args['--output']}{os.sep}pad.txt", ciphertext_path=f"{args['--output']}{os.sep}ciphertext.txt") if args["--stream"]: print(f"Ciphertext: {ciphertext}") print(f"Pad: {pad}") # ================== Decrypt Argument Parsing ================== if args["decrypt"]: with open(args["<ciphertext>"], encoding="utf-8") as ciphertext_file: args["<ciphertext>"] = ciphertext_file.read() with open(args["<pad>"], encoding="utf-8") as pad_file: args["<pad>"] = pad_file.read() if args["--output"]: if not os.path.isdir(args["--output"]): # If no valid output directory specified args["--output"] = os.curdir print(f"Provided output path was not valid using {os.curdir} instead") else: args["--output"] = os.curdir plaintext = decrypt(args["<ciphertext>"], args["<pad>"], text_path=f"{args['--output']}{os.sep}plaintext.txt") if args["--stream"]: print(plaintext)