Created
February 23, 2013 23:57
-
-
Save bradfitz/5021919 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include "sha1.h" | |
#include <SoftwareSerial.h> | |
SoftwareSerial SerialRNXV(2, 3); | |
int irVal = 0; | |
int distOn = 0; // getting distance | |
const int ms = 1; // unit of milliseconds | |
bool authed = false; | |
const int irValPin = 0; // the analog input pin for the ir reader | |
const int togglePin = 4; | |
const int buttonPin = 7; | |
const int unconnectedPin = 8; // for reading a "random" number from | |
const int challengeLength = 20; | |
char challenge [challengeLength+1]; | |
const int lineBufCap = 80; | |
char lineBuf[lineBufCap]; | |
int lineBufLen = 0; | |
void setup() { | |
Serial.begin(9600); | |
randomSeed(analogRead(unconnectedPin)); | |
// start software serial for communication with wifly | |
SerialRNXV.begin(9600); | |
// set output pin for toggling the circuit that toggles the door line | |
pinMode(togglePin, OUTPUT); | |
// set input for button | |
pinMode(buttonPin, INPUT); | |
} | |
int nloop = 0; | |
int lastButtonState = 0; | |
int timeButtonDown = 0; // capped at kMaxInt | |
const int kMaxInt = 32767; | |
const int kShortPress = 12000; | |
int inLongMode = 0; // if >0, don't open garage. decremented every time wrap. | |
void loop() { | |
nloop++; | |
if (nloop == 0) { | |
wifiPrint("TIME_WRAPPED\n"); | |
if (inLongMode > 0) { | |
inLongMode--; | |
} | |
} | |
if ((nloop & 0xfff) == 0xfff) { | |
int dist = analogRead(irValPin); | |
char buf[50]; | |
sprintf(buf, "DIST %d\n", dist); | |
wifiPrint(buf); | |
} | |
if (SerialRNXV.available() > 0){ | |
//char buf[12]; | |
//int inByte = SerialRNXV.read(); // Read next byte | |
//Serial.println(itoa(inByte, buf, 10)); | |
readWifiByte(); | |
} | |
int buttonNow = (digitalRead(buttonPin) == HIGH); | |
if (buttonNow != lastButtonState) { | |
lastButtonState = buttonNow; | |
if (buttonNow) { | |
timeButtonDown = 0; | |
} else { | |
char buf[19]; // len("BUTTON_DOWN ") + 5 (32k) + len("\n\0") | |
sprintf(buf, "BUTTON_DOWN %d\n", timeButtonDown); | |
wifiPrint(buf); | |
int isShortPress = timeButtonDown <= kShortPress; | |
if (isShortPress && !inLongMode) { | |
toggleDoor(); | |
} | |
if (!isShortPress) { | |
inLongMode = 3; // don't open garage on short press for 3 time wraps. | |
} | |
} | |
} | |
if (buttonNow && timeButtonDown < kMaxInt) { | |
timeButtonDown++; | |
} | |
if (distOn) { | |
delay(50); | |
} | |
} | |
void readWifiByte() { | |
int inByte = SerialRNXV.read(); | |
if (inByte < 0) { | |
return; | |
} | |
lineBuf[lineBufLen] = inByte; | |
lineBufLen++; | |
if (lineBufLen >= lineBufCap) { | |
lineBufLen = 0; // fuck it, too long of a line. | |
} | |
if (inByte == '*') { | |
if (lineBufHasSuffix("*OPEN*")) { | |
lineBufLen = 0; | |
generateChallenge(); | |
SerialRNXV.print("\nCHAL "); | |
SerialRNXV.println(challenge); | |
} else if (lineBufHasSuffix("*CLOS*")) { | |
lineBufLen = 0; | |
} | |
} | |
if (inByte == '\n') { | |
lineBuf[lineBufLen-1] = '\0'; | |
processWifiLine(lineBuf); | |
lineBufLen = 0; | |
} | |
} | |
void processWifiLine(char* line) { | |
if (strncmp(line, "OPEN ", 5) == 0) { | |
char* resp = line + 5; | |
char correctHexResp[41]; | |
uint8_t *key = (uint8_t*)"PASSWORD_HERE"; | |
Sha1.initHmac(key,11); | |
Sha1.print(challenge); | |
uint8_t* hash = Sha1.resultHmac(); | |
for (int i=0; i<20; i++) { | |
correctHexResp[i*2+0] = ("0123456789abcdef"[hash[i]>>4]); | |
correctHexResp[i*2+1] = ("0123456789abcdef"[hash[i]&0xf]); | |
} | |
correctHexResp[40] = '\0'; | |
if (strcmp(resp, correctHexResp) == 0) { | |
wifiPrint("OPENOK\n"); | |
toggleDoor(); | |
} else { | |
Serial.println("fail. got vs. want:"); | |
Serial.println(resp); | |
Serial.println(correctHexResp); | |
Serial.println(challenge); | |
} | |
generateChallenge(); // prevent replay attacks / guessing | |
return; | |
} | |
Serial.print("unhandled wifi line command: "); | |
Serial.println(line); | |
} | |
int lineBufHasSuffix(char* suf) { | |
int l = strlen(suf); | |
for (int i = 0; i < l; i++) { | |
if (lineBuf[(lineBufLen-l+i+lineBufCap)%lineBufCap] != suf[i]) { | |
return 0; | |
} | |
} | |
return 1; | |
} | |
void wifiPrint(char* s) { | |
SerialRNXV.print(s); | |
Serial.print("WIFI: "); | |
Serial.print(s); | |
if (strstr(s, "\n") == NULL) { | |
Serial.print("\n"); | |
} | |
} | |
void toggleDoor() { | |
wifiPrint("TOGGLE_GARAGE\n"); | |
digitalWrite(togglePin, HIGH); | |
delay(200 * ms); | |
digitalWrite(togglePin, LOW); | |
} | |
void generateChallenge() { | |
int i; | |
for (i = 0; i < challengeLength; i++) { | |
challenge[i] = char(random('A', 'Z'+1)); | |
} | |
challenge[challengeLength] = 0; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment