Frequently, while at the office or out of town, I find (to my dismay) that I need to access files on my desktop computer at home. The inevitable results are special trips and wasted time. While I could leave my desktop on indefinitely and access files remotely as, the inordinate amount of electricity that it consumes literally doubles my electric bill. Wake on LAN (WOL) would be another option, but I don't want to give anyone in the world the ability to start my computer. Moreover, if I should ever crash my system while logged in remotely, I need a way to force it to reboot. With this project, I've solved both problems for good, for the cost of about 3 months of running my desktop all day.Parts:
- Arduino Duemilanove
- Arduino Ethernet Shield
- Arduino ProtoShield Kit
- Wire Wrap Pins
- 3:8 Decoders (x2, optional)
- 16 Pin IC Socket (x2, for the decoders)
- SPST 5VDC Reed Relay
- PNP General Purpose Transistor (such as the 2N3906)
- Resistors (1 4.7k and 1 10k)
- Various plugs/jacks for connecting the Arduino to my PC.
- Power Switch Extension Cable (If you don\'t want to cut the power switch cable in your case)
The heart of this project is an Arduino Duemilanove microcontroller, equipped with an Ethernet adapter, and a home-made circuit that connects it to power switch on my computer. The Arduino is always on, so at any point in time (and from anywhere in the world), I can command the Arduino to start up my computer.
The simplest possible implementation would have the Arduino trigger the power switch any time it received a packet on some specific port. While this might work in practice, there is one obvious problem--it would allow anyone in the world to start up or shut down my computer (most likely accidentally). I've addressed this problem in the carefully crafted software running on both the Arduino, and my laptop, from which I access the Arduino remotely.
My first layer of security is a set of randomly-selected 64-bit binary strings that encode the messages to the Arduino. The Arduino component of my software will respond only to one of these exact strings. The chances of a stray packet carrying the startup signal reaching the Arduino are negligible.
As a second layer of security (which is undoubtedly overkill), I implemented some rudimentary cryptography in the communication protocol. Prior to sending any message, my laptop and the Arduino exchange a secret key with Diffie-Hellman key exchange. All messages between my laptop and the Arduino are encrypted with the key. Moreover, the key is invalidated after each message, which ensures that no message to or from the Arduino will be repeated in my lifetime.
To avoid the lose of unsaved work, I need to ensure that my software won't accidentally shut off my computer. I've handled this problem with some simple status checking. Before the Arduino triggers the power switch, it sends my desktop an ICMP echo request (ping). If it receives a response, it knows that my desktop is already on, and ignores the power request. Only if it receives will trigger the power button.
Because I can't change the Arduino software remotely, most of the code runs on my laptop. The Arduino supports only a small set of low-level functions for communication. A typical exchange works as follows:
1. My laptop randomly picks number a, and then computes g^a mod p, where p (a prime) and g are randomly selected integers, known in advance by both my laptop and the Arduino. My laptop places the resulting 64-bit number in a single UDP packet. The packet also includes 8-bit sequence number (since UDP does not guarantee in-order delivery) and an 8-bit code that indicates a key-exchange request.
2. When the Arduino receives the packet, it first checks the 8-bit code and concludes that the packet is a key-exchange request. It then proceeds to pick a random number b, and computes g^b (mod p). It places the result in a response packet contains, which it sends back to my laptop. The response contains the same sequence number (so that my laptop knows which message the Arduino is responding to), and the same 8-bit key exchange code.
3. The Arduino now knows b (which it picked itself) and g^a (mod p) (which it received in the key request packet). It then computes (g^a)^b mod p. Similarly, my laptop knows a (which it picked itself) and g^b mod p (which it received from the Arduino). It then computes (g^b)^a (mod p). Each computation produces the same result, which serves as a secret key known by only the Arduino and my laptop. This is mechanism is called Diffie-Hellman key exchange.
4. After my laptop has computed the key, it needs to determine if my desktop is already on. To this end, my laptop sends a second packet to the Arduino, carrying a pre-determined message that indicates a status query. The first byte of this packet is a code which indicates that the packet contains an encrypted command. As with the key exchange, the second byte contains a sequence number. The final 8 bytes contain the pre-determined message, encrypted with the key. 5. When the Arduino receives the packet, it once again starts by investigating the first byte, which reveals that the packet contains an encrypted command. The Arduino then proceeds to decrypt the command with the key. Finally, by comparing to the pre-determined constants, the Arduino discovers that the command is a status request.
6. To determine if my desktop is on, the Arduino sends an ICMP ping. If, after four attempts, it does not receive a response, it assumes that my desktop is off. In each case, the Arduino sends a pre-determined random binary string as its response, also encrypted with the key. The first and second bytes contain, respectively, the 8-bit message code and the sequence number used by the incoming packet. The Arduino also invalidates the key, which will cause it to ignore any incoming commands until a new key is exchanged.
7. When my laptop receives the response, it decrypts with the key (which it has not yet invalidated itself). If the key indicates that my desktop is on, my laptop does nothing more. If my desktop is off, my laptop initiates a new key exchange.
8. After the new key exchange, my laptop sends another pre-determined message encrypted with the new key, indicating that the Arduino should trigger the power button. The Arduino responds by sending the power-on signal to the switch-control circuit. The power-on signal is a 6-bit code, written in parallel to 6 of the Arduino's digital output pins. The switch-control circuit uses two 74ALS138 3:8 decoders to select a single combination of these 6 pins as the switch-control signal. This is intended to prevent the Arduino from accidentally triggering the power switch after a software or hardware glitch.
9. After triggering the power switch, the Arduino responds with a pre-determined acknowledge message (encrypted with the key) and invalidates the key.
All normal exchanges between the Arduino and my laptop consist of a message sent to the Arduino containing a message code, sequence number, and message data, followed by a response from the Arduino to my laptop with the same message code and sequence number. To deal with packet loss, I use two additional pre-determined messages. First, if after a short timeout interval, my laptop has not received a response, it can send a special repeat-request packet. When the Arduino receives a repeat request packet (again indicated by the first byte) it retransmits the last packet it sent. If multiple copies of a packet are sent, my laptop uses the sequence numbers to eliminate duplicates.
If the Arduino is delayed (for example, while waiting for ping responses from my desktop), it can send a special wait message, again indicated by the first byte. If my laptop receives a wait message, it will reset its timer to zero, thus avoiding timeout.
If my desktop should ever crash while I'm logged on remotely, my laptop can also send a force shutdown message. My laptop will send this message regardless of whether my desktop is on or off. When the Arduino receives a force-shutdown message, it will press and hold the power button for 10 seconds. I do occasionally crash my computer while doing research (it's easy to do when you're dealing with 100,000 x 100,000 matrices), so this is a very useful feature.
The power switch control circuit uses a reed relay to short out the power switch pins on my motherboard. I installed a jack in the back of my case, which gives me access to the power pins from the outside. I tapped the wires from my case power switch, so that the front panel power button still functions.
For those interested, my software is available for download.
My ICMP Ping Library
The TrueRandom Library
Visual Studio 2008 Project
Windows Binary (32 and 64 bit versions included)
Note: The control program will create the registry key HKEY_CURRENT_USER\Software\Remote_Startup to store the IP address and port number. If you run the software but don't intend to use it in the future, you can use regedit to remove this key. The software will not make any other changes to your system.