Stuff
This commit is contained in:
parent
d28c6375c8
commit
ac92458573
8 changed files with 327 additions and 0 deletions
5
.gitignore
vendored
Normal file
5
.gitignore
vendored
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
# Byte-compiled / optimized / DLL files
|
||||||
|
__pycache__/
|
||||||
|
*.py[cod]
|
||||||
|
*$py.class
|
||||||
|
|
25
INSTALL.md
Normal file
25
INSTALL.md
Normal file
|
@ -0,0 +1,25 @@
|
||||||
|
sudo useradd unlock -m -s /opt/keymatic/keymatic.py
|
||||||
|
sudo useradd lock -m -s /opt/keymatic/keymatic.py
|
||||||
|
sudo useradd open -m -s /opt/keymatic/keymatic.py
|
||||||
|
sudo useradd door -m -s /opt/keymatic/keymatic.py
|
||||||
|
|
||||||
|
sudo mkdir /home/unlock/.ssh
|
||||||
|
sudo mkdir /home/lock/.ssh
|
||||||
|
sudo mkdir /home/open/.ssh
|
||||||
|
sudo mkdir /home/door/.ssh
|
||||||
|
|
||||||
|
sudo ln -s /opt/keymatic/authkeyfile/authorized_keys /home/unlock/.ssh/authorized_keys
|
||||||
|
sudo ln -s /opt/keymatic/authkeyfile/authorized_keys /home/lock/.ssh/authorized_keys
|
||||||
|
sudo ln -s /opt/keymatic/authkeyfile/authorized_keys /home/open/.ssh/authorized_keys
|
||||||
|
sudo ln -s /opt/keymatic/authkeyfile/authorized_keys /home/door/.ssh/authorized_keys
|
||||||
|
|
||||||
|
|
||||||
|
https://www.npmjs.com/package/keyble
|
||||||
|
sudo apt install npm
|
||||||
|
sudo npm install --update --global --unsafe-perm keyble
|
||||||
|
sudo keyble-registeruser --user_name PI --qr_code_data M001A.....
|
||||||
|
|
||||||
|
create config.py
|
||||||
|
|
||||||
|
crontab
|
||||||
|
2 * * * * cd /opt/keymatic;./update_keys.py
|
8
config.py.example
Normal file
8
config.py.example
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
device_mac = "00:1a:22:..."
|
||||||
|
user_key = ""
|
||||||
|
|
||||||
|
ldap_cafile = "l511_ca.crt"
|
||||||
|
ldap_server = "ldaps://leidap.server.c3h"
|
||||||
|
ldap_user = "cn=lock,ou=applications,dc=leitstelle511,dc=net"
|
||||||
|
ldap_pass = ""
|
||||||
|
ldap_filter = "(&(objectClass=posixaccount)(memberOf=cn=keymatic,ou=groups,dc=leitstelle511,dc=net))"
|
66
eq3crypto.py
Normal file
66
eq3crypto.py
Normal file
|
@ -0,0 +1,66 @@
|
||||||
|
#!/usr/bin/env python3
|
||||||
|
from Crypto.Cipher import AES
|
||||||
|
|
||||||
|
def dumpNum(n):
|
||||||
|
s = ""
|
||||||
|
for v in n:
|
||||||
|
if len(s) > 0:
|
||||||
|
s = s + " "
|
||||||
|
s = s + str(v)
|
||||||
|
print(s)
|
||||||
|
|
||||||
|
def xor_bytes(a,b):
|
||||||
|
z = []
|
||||||
|
for v in a:
|
||||||
|
z.append(v ^ b[len(z)])
|
||||||
|
return bytes(z)
|
||||||
|
|
||||||
|
def uInt16ToBytes(a):
|
||||||
|
return bytes([a >> 8, a & 0xff])
|
||||||
|
|
||||||
|
def getNonce(msgid, sessNonce, seccnt):
|
||||||
|
return bytes([msgid]) + sessNonce + bytes([0,0]) + uInt16ToBytes(seccnt)
|
||||||
|
|
||||||
|
def crypt_data(data, msgid, sessNonce, seccnt, key):
|
||||||
|
cipher = AES.new(key, AES.MODE_ECB)
|
||||||
|
nonce = getNonce(msgid, sessNonce, seccnt)
|
||||||
|
blkid = 1
|
||||||
|
o = cipher.encrypt(bytes([1]) + nonce + uInt16ToBytes(blkid))
|
||||||
|
return xor_bytes(data, o)
|
||||||
|
|
||||||
|
def compute_auth(data, msgid, sessNonce, seccnt, key):
|
||||||
|
cipher = AES.new(key, AES.MODE_ECB)
|
||||||
|
nonce = getNonce(msgid, sessNonce, seccnt)
|
||||||
|
padded_data_length = 16
|
||||||
|
padded_data = data.ljust(padded_data_length, b'\0')
|
||||||
|
o = cipher.encrypt(bytes([9]) + nonce + uInt16ToBytes(len(data)))
|
||||||
|
#TODO: Implement for loop for chunked data
|
||||||
|
o = cipher.encrypt(xor_bytes(o, padded_data))
|
||||||
|
xv = cipher.encrypt(bytes([1]) + nonce + bytes([0,0]))
|
||||||
|
return xor_bytes(o[0:4], xv)
|
||||||
|
|
||||||
|
def sendMsg(msgId, data):
|
||||||
|
global remote_nonce, key
|
||||||
|
getMsg(msgId, data, remote_nonce, key)
|
||||||
|
|
||||||
|
def getMsg(msgId, data, remote_nonce, key):
|
||||||
|
seccnt = 1
|
||||||
|
cd = crypt_data(data, msgId, remote_nonce, seccnt, key)
|
||||||
|
bseccnt = uInt16ToBytes(seccnt)
|
||||||
|
authval = compute_auth(data, msgId, remote_nonce, seccnt, key)
|
||||||
|
seccnt += 1
|
||||||
|
# dumpNum(bytes([msgId]) + cd + bseccnt + authval)
|
||||||
|
payload = (bytes([128, msgId]) + cd + bseccnt + authval)
|
||||||
|
# print(payload.hex())
|
||||||
|
return payload
|
||||||
|
|
||||||
|
|
||||||
|
#print("TEST")
|
||||||
|
#key = bytes.fromhex("3b74f06324ad365bc25916a01c547d1d")
|
||||||
|
#local_nonce = "12345678"
|
||||||
|
#remote_nonce = bytes([123,122,83,88,105,62,85,55])
|
||||||
|
#remote_nonce = bytes.fromhex("d7 37 24 61 da f7 0f df")
|
||||||
|
#
|
||||||
|
#padcmd = bytes([1,0,0,0,0,0,0,0])
|
||||||
|
#dumpNum(crypt_data(padcmd, 130, remote_nonce, 1, key))
|
||||||
|
#sendMsg(135, padcmd)
|
81
keymatic.py
Executable file
81
keymatic.py
Executable file
|
@ -0,0 +1,81 @@
|
||||||
|
#!/usr/bin/env python3
|
||||||
|
import subprocess
|
||||||
|
import time
|
||||||
|
import eq3crypto
|
||||||
|
import os
|
||||||
|
import config
|
||||||
|
import sys
|
||||||
|
|
||||||
|
pstart = time.time()
|
||||||
|
writeHandle = 0x411
|
||||||
|
readHandle = 0x421
|
||||||
|
|
||||||
|
def tsLog(m = ""):
|
||||||
|
global pstart
|
||||||
|
print("{:.3f}".format(time.time() - pstart) + " " + m)
|
||||||
|
|
||||||
|
def getBuffer(p):
|
||||||
|
val = p.stdout.peek()
|
||||||
|
val = p.stdout.read(len(val))
|
||||||
|
#print(val)
|
||||||
|
return val
|
||||||
|
|
||||||
|
def expect(p, s, t=0):
|
||||||
|
b = ""
|
||||||
|
while True:
|
||||||
|
b = b + getBuffer(p).decode()
|
||||||
|
if s in b:
|
||||||
|
return b
|
||||||
|
|
||||||
|
def getNotif(p):
|
||||||
|
expect(p, "Notification")
|
||||||
|
|
||||||
|
|
||||||
|
def sendCmd(p, s):
|
||||||
|
print("<< " + s)
|
||||||
|
p.stdin.write(s.encode())
|
||||||
|
p.stdin.write(b"\n")
|
||||||
|
p.stdin.flush()
|
||||||
|
|
||||||
|
def getNotifVal(s):
|
||||||
|
r = s.split("value: ")[-1].split("\n")[0]
|
||||||
|
print(">> " + r)
|
||||||
|
return r
|
||||||
|
|
||||||
|
actionStr = os.getenv("HOME")
|
||||||
|
if "door" in actionStr:
|
||||||
|
print("Door user")
|
||||||
|
actionStr = sys.argv[-1]
|
||||||
|
action = 0
|
||||||
|
tsLog("Start")
|
||||||
|
if "open" in actionStr:
|
||||||
|
action = 2
|
||||||
|
if "unlock" in actionStr:
|
||||||
|
action = 1
|
||||||
|
try:
|
||||||
|
p = subprocess.Popen(["gatttool", "-I"], stdout=subprocess.PIPE, stdin=subprocess.PIPE)
|
||||||
|
expect(p, "[LE]")
|
||||||
|
tsLog("INIT DONE")
|
||||||
|
sendCmd(p, "connect " + config.device_mac)
|
||||||
|
p.stdin.flush()
|
||||||
|
expect(p, "Connection successful")
|
||||||
|
tsLog("CONNECT DONE")
|
||||||
|
sendCmd(p, "char-write-req 0x0411 8002014DC7e11BAE13FECB0000000000")
|
||||||
|
notifNonce = bytes.fromhex(getNotifVal(expect(p, "Notification")))
|
||||||
|
if notifNonce[0:2] == b'\x80\x03':
|
||||||
|
tsLog("Nonce received")
|
||||||
|
remoteNonce = notifNonce[3:(3+8)]
|
||||||
|
msg = eq3crypto.getMsg(135, bytes([action,0,0,0,0,0,0,0]), remoteNonce, bytes.fromhex(config.user_key))
|
||||||
|
sendCmd(p, "char-write-req 0x0411 " + msg.hex())
|
||||||
|
getNotifVal(expect(p, "Notification"))
|
||||||
|
tsLog("MOVING")
|
||||||
|
getNotifVal(expect(p, "Notification"))
|
||||||
|
tsLog("DONE")
|
||||||
|
finally:
|
||||||
|
print("FINALLY")
|
||||||
|
try:
|
||||||
|
p.communicate(input=b"exit\n",timeout=2)
|
||||||
|
print("NORMAL EXIT")
|
||||||
|
except:
|
||||||
|
print("KILL")
|
||||||
|
p.kill()
|
30
ldap_query.py
Executable file
30
ldap_query.py
Executable file
|
@ -0,0 +1,30 @@
|
||||||
|
#!/usr/bin/env python3
|
||||||
|
import ldap
|
||||||
|
import config
|
||||||
|
ldap.set_option(ldap.OPT_X_TLS_CACERTFILE, config.ldap_cafile)
|
||||||
|
l = ldap.initialize(config.ldap_server)
|
||||||
|
l.simple_bind_s(config.ldap_user, config.ldap_pass)
|
||||||
|
r = l.search_s("dc=leitstelle511,dc=net", ldap.SCOPE_SUBTREE, "(&(objectClass=posixaccount)(memberOf=cn=keymatic,ou=groups,dc=leitstelle511,dc=net))", ["sshKey", "memberOf", "mail"])
|
||||||
|
#r = l.search_s("dc=leitstelle511,dc=net", ldap.SCOPE_SUBTREE, config.ldap_filter, ["sshKey", "memberOf", "mail"])
|
||||||
|
|
||||||
|
def checkKey(bk):
|
||||||
|
try:
|
||||||
|
k = bk.decode()
|
||||||
|
kp = k.split(' ')
|
||||||
|
if "keymatic" in kp[-1].lower():
|
||||||
|
return True
|
||||||
|
|
||||||
|
except:
|
||||||
|
print("# Error while checking Key")
|
||||||
|
return False
|
||||||
|
|
||||||
|
for e in r:
|
||||||
|
if 'sshKey' in e[1]:
|
||||||
|
print("# User: {}".format(e[0]))
|
||||||
|
for k in e[1]['sshKey']:
|
||||||
|
if(checkKey(k)):
|
||||||
|
print(k.decode())
|
||||||
|
elif False:
|
||||||
|
print("# User: {} has no Key".format(e[0]))
|
||||||
|
if('mail' in e[1]):
|
||||||
|
print("# - MAIL: {}".format(e[1]['mail']))
|
82
status_alpha.py
Executable file
82
status_alpha.py
Executable file
|
@ -0,0 +1,82 @@
|
||||||
|
#!/usr/bin/env python3
|
||||||
|
import subprocess
|
||||||
|
import time
|
||||||
|
import eq3crypto
|
||||||
|
import os
|
||||||
|
import config
|
||||||
|
import sys
|
||||||
|
|
||||||
|
pstart = time.time()
|
||||||
|
writeHandle = 0x411
|
||||||
|
readHandle = 0x421
|
||||||
|
|
||||||
|
def tsLog(m = ""):
|
||||||
|
global pstart
|
||||||
|
print("{:.3f}".format(time.time() - pstart) + " " + m)
|
||||||
|
|
||||||
|
def getBuffer(p):
|
||||||
|
val = p.stdout.peek()
|
||||||
|
val = p.stdout.read(len(val))
|
||||||
|
#print(val)
|
||||||
|
return val
|
||||||
|
|
||||||
|
def expect(p, s, t=0):
|
||||||
|
b = ""
|
||||||
|
while True:
|
||||||
|
b = b + getBuffer(p).decode()
|
||||||
|
if s in b:
|
||||||
|
return b
|
||||||
|
|
||||||
|
def getNotif(p):
|
||||||
|
expect(p, "Notification")
|
||||||
|
|
||||||
|
|
||||||
|
def sendCmd(p, s):
|
||||||
|
print("<< " + s)
|
||||||
|
p.stdin.write(s.encode())
|
||||||
|
p.stdin.write(b"\n")
|
||||||
|
p.stdin.flush()
|
||||||
|
|
||||||
|
def getNotifVal(s):
|
||||||
|
r = s.split("value: ")[-1].split("\n")[0]
|
||||||
|
print(">> " + r)
|
||||||
|
return r
|
||||||
|
|
||||||
|
actionStr = os.getenv("HOME")
|
||||||
|
if "door" in actionStr:
|
||||||
|
print("Door user")
|
||||||
|
actionStr = sys.argv[-1]
|
||||||
|
action = 0
|
||||||
|
tsLog("Start")
|
||||||
|
if "open" in actionStr:
|
||||||
|
action = 2
|
||||||
|
if "unlock" in actionStr:
|
||||||
|
action = 1
|
||||||
|
try:
|
||||||
|
p = subprocess.Popen(["gatttool", "-I"], stdout=subprocess.PIPE, stdin=subprocess.PIPE)
|
||||||
|
expect(p, "[LE]")
|
||||||
|
tsLog("INIT DONE")
|
||||||
|
sendCmd(p, "connect " + config.device_mac)
|
||||||
|
p.stdin.flush()
|
||||||
|
expect(p, "Connection successful")
|
||||||
|
tsLog("CONNECT DONE")
|
||||||
|
sendCmd(p, "char-write-req 0x0411 8002014DC7e11BAE13FECB0000000000")
|
||||||
|
notifNonce = bytes.fromhex(getNotifVal(expect(p, "Notification")))
|
||||||
|
if notifNonce[0:2] == b'\x80\x03':
|
||||||
|
tsLog("Nonce received")
|
||||||
|
remoteNonce = notifNonce[3:(3+8)]
|
||||||
|
tp = time.strftime("%y %m %d %H %M %S").split()
|
||||||
|
msg = eq3crypto.getMsg(0x82, bytes([int(tp[0]),int(tp[1]),int(tp[2]),int(tp[3]),int(tp[4]),int(tp[5]),0,0]), remoteNonce, bytes.fromhex(config.user_key))
|
||||||
|
sendCmd(p, "char-write-req 0x0411 " + msg.hex())
|
||||||
|
#getNotifVal(expect(p, "Notification"))
|
||||||
|
#tsLog("MOVING")
|
||||||
|
getNotifVal(expect(p, "Notification"))
|
||||||
|
tsLog("DONE")
|
||||||
|
finally:
|
||||||
|
print("FINALLY")
|
||||||
|
try:
|
||||||
|
p.communicate(input=b"exit\n",timeout=2)
|
||||||
|
print("NORMAL EXIT")
|
||||||
|
except:
|
||||||
|
print("KILL")
|
||||||
|
p.kill()
|
30
update_keys.py
Executable file
30
update_keys.py
Executable file
|
@ -0,0 +1,30 @@
|
||||||
|
#!/usr/bin/env python3
|
||||||
|
import subprocess
|
||||||
|
import hashlib
|
||||||
|
import sys
|
||||||
|
|
||||||
|
destfile = "authkeyfile/authorized_keys"
|
||||||
|
|
||||||
|
p = subprocess.Popen(["./ldap_query.py"], stdout=subprocess.PIPE, stdin=subprocess.PIPE)
|
||||||
|
(po, pr) = p.communicate()
|
||||||
|
if(p.returncode != 0):
|
||||||
|
print("Data from ldap_query.py seems to be invalid. QUIT")
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
newhash = hashlib.md5(po).hexdigest()
|
||||||
|
#print(newhash)
|
||||||
|
|
||||||
|
try:
|
||||||
|
f = open(destfile, "rb")
|
||||||
|
oldhash = hashlib.md5(f.read()).hexdigest()
|
||||||
|
f.close()
|
||||||
|
# print(oldhash)
|
||||||
|
except:
|
||||||
|
oldhash = None
|
||||||
|
print("cannot open auth key file for read")
|
||||||
|
|
||||||
|
if newhash != oldhash:
|
||||||
|
# print("Updating file")
|
||||||
|
f = open(destfile, "wb")
|
||||||
|
f.write(po)
|
||||||
|
f.close()
|
Loading…
Reference in a new issue