Skip to content

Instantly share code, notes, and snippets.

@jramseygreen
Last active May 15, 2022 16:34
Show Gist options
  • Save jramseygreen/7da60a232656f10fbf1367db67e7ed86 to your computer and use it in GitHub Desktop.
Save jramseygreen/7da60a232656f10fbf1367db67e7ed86 to your computer and use it in GitHub Desktop.
websocket connection python <--> javascript with RSA encrypted tunnel
import base64
from Crypto.PublicKey import RSA
from Crypto.Cipher import PKCS1_v1_5
# pass in the public key of the client to communicate with
class Crypt:
def __init__(self):
# 1024 means the keysize will be 1024 bits
key_pair = RSA.generate(1024)
self.__public_key = key_pair.publickey().exportKey().decode()
self.__private_key = key_pair.exportKey().decode()
self.__foreign_public_key = ""
# returns key to send to others
def get_public_key(self) -> str:
return self.__public_key
# key received from others to encrypt data with
def set_foreign_public_key(self, key: str):
self.__foreign_public_key = key
def has_foreign_public_key(self) -> bool:
return bool(self.__foreign_public_key)
# decrypt using private key
def decrypt(self, message: str) -> str:
priv_key = RSA.importKey(self.__private_key.encode())
cipher = PKCS1_v1_5.new(priv_key)
return cipher.decrypt(base64.b64decode(message.encode()), "dummy text").decode()
# encrypt using foreign public key
def encrypt(self, message) -> str:
pub_key = RSA.importKey(self.__foreign_public_key.encode())
cipher = PKCS1_v1_5.new(pub_key)
return base64.b64encode(cipher.encrypt(message.encode())).decode()
<html>
<!-- jsencrypt -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/jsencrypt/2.3.1/jsencrypt.min.js" integrity="sha512-zDvrqenA0eFJZCxBsryzUZcvihvNlEXbteMv62yRxdhR4s7K1aaz+LjsRyfk6M+YJLyAJEuuquIAI8I8GgLC8A==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
<script type="module">
const host = "localhost"
const port = "8080"
const testText = "hello there you stallion you"
// crypt instance + personal private key / personal public key
const crypt = new JSEncrypt({default_key_size: 1024})
const privateKey = crypt.getPrivateKey()
const publicKey = crypt.getPublicKey()
var connection = null
var foreignPublicKey = "" // will be sent by server
window.onload = function() {
// connect to ws server
connection = new WebSocket("ws://" + host + ":" + port)
connection.onopen = function () {
console.log("connected to websocket server")
// send key immediately on open
connection.send(publicKey) // sent in naitive function not wrapper
};
connection.onerror = function (error) {
console.log('WebSocket Error ' + error)
};
connection.onmessage = function (e) {
console.log('received raw: ' + e.data)
// first message will be foreign public key
if (!foreignPublicKey) {
foreignPublicKey = e.data
// send some text through the wrapper after setting the key
send(testText)
return
}
crypt.setPrivateKey(privateKey)
var message = crypt.decrypt(e.data)
console.log("received decrypted: " + message)
}
}
// send wrapper for every message apart from key
function send(message) {
console.log("sent raw: " + message)
if (foreignPublicKey) {
crypt.setPublicKey(foreignPublicKey)
message = crypt.encrypt(message)
}
connection.send(message)
console.log("sent encrypted: " + message)
}
</script>
</html>
import ws_server
import crypt
def on_message(client, server, message):
print("received raw:", message)
# first message will be foreign public key
if not crypt.has_foreign_public_key():
crypt.set_foreign_public_key(message)
return
message = crypt.decrypt(message)
print("received decrypted: " + message)
send_message(client, "message received: " + message)
def on_new_client(client, server):
print(client, "joined the server")
# send public key on new connection
server.send_message(client, crypt.get_public_key()) # sent in naitive function not wrapper
def on_client_left(client, server):
print(client, "left the server")
# send wrapper for every message apart from key
def send_message(client, message):
print("sent raw:", message)
message = crypt.encrypt(message)
websocket_server.send_message(client, message)
print("sent encrypted:", message)
host = "localhost"
port = 8080
# start ws server
websocket_server = ws_server.start_server(host, port)
# set event methods
websocket_server.set_fn_message_received(on_message)
websocket_server.set_fn_new_client(on_new_client)
websocket_server.set_fn_client_left(on_client_left)
print("started ws server")
# make crypt instance
crypt = crypt.Crypt()
from websocket_server import WebsocketServer
def start_server(host, port):
websocket_server = WebsocketServer(host=host, port=port)
websocket_server.run_forever(threaded=True)
return websocket_server
@jramseygreen
Copy link
Author

Uses pycryptodome and websocket-server pip modules (pip install pycryptodome, pip install websocket-server) - jsencrypt on the front end

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment