Skip to content

Commit

Permalink
Initial commit: a working login function without a database
Browse files Browse the repository at this point in the history
  • Loading branch information
etrian-dev committed Feb 18, 2022
0 parents commit f40fe3e
Show file tree
Hide file tree
Showing 27 changed files with 17,060 additions and 0 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
__pycache__
47 changes: 47 additions & 0 deletions chatroom/Auth.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
from . import User


# Create users
users = dict()
user_map = dict() # reverse lookup from username to user ID(s)
for u in ['mario', 'luigi', 'chiara' , 'jacopo', 'andrea', 'beatrice']:
new_user = User.User(u, 'pwd')
print('Created new user:', new_user, sep='\n')
users[new_user] = False # not logged
if u not in user_map.keys():
user_map[u] = [new_user.user_id]
else:
user_map[u].append(new_user.user_id)

from flask import (
Blueprint, flash, g, redirect, render_template, request, session, url_for
)

blueprint = Blueprint('auth', __name__,url_prefix='/auth')

@blueprint.route('/', methods=['GET'])
@blueprint.route('/login', methods=['GET', 'POST'])
def login():
print(request, request.get_data(as_text=True), sep='\n')
error = None
if request.method == 'POST':
username = request.form['username']
pwd = request.form['pwd']

if (not username) or (not pwd):
error = 'Username o password non specificata'
else:
if username not in user_map.keys():
error = 'Utente inesistente'
found = False
for user in users.keys():
if user.username == username and user.check_pwd(pwd):
users[user] = True # set user to logged
return redirect(url_for('chat.home_user', username=username))
if not found:
error = 'Password errata'
if error is not None:
print(error)
# store error to be shown
flash(error)
return render_template('login.html', error=error)
46 changes: 46 additions & 0 deletions chatroom/Chat.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
from time import time

class Chat:
"""Defines a chat between two users.
"""
def __init__(self, user: str):
self.recipient = user
self.creation_tstamp = int(time.time())
self.messages = []

def add_message(data: str, timestamp):
"""Adds a new message to this chat.
"""
self.messages.append(Msg.EncryptedMsg(data, timestamp))
def delete_message(target):
"""Deletes a message from this chat.
"""
try:
i = self.messages.index(target)
del self.messages[i]
except ValueError:
print("Message", target, "not found")

from flask import (Blueprint, request, render_template)

blueprint = Blueprint('chat', __name__, url_prefix='/chats')

@blueprint.route('/<username>', methods=['GET'])
def home_user(username=None):
return render_template('index.html', username=username)

@blueprint.route('/<creator>/', methods=['GET'])
# TODO: post
def create_chat(creator):
data = request.get_json()
if data is not None:
pass
else:
pass
return "POSTed chat by " + creator


@blueprint.route('/<creator>/<recipient>/', methods=['GET'])
# TODO: delete
def delete_chat(creator, recipient):
return "DELETED chat between " + creator + " and " + recipient
36 changes: 36 additions & 0 deletions chatroom/Msg.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
class EncryptedMsg:
def __init__(self, data: str, stamp: int):
self.message = data
self.timestamp = stamp

from flask import Blueprint

blueprint = Blueprint('msg', __name__, url_prefix='/msg')


@blueprint.route('/<sender>/<receiver>/', methods=['GET'])
def get_all_messages(sender, receiver):
return f"GET all msg from {sender} to {receiver}"


@blueprint.route('/<sender>/<receiver>/<int:msg_id>/', methods=['GET'])
def get_message(sender, receiver, msg_id):
return f"GET msg from {sender} to {receiver}: ID = {msg_id}"


@blueprint.route('/<sender>/<receiver>/', methods=['GET'])
# TODO: post
def send_message(sender, receiver):
return f"POSTed msg from {sender} to {receiver}"


@blueprint.route('/<sender>/<receiver>/<int:msg_id>', methods=['GET'])
# TODO: put
def edit_message(sender, receiver, msg_id):
return f"PUTed msg from {sender} to {receiver}: {msg_id}"


@blueprint.route('/<sender>/<receiver>/<int:msg_id>', methods=['GET'])
# TODO: delete
def delete_message(sender, receiver, msg_id):
return f"DELETEed msg from {sender} to {receiver}"
55 changes: 55 additions & 0 deletions chatroom/User.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
from . import Chat
from chatroom.crypto import miller_rabin, genrandom, rsa

from secrets import token_bytes
from hashlib import sha3_256
from random import getrandbits

PRIME_LEN = 15
ITERATIONS = 10
SALT_LEN = 16


class User:
def __init__(self, user: str, pwd: str):
# User login info
self.user_id = getrandbits(64)
self.username = user
# TODO: hash + salt pwd
#hash_obj = sha3_256()
#hash_obj.update(token_bytes(SALT_LEN))
#hash_obj.update(bytes(pwd, encoding='UTF-8'))
#self.password_hashsalt = hash_obj.digest()
self.password = pwd
# cryptographic key generation
p = genrandom.gen_prime(PRIME_LEN, ITERATIONS)
q = genrandom.gen_prime(PRIME_LEN, ITERATIONS)
while (p == q) or (not miller_rabin.miller_rabin_test(q, ITERATIONS)):
q += 2
(e, d) = rsa.rsa_gen_keypair(p, q)
self.pub_key = (p * q, e)
self.priv_key = d
# Chats info
self.chats = dict()
def check_pwd(self, guess: str) -> bool:
return self.password == guess

def create_chat(recipient: str):
"""Creates a new chat with the given recipient.
"""
newchat = Chat(recipient)
self.chats[recipient] = newchat
def __repr__(self):
return 'User.Chatroom_user(' + self.username + ')'
def __str__(self):
s = 'User ' + self.user_id.__str__() + '\n'
s += 'Username: ' + self.username + '\n'
s += 'Password: ' + self.password + '\n'
s += self.chats.__str__() + '\n'
s += 'PUB_KEY:\n\t' + 'n = ' + hex(self.pub_key[0])[2:] + '\n\t' + 'e = ' + hex(self.pub_key[1])[2:] + '\n'
s += 'PRIV_KEY: ' + hex(self.priv_key)[2:] + '\n'
return s
def __hash__(self) -> int:
return self.user_id
def __eq__(self, other) -> bool:
return self.user_id == other.user_id
23 changes: 23 additions & 0 deletions chatroom/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import os

from flask import Flask, render_template

from . import (Auth, Chat, Msg)


def create_app(testing=None):
app = Flask(__name__, instance_relative_config=True)
# app.config.from_mapping(
# SECRET_KEY='dev')
# if testing is None:
# app.config.from_pyfile('config.py', silent=True)
# else:
# app.config.from_mapping(testing)
app.register_blueprint(Auth.blueprint)
app.register_blueprint(Chat.blueprint)
app.register_blueprint(Msg.blueprint)

print(app.url_map)
return app


1 change: 1 addition & 0 deletions chatroom/chat_client.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
# a chatting client that uses RSA to encrypt messages
1 change: 1 addition & 0 deletions chatroom/crypto/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@

46 changes: 46 additions & 0 deletions chatroom/crypto/cbc.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
def cbc_mode(msg: bytes, iv: bytes, encrypt, pk: (int, int) , blocksize=1024):
"""A generator that splits the message into blocks using CBC.
This generator receives in input the message to be sent and splits it into
fixed-lenght blocks (1K bits by default). Each block is derived from the previous
using cipher block chaining (CBC).
"""
offset = 0
# An initialization vector (IV) is required to start the chain
prev = int.from_bytes(iv, byteorder='big')
while offset < len(msg):
# Extracts the next block from the message
block = msg[offset:offset+blocksize-1]
print(f"block from {offset} to {offset+blocksize-1}")
print(block)
# Convert each block into an integer
x = int.from_bytes(block, byteorder='big')
print(f"x = {x}")
# The plaintext is XOR'd with the previous block's ciphertext
x = x ^ prev
print(f"x ^ prev = {x}")
# The resulting block is encrypted and sent to output
cipher = encrypt(x, pk[0], pk[1])
print(f"cipher = {cipher}")
yield cipher
# Updates the cipher block and the offset inside the message
prev = cipher
offset += blocksize

from . import genrandom
from . import rsa

if __name__ == "__main__":
msg = input("msg: ")
p = genrandom.gen_prime(384)
q = genrandom.gen_prime(512)
(e,n) = rsa.rsa_encrypt(p, q)
# cipher in cbc mode
gen = cbc_mode(
bytes(msg, 'utf-8'),
token_bytes(16),
rsa.rsa_encrypt,
(e,n),
blocksize=16)
for block in gen:
print(f"=====\n{block}\n=====")
14 changes: 14 additions & 0 deletions chatroom/crypto/extended_euclid.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
def extended_euclid(a: int, b: int) -> (int, int, int):
if b == 0:
return (a, 1, 0)
(rem, x1, y1) = extended_euclid(b, a % b)
#print(f"rem = {rem}, x1 = {x1}, y1 = {y1}")
return (rem, y1, x1 - (a // b) * y1)

if __name__ == "__main__":
a = int(input("a = "))
b = int(input("b = "))
print(f"Find x,y,z so that {a}x + {b}y = z")

(z, x, y) = extended_euclid(a, b)
print(f"z = {z}, x = {x}, y = {y}")
22 changes: 22 additions & 0 deletions chatroom/crypto/fastexp.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
def fastexp(x: int, y: int , m: int) -> int:
"""Modular exponentiation function.
This function implements the operation
x^y mod m, where x, y and m are integers,
doing a logarithmic number of operations
"""
next = x
res = 1
while y > 0:
if y % 2 == 1:
res = (res * next) % m
next = (next * next) % m;
y = y // 2
return res

if __name__ == "__main__":
x = input("Enter x: ")
y = input("Enter y: ")
m = input("Enter m: ")
res = fastexp(int(x), int(y), int(m))
print(f"{x}^{y} mod {m} = {res}")
25 changes: 25 additions & 0 deletions chatroom/crypto/genrandom.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
from secrets import randbits
from . import miller_rabin

def gen_prime(bitlen: int, iters: int) -> int:
"""Generates a probably prime integer of bitlen bits.
The Miller-Rabin primality test is performed on a randomly
generated integer of (at least) bitlen bits. If such number
passes iters iterations of the test then it's declared prime
and returned.
"""
if bitlen <= 0 or iters <= 0:
return -1
guess = randbits(bitlen)
# ensure the highest bit set and odd number
mask = 0x1 << (bitlen - 1)
guess = guess|mask|0x1
while(not miller_rabin.miller_rabin_test(guess, iters)):
guess += 2
return guess

if __name__ == "__main__":
bits = int(input("#bits = "))
iter = int(input("iterations = "))
print("probably prime:", gen_prime(bits, iter))
39 changes: 39 additions & 0 deletions chatroom/crypto/miller_rabin.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
from . import fastexp
import secrets

def miller_rabin_test(guess: int, iters: int) -> bool:
"""Performs a Miller-Rabin primality test.
The Miller-Rabin test on the primality of guess ensures that,
if true is returned, then guess is prime with probability
1 - 4^(-iters). If the function returs False, then guess in
certaintly composite.
"""
w = 0
z = guess - 1
while(z % 2 == 0):
w += 1
z = z // 2
i = 0;
while i < iters:
witness = 2 + secrets.randbelow(guess - 3)
tmp = fastexp.fastexp(witness, z, guess)
if not (tmp == 1 or tmp + 1 == guess):
j = 1
while j < w:
tmp = fastexp.fastexp(tmp, 2, guess)
if tmp + 1 == guess:
break
j += 1
if j >= w:
return False
i += 1
return True

if __name__ == "__main__":
n = int(input("number: "))
iter = int(input("iterations: "))
if miller_rabin_test(n,iter):
print(n, "is probably prime (probability >=", 1.0 - 4.0**(-iter))
else:
print(n, "is certaintly composite")
Loading

0 comments on commit f40fe3e

Please sign in to comment.