Login with a serial RFID / NFC reader under Windows and Linux

Sweet, this’ll come in handy. Thanks!

1 Like

@fraggersparks are you taking notes? Wake up call :slight_smile:

I was going to see if I can find or make something to decrypt my LUKS partition during boot. Have a yubi key + a password combo right now.

1 Like

Not terribly difficult to do, unless your LUKS partition is your boot partition, in which case you’ll probably have to make an initrd image that loads the appropriate drivers, handles reading your implant and recovers the LUKS key before doing the chroot. If your LUKS partition is something else, like /home, you can do all that in the regular system, which is easier.

It’s my boot partition. So yeah what you said.

Maybe I might get cracking on something like that, if I have some time :slight_smile:

GnuPG i believe has a solid foundation for this to work. I’ve been swamped (and the Rona’s impacted my work - busy!) but this is next on the list.

1 Like

If you do I’d definitely be interested. I was going to wait for the Apex line because it’s an actual secure element

Bleh… Why wait for the Apex line when we already have s00per secure Mifare Classics eh? :slight_smile:

More seriously, what I was thinking of is a generic mechanism to wait for input from a contactless smartcard / implant at boot time to decrypt the root partition. Once that’s done, you could plug in a shite UID-based authentication, or a more advance challenge-response thing, whatever you fancy. Maybe it even already exists, I haven’t checked.

Oh well then, have at it. I don’t have time either :slight_smile:

I have a challenge response slot on my yubi key yeah.

This is already implemented, interestingly enough. YubiKey login has a PAM and i think a similar mechanism can be used to decrypt the root partition with LUKS.

1 Like

Yes, I use yubikey-luks which adds a 2nd factor using a challenge response in slot 2 of the YubiKey.

I’ve added provisions in SiRFIDaL to read a UID and pass it to cryptsetup. So you would do something like this to set it up (as root):

  • Get the UID you want to use as a crypto key for the volume with sirfidal_getuids.py
  • Do cryptsetup luksAddKey /dev/<your encrypted volume> and paste the UID when it prompts for a key
  • Then to open it at boot time with your implant: sirfidal_getuids.py -q -s '' | cryptsetup -d- luksOpen /dev/<your encrypted volume> <mapper>

You would just have to setup your source of UIDs (pcscd, serial port, keyboard wedge or cellphone) and start sirfidal_server at boot time before opening the LUKS volume.

1 Like

The script I had posted above works, but it didn’t always work reliably. As I was trying to figure out why, I realized something: Rohos Logon Key really expects UIDs to come in specific data formats from the serial readers it supports nominally. The script however simply passes it raw LF-terminated ASCII UIDs.

So I modified it a bit: now it simulates an Easyident FS-2044 RFID reader (one of the readers Rohos Logon Key explicitely supports). With that new version, Rohos unlocks each and every time without fail.

Here it is:

#!/usr/bin/python3

# This program emulates an Easyident FS-2044 RFID reader with UIDs read from a
# generic, 10-digit UID, 9600 baud serial RFID reader, for use as an input
# device by Rohos Logon Key.
#
# This program requires a virtual null modem cable such as com0com, with
# Rohos Logon Key listening to one end of the null modem cable, and this
# program outputting fake Easyident frames to the other end.
#
# Additionally, this program can kill a running Windows screensaver whenever a
# UID is read, so that the Windows logon screen is automatically brought up
# before passing the UID to Rohos Logon Key, thereby alleviating the need to
# press a key to activate the logon screen.



# Parameters
incomport="COM2"		# Input COM port for the generic serial reader
outcomport="COM4"		# Output COM port for the virtual null modem
				# Rohos Logon Key is connected to the
				# other end of
screensaver="ribbons.scr"	# Set to None to bypass killing the screensaver



# Modules
import os
import time
import serial



# Main program
incomport_fd=None
outcomport_fd=None

hexdigits = "0123456789ABCDEF"

while True:

  uid=None

  if not incomport_fd:
    try:
      incomport_fd = serial.Serial(incomport)
    except:
      print("Error opening input COM port {}".format(incomport))
      incomport_fd = None
      time.sleep(0.2)
      continue

  # Read a UID from the serial RFID reader
  try:
    uid=incomport_fd.readline().strip().decode("ascii")
  except:
    print("Read error")
    incomport_fd = None
    time.sleep(0.2)
    continue

  if not outcomport_fd:
    try:
      outcomport_fd = serial.Serial(outcomport)
    except:
      print("Error opening output COM port {}".format(outcomport))
      outcomport_fd = None
      time.sleep(0.2)
      continue

  uid = "".join([c for c in uid.upper() if c in hexdigits])

  print("UID read in:", uid)

  if len(uid) != 10:
    print("  Incompatible UID (not 10 digits) - giving up")
    continue

  # Kill the screensaver
  if screensaver:
    try:
      os.system("taskkill /f /t /im {}".format(screensaver))
    except:
      pass

  # Create a simulated Easyident data frame
  csum = sum([ord(c) - ord("0" if c.isdigit() else "7") for c in uid]) & 0xf
  easyident_frame = b"\x8a" + (uid + hexdigits[csum]).encode("ascii") + b"\r\n"

  # Pass on the fake Easyident frame to Rohos Logon Key
  try:
    outcomport_fd.write(easyident_frame)
    outcomport_fd.flush()
    print("  UID sent out")
  except:
    print("  Write error")
    incomport_fd = None
    time.sleep(0.2)
2 Likes

Microsoft pushed a Windows update on Friday that breaks Rohos in serial mode.

My foot reader is now dead.

Fuck Microsoft…

Dicks!

Any legitimate reason for it?
Have you “raised a ticket”?
How long did it take you to work out the cause?

Well I suppose the legitimate reason is that my company’s IT guy is anal about keeping up with updates. I suppose he’s right too. He would be righter if he ditched Windows but this is a Microsoft shop, so…

But he retires in 1 1/2 year and I’m next in line. And I’m already installing Linux right and left and proving by example that it’s nicer when done right, so there is hope :slight_smile:

Yeah I reported it to the dev. We’ll see what he says. I’m not too hopeful though: he seems to frown upon what I’m doing with his baby - i.e. using it for insecure applications. I have a feeling he’s not too keen on supporting serial readers, from what he told me in the past. We’ll see.

It took me forever to find out the cause. The clincher was when I uninstalled everything - com2com, my Python script, Rohos, cleaned the registry squeaky clean - then reinstalled Rohos vanilla and simply configured it to listen to a real serial port to which nothing was connected, and seeing card IDs being read. That’s a dead giveaway.

I managed to get Rohos to cooperate with my RFID serial reader again. Most of the time anyway.

Rohos has a really weird way of handling the serial port. I think it’s using a custom reader protocol that I don’t understand. But no matter how hard I try to reverse engineer it, I’m not really able to find out exactly what it needs to work well. Nor can I find the specs of the serial readers it’s supposed to support anywhere online. Not that it would be terribly useful: Rohos simply links to third party libraries to support those readers as far as I can tell, and those manufacturer-provided libraries are rarely fully documented.

Anyway, here’s a new script that manages to pass UIDs from a generic serial reader to Rohos. It’s seriously dirty and hacky but it seems to work more or less reliably:

#!/usr/bin/python3

# This program sends UIDs read from a generic 9600 8N1 serial RFID reader to
# Rohos Logon Key, configured to use the authentication device type
# "RFID Easyident/Addimat/KCY/pcProx/Stahl", using the weird serial protocol
# it seems to be using in that mode.
#
# It requires a virtual null modem provided by com0com, with RTS/CTS "cabled"
# in the com0com setup utility (default), "emulate baud rate" enabled",
# "enable buffer overrun" enabled and Rohos Logon Key configured to be
# listening to one end of the null modem cable.
#
# Additionally, this program can kill a running Windows screensaver whenever a
# UID is read, so that the Windows logon screen is automatically brought up
# before passing the UID to Rohos Logon Key, thereby alleviating the need to
# press a key to activate the logon screen.
#
# Please note that the way Rohos Logon Key is listening to the serial port in
# "RFID Easyident/Addimat/KCY/pcProx/Stahl" mode is totally unclear. The way
# this program sends UIDs to it is highly unusual, but it seems to be the only
# way to get Rohos Logon Key to accept UIDs somewhat reliably. This is probably
# not correct, and probably abuses the program's normal operation.



# Parameters
incomport   = "COM2"		# Input COM port for the generic serial reader
outcomport  = "COM4"		# Output COM port for the virtual null modem
							# Rohos Logon Key is connected to the
							# other end of
screensaver = "ribbons.scr"	# Set to None to bypass killing the screensaver



# Modules
import os
import time
import serial
from datetime import datetime



# Main program
incomport_fd = None
outcomport_fd = None

recbuf = b""

while True:

  uid = None

  if incomport_fd is None:
    try:
      incomport_fd = serial.Serial(incomport, timeout = .5)
    except:
      print("Error opening input COM port {}".format(incomport))
      incomport_fd = None
      time.sleep(0.2)
      continue

  # Read a UID from the serial RFID reader
  uid = b""
  b = b""
  while True:

    try:
      b = incomport_fd.read(1)
    except:
      print("Read error")
      incomport_fd = None
      time.sleep(0.2)
      break

    if b:
      if b in b"0123456789abcdefABCDEF":
        recbuf += b.upper()
      elif b == b"\n":
        uid = recbuf
        recbuf = b""
    else:
      if uid:
        break

  if incomport_fd is None:
    continue

  if outcomport_fd is None:
    try:
      outcomport_fd = serial.Serial(outcomport)
      cts = outcomport_fd.cts
    except:
      print("Error opening output COM port {}".format(outcomport))
      outcomport_fd = None
      time.sleep(0.2)
      continue

  print("UID read in:", uid.decode("ascii"))

  # Kill the screensaver
  if screensaver is not None:
    print("  Killing the screensaver")
    try:
      os.system("taskkill /f /t /im {}".format(screensaver))
    except:
      pass

  # Pass on the UID to Rohos Logon key twice, it case it misses the first time
  for i in range(2):

    # First wait for a falling edge on CTS
    now = datetime.now().timestamp()
    cts_wait_timeout = now + 2
    prev_cts = cts
    cts = outcomport_fd.cts
    while not (cts and not prev_cts) and now < cts_wait_timeout:
      prev_cts = cts
      cts = outcomport_fd.cts
      now = datetime.now().timestamp()

    # If we can send the UID, do so. Otherwise give up
    if cts and not prev_cts:
      try:
        outcomport_fd.write(uid)
        outcomport_fd.flush()
        print("  UID sent out {}".format("once" if i == 0 else "twice"))
      except:
        print("  Write error")
        outcomport_fd = None

    # If the CTS thing fails, make sure we don't end up in a tight loop
    time.sleep(.5)

EDIT:

Oh and yeah, another thing: if you have a pcProx Sonar connected to your computer, you’ll have to delete or rename C:\Windows\system32\pcProxAPI.dll and C:\Windows\SysWOW64\pcProxAPI.dll to disable the pcProx API: it turns out that library (or Rohos) only checks the VID (vendor ID) of the various USB devices listed in the system to determine the presence of a pcProx reader. Of course, the Sonar being made by the same manufacturer, it has the same VID. But it’s not a reader, so it messes everything up.

Took me forever to find that one…

1 Like

When I select the RFID reader in options and click ok. I get a message saying “Authentication key is not installed. Failed to load Rohos_ed-fs_2044.dll”
I can’t move to set up authorization because for some reason the ACR122 is not being recognized.
Any suggestions?

I’m having the same issue my acr122u doesn’t show in com’s or rohos
only seems to work at all with the acr122utools