Added a copy to clipboard button, Cleanup Code, Added Readme

This commit is contained in:
devoalda 2023-04-22 09:21:57 +08:00
parent 04b358021a
commit 2d9807410c
9 changed files with 347 additions and 31 deletions

170
.gitignore vendored Normal file
View File

@ -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/

View File

@ -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}')

111
README.MD Normal file
View File

@ -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
View File

@ -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

6
requirements.txt Normal file
View File

@ -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

View File

@ -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);

View File

@ -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);

View File

@ -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>

View File

@ -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>