USB Auth

From Makers Local 256
Jump to: navigation, search

Demonstration Materials

Concept

A computer will monitor for new USB devices being plugged into the system. If the device is on the approved list, it will instruct an external system to unlock a door.

Implementation

Authentication Flow

  1. User inserts key into USB hub hooked to a PC
  2. Computer reads serial ID of key
  3. Computer compares serial ID to list of valid serial ID in a table \ DB \ Flat File
  4. If good, computer writes data ("Unlock!") to USB line of Microcontroller
  5. Microcontroller instructs servo to go to unlocked position for 5-10 seconds.


The flowchart for the circuit is below.

10/04/2008

Parts List

  1. Servo $12
  2. Tubberware $6
  3. Freeduino (Diecimila) Development Board $36
  4. Breadboard $5(?)
  5. Solder, Soldering Iron (On Hand)
  6. 15k Ohm Resistors (On Hand)
  7. Button (On Hand)
  8. Powered USB Hub ? (Necessary: for powering Freeduino with only USB and a laptop)
  9. Unpowered UBS Hub (Optional: Hub to put outside of door to plug USB keychains into)

Electrical Interface

Electrical Interface by Omegix

Note: "Freeduino PWM Pin P" Should be "Freeduino PWM Pin 9"
Note: The pull down resistor on Pin 3 was removed. The internal pullup resistor of the atmega chip is used now instead, and the interrupt is tripped on a LOW instead of a HIGH.

10/21/2008


The resistors here are just pull down resistors.
The reed switch is one of those window sensors commonly found in home security systems.
The push button is for the inside of the door so people can unlock the door to get out. Pin 9 is the for the Servo signal.

Mechanical Interface

Mechanical Interface design by Gregabyte

Project Enclosure

We wanted a project enclosure that we could easily take on and off the door. Also we wanted something that was firm and see-through so people could see the project in action. Tupperware! Thank you, Rubbermaid.

10/04/2008

Mechanical Override

Note: Mechanical override will not be implemented till after Phreaknic Omegix 14:58, 21 October 2008 (CDT)

The idea here is to have a servo attached to a standard deadbolt. The microcontroller will need to not only receive a signal from the computer, but also sense a window-open detector, and control a servo.

If you were to attach the stick to the deadbolt turner or the plastic connected to the servo motor shaft, that would allow for a manual unlocker for the door in the event of a power failure


This image from Gregabyte shows a mechanical override system that could be implemented for under $20

10/04/2008

Code

USB Reader Code

Coded by Brimstone


#!/bin/sh

# variables!
mymu=A6005ycb
mydev=/dev/ttyUSB0
mydb=usb-keys.txt

# first, define some common functions
function lsserial {
	lsusb -v | awk '/iSerial/ {if ($2 == "3" || $2 == "2") {print $3}}'
}

# figure out whats attached
# check for our microcontroller
if [ $(lsserial | grep -c $mymu) = 0 ] ; then
	echo -n "I don't see the microcontroller "
	if [ -e $mydev ]; then
		echo "but we have a $mydev ?"
	else
		echo
	fi
	exit 1
else
	if [ ! -e $mydev ]; then
		echo "I see the microcontroller, but no $mydev"	
		exit 1
	fi
fi

if [ -e $mydb ] ; then
	echo "Found serials for the following people:"
	awk -F, '{print $1}' $mydb
else
	echo "Didn't find keyfile $mydb"
	exit 1
fi

# all good, lets go
preserial=$(lsserial | grep -v $mymu)
if [ -n "$preserial" ]; then
	echo "I've detected the following serial devices already:"
	echo $preserial
fi

echo "Ready and waiting"

# main loop that watches /var/log/messages
(
	tail -n 0 -f /var/log/messages | awk '/new.*USB device/ {print "Attached"; fflush()} /USB disconnect/ {print "Dettached"; fflush()}'
) | (
# main loop that reads that cleaned /var/log/messages
	while read cmd; do
		if [ $cmd == "Attached" ] ; then
			for ser in $(lsserial | grep -v $mymu); do
				echo "Checking for $ser in flat file"
				if [ $(grep -c $ser $mydb) = 1 ]; then
					name=$(awk -F, "/$ser/ {print \$1}" $mydb)
					echo "Unlocking for $name!"
					echo -n U > $mydev
					error=$?
					if [ $error != 0 ]; then
						echo "There was an error ($error) writing to $mydev"
					fi
				else
					echo "Didn't find it in flat file"
				fi
			done
		else
			echo "Got $cmd but nothing implemented for it"
		fi
	done
)

Freeduino Code

Coded by Omegix


//////////////////////////
/// Deadbolt Unlocker Application
/// This code is for a Freeduino deicimila.
/// Code will wait until it sees a "U" character on the serial input
/// And then set a PWM signal to a pre-determined associated physical position corresponding
/// To the unlocked position of a deadbolt.
///
/// Author:  Jeff Cotten
/// Changes:
/// - 12/6/08:  Changed the Override button to activate on LOW rathan than HIGH (this also caused a hardware change)   
/// - 12/7/08:  Turned on the pull up internal 20K Ohm pull-up resistor on the atmel chip
/////////////////////////




#include <Servo.h>

#define interrupt1PinA 3 //This is the Pin that the manual override button should be connected to

volatile unsigned int interrupt1Value = 0;

char incomingChar = 0;
Servo myServo;
int pos;
int DoorSensePin = 2;  //this is the PIN that the reed switch is connected to
int lockedPosition = 115;  //This is the value that the servo wants to be at the correct physical position
int unlockedPosition = 28;  //This is the value that the servo wants to be at the correct physical position

boolean HasForceUnlockHappened = 0;  //this is used by the interrupt routine as a workaround to using timers

void setup()
{
  Serial.begin(9600);
  Serial.flush();
  
  myServo.attach(9);  // attaches the servo on pin 9 to the servo object 
  Lock();  //default to locked position at powerup
  //myServo.write(28); //default to locked at powerup
  
  pinMode(DoorSensePin, INPUT);  //designate pin2 as a sensing (input) pin  
  pinMode(interrupt1PinA, INPUT);  
  digitalWrite(interrupt1PinA, HIGH);  //this turns on the internal 20k ohm pullup resistor
  
  //Interrupt pin used is Pin #3  
  attachInterrupt(1, ForceUnlock, LOW);  //when interrupt happens, run ForceUnlock function
}

void ForceUnlock() //it is important that no timer related functions happen during an interrupt routine
{
    Serial.println("Force Unlock Button Pressed! Interrupt Called!");
    myServo.write(unlockedPosition);  //cannot call regular Unlock function as it has a delay() call  
    HasForceUnlockHappened = 1;
}



void loop()
{
  //Serial.println("In Main Loop");  //TROUBLESHOOTING LINE
  if (HasForceUnlockHappened == 1) //if an interrupt driven ForceUnlock has happened, then need to WaitToLock
  {
    HasForceUnlockHappened = 0;  //reset till next interrupt
    WaitToLock();
  }  
  if (Serial.available() > 0)
  {
     incomingChar = Serial.read(); 
     
     Serial.print("I recieved: ");
     Serial.println(incomingChar, DEC);
     //Serial.print("The DoorSense Value is: ");
     //Serial.println(IsDoorOpen(), DEC);
    
    // Code for Unlocking Door.  Unlock does not care if door is closed or not.
    if (incomingChar == 85) //"U" is 85 in DEC.  U is for Unlock
    {
           Serial.println("Unlocking!");          
           Unlock();
    }

    //Code for Locking Door.  Lock cares if door is open or closed.
    if (incomingChar == 76)  //"L" is 76 in DEC.  L is for Lock
    {
         if (IsDoorOpen() == 0)  
         {
           Serial.println("Locking!");          
           Lock();
         }    
         if (IsDoorOpen() == 1) { Serial.println("Door is Open!!"); }         
    }
    
  }// if serial end
}//loop end

//IsDoorOpen should return a 1 if Door is Open, and a 0 if Door is Closed.
boolean IsDoorOpen()
{
  if (digitalRead(DoorSensePin) == 1) { return 1; }
  if (digitalRead(DoorSensePin) == 0) { return 0; }  
}

  
  void Unlock()
  {
    myServo.write(unlockedPosition);
    delay(100);
    WaitToLock();
  }
  
  void Lock()
  {
    myServo.write(lockedPosition);
  }
  
//This function will loop until the door is closed for 5 seconds and then Lock.
void WaitToLock()
{
BeginWaitingToLock:
   while (IsDoorOpen() == 1)  { /* Serial.println("Door Needs to Close.");    /* do nothing */ }  
   //At this point Door should have shut
   Serial.println("Door has been shut! Waiting 5 seconds.");
   delay(1000 * 5); //wait 5 seconds
   if (IsDoorOpen() == 0) // if door is still closed after delay, then lock
   {
      Lock(); 
   }
   if (IsDoorOpen() == 1) 
   { 
     Serial.println("Door Did not remain shut.  Starting over loop.");
     goto BeginWaitingToLock;
   }
   
   
}





Freeduino Code Change Log
  • 12-6-08: Changed interrupt pin for manually unlocking the door to detect LOW instead of HIGH.
    • This also meant using the external button's Normally Closed feature instead of Normally Open
    • Reason For this change was that the prototype equipment is not grounded to natural ground. The RF noise and Static Electricity was causing a HIGH signal on the wire which was randomly unlocking issuing the command to unlock the door
    • KNOWN ISSUES: The method called by the interrupt to unlock the door does not debounce the signal.

This is due to the interrupt disabling the timer function on the Freeduino. There should be a way to work around this, but it will likely not be resolved in Version 1.

C Code Implementation

As of 4/29/13, the latest version is written in C, not Arduino language.

External Links

  • Adam Argo developed an iPhone door unlocker
    • Good advantages include
      • A Switch to leave the door unlocked for a period of time
      • Not using an Interrupt, keeping the scan of the pins in the main loop
      • Much cleaner appearance

In the Media