Flashing morse code on a LED implant

Absolutely! I really like them, but they are definitely one of the most care-intensive bodymods… You’ll basically have to take care of them for as long as you have them.

I read this out of context and thought you were referring to the FlexNExT :scream: I just scrolled up and realized you were referring to transdermals.

Hehe, nah - guess that little guy will be all nice soon and stay like that forever :wink:

Since not everybody has a Proxmark3, here’s a version of the script that uses an ACR122U reader instead. The performance is similarly craptastic, but at least it work. really good! It goes up to 135 WPM on an ordinary PC [EDIT: I thought it was crap because I coded it in a virtual machine, and it won’t go over 10 WPM without timing overruns in that kind of environment]

Tested on Linux running PCSC-Lite. It ought to work in Windows with very minor modifications, but I haven’t tried.

#!/usr/bin/python3

### Parameters
default_wpm     = 10 #words per minute
msg_start_pause = "   "
msg_end_pause   = "   "



### Modules
import sys
import argparse
from time import sleep
from datetime import datetime
from smartcard.scard import *



### Defines
# Morse code dictionary
morsecode = {
	"A":     ".-",
	"B":     "-...",
	"C":     "-.-.",
	"D":     "-..",
	"E":     ".",
	"F":     "..-.",
	"G":     "--.",
	"H":     "....",
	"I":     "..",
	"J":     ".---",
	"K":     "-.-",
	"L":     ".-..",
	"M":     "--",
	"N":     "-.",
	"O":     "---",
	"P":     ".--.",
	"Q":     "--.-",
	"R":     ".-.",
	"S":     "...",
	"T":     "-",
	"U":     "..-",
	"V":     "...-",
	"W":     ".--",
	"X":     "-..-",
	"Y":     "-.--",
	"Z":     "--..",
	"1":     ".----",
	"2":     "..---",
	"3":     "...--",
	"4":     "....-",
	"5":     ".....",
	"6":     "-....",
	"7":     "--...",
	"8":     "---..",
	"9":     "----.",
	"0":     "-----",
	"=":     "-...-",
	"/":     "-..-.",
	"?":     "..--..",
	",":     "--..--",
	".":     ".-.-.-",
	":":     "---...",
	"'":     ".----.",
	'"':     ".-..-.",
	"_":     "..--.-",
	"(":     "-.--.",
	")":     "-.--.-",
	"#":     "-.---",
	"-":     "-....-",
	"|":     "...-..",
	"\\":    "-.....",
	"*":     "-----.",
	";":     "-.-.-.",
	"@":     ".--.-.",
	"^":     "....--.-.",
	"$":     "...-..-",
	"!":     "....-.",
	">":     "....---.",
	"]":     "....-....",
	"[":     "....-..",
	"<":     "....-.-..",
	"&":     "....--.",
	"%":     "....-.--.",
	"~":     "....--",
	"+":     ".-.-.",
	"{":     "....-.--",
	"}":     "....--..-",
	"[AR]":  ".-.-.",
	"[AS]":  ".-...",
	"[BK]":  "-...-.-",
	"[BT]":  "-...-",
	"[KA]":  "-.-.-",
	"[CL]":  "-.-..-..",
	"[KN]":  "-.--.",
	"[VA]":  "...-.-",
	"[VE]":  "...-.",
	"[GR]":  "--..-.",
	"[HM]":  "....--",
	"[IX]":  "..-..-",
	"[IMI]": "..--..",
	"[INT]": "..-.-",
	"[SOS]": "...---..."}

# CCID escape command
ioctl_ccid_escape = SCARD_CTL_CODE(1)	# For PCSC-Lite. Use 3500 for Windows

# ACR122U pseudo-APDU commands
cmd_get_fw_revision = [0xff, 0x00, 0x48, 0x00, 0x00]
cmd_disable_polling = [0xff, 0x00, 0x51, 0x00, 0x00]
cmd_enable_polling  = [0xff, 0x00, 0x51, 0xff, 0x00]

# PN53x commands, wrapped in ACR122U direct transmit pseudo-APDUs
cmd_rf_field_off    = [0xff, 0x00, 0x00, 0x00, 0x04, 0xd4, 0x32, 0x01, 0x00]
cmd_rf_field_on     = [0xff, 0x00, 0x00, 0x00, 0x04, 0xd4, 0x32, 0x01, 0x01]



### Routines
def send_acr122u_control_command(cmd, hcard):
  """Send the ACR122U a control command, return the raw result and raise an
  exception in case of error
  """

  hresult, response = SCardControl(hcard, ioctl_ccid_escape, cmd)
  if hresult != SCARD_S_SUCCESS:
     raise SystemError("Failure to control: {}".format(
			SCardGetErrorMessage(hresult)))
  return(response)
  


### Main routine
def main():
  """Main routine
  """

  # Read the command line arguments
  argparser = argparse.ArgumentParser()
  argparser.add_argument(
	  "-w", "--words-per-minute",
	  type = int,
	  help = "Rate of the morse code (default: {})".format(default_wpm),
	  default = default_wpm,
          required = False
	)
  argparser.add_argument(
	  "message",
	  type = str,
	  help = "Text to output in morse code on LED implant",
	)
  args = argparser.parse_args()

  wpm = args.words_per_minute
  msg = args.message.upper()

  if not msg:
    print("Nothing to do")
    return(0)



  # Add a pause at the beginning and at the end of the message
  msg = msg_start_pause + msg + msg_end_pause

  # Turn the message into a sequence of field-on durations (positive) and
  # field-off durations (negative)
  morsechars = []
  i = 0
  while i < len(msg):

    if msg[i] == "[":
      j = msg.find("]", i + 1)
      if j > 0 and msg[i : j + 1] in morsecode:
        morsechars.append(morsecode[msg[i : j + 1]])
        i = j + 1
        continue

    if msg[i] == " " or msg[i] == "\t":
      morsechars.append(" ")

    elif msg[i] in morsecode:
      morsechars.append(morsecode[msg[i]])

    else:
      print("Untranslatable in morse code: {} - dropped".format(msg[i]))

    i += 1

  ditlen = 1.2 / wpm 
      
  morseseq = []
  for mc in morsechars:

    if mc == " ":
      if morseseq:
        morseseq[-1] = -ditlen * 7
      else:
        morseseq.append(-ditlen * 7)
      continue

    for c in mc:
      if c == ".":
        morseseq.append(ditlen)
      else:
        morseseq.append(ditlen * 3)
      morseseq.append(-ditlen)

    morseseq[-1] = -ditlen * 3



  # Establish context and connect to the reader
  try:
    hresult, hcontext = SCardEstablishContext(SCARD_SCOPE_USER)
    hresult, hcard, dwActiveProtocol = SCardConnect(hcontext,
					'ACS ACR122U PICC Interface 00 00',
					SCARD_SHARE_DIRECT, SCARD_PROTOCOL_T0)
  except:
    print("Cannot connect to ACR122U")
    return(-1)

  # Get the ACR122U's firmware revision number, to test that CCID escape has
  # been enabled and to double-check that the reader is indeed an ACR122U
  try:
    fwrev = "".join([chr(v) for v in send_acr122u_control_command(
		cmd_get_fw_revision, hcard)])
  except:
    print("Error getting ACR122U firmware revision number.")
    print("Is the CCID exchange command allowed in /etc/libccid_Info.plist")
    return(-2)
  
  if fwrev[:7].upper() != "ACR122U":
    print('Error: "{}" does not appear to be an ACR122U'.format(fwrev))
    return(-3)

  # Disable polling so the reader won't try to read the implant when the field
  # is turned on
  try:
    send_acr122u_control_command(cmd_disable_polling, hcard)
  except:
    print("Error disabling polling")
    return(-4)

  # Play the morse code sequence
  warn_if_too_fast = True
  for d in morseseq:

    # Flip the RF field on or off
    cmd_start_tstamp = datetime.now().timestamp()
    try:
      send_acr122u_control_command(cmd_rf_field_off if d < 0 \
					else cmd_rf_field_on, hcard)
    except:
      print("Error switching the RF field {}".format("off" if d < 0 else "on"))
      return(-5)
    cmd_duration = datetime.now().timestamp() - cmd_start_tstamp

    # Wait for however long it takes to match the duration in the sequence
    remaining_wait = abs(d) - cmd_duration
    if remaining_wait > 0:
      sleep(remaining_wait)
    else:
      if warn_if_too_fast:
        print("Warning: {} WPM is too fast for the ACR122U and/or your " \
		"computer.".format(wpm))
        print("Morse code timing may appear incorrect")
        warn_if_too_fast = False        

  # Re-enable the RF field and re-enable polling so the reader can work again
  # as a regular reader
  try:
    send_acr122u_control_command(cmd_rf_field_on, hcard)
  except:
    print("Error re-enabling the RF field")
    return(-5)

  try:
    send_acr122u_control_command(cmd_enable_polling, hcard)
  except:
    print("Error re-enabling polling")
    return(-6)

      

### Jump to the main routine
if __name__ == "__main__":
  sys.exit(main())
1 Like

Here’s yet another version of the script: this one can talk to an ACR122U through the PS/SC, or directly to any PN53x reader through USB (including an ACR122U):

#!/usr/bin/python3
"""Small program to flash a morse code message on an NFC LED implant using
either a ACR122U reader through PC/SC, or a PN53x-based USB reader directly
(including a ACR122U)

The pyscard module is required for operation with PC/SC
The nfcpy module is required for direct USB operation with a PN53x-based reader
"""

### Parameters
default_interface = "pn53x_usb"
default_wpm       = 10 #words per minute
msg_start_pause   = "   "
msg_end_pause     = "   "



### Modules
import sys
import argparse
from time import sleep
from datetime import datetime



### Defines
# Morse code dictionary
morsecode = {
	"A":     ".-",
	"B":     "-...",
	"C":     "-.-.",
	"D":     "-..",
	"E":     ".",
	"F":     "..-.",
	"G":     "--.",
	"H":     "....",
	"I":     "..",
	"J":     ".---",
	"K":     "-.-",
	"L":     ".-..",
	"M":     "--",
	"N":     "-.",
	"O":     "---",
	"P":     ".--.",
	"Q":     "--.-",
	"R":     ".-.",
	"S":     "...",
	"T":     "-",
	"U":     "..-",
	"V":     "...-",
	"W":     ".--",
	"X":     "-..-",
	"Y":     "-.--",
	"Z":     "--..",
	"1":     ".----",
	"2":     "..---",
	"3":     "...--",
	"4":     "....-",
	"5":     ".....",
	"6":     "-....",
	"7":     "--...",
	"8":     "---..",
	"9":     "----.",
	"0":     "-----",
	"=":     "-...-",
	"/":     "-..-.",
	"?":     "..--..",
	",":     "--..--",
	".":     ".-.-.-",
	":":     "---...",
	"'":     ".----.",
	'"':     ".-..-.",
	"_":     "..--.-",
	"(":     "-.--.",
	")":     "-.--.-",
	"#":     "-.---",
	"-":     "-....-",
	"|":     "...-..",
	"\\":    "-.....",
	"*":     "-----.",
	";":     "-.-.-.",
	"@":     ".--.-.",
	"^":     "....--.-.",
	"$":     "...-..-",
	"!":     "....-.",
	">":     "....---.",
	"]":     "....-....",
	"[":     "....-..",
	"<":     "....-.-..",
	"&":     "....--.",
	"%":     "....-.--.",
	"~":     "....--",
	"+":     ".-.-.",
	"{":     "....-.--",
	"}":     "....--..-",
	"[AR]":  ".-.-.",
	"[AS]":  ".-...",
	"[BK]":  "-...-.-",
	"[BT]":  "-...-",
	"[KA]":  "-.-.-",
	"[CL]":  "-.-..-..",
	"[KN]":  "-.--.",
	"[VA]":  "...-.-",
	"[VE]":  "...-.",
	"[GR]":  "--..-.",
	"[HM]":  "....--",
	"[IX]":  "..-..-",
	"[IMI]": "..--..",
	"[INT]": "..-.-",
	"[SOS]": "...---..."}

# CCID escape command
ioctl_ccid_escape_code = 1	# 1 for PCSC-Lite, 3500 for Windows

# ACR122U pseudo-APDU commands
cmd_get_fw_revision = [0xff, 0x00, 0x48, 0x00, 0x00]
cmd_disable_polling = [0xff, 0x00, 0x51, 0x00, 0x00]
cmd_enable_polling  = [0xff, 0x00, 0x51, 0xff, 0x00]

# PN53x commands, wrapped in ACR122U direct transmit pseudo-APDUs
cmd_rf_field_off    = [0xff, 0x00, 0x00, 0x00, 0x04, 0xd4, 0x32, 0x01, 0x00]
cmd_rf_field_on     = [0xff, 0x00, 0x00, 0x00, 0x04, 0xd4, 0x32, 0x01, 0x01]



### Routines
def send_acr122u_control_command(cmd, hcard):
  """Send the ACR122U a control command, return the raw result and raise an
  exception in case of error
  """

  hresult, response = SCardControl(hcard, ioctl_ccid_escape, cmd)
  if hresult != SCARD_S_SUCCESS:
     raise SystemError("Failure to control: {}".format(
			SCardGetErrorMessage(hresult)))
  return(response)



def nfc_morse_player(do_pcsc, wpm, msg):
  """Morse code player
  """

  if not msg:
    print("Nothing to do!")
    return(0)

  # Add a pause at the beginning and at the end of the message
  msg = msg_start_pause + msg + msg_end_pause

  # Turn the message into a sequence of field-on durations (positive) and
  # field-off durations (negative)
  msg = msg.upper()
  morsechars = []
  i = 0
  while i < len(msg):

    if msg[i] == "[":
      j = msg.find("]", i + 1)
      if j > 0 and msg[i : j + 1] in morsecode:
        morsechars.append(morsecode[msg[i : j + 1]])
        i = j + 1
        continue

    if msg[i] == " " or msg[i] == "\t":
      morsechars.append(" ")

    elif msg[i] in morsecode:
      morsechars.append(morsecode[msg[i]])

    else:
      print("Untranslatable in morse code: {} - dropped".format(msg[i]))

    i += 1

  ditlen = 1.2 / wpm 
      
  morseseq = []
  for mc in morsechars:

    if mc == " ":
      if morseseq:
        morseseq[-1] = -ditlen * 7
      else:
        morseseq.append(-ditlen * 7)
      continue

    for c in mc:
      if c == ".":
        morseseq.append(ditlen)
      else:
        morseseq.append(ditlen * 3)
      morseseq.append(-ditlen)

    morseseq[-1] = -ditlen * 3



  # Set things up using the PC/SC interface
  if do_pcsc:

    # Establish context and connect to the reader
    try:
      hresult, hcontext = SCardEstablishContext(SCARD_SCOPE_USER)
      hresult, hcard, dwActiveProtocol = SCardConnect(hcontext,
					'ACS ACR122U PICC Interface 00 00',
					SCARD_SHARE_DIRECT, SCARD_PROTOCOL_T0)
    except:
      print("Cannot connect to ACR122U")
      return(-1)

    # Get the ACR122U's firmware revision number, to test that CCID escape has
    # been enabled and to double-check that the reader is indeed an ACR122U
    try:
      fwrev = "".join([chr(v) for v in send_acr122u_control_command(
		cmd_get_fw_revision, hcard)])
    except:
      print("Error getting ACR122U firmware revision number.")
      print("Is the CCID exchange command allowed in /etc/libccid_Info.plist")
      return(-2)
    
    if fwrev[:7].upper() != "ACR122U":
      print('Error: "{}" does not appear to be an ACR122U'.format(fwrev))
      return(-3)

    # Disable polling so the reader won't try to read the implant when the field
    # is turned on
    try:
      send_acr122u_control_command(cmd_disable_polling, hcard)
    except:
      print("Error disabling polling")
      return(-4)

  # Set things up using the direct PN53x USB interface
  else:

    # Open the PN53x USB reader
    try:
      clf = ContactlessFrontend()
      if not clf.open("usb"):
        raise SystemError
    except:
      print("Error opening the PN53x USB reader")
      return(-1)



  # Play the morse code sequence
  warn_if_too_fast = True
  for d in morseseq:

    # Flip the RF field on or off
    cmd_start_tstamp = datetime.now().timestamp()
    try:
      if do_pcsc:	# Use the PC/SC interface
        send_acr122u_control_command(cmd_rf_field_off if d < 0 \
					else cmd_rf_field_on, hcard)
      else:		# Use the direct PN53x USb interface
        clf.device.chipset.rf_configuration(0x01, b"\00" if d < 0 else b"\01")
    except:
      print("Error switching the RF field {}".format("off" if d < 0 else "on"))
      return(-5)
    cmd_duration = datetime.now().timestamp() - cmd_start_tstamp

    # Wait for however long it takes to match the duration in the sequence
    remaining_wait = abs(d) - cmd_duration
    if remaining_wait > 0:
      sleep(remaining_wait)
    else:
      if warn_if_too_fast:
        print("Warning: {} WPM is too fast for the ACR122U and/or your " \
		"computer.".format(wpm))
        print("Morse code timing may appear incorrect")
        warn_if_too_fast = False        



  # Clean things up using the PC/SC interface
  if do_pcsc:

    # Re-enable the RF field and re-enable polling so the reader can work again
    # as a regular reader
    try:
      send_acr122u_control_command(cmd_rf_field_on, hcard)
    except:
      print("Error re-enabling the RF field")
      return(-5)

    try:
      send_acr122u_control_command(cmd_enable_polling, hcard)
    except:
      print("Error re-enabling polling")
      return(-6)

  # Clean things up using the direct PN53x USb interface
  else:

    clf.close()

      

### Main routine
if __name__ == "__main__":

  # Read the command line arguments
  argparser = argparse.ArgumentParser()
  argparser.add_argument(
	  "-i", "--interface",
	  type = str,
	  help = "Reader interface (default: {})".format(default_interface),
	  choices = ("pcsc", "pn53x_usb"),
	  default = default_interface,
          required = False 
	)
  argparser.add_argument(
	  "-w", "--words-per-minute",
	  type = int,
	  help = "Rate of the morse code (default: {})".format(default_wpm),
	  default = default_wpm,
          required = False
	)
  argparser.add_argument(
	  "message",
	  type = str,
	  help = "Text to output in morse code on LED implant",
	)
  args = argparser.parse_args()

  do_pcsc = args.interface == "pcsc"

  # Conditionally import the relevant module here, so the user doesn't have to
  # install the other if they don't plan on using that particular interface
  if do_pcsc:
    from smartcard.scard import *	# From the pyscard package

    # We can only set this variable here
    ioctl_ccid_escape = SCARD_CTL_CODE(ioctl_ccid_escape_code)

  else:
    from nfc import *			# From the nfcpy package

  sys.exit(nfc_morse_player(do_pcsc, args.words_per_minute, args.message))

Essentially, any USB PN53x reader that works with libnfc will work with the direct USB mode. The reason I added it is because I wanted to use my DL533N-XL long-range reader to drive my doNExT’s LEDs, and the DL533N-XL isn’t supported by PCSC-Lite.

And look how gloriously it works: my arm is about half an inch off the reader and it lights up like a Christmas tree!

1 Like

Maybe it’s time you get a repo for this?
Whatever I watch on dailymotion, the next video is always a trailer of:

Yes, Dailymotion sucks major ass. I hate it with a passion (and Vimeo sucks even harder). But it has one advantage: it’s not Youtube / Google. At least not completely.

I thought of compressing the video to under 8 gigs and uploading it here directly, but then I’d be wasting Amal’s bandwidth.

As for a repo for the code, those are transitional trial-and-error code snippets, to try and figure out on which hardware I’ll base my smart NFC bracelet thingy. I really can’t be bothered to upload it on Github.

1 Like

I love the idea:
In a Dystopian future, a small group of individuals rebel against the man.
Trading secrets and information in plain sight,
small “info stations” are set up around the city, they could look like power boxes on electric poles, mail boxes, The button box for the stop lights at the pedestrian crossing.
But when the bio hackers rest their arm on the station, they get the Morse code information within seconds.

Info can consist of:
Place/date of next rebel meeting
what streets the drone militia is roaming that day
a request for someone to come help fix a computer (XD)

Anyway, back on topic.
This concept is really cool, i love giving the blinkies even more application

3 Likes

Actually I’m thinking of another application for the blinkies - a security applicaton. Imagine this:

There’s a camera in a fixed position on top of the reader. When I present my arm, the computer sees the blinkies light up, recognizes the triangular shape and orientation on my arm, flashes them quickly a few times in a random pattern to check if the feedback from the camera matches, and only then triggers a read and checks the password on the NTAG.

It’s still not proper crypto security, but I reckon it would make it really quite hard to impersonate me.

2 Likes

Thats really smart

p1bs95

6 Likes

I didn’t know Adrien Brody had placed such a big order of FlexNExTs :slight_smile:

1 Like

It was a promo deal hahah

1 Like