Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Use native python TLS-PSK #123

Open
wants to merge 10 commits into
base: main
Choose a base branch
from
6 changes: 3 additions & 3 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
FROM python:3.10-slim
FROM python:3.13-slim

ARG BASHIO_VERSION="v0.16.2"
ARG BASHIO_SHA256="d0f0c780c4badd103c00c572b1bf9645520d15a8a8070d6e3d64e35cb9f583aa"
Expand All @@ -8,9 +8,9 @@ WORKDIR /app
COPY requirements.txt ./

RUN apt-get update && \
apt-get install -y --no-install-recommends curl tar gcc python3-dev libssl-dev libxml2-dev libxslt-dev python3-dev jq && \
apt-get install -y --no-install-recommends curl tar gcc jq python3-dev libxml2-dev libxslt-dev && \
pip3 install -r requirements.txt && \
apt-get remove -y gcc python3-dev libssl-dev && \
apt-get remove -y gcc python3-dev && \
apt-get autoremove -y \
&& curl -J -L -o /tmp/bashio.tar.gz \
"https://github.com/hassio-addons/bashio/archive/${BASHIO_VERSION}.tar.gz" \
Expand Down
35 changes: 11 additions & 24 deletions HCSocket.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@
from base64 import urlsafe_b64decode as base64url
from datetime import datetime

import sslpsk
import websocket
from Crypto.Cipher import AES
from Crypto.Hash import HMAC, SHA256
Expand All @@ -25,17 +24,6 @@ def now():
return datetime.now().strftime("%Y-%m-%d %H:%M:%S.%f")


# Monkey patch for sslpsk in pip using the old _sslobj
def _sslobj(sock):
if (3, 5) <= sys.version_info <= (3, 7):
return sock._sslobj._sslobj
else:
return sock._sslobj


sslpsk.sslpsk._sslobj = _sslobj


class HCSocket:
def __init__(self, host, psk64, iv64=None, domain_suffix=""):
self.host = host
Expand Down Expand Up @@ -77,6 +65,15 @@ def hmac_msg(self, direction, enc_msg):
hmac_msg = self.iv + direction + enc_msg
return hmac(self.mackey, hmac_msg)[0:16]

def wrap_socket_psk(self, tcp_socket):
if not ssl.HAS_PSK:
raise NotImplementedError("OpenSSL library does not have support for TLS-PSK")

context = ssl.SSLContext(ssl.PROTOCOL_TLSv1_2)
context.set_ciphers("PSK") # Originally ECDHE-PSK-CHACHA20-POLY1305
context.set_psk_client_callback(lambda hint: (None, self.psk))
return context.wrap_socket(tcp_socket, server_hostname=self.host)

def decrypt(self, buf):
if len(buf) < 32:
print("Short message?", buf.hex(), file=sys.stderr)
Expand Down Expand Up @@ -137,12 +134,7 @@ def reconnect(self):
sock.connect((self.host, self.port))

if not self.http:
sock = sslpsk.wrap_socket(
sock,
ssl_version=ssl.PROTOCOL_TLSv1_2,
ciphers="ECDHE-PSK-CHACHA20-POLY1305",
psk=self.psk,
)
sock = self.wrap_socket_psk(sock)

print(now(), "CON:", self.uri)
self.ws = websocket.WebSocket()
Expand Down Expand Up @@ -177,12 +169,7 @@ def run_forever(self, on_message, on_open, on_close, on_error):
sock.connect((self.host, self.port))

if not self.http:
sock = sslpsk.wrap_socket(
sock,
ssl_version=ssl.PROTOCOL_TLSv1_2,
ciphers="ECDHE-PSK-CHACHA20-POLY1305",
psk=self.psk,
)
sock = self.wrap_socket_psk(sock)

def _on_open(ws):
self.dprint("on connect")
Expand Down
1 change: 0 additions & 1 deletion requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ bs4
requests
pycryptodome
websocket-client
sslpsk
paho.mqtt==1.6.1
lxml
click
Expand Down