Initial Commit

This commit is contained in:
devoalda 2023-04-21 22:15:14 +08:00
commit 04b358021a
7 changed files with 732 additions and 0 deletions

View File

@ -0,0 +1,205 @@
import os
import secrets
from collections import deque
from typing import IO
class CaesarCipher:
def __init__(self, shift: int, pad: deque = None, file_name: str = None, use_pad: bool = False,
file: IO[str] = None):
"""
Constructor for CaesarCipher class
:param shift: value to shift the alphabet by
:type shift: int
:param pad: pad to use for encryption/decryption
:type pad: deque
:param file_name: path to file containing pad
:type file_name: str
:param use_pad: True: use pad, False: generate pad
:type use_pad: bool
"""
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'
}
}
if use_pad is False:
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:
self.read_file(file)
else:
self.pad = pad if pad else self.gen_pad(self.default_pad_length)
def read_file(self, file: IO[str]) -> None:
"""
Read file object into deque, space delimited or comma delimited
:param file: file object to read
:type file: IO[str]
"""
# Try space delimited, then comma delimited
try:
self.pad = deque([int(num) for num in filter(str.isdigit, file.read().split(' '))])
print(f'Space Pad: {self.pad}')
except ValueError:
self.pad = deque([int(num) for num in filter(str.isdigit, file.read().split(','))])
print(f'comma Pad: {self.pad}')
except Exception as e:
print(f'Error reading file: {e}')
def get_pad(self) -> int:
"""
Get the next value from the pad
:return: next value from the pad
:rtype: int
"""
try:
pad_val = self.pad.popleft()
except (IndexError, AttributeError):
print(f'Error! Please pass the pad/pad file as an argument!')
self.gen_pad()
pad_val = self.pad.popleft()
return pad_val
def encrypt(self, plain_text: str) -> str:
"""
Encrypt plain_text using the Caesar Cipher
:param plain_text: text to encrypt
:type plain_text: str
:return: cipher text
:rtype: str
"""
result = ""
for char in plain_text:
if not char.isalpha():
result += char
else:
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}')
return result
def decrypt(self, cipher_text: str) -> str:
"""
Decrypt cipher_text using the Caesar Cipher
:param cipher_text: text to decrypt
:type cipher_text: str
:return: plain text
:rtype: str
"""
result = ""
for char in cipher_text:
if not char.isalpha():
result += char
else:
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)
return result
def gen_pad(self, length: int = None) -> None:
"""
Generates a pad of random numbers, stores it in self.pad, and writes it to all default files (pad.txt, pad.csv)
:param length: length of pad to generate, defaults to 100
:type length: int
:return: None
"""
length = length if length else self.default_pad_length
pad = deque()
for i in range(length):
pad.append(secrets.randbelow(length))
self.pad = pad
# write to all default files
for key, value in self.file_type_dict.items():
self.write_pad_to_file(value['default_file_name'])
def write_pad_to_file(self, file_name: str = None) -> None:
"""
Writes the pad to a file. If no file name is provided, the default file name is used.
:param file_name: name of file to write pad to
:type file_name: str
:return: None
"""
file_name = file_name if file_name else self.file_type_dict[os.path.splitext(file_name)[1]]['default_file_name']
with open(file_name, 'w') as f:
if file_name.endswith('.csv'):
for i in self.pad:
f.write(f'{i},')
else:
for i in self.pad:
f.write(f'{i} ')
def convert_txt_to_list(self, file_name: str = None) -> None:
"""
Parses a text file containing a pad and stores it in object
:param file_name: name of text file to read pad from
:type file_name: str
:return: None
"""
file_name = file_name if file_name else self.file_type_dict[os.path.splitext(file_name)[1]]['default_file_name']
try:
with open(file_name, 'r') as f:
pad = f.readline()
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)
def convert_csv_to_list(self, file_name: str = None) -> None:
"""
Parses a csv file containing a pad and stores it in object
:param file_name: name of csv file to read pad from
:return: None
"""
file_name = file_name if file_name else self.file_type_dict[os.path.splitext(file_name)[1]]['default_file_name']
try:
with open(file_name, 'r') as f:
pad = f.readline()
pad = [int(x) for x in pad.split(',') for x in x.split(' ') if x.strip()]
self.pad = deque(pad)
except FileNotFoundError:
print(f'File {file_name} not found. Please check the file name and try again.')
exit(1)
if __name__ == "__main__":
text = "Hello World, this is a test!"
cipher = CaesarCipher(40, use_pad=False)
enc = cipher.encrypt(text)
decipher = CaesarCipher(40, use_pad=False)
dec = decipher.decrypt(enc)
print(f'Original: {text}')
print(f'Encrypted: {enc}')
print(f'Decrypted: {dec}')
assert text == dec, "Decrypted text does not match original text."

98
app.py Normal file
View File

@ -0,0 +1,98 @@
import io
import base64
from flask import Flask, render_template, request, jsonify
from Ciphers.CaesarCipher.CaesarCipher import CaesarCipher
app = Flask(__name__)
@app.route('/')
def index():
return render_template('base.html')
@app.route('/b64', methods=['POST'])
def b64():
if 'b64_plaintext_input' in request.form:
text = request.form['b64_plaintext_input']
ciphertext_input = False
elif 'b64_ciphertext_input' in request.form:
text = request.form['b64_ciphertext_input']
ciphertext_input = True
else:
return jsonify({'error': 'No input provided'})
result = {}
if ciphertext_input:
base64_bytes = text.encode("ascii")
sample_string_bytes = base64.b64decode(base64_bytes)
result['cleartext'] = str(sample_string_bytes, "ascii")
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():
if 'plaintext_input' in request.form:
text = request.form['plaintext_input']
ciphertext_input = False
elif 'ciphertext_input' in request.form:
text = request.form['ciphertext_input']
ciphertext_input = True
else:
return jsonify({'error': 'No input provided'})
key = int(request.form['key'])
result = {}
if ciphertext_input:
pad_file = request.files.get('pad_file')
if pad_file:
pad = io.StringIO(pad_file.stream.read().decode('utf-8'))
cipher = CaesarCipher(shift=key, use_pad=True, file=pad)
else:
cipher = CaesarCipher(shift=key, use_pad=False)
result['cleartext'] = cipher.decrypt(text)
if pad_file:
pad.seek(0)
new_cipher = CaesarCipher(shift=key, use_pad=True, file=pad)
encrypted_text = new_cipher.encrypt(result['cleartext'])
else:
new_cipher = CaesarCipher(shift=key, use_pad=False)
encrypted_text = new_cipher.encrypt(result['cleartext'])
result['ciphertext'] = encrypted_text
else:
pad_file = request.files.get('pad_file')
if pad_file:
pad = io.StringIO(pad_file.stream.read().decode('utf-8'))
cipher = CaesarCipher(shift=key, use_pad=True, file=pad)
else:
cipher = CaesarCipher(shift=key, use_pad=False)
result['ciphertext'] = cipher.encrypt(text)
if pad_file:
pad.seek(0)
new_cipher = CaesarCipher(shift=key, use_pad=True, file=pad)
decrypted_text = new_cipher.decrypt(result['ciphertext'])
else:
new_cipher = CaesarCipher(shift=key, use_pad=False)
decrypted_text = new_cipher.decrypt(result['ciphertext'])
result['cleartext'] = decrypted_text
return jsonify(result)
if __name__ == '__main__':
app.run(host='0.0.0.0', port=3000, debug=True)

View File

@ -0,0 +1,142 @@
<div class="form-group">
<form method="POST" action="{{ url_for('encrypt_decrypt') }}">
<label for="ciphertext_input">
Enter Cipher text here:
</label>
<input type="text" id="ciphertext_input" name="ciphertext_input"
placeholder="Enter your text here" class="form-control">
<div class="form-group">
<label for="key-input-decrypt">Shift Value:</label>
<div class="input-group">
<span class="input-group-prepend">
<button class="btn btn-outline-secondary" type="button" onclick="decrementKeyDecrypt()">-</button>
</span>
<label for="key-input-decrypt"></label><input type="text" id="key-input-decrypt"
name="key-input-decrypt" class="form-control" min="1"
max="1000000000000000" value="3"
oninput="updateSliderValue()">
<span class="input-group-append">
<button class="btn btn-outline-secondary" type="button" onclick="incrementKeyDecrypt()">+</button>
</span>
</div>
</div>
<div>
<label for="key-slider-decrypt">
Enter Shift Value
</label>
<input type="range" id="key-slider-decrypt" name="key" min="1"
max="1000000000000000" value="3" class="form-control"
oninput="updateKeyInput()">
</div>
<div class="custom-file">
<span class="string">Upload pad file:</span>
<input type="file" id="file-input-decrypt" onchange="updateLabelDecrypt()">
<label for="file-input-decrypt" id="file-label-decrypt">Choose file</label>
<button id="remove-file-btn-decrypt" onclick="removeFileDecrypt()" style="display: none;">Remove
</button>
</div>
<div class="container">
<div class="row justify-content-center">
<div class="col-lg-8">
<div class="form-group">
<label for="ciphertext-decrypt">Cipher Text:</label><input type="text" id="ciphertext-decrypt"
name="ciphertext-decrypt"
placeholder="Cipher Text"
class="form-control" readonly>
</div>
</div>
</div>
</div>
<div class="container">
<div class="row justify-content-center">
<div class="col-lg-8">
<div class="form-group alert alert-success">
<label for="cleartext-decrypt">Clear Text:</label>
<input type="text" id="cleartext-decrypt" name="cleartext-decrypt" placeholder="Clear Text"
class="form-control" readonly>
</div>
</div>
</div>
</div>
</form>
</div>
<script>
function update_decrypt() {
let ciphertext = document.getElementById('ciphertext_input').value;
let key = document.getElementById('key-slider-decrypt').value;
{#let xhrEncrypt = new XMLHttpRequest();#}
let pad_file = document.getElementById('file-input').files[0];
let formData = new FormData();
formData.append('ciphertext_input', ciphertext);
formData.append('key', key);
formData.append('pad_file', pad_file);
let xhrEncrypt = new XMLHttpRequest();
xhrEncrypt.open('POST', '{{ url_for("encrypt_decrypt") }}');
xhrEncrypt.onload = function () {
let ciphertext = JSON.parse(xhrEncrypt.responseText)['ciphertext'];
let cleartext = JSON.parse(xhrEncrypt.responseText)['cleartext'];
document.getElementById('ciphertext-decrypt').value = ciphertext;
document.getElementById('cleartext-decrypt').value = cleartext;
};
xhrEncrypt.send(formData);
}
function updateSliderValueDecrypt() {
document.getElementById('key-slider-decrypt').value = document.getElementById('key-input-decrypt').value;
update_decrypt();
}
function updateKeyInputDecrypt() {
document.getElementById('key-input-decrypt').value = document.getElementById('key-slider-decrypt').value;
update_decrypt();
}
function incrementKeyDecrypt() {
let keyInput = document.getElementById('key-input-decrypt');
let currentValue = parseInt(keyInput.value);
if (currentValue < parseInt(keyInput.max)) {
keyInput.value = currentValue + 1;
updateSliderValueDecrypt();
}
}
function decrementKeyDecrypt() {
let keyInput = document.getElementById('key-input-decrypt');
let currentValue = parseInt(keyInput.value);
if (currentValue > parseInt(keyInput.min)) {
keyInput.value = currentValue - 1;
updateSliderValueDecrypt();
}
}
function updateLabelDecrypt() {
let fileInput = document.getElementById('file-input-decrypt');
let fileLabel = document.getElementById('file-label-decrypt');
let removeBtn = document.getElementById('remove-file-btn-decrypt');
if (fileInput.value) {
fileLabel.innerHTML = fileInput.value.match(/[\/\\]([\w\d\s\.\-\(\)]+)$/)[1];
removeBtn.style.display = 'inline-block';
} else {
fileLabel.innerHTML = 'Choose file';
removeBtn.style.display = 'none';
}
}
function removeFileDecrypt() {
let fileInput = document.getElementById('file-input-decrypt');
let fileLabel = document.getElementById('file-label-decrypt');
let removeBtn = document.getElementById('remove-file-btn-decrypt');
fileInput.value = '';
fileLabel.innerHTML = 'Choose file';
removeBtn.style.display = 'none';
}
document.getElementById('ciphertext_input').addEventListener('input', update_decrypt);
document.getElementById('key-slider-decrypt').addEventListener('input', updateKeyInputDecrypt);
document.getElementById('key-input-decrypt').addEventListener('input', updateSliderValueDecrypt);
</script>

View File

@ -0,0 +1,138 @@
<div class="form-group">
<form method="POST" action="{{ url_for('encrypt_decrypt') }}">
<label for="plaintext_input">
Enter Plaintext Here:
</label>
<input type="text" id="plaintext_input" name="plaintext_input"
placeholder="Enter your text here" class="form-control">
<div class="form-group">
<label for="key-input">Shift Value:</label>
<div class="input-group">
<span class="input-group-prepend">
<button class="btn btn-outline-secondary" type="button" onclick="decrementKey()">-</button>
</span>
<input type="text" id="key-input" name="key" class="form-control" min="1" max="1000000000000000"
value="3" oninput="updateSliderValue()">
<span class="input-group-append">
<button class="btn btn-outline-secondary" type="button" onclick="incrementKey()">+</button>
</span>
</div>
</div>
<div>
<label for="key-slider">
Enter shift value:
</label>
<input type="range" id="key-slider" name="key" min="1" max="1000000000000000"
value="3"
class="form-control" oninput="updateKeyInput()">
</div>
<div class="custom-file">
<input type="file" id="file-input" onchange="updateLabel()">
<label for="file-input" id="file-label">Choose file</label>
<button id="remove-file-btn" onclick="removeFile()" style="display: none;">Remove</button>
</div>
<div class="container">
<div class="row justify-content-center">
<div class="col-lg-8">
<div class="form-group alert alert-success">
<label for="ciphertext">Cipher Text:</label>
<input type="text" id="ciphertext" name="ciphertext" placeholder="Cipher Text"
class="form-control" readonly>
</div>
</div>
</div>
</div>
<div class="container">
<div class="row justify-content-center">
<div class="col-lg-8">
<div class="form-group">
<label for="cleartext">Clear Text:</label>
<input type="text" id="cleartext" name="cleartext" placeholder="Clear Text"
class="form-control" readonly >
</div>
</div>
</div>
</div>
</form>
</div>
<script>
function update() {
let plaintext = document.getElementById('plaintext_input').value;
let key = document.getElementById('key-slider').value;
let pad_file = document.getElementById('file-input').files[0];
let formData = new FormData();
formData.append('plaintext_input', plaintext);
formData.append('key', key);
formData.append('pad_file', pad_file);
let xhrEncrypt = new XMLHttpRequest();
xhrEncrypt.open('POST', '{{ url_for("encrypt_decrypt") }}');
xhrEncrypt.onload = function () {
let ciphertext = JSON.parse(xhrEncrypt.responseText)['ciphertext'];
let cleartext = JSON.parse(xhrEncrypt.responseText)['cleartext'];
document.getElementById('ciphertext').value = ciphertext;
document.getElementById('cleartext').value = cleartext;
};
xhrEncrypt.send(formData);
}
function updateSliderValue() {
document.getElementById('key-slider').value = document.getElementById('key-input').value;
update();
}
function updateKeyInput() {
document.getElementById('key-input').value = document.getElementById('key-slider').value;
update();
}
function incrementKey() {
let keyInput = document.getElementById('key-input');
let currentValue = parseInt(keyInput.value);
if (currentValue < parseInt(keyInput.max)) {
keyInput.value = currentValue + 1;
updateSliderValue();
}
}
function decrementKey() {
let keyInput = document.getElementById('key-input');
let currentValue = parseInt(keyInput.value);
if (currentValue > parseInt(keyInput.min)) {
keyInput.value = currentValue - 1;
updateSliderValue();
}
}
function updateLabel() {
let fileInput = document.getElementById('file-input');
let fileLabel = document.getElementById('file-label');
let removeBtn = document.getElementById('remove-file-btn');
if (fileInput.value) {
fileLabel.innerHTML = fileInput.value.match(/[\/\\]([\w\d\s\.\-\(\)]+)$/)[1];
removeBtn.style.display = 'inline-block';
} else {
fileLabel.innerHTML = 'Choose file';
removeBtn.style.display = 'none';
}
}
function removeFile() {
let fileInput = document.getElementById('file-input');
let fileLabel = document.getElementById('file-label');
let removeBtn = document.getElementById('remove-file-btn');
fileInput.value = '';
fileLabel.innerHTML = 'Choose file';
removeBtn.style.display = 'none';
}
document.getElementById('plaintext_input').addEventListener('input', update);
document.getElementById('key-slider').addEventListener('input', updateKeyInput);
document.getElementById('key-input').addEventListener('input', updateSliderValue);
</script>

88
templates/base.html Normal file
View File

@ -0,0 +1,88 @@
<!doctype html>
<html lang="en">
<head>
<!-- Required meta tags -->
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
<!-- Bootstrap CSS -->
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css"
integrity="sha384-ggOyR0iXCbMQv3Xipma34MD+dH/1fQ784/j6cY/iJTQUOhcWr7x9JvoRxT2MZw1T" crossorigin="anonymous">
<title>Cipher App</title>
</head>
<body class="container-fluid bg-light">
<div class="mt-4 p-5 bg-info text-white rounded">
<h1>Cipher App</h1>
<p>Made with Flask</p>
<p>By: <a href="https://devblog.periodicc.com/about/" class="text-white">Devoalda</a></p>
</div>
<div class="container-fluid">
<h1 class="mt-3">Caesar Cipher</h1>
<ul class="nav nav-tabs mx-auto">
<li class="nav-item">
<a class="nav-link active" data-toggle="tab" href="#plaintext-tab">Encrypt</a>
</li>
<li class="nav-item">
<a class="nav-link" data-toggle="tab" href="#ciphertext-tab">Decrypt</a>
</li>
</ul>
<div class="tab-content container-fluid">
<div id="plaintext-tab" class="tab-pane fade show active">
<!-- Your plaintext input form here -->
<!-- URL for /encrypt -->
<div class="container-fluid mt-3">
{% include "CaesarEncrypt.html" %}
</div>
</div>
<div id="ciphertext-tab" class="tab-pane fade">
<!-- Your ciphertext input form here -->
<div class="container-fluid mt-3">
{% include "CaesarDecrypt.html" %}
</div>
</div>
</div>
</div>
<div class="container-fluid">
<h1 class="mt-3">Base 64 Encoding</h1>
</div>
<div class="container-fluid">
<ul class="nav nav-tabs mx-auto">
<li class="nav-item">
<a class="nav-link active" data-toggle="tab" href="#b64-plaintext-tab">Encrypt</a>
</li>
<li class="nav-item">
<a class="nav-link" data-toggle="tab" href="#b64-ciphertext-tab">Decrypt</a>
</li>
</ul>
<div class="tab-content">
<div id="b64-plaintext-tab" class="tab-pane fade show active">
<!-- Your plaintext input form here -->
<div class="container-fluid mt-3">
{% include "base64Encode.html" %}
</div>
</div>
<div id="b64-ciphertext-tab" class="tab-pane fade">
<!-- Your ciphertext input form here -->
<div class="container-fluid mt-3">
{% include "base64Decode.html" %}
</div>
</div>
</div>
</div>
<!-- Optional JavaScript -->
<!-- jQuery first, then Popper.js, then Bootstrap JS -->
<script src="https://code.jquery.com/jquery-3.3.1.slim.min.js"
integrity="sha384-q8i/X+965DzO0rT7abK41JStQIAqVgRVzpbzo5smXKp4YfRvH+8abtTE1Pi6jizo"
crossorigin="anonymous"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.14.7/umd/popper.min.js"
integrity="sha384-UO2eT0CpHqdSJQ6hJty5KVphtPhzWj9WO1clHTMGa3JDZwrnQq4sF86dIHNDz0W1"
crossorigin="anonymous"></script>
<script src="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/js/bootstrap.min.js"
integrity="sha384-JjSmVgyd0p3pXB1rRibZUAYoIIy6OrQ6VrjIEaFf/nJGzIxFDsf4x0xIM+B07jRM"
crossorigin="anonymous"></script>
</body>
</html>

View File

@ -0,0 +1,30 @@
<div class="form-group">
<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">
<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>
</div>
</form>
</div>
<script>
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(){
document.getElementById("b64_ciphertext_decrypt").value = JSON.parse(xhrRequest.responseText)['cleartext'];
};
xhrRequest.send(formData);
}
document.getElementById('b64_plaintext_input_decrypt').addEventListener('input', b64DecryptUpdate);
</script>

View File

@ -0,0 +1,31 @@
<div class="form-group">
<form method="POST" action="{{ url_for('b64') }}">
<label for="b64_plaintext_input">Enter Plaintext Here:</label>
<input type="text" id="b64_plaintext_input" name="b64_plaintext_input"
placeholder="Enter your text here" class="form-control">
<div class="alert alert-success">
<label for="b64_ciphertext">
Cipher Text:
</label>
<input type="text" id="b64_ciphertext" name="b64_ciphertext"
placeholder="Cipher Text" class="form-control" readonly>
</div>
</form>
</div>
<script>
function b64Update() {
let plaintext = document.getElementById("b64_plaintext_input").value;
let formData = new FormData();
formData.append('b64_plaintext_input', plaintext);
let xhrRequest = new XMLHttpRequest();
xhrRequest.open('POST', '/b64');
xhrRequest.onload = function () {
document.getElementById("b64_ciphertext").value = JSON.parse(xhrRequest.responseText)['ciphertext'];
};
xhrRequest.send(formData);
}
document.getElementById('b64_plaintext_input').addEventListener('input', b64Update);
</script>