[ TechnoCage | Caskey | USB Wireless Security Lock ]

Hacking on the USB Wireless Security Lock

Also known as the "Cypress Ultra Mouse"

picture of usb lock

About a week ago I picked up this nifty usb lock from the store for about 20USD. I'd seen it for sale on think geek and since I was spending a gift certificate, I figured that I may as well pick one up. Getting it to respond under linux (from userspace) was a bit of a trick, especially since I have never done any usb programming before.

From what I've read and seen online, the device is essentially an el-cheapo brand wireless mouse stripped of the guts that make it a mouse leaving the receiver and the transmitter in the 'fob'. The fob blinks its led every 2 seconds, and the receiver blinks its light every 1 second. Each time the receiver blinks, it sends 3 interrupt transmissions with four bytes in each. The first is always zero, the second and third appear to be the fob's id and the last is a 1 if the fob has just connected (or reconnected) and a 0 if otherwise. Obviously each fob appears to have an id of at most 16 bits and so you would not want to use this for any serious security application.

1 byte 1 byte 1 byte 1 byte
0x00 always id part 1 id part 2 0x00 = update
0x01 = first report
Data transmission contents

TIP: I never bothered with the cdrom so this may be on there, but the fob's big green button, when held down for about 3 seconds turns the fob off or on and when pressed briefly while on, appears to 're-sync' the fob with the dongle. I recommend you not forget to turn it off as the packaging says the battery only has a life of around 2000 hours (that's a bit shy of 3mos continuous use). Of course a huge unprotected button in your pocket is unlikely to stay off for long.

The good news is that libusb had provided most of the heavy lifting for me, and all I needed to do was figure out how to make the darned thing start responding. Note: all of my tests were done on a relatively old distribution of linux running kernel 2.4.18.

After building and installing the libusb distribution (after munging the Makefile to skip over C++ junk which was broken on my system), I copied the testlibusb.c source to a temporary directory and started making changes. I knew nothing about USB and it took me an hour or two to figure the right order of invocation. Annoyingly the 'documentation' for the wonderful library is quite spare. I did discover that, once I had the device pointer, the following sequence of operations would yield results:

  1. usb_open(dev), this is a prerequisite to all of the libusb operations on a device. It returns a 'handle' used in all other operations.
  2. usb_claim_interface(handle, 0), after examining the output of the enumeration of the interfaces, I discovered that the usb fob has only one interface and according to the docs, I have to claim it before I use it. If I understand correctly, this function is primarily to inform the host O/S that something is using the device. Not sure though.
  3. usb_set_configuration(handle, 1), I'm not sure what this does, exactly, or even if it is necessary, but it doesn't return an error and it is in my working code.
  4. usb_interrupt_read(lock_device, 1, buffer, 4, 500000), this is the magic. After the above, a loop continuously calling this function will return the four bytes of data containing the fob id and whether or not it just connected.

There is a 2.6 kernel module out there which uses this with pam to block logins when the fob isn't present. However I've not seen much else. I figured I'd post my hacked up version of the test program so people can see the mess of code I made trying to get the fob to work. All the code does is enter a loop where 1000 times it asks the usb dongle for the data message. From what I can tell, this exhausts the functionality of the system, and all that remains is for someone to do something useful with this.

You can download my completely unedited hacked on version of the testlibusb program as copied straight from my temp directory. At the bottom of the page is the one meaningful function which, once the device is found in the usb tree, does the work. This code is hack and slash, and most certainly not meant to be anything other than a guide of where I got to in making it work then quit banging on it.

Given that my keyring has plenty of work to do just keeping my keys in order, I'll probably never carry or use this toy, but it was fun to play with. Plus, you have to give credit to a company which quite cleverly hacked together a basic proximity identity system using the guts of a mouse. Had this product instead been on hackaday as 'make your own remote security key out of a mouse', people would be falling over themselves talking about how cool it is.

#define USB_LOCK_VENDOR 0x04b4
#define USB_LOCK_PRODUCT 0x7417

void do_usblock(struct usb_device *dev) {
  usb_dev_handle *lock_device = 0;
  int ret = 0;
  int i, j ;

  printf("Doing usblock\n");
  if(dev->descriptor.idVendor != USB_LOCK_VENDOR ||
     dev->descriptor.idProduct != USB_LOCK_PRODUCT) {
    printf("ERR: Wasn't passed a usblock!\n");
    return;
  }

  lock_device = usb_open(dev);
  if(lock_device > 0) {
    char buffer[512];
    ret = usb_claim_interface(lock_device, 0);
    if(ret < 0) {
      printf("Failed to claim interface 0: %d EBUS: %d ENONM: %d\n", ret, EBUSY, ENOMEM);
      goto bail;
    }

    ret = usb_set_configuration(lock_device, 1);
    if(ret < 0) {
      printf("Failed to set config 1: %d EBUS: %d ENONM: %d\n", ret, EBUSY, ENOMEM);
      goto bail;
    }

    i = 1000;
    while(i--) {
      ret = usb_interrupt_read(lock_device, 1, buffer, 4, 500000);
      if(ret < 0) {
        printf("Failure usb_interrupt_read  %d '%s'\n", ret, strerror(-ret));
        goto bail;
      }
      printf("%04x Read %d bytes: ", i, ret);
      for(j = 0; j < ret; j++) {
        printf("%02x ", ((int)buffer[j] & 0x0ff));
    }
    printf("\n");
  }

bail:
  usb_close(lock_device);
}

If you have any comments or questions, feel free to email me.



Last updated: 2005-06-19