Added a copy to clipboard button, Cleanup Code, Added Readme
This commit is contained in:
parent
04b358021a
commit
2d9807410c
|
@ -0,0 +1,170 @@
|
|||
### Example user template template
|
||||
### Example user template
|
||||
|
||||
# IntelliJ project files
|
||||
.idea
|
||||
*.iml
|
||||
out
|
||||
gen
|
||||
### Python template
|
||||
# Byte-compiled / optimized / DLL files
|
||||
__pycache__/
|
||||
*.py[cod]
|
||||
*$py.class
|
||||
|
||||
# C extensions
|
||||
*.so
|
||||
|
||||
# Distribution / packaging
|
||||
.Python
|
||||
build/
|
||||
develop-eggs/
|
||||
dist/
|
||||
downloads/
|
||||
eggs/
|
||||
.eggs/
|
||||
lib/
|
||||
lib64/
|
||||
parts/
|
||||
sdist/
|
||||
var/
|
||||
wheels/
|
||||
share/python-wheels/
|
||||
*.egg-info/
|
||||
.installed.cfg
|
||||
*.egg
|
||||
MANIFEST
|
||||
|
||||
# PyInstaller
|
||||
# Usually these files are written by a python script from a template
|
||||
# before PyInstaller builds the exe, so as to inject date/other infos into it.
|
||||
*.manifest
|
||||
*.spec
|
||||
|
||||
# Installer logs
|
||||
pip-log.txt
|
||||
pip-delete-this-directory.txt
|
||||
|
||||
# Unit test / coverage reports
|
||||
htmlcov/
|
||||
.tox/
|
||||
.nox/
|
||||
.coverage
|
||||
.coverage.*
|
||||
.cache
|
||||
nosetests.xml
|
||||
coverage.xml
|
||||
*.cover
|
||||
*.py,cover
|
||||
.hypothesis/
|
||||
.pytest_cache/
|
||||
cover/
|
||||
|
||||
# Translations
|
||||
*.mo
|
||||
*.pot
|
||||
|
||||
# Django stuff:
|
||||
*.log
|
||||
local_settings.py
|
||||
db.sqlite3
|
||||
db.sqlite3-journal
|
||||
|
||||
# Flask stuff:
|
||||
instance/
|
||||
.webassets-cache
|
||||
|
||||
# Scrapy stuff:
|
||||
.scrapy
|
||||
|
||||
# Sphinx documentation
|
||||
docs/_build/
|
||||
|
||||
# PyBuilder
|
||||
.pybuilder/
|
||||
target/
|
||||
|
||||
# Jupyter Notebook
|
||||
.ipynb_checkpoints
|
||||
|
||||
# IPython
|
||||
profile_default/
|
||||
ipython_config.py
|
||||
|
||||
# pyenv
|
||||
# For a library or package, you might want to ignore these files since the code is
|
||||
# intended to run in multiple environments; otherwise, check them in:
|
||||
# .python-version
|
||||
|
||||
# pipenv
|
||||
# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
|
||||
# However, in case of collaboration, if having platform-specific dependencies or dependencies
|
||||
# having no cross-platform support, pipenv may install dependencies that don't work, or not
|
||||
# install all needed dependencies.
|
||||
#Pipfile.lock
|
||||
|
||||
# poetry
|
||||
# Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control.
|
||||
# This is especially recommended for binary packages to ensure reproducibility, and is more
|
||||
# commonly ignored for libraries.
|
||||
# https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control
|
||||
#poetry.lock
|
||||
|
||||
# pdm
|
||||
# Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control.
|
||||
#pdm.lock
|
||||
# pdm stores project-wide configurations in .pdm.toml, but it is recommended to not include it
|
||||
# in version control.
|
||||
# https://pdm.fming.dev/#use-with-ide
|
||||
.pdm.toml
|
||||
|
||||
# PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm
|
||||
__pypackages__/
|
||||
|
||||
# Celery stuff
|
||||
celerybeat-schedule
|
||||
celerybeat.pid
|
||||
|
||||
# SageMath parsed files
|
||||
*.sage.py
|
||||
|
||||
# Environments
|
||||
.env
|
||||
.venv
|
||||
env/
|
||||
venv/
|
||||
ENV/
|
||||
env.bak/
|
||||
venv.bak/
|
||||
|
||||
# Spyder project settings
|
||||
.spyderproject
|
||||
.spyproject
|
||||
|
||||
# Rope project settings
|
||||
.ropeproject
|
||||
|
||||
# mkdocs documentation
|
||||
/site
|
||||
|
||||
# mypy
|
||||
.mypy_cache/
|
||||
.dmypy.json
|
||||
dmypy.json
|
||||
|
||||
# Pyre type checker
|
||||
.pyre/
|
||||
|
||||
# pytype static type analyzer
|
||||
.pytype/
|
||||
|
||||
# Cython debug symbols
|
||||
cython_debug/
|
||||
|
||||
# PyCharm
|
||||
# JetBrains specific template is maintained in a separate JetBrains.gitignore that can
|
||||
# be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore
|
||||
# and can be added to the global gitignore or merged into this file. For a more nuclear
|
||||
# option (not recommended) you can uncomment the following to ignore the entire idea folder.
|
||||
#.idea/
|
||||
|
|
@ -21,26 +21,17 @@ class CaesarCipher:
|
|||
|
||||
self.shift = shift
|
||||
self.default_pad_length = 100
|
||||
self.file_type_dict = {
|
||||
'.txt': {
|
||||
'function': self.convert_txt_to_list,
|
||||
'default_file_name': 'pad.txt'
|
||||
},
|
||||
'.csv': {
|
||||
'function': self.convert_csv_to_list,
|
||||
'default_file_name': 'pad.csv'
|
||||
}
|
||||
}
|
||||
self.file_type_dict = {'.txt': {'function': self.convert_txt_to_list, 'default_file_name': 'pad.txt'},
|
||||
'.csv': {'function': self.convert_csv_to_list, 'default_file_name': 'pad.csv'}}
|
||||
|
||||
if use_pad is False:
|
||||
if not use_pad:
|
||||
self.pad = deque([0] * self.default_pad_length)
|
||||
else:
|
||||
if file_name:
|
||||
file_name, file_extension = os.path.splitext(file_name)
|
||||
print(f'{file_name}, {file_extension}')
|
||||
if file_extension in self.file_type_dict:
|
||||
self.file_type_dict[file_extension]["function"](file_name + file_extension)
|
||||
if file:
|
||||
elif file:
|
||||
self.read_file(file)
|
||||
else:
|
||||
self.pad = pad if pad else self.gen_pad(self.default_pad_length)
|
||||
|
@ -50,6 +41,8 @@ class CaesarCipher:
|
|||
Read file object into deque, space delimited or comma delimited
|
||||
:param file: file object to read
|
||||
:type file: IO[str]
|
||||
:return: None
|
||||
:rtype: None
|
||||
"""
|
||||
# Try space delimited, then comma delimited
|
||||
try:
|
||||
|
@ -94,7 +87,7 @@ class CaesarCipher:
|
|||
pad_val = self.get_pad()
|
||||
result += chr((ord(char) + self.shift - 65 + pad_val) % 26 + 65) if char.isupper() else chr(
|
||||
(ord(char) + self.shift - 97 + pad_val) % 26 + 97)
|
||||
print(f'Result: {result}')
|
||||
# print(f'Result: {result}')
|
||||
return result
|
||||
|
||||
def decrypt(self, cipher_text: str) -> str:
|
||||
|
@ -166,6 +159,7 @@ class CaesarCipher:
|
|||
pad = [int(i) for i in pad.split(' ') if i.strip()]
|
||||
self.pad = deque(pad)
|
||||
|
||||
|
||||
except FileNotFoundError:
|
||||
print(f'File {file_name} not found. Please check the file name and try again.')
|
||||
exit(1)
|
||||
|
@ -198,6 +192,12 @@ if __name__ == "__main__":
|
|||
decipher = CaesarCipher(40, use_pad=False)
|
||||
dec = decipher.decrypt(enc)
|
||||
|
||||
cipher2 = CaesarCipher(40, use_pad=True, file_name='./pad.txt')
|
||||
enc = cipher.encrypt(text)
|
||||
|
||||
decipher2 = CaesarCipher(40, use_pad=True, file_name='./pad.txt')
|
||||
dec = decipher.decrypt(enc)
|
||||
|
||||
print(f'Original: {text}')
|
||||
print(f'Encrypted: {enc}')
|
||||
print(f'Decrypted: {dec}')
|
||||
|
|
|
@ -0,0 +1,111 @@
|
|||
# Cipher App
|
||||
|
||||
This is a simple cipher app that features:
|
||||
|
||||
- Caesar Cipher
|
||||
- Base64 Encoding/Decoding
|
||||
|
||||
This is done using flask and python, with a simple html frontend and a Caesar Cipher python script.
|
||||
|
||||
### Usage
|
||||
|
||||
```bash
|
||||
# Install the requirements
|
||||
pip install -r requirements.txt
|
||||
|
||||
# Run the app
|
||||
python app.py
|
||||
```
|
||||
|
||||
### File Locations
|
||||
|
||||
All current and future cipher files will be located in the `Ciphers` folder.
|
||||
|
||||
Web application files are located in root directory.
|
||||
|
||||
## Caesar Cipher
|
||||
|
||||
The Caesar Cipher is a simple cipher that shifts the alphabet by a certain amount. For example, if the shift is 3, then
|
||||
A becomes D, B becomes E, and so on. This is done by using the `ord()` and `chr()` functions in python.
|
||||
|
||||
What's different about this Caesar Cipher portion is the ability to include a One Time Pad (OTP) in the form of a `CSV`
|
||||
or `TXT` file. This fortifies the cipher by adding a predefined shift to the characters.
|
||||
The OTP looks like this:
|
||||
|
||||
```text
|
||||
19 33 71 15 21 25 43 38 9 68 2 79 85 97 62 80 63 61 5 71 97 73 47 20 5 6 11 83 3 97 61 11 92 67 11 59 9 53 97 39 94 63 4 99 16 3 43 42 93 28 41 18 72 75 92 16 66 82 77 10 36 1 40 73 78 11 90 94 31 70 52 52 80 45 15 60 70 6 47 29 36 28 4 90 92 8 36 56 63 85 37 81 82 35 62 20 41 41 79 68
|
||||
```
|
||||
|
||||
Where each number is a shift value for each character in the message.
|
||||
|
||||
The OTP will be generated and saved into both a `CSV` and `TXT` file if `use_pad` is set to `True` but no `file_name`
|
||||
or `file` is provided. This is done with `secrets` instead of `random` to ensure that the OTP is cryptographically
|
||||
secure.
|
||||
> Read more about `secrets` [here](https://docs.python.org/3/library/secrets.html#module-secrets)
|
||||
|
||||
### Usage of Caesar Cipher class
|
||||
|
||||
```python
|
||||
# Import the class
|
||||
from collections import deque
|
||||
|
||||
text = "Hello World, this is a test!"
|
||||
|
||||
# Pad Declaration using a list in a deque
|
||||
pad = deque([19, 33, 71, 15, 21, 25, 43, 38, 9, 68, 2, 79, 85])
|
||||
|
||||
cipher = CaesarCipher(40, use_pad=False)
|
||||
enc = cipher.encrypt(text)
|
||||
|
||||
decipher = CaesarCipher(40, use_pad=False)
|
||||
dec = decipher.decrypt(enc)
|
||||
|
||||
cipher2 = CaesarCipher(40, use_pad=True, file_name='./pad.txt')
|
||||
enc = cipher.encrypt(text)
|
||||
|
||||
decipher2 = CaesarCipher(40, use_pad=True, file_name='./pad.txt')
|
||||
dec = decipher.decrypt(enc)
|
||||
```
|
||||
|
||||
The Constructor allows for multiple parameters:
|
||||
|
||||
- `shift` - The shift value for the cipher (Default in the Web Application is 3, no default in the class)
|
||||
- `pad` - `deque` object containing the OTP (Default is `None`)
|
||||
- `file_name` - The name of the file containing the OTP (Default is `None`)
|
||||
- `file` - The file containing the OTP (Default is `None`)
|
||||
- `use_pad` - Whether to use the OTP (Default is `False`)
|
||||
|
||||
Above is the sample usage of the class. The object will have to be recreated for each message to be encrypted/decrypted
|
||||
since
|
||||
the OTP is a one time use.
|
||||
|
||||
## Base64 Encoding/Decoding
|
||||
|
||||
Base64 is a way to encode binary data into a string format. This is done by splitting the binary data into 6-bit chunks
|
||||
and then converting each chunk into a character. This is done by using the `base64` module in python.
|
||||
|
||||
The base64 encoding/decoding is done using the `base64` module in the web application.
|
||||
|
||||
## Web Application
|
||||
|
||||
The web application is done using flask and python. The frontend is done using html and css.
|
||||
|
||||
This is a simple web application that allows the user to encrypt/decrypt messages using the Caesar Cipher and Base64
|
||||
Encoding/Decoding.
|
||||
|
||||
Basic Functions:
|
||||
|
||||
- Fields are automatically updated as the user types in the message.
|
||||
- The user can choose to use the OTP (via a file upload)
|
||||
- Sliders can be used to change the shift value for the Caesar Cipher
|
||||
- Both the Caesar Cipher and Base64 Encoding/Decoding can be used at the same time
|
||||
|
||||
### Launching the Web Application
|
||||
|
||||
To launch the web application, run the `app.py` file. This will launch the web application on `localhost:5000`.
|
||||
|
||||
```bash
|
||||
python app.py
|
||||
```
|
||||
|
||||
Ensure that the requirements in `requirements.txt` file is installed before running the application.
|
7
app.py
7
app.py
|
@ -1,5 +1,5 @@
|
|||
import io
|
||||
import base64
|
||||
import io
|
||||
|
||||
from flask import Flask, render_template, request, jsonify
|
||||
|
||||
|
@ -32,14 +32,13 @@ def b64():
|
|||
else:
|
||||
sample_string_bytes = text.encode("ascii")
|
||||
base64_bytes = base64.b64encode(sample_string_bytes)
|
||||
# print(f'Encoded string: {base64_bytes.decode("ascii")}')
|
||||
result['ciphertext'] = str(base64_bytes.decode("ascii"))
|
||||
|
||||
return jsonify(result)
|
||||
|
||||
|
||||
@app.route('/encrypt_decrypt', methods=['POST'])
|
||||
def encrypt_decrypt():
|
||||
@app.route('/CaesarCipherED', methods=['POST'])
|
||||
def CaesarCipherED():
|
||||
if 'plaintext_input' in request.form:
|
||||
text = request.form['plaintext_input']
|
||||
ciphertext_input = False
|
||||
|
|
|
@ -0,0 +1,6 @@
|
|||
click==8.1.3
|
||||
Flask==2.2.3
|
||||
itsdangerous==2.1.2
|
||||
Jinja2==3.1.2
|
||||
MarkupSafe==2.1.2
|
||||
Werkzeug==2.2.3
|
|
@ -1,5 +1,5 @@
|
|||
<div class="form-group">
|
||||
<form method="POST" action="{{ url_for('encrypt_decrypt') }}">
|
||||
<form method="POST" action="{{ url_for('CaesarCipherED') }}">
|
||||
<label for="ciphertext_input">
|
||||
Enter Cipher text here:
|
||||
</label>
|
||||
|
@ -54,6 +54,7 @@
|
|||
<label for="cleartext-decrypt">Clear Text:</label>
|
||||
<input type="text" id="cleartext-decrypt" name="cleartext-decrypt" placeholder="Clear Text"
|
||||
class="form-control" readonly>
|
||||
<span onclick="copyToClipboardCaesarDecrypt()" class="btn btn-primary">Copy to Clipboard</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -74,7 +75,7 @@
|
|||
formData.append('pad_file', pad_file);
|
||||
|
||||
let xhrEncrypt = new XMLHttpRequest();
|
||||
xhrEncrypt.open('POST', '{{ url_for("encrypt_decrypt") }}');
|
||||
xhrEncrypt.open('POST', '{{ url_for("CaesarCipherED") }}');
|
||||
xhrEncrypt.onload = function () {
|
||||
let ciphertext = JSON.parse(xhrEncrypt.responseText)['ciphertext'];
|
||||
let cleartext = JSON.parse(xhrEncrypt.responseText)['cleartext'];
|
||||
|
@ -136,6 +137,12 @@
|
|||
removeBtn.style.display = 'none';
|
||||
}
|
||||
|
||||
function copyToClipboardCaesarDecrypt() {
|
||||
const ciphertextInput = document.getElementById("cleartext-decrypt");
|
||||
ciphertextInput.select();
|
||||
document.execCommand("copy");
|
||||
}
|
||||
|
||||
document.getElementById('ciphertext_input').addEventListener('input', update_decrypt);
|
||||
document.getElementById('key-slider-decrypt').addEventListener('input', updateKeyInputDecrypt);
|
||||
document.getElementById('key-input-decrypt').addEventListener('input', updateSliderValueDecrypt);
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
<div class="form-group">
|
||||
<form method="POST" action="{{ url_for('encrypt_decrypt') }}">
|
||||
<form method="POST" action="{{ url_for('CaesarCipherED') }}">
|
||||
<label for="plaintext_input">
|
||||
Enter Plaintext Here:
|
||||
</label>
|
||||
|
@ -38,6 +38,7 @@
|
|||
<label for="ciphertext">Cipher Text:</label>
|
||||
<input type="text" id="ciphertext" name="ciphertext" placeholder="Cipher Text"
|
||||
class="form-control" readonly>
|
||||
<span onclick="copyToClipboardCaesarEncrypt()" class="btn btn-outline-secondary">Copy to Clipboard</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -48,7 +49,7 @@
|
|||
<div class="form-group">
|
||||
<label for="cleartext">Clear Text:</label>
|
||||
<input type="text" id="cleartext" name="cleartext" placeholder="Clear Text"
|
||||
class="form-control" readonly >
|
||||
class="form-control" readonly>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -68,7 +69,7 @@
|
|||
formData.append('pad_file', pad_file);
|
||||
|
||||
let xhrEncrypt = new XMLHttpRequest();
|
||||
xhrEncrypt.open('POST', '{{ url_for("encrypt_decrypt") }}');
|
||||
xhrEncrypt.open('POST', '{{ url_for("CaesarCipherED") }}');
|
||||
xhrEncrypt.onload = function () {
|
||||
let ciphertext = JSON.parse(xhrEncrypt.responseText)['ciphertext'];
|
||||
let cleartext = JSON.parse(xhrEncrypt.responseText)['cleartext'];
|
||||
|
@ -130,6 +131,13 @@
|
|||
removeBtn.style.display = 'none';
|
||||
}
|
||||
|
||||
function copyToClipboardCaesarEncrypt() {
|
||||
const ciphertextInput = document.getElementById("ciphertext");
|
||||
ciphertextInput.select();
|
||||
document.execCommand("copy");
|
||||
alert("Copied to clipboard!");
|
||||
}
|
||||
|
||||
document.getElementById('plaintext_input').addEventListener('input', update);
|
||||
document.getElementById('key-slider').addEventListener('input', updateKeyInput);
|
||||
document.getElementById('key-input').addEventListener('input', updateSliderValue);
|
||||
|
|
|
@ -2,29 +2,37 @@
|
|||
<form method="POST" action="{{ url_for('b64') }}">
|
||||
<label for="b64_plaintext_input_decrypt">Enter Cipher Text Here:</label>
|
||||
<input type="text" id="b64_plaintext_input_decrypt" name="b64_plaintext_input_decrypt"
|
||||
placeholder="Enter your text here" class="form-control">
|
||||
placeholder="Enter your text here" class="form-control">
|
||||
<div class="alert alert-success">
|
||||
<label for="b64_ciphertext_decrypt">
|
||||
Clear Text:
|
||||
</label>
|
||||
<input type="text" id="b64_ciphertext_decrypt" name="b64_ciphertext_decrypt"
|
||||
placeholder="Cipher Text" class="form-control" readonly>
|
||||
<label for="b64_ciphertext_decrypt">
|
||||
Clear Text:
|
||||
</label>
|
||||
<input type="text" id="b64_ciphertext_decrypt" name="b64_ciphertext_decrypt"
|
||||
placeholder="Cipher Text" class="form-control" readonly>
|
||||
<span onclick="copyToClipboardB64Decrypt()" class="btn btn-primary">Copy to Clipboard</span>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
function b64DecryptUpdate(){
|
||||
function b64DecryptUpdate() {
|
||||
let plaintext = document.getElementById("b64_plaintext_input_decrypt").value;
|
||||
let formData = new FormData();
|
||||
formData.append('b64_ciphertext_input', plaintext);
|
||||
|
||||
let xhrRequest = new XMLHttpRequest();
|
||||
xhrRequest.open('POST', '/b64');
|
||||
xhrRequest.onload = function(){
|
||||
xhrRequest.onload = function () {
|
||||
document.getElementById("b64_ciphertext_decrypt").value = JSON.parse(xhrRequest.responseText)['cleartext'];
|
||||
};
|
||||
xhrRequest.send(formData);
|
||||
}
|
||||
|
||||
function copyToClipboardB64Decrypt() {
|
||||
const ciphertextInput = document.getElementById("b64_ciphertext_decrypt");
|
||||
ciphertextInput.select();
|
||||
document.execCommand("copy");
|
||||
}
|
||||
|
||||
document.getElementById('b64_plaintext_input_decrypt').addEventListener('input', b64DecryptUpdate);
|
||||
</script>
|
||||
|
|
|
@ -9,6 +9,7 @@
|
|||
</label>
|
||||
<input type="text" id="b64_ciphertext" name="b64_ciphertext"
|
||||
placeholder="Cipher Text" class="form-control" readonly>
|
||||
<span onclick="copyToClipboardB64Encrypt()" class="btn btn-primary">Copy to Clipboard</span>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
|
@ -27,5 +28,11 @@
|
|||
xhrRequest.send(formData);
|
||||
}
|
||||
|
||||
function copyToClipboardB64Encrypt() {
|
||||
const ciphertextInput = document.getElementById("b64_ciphertext");
|
||||
ciphertextInput.select();
|
||||
document.execCommand("copy");
|
||||
}
|
||||
|
||||
document.getElementById('b64_plaintext_input').addEventListener('input', b64Update);
|
||||
</script>
|
||||
|
|
Loading…
Reference in New Issue