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)