CECS Home | ANU Home | Search ANU
The Australian National University
ANU College of Engineering and Computer Science
School of Computer Science
Printer Friendly Version of this Document

UniSAFE

Operating Systems Implementation

Assignment 2 - A Device Driver for a Hardware Encryption Key

Objective

This assignment is intended to give the student an opportunity to explore interfacing a real hardware device with a modern Operating System by:

  • firstly, writing an application-level (user-space) library
  • secondly, writing a Linux kernel device driver module

An additional learning objective is to investigate the operation of the Universal Serial Bus (USB) from an Operating Systems perspective.

The real device to be interfaced is a USB based "hardware" encryption "key".

Note: the term "key" in this assignment specification will be used to both refer to the hardware device and to the encryption data. This may look ambiguous, hopefully the context will make it clear...

This assignment is to be undertaken preferably in groups of 2. Both members of each group are to be enrolled in the same course code (COMP3300 or COMP6330).

Background

Hardware Encryption Keys

A hardware encryption key is a device that can encrypt a block of data using an encryption "key" which it will generally keep secret. Such devices can be useful for a variety of purposes, in particular authentication, that is, "proving" that someone has the device in their possession.

A system requiring authentication knows how the device will encrypt any random block of data, generally by knowing the same encryption "key" stored on the device. Such a system can then "challenge" the target system with a very random (hard for an attacker to guess) block of data. The target system with the hardware encryption key will then encrypt the random block and send the "response" back. The authenticating system then compares the actual response with the expected response to determine if the hardware key was used.

If the encryption key (secret data) can be discovered from the device, then a purely software system could be used to "masquerade" as the real hardware device, rendering any protection useless.

In our case, the hardware encryption device will actually be a microcontroller programmed to implement the Advanced Encryption Standard (AES) 128-bit symmetric key algorithm. The microcontroller is also programmed to implement the peripheral part of the Universal Serial Bus (USB) protocol in software, using a technique called "bit-banging". Due to timing constraints, only the lowest-speed USB protocol can be implemented (1.5Mbit/sec). For the purposes of transferring 128-bit "plaintext" and "crypto" data, 1.5Mbit/sec will be sufficient.

The Hardware

Each assignment group will be issued with an encryption device. It will be one of either a SparkFun Electronics AVR-Stick, or an Evil Mad Science Diavolino-based system. In both cases, the microcontroller is an Atmel AVR, with the AVR-Stick using an ATTiny85 running at 16.5MHz and the Diavolino using an ATMega328p running at 16MHz. The two CPUs are source-code and binary-compatible, but the differing speeds and on-chip peripherals etc. mean that separate binary images are required for each variant.

The AVR CPUs have a Harvard architecture (separate code and data address spaces), and store the program code in Flash memory (8k on ATTiny85 and 32k on ATMega328p) and store data in on-chip RAM. Also, the CPUs have Electrically Erasable Programmable Read-Only Memory (EEPROM), that is useful for storing the encryption key persistently.

In both cases, the Universal Serial Bus interface is based on the V-USB Virtual USB Port for AVR microcontrollers written as an open-source library by German company Objective Development. This software-only implementation of the USB device specification allows us to program the AVR-Stick and the Diavolino to implement virtually any USB device we wish.

Note that the V-USB implementation and the associated electronics do NOT strictly adhere to the USB low-speed standard, but are close enough to work in almost all cases.

Universal Serial Bus

The Universal Serial Bus is well documented "on the web" in many places, including the Wikipedia USB article.

The basics:

  • "multiple-access" - multiple USB devices (up to 127) can share the same bus.
  • "plug-and-play" - USB devices can be added and removed whilst the system is running.
  • "bus-powered" - the USB can provide power to most low-powered devices.
  • multi-speed - the USB 1.1 standard allows devices running at 1.5Mbit/sec and 12Mbit/sec to co-exist on the bus. USB 2.0 also allows devices to run at 480Mbit/sec. USB 3.0 is faster again.
  • enumeration - each USB device can present ID codes that help the host to identify the device, manufacturer and class.

Of particular note is the support for the USB in the Linux kernel. The Linux kernel provides an abstraction of the USB interface at a low-level to user-space processes that allow a process to "bind" to a particular USB device and to have more-or-less full access to that device whilst simultaneously providing separation from other USB devices on the same bus.

The kernel also allows device driver code in the kernel to discover when USB devices of particular interest are plugged in and to then initialise and take control over the new devices.

The hardware encryption device will appear on the USB device with vendor code 0xf055 and device code 0xcec5 and the "Vendor-specific" class (0xff).

Interface to Encryption device

The software implementation of the USB protocol on the AVR CPUs (V-USB) necessarily only supports USB's "Low Speed" (LS) mode. In this mode, the maximum number of bytes that USB can transfer in one transaction is 8 (why would this be so?).

A further limitation of the Low Speed USB mode is that it only supports the control (compulsory) and interrupt endpoints. Although it is outside the USB specification to use the bulk and/or isochronous modes, most modern USB host operating systems seem to allow these modes with Low Speed mode in any case.

We are attempting to implement 128-bit encryption, which means that each block of data to encrypt (plaintext) will be 16 bytes, and the resultant block of cyphertext will be the same size. The challenge here is to get the plaintext to the device over Low Speed USB and to get the result back again. There are many different ways to do this. The protocol implemented for this assignment is deliberately somewhat cumbersome to help students understand the issues involved.

The code running on the hardware encryption devices only responds to the control endpoint messages of type "vendor" (it has no "class" type messages). The code could have been written to respond to the interrupt endpoint messages as well, but hasn't been. The control endpoint has three main message types that are used: Setup, In and Out.

The Setup requests implemented are:

  • 0: Echo - returns the two bytes in the value field
  • 1: Status - returns 2 bytes: first = 1 if an encryption is in progress, second = 1 if the LED is flashing
  • 2: LED on - (only on AVR-Stick) turns on white LED
  • 3: LED off - (only on AVR-Stick) turns off white LED
  • 4 - 7: each request sets up 4 bytes of data to encrypt
  • 8 - 9: return first or second 8 bytes of encrypted data
  • 10: start encryption
  • 11: control flashing LED, value = 0: stop flashing, value = 1: enable flashing
  • 12: upload or download encryption key (16 bytes)
  • 13: report 2 byte s/w version (major:minor) (not in all implementations)

All the keys are presently programmed with the same encryption key, which is: 0x4f7065726174696e6753797374656d73

So, to perform an encryption, your code needs to transfer the 16 bytes of plaintext data 4 bytes at a time using control requests 4, 5, 6 and 7 with the 4 bytes in the value and index. Then use control request 10 to start the encryption, control request 1 to check the status for when it is complete (encryption usually completes before the status request completes, so don't be surprised if it is always 0). Then use In control requests 8 and 9 to return the 16 bytes of ciphertext, 8 bytes at a time.

For testing etc. you can use control request 0 to echo some data back, control request 11 to enable/disable the flashing LED, control request 12 to get the encryption key etc.

The Assignment

The assignment is to be undertaken in two stages.

Stage 1

In the first stage, the task is to write some user-space interface routines and a program to test and demonstrate the interface routines. The interface routines should use the Linux libusb library to discover the device and interface with it, although you can by-pass this library if you can discuss the pros and cons of doing so.

Your test and demonstration program should simply provide an example implementation of passing some data to the hardware key to be encrypted, getting the result and comparing it with the expected result.

The first stage should be attempted by all groups and a well-written, well-documented and successful implementation will be sufficient for a pass grade for this assignment.

Discuss in your Readme.txt file some of the uses and weaknesses of hardware encryption keys in general, this implementation in particular and of your code and it's interaction with the Operation System.

Stage 2

Once the first stage is complete, the second-stage task is to write a Linux kernel device driver module that exposes the hardware encryption device as a file in the file-system. Accompanying application utilities will demonstrate opening the file, writing a data to be encrypted to it, reading the encrypted data back and comparing it with the expected result.

Most of the details of how you do this will be left to each assignment group. Additional features that may gain additional marks include: support for multiple keys, ability to cleanly unload the module, automatic notification when the device is plugged in or removed and other features that the assignment group may come up with.

Excellent implementation of the device driver, additional features and documentation can gain up to a high distinction grade for this assignment.

Administrivia

A subversion (svn) repository will be set up for each assignment 2 group. You will need to e-mail bob@cs.anu.edu.au with the members of your group and I will reply with the URL to your subversion repository. Marks will be awarded for the pattern of commits and accompanying comments in the subversion repository. Assignment submission will simply be the state of your subversion repository as at the deadline of 10pm Friday, 22rd October, 2010.

Each group will be issued with one or other version of the hardware key. These keys are to be returned by end of week 13 (Friday 30th October). Each key will have a small serial number written on it.

Each key will have a unique AES-128 encryption key (I hope) associated with it's serial number which I will e-mail to each group when subversion repositories are allocated.

Warnings

Please note that the AVR-Sticks are particularly small and easy to lose. Take care not to lose it!

Please also note that the extra components to add the USB interface to the Diavolino boards make them somewhat fragile. Please handle, store and transport with care. If your board is damaged, please e-mail bob@cs.anu.edu.au to make arrangements to have it repaired.

Please also note that in both cases, the hardware encryption keys are based on development boards and are not packaged for consumer use. This means that the conductors etc. are exposed. Ensure that you don't place the units on conductive surfaces whilst in use. Also, avoid touching the metal parts when transporting to avoid corrosion resulting from contact with body oils. Whilst USB runs at only 5V and is therefore quite safe, if your computer has some other hardware fault, it is possible, but highly unlikely, that in some extreme circumstances higher voltages may be present on the conductors. Always handle the electronics by the edges, away from any conductors.

Development Details

For the Engineers amongst us, here is the schematic of the AVR-Stick.

The software for the Atmel chips on the hardware encryption devices is written in C and compiled with the open source GNU C Compiler (gcc) for AVR (gcc-avr) available for most versions of Linux as well as for MacOSX and Windows. The source code for the AVR-Stick version is available here and the code for the Diavolino version is available here.

The binary images are programmed into the devices using the open-source avrdude Atmel AVR Downloader/UploaDEr utility program, also available for most versions of Linux etc.

The AVR-Sticks are programmed with the Dangerous Prototypes Bus Pirate USB-based programmer, with an 8-pin Small Outline IC (SOIC) clip to clamp directly onto the ATTiny85 device. The Diavolinos use the Arduino bootloader and are programmed with a Future Technology Devices International (FTDI) USB-Serial adapter cable.

All parts and most of the development tools were purchased from Little Bird Electronics, an Sydney-based boutique online electronics supplier.