In this tutorial we're going to explore the security of computer screen lock. Operating systems have a configurable timeout that will lock your screen if the user haven't touched the mouse or keyboard.
Usually the default is around one minute. If you follow this default and leave your computer in a busy environment someone might access your computer in that minute until the screen locks. If you set it to a few seconds you'll get the lock screen very often when you're not touching the keyboard and that's annoying...
One day a work colleague asked me if I can "fix" this issue by some kind of device that locks the computer when he's not there, and I took the challenge :)
I've explored several options in my head like using arduinos and an infrared thermometer sensor, PIR sensor or maybe using face detection on the computer, but i've settled to a simpler method:
We're going to combine Arduino Leonardo HID functionality (emulate keyboard) with an ultrasonic distance sensor to detect if a person is using the computer, if not the device will send a key combination through USB to lock the computer.
If you like this project, you can check out more like this on: GitHub and YouTube.
Step 1: ComponentsBecause this is a proof of concept we're going to build the device on a breadboard
You'll need:
1. Arduino Leonardo (it's important to use Leonardo because it can emulate keyboard)
2. HC-SR04 ultrasonic distance sensor
3. 2 x 10 K variable resistors
4. Breadboard, breadboard wires
5. USB cable
6. OLED display (https://www.adafruit.com/product/931)
Step 2: Assembly & UploadFirst check if you have all the needed components and an Arduino IDE. I'm going to briefly go to the connection steps, and you can always take a look on the attached fritzing schematic
Assembly
1. Put the Leonardo on the breadboard and hold it in place with a rubber band
2. Put the two variable resistors, the OLED display and the ultrasonic sensor on the breadboard
3. Connect grounds and vcc's
4. Connect the middle pins of the resistors to the arduino A0 and A1
5. Connect the SDA and SCL of the display to the SDA and SCL marked on the Leonardo
6. Connect the trigger and echo pin of the ultrasonic sensor to the 12, 13 digital pins of the Leonardo
7. Connect the USB to the computer
Upload
First of all you'll need to download and install the necessary arduino libraries:
1. GOFi2cOLED library: https://github.com/hramrach/GOFi2cOLED
2. Ultrasonic-HC-SR04 library: https://github.com/JRodrigoTech/Ultrasonic-HC-SR04
If you don't know how to install arduino libraries check out this tutorial.
After you have downloaded and installed the libraries above, you can clone or download my arduino repository located here: https://github.com/danionescu0/arduino, and we'll use this sketch: https://github.com/danionescu0/arduino/tree/master...
Or you can copy and paste the code below:
/*
* Libraries used by this project:
*
* GOFi2cOLED: https://github.com/hramrach/GOFi2cOLED
* Ultrasonic-HC-SR04: https://github.com/JRodrigoTech/Ultrasonic-HC-SR04
*/
#include "Keyboard.h"
#include "Wire.h"
#include "GOFi2cOLED.h"
#include "Ultrasonic.h"
GOFi2cOLED GOFoled;
Ultrasonic ultrasonic(12,13);
const byte distancePot = A0;
const byte timerPot = A1;
const float percentMaxDistanceChangedAllowed = 25;
int actualDistance;
unsigned long maxDistanceDetectionTime;
bool lockTimerStarted = false;
void setup()
{
Serial.begin(9600);
Keyboard.begin();
initializeDisplay();
}
void loop()
{
clearDisplay();
actualDistance = getActualDistance();
writeStatusData();
doDisplay();
if (!lockTimerStarted && shouldEnableLockTimer()) {
lockTimerStarted = true;
maxDistanceDetectionTime = millis();
Serial.println("lock timer begin");
} else if (!shouldEnableLockTimer()){
Serial.println("lock timer disabled");
lockTimerStarted = false;
}
if (shouldLockScreen()) {
lockScreen();
Serial.println("Lock screen");
}
delay(100);
}
bool shouldLockScreen()
{
return lockTimerStarted && (millis() - maxDistanceDetectionTime) / 1000 > getTimer();
}
bool shouldEnableLockTimer()
{
int allowedDistance = percentMaxDistanceChangedAllowed / 100 * getDistance();
return getTimer() > 1 && getDistance() > 1 && actualDistance - getDistance() > allowedDistance;
}
void writeStatusData()
{
setDisplayText(1, "MinDistance:", String(getDistance()));
setDisplayText(1, "Timer:", String(getTimer()));
setDisplayText(1, "ActualDistance:", String(actualDistance));
int countDown = getTimer() - (millis() - maxDistanceDetectionTime) / 1000;
String message = "";
if (shouldLockScreen()) {
message = "lock sent";
} else if (shouldEnableLockTimer() && countDown >= 0) {
message = ".." + String(countDown);
} else {
message = "no";
}
setDisplayText(1, "Locking: ", message);
}
void initializeDisplay()
{
GOFoled.init(0x3C);
GOFoled.clearDisplay();
GOFoled.setCursor(0, 0);
}
void setDisplayText(byte fontSize, String label, String data)
{
GOFoled.setTextSize(fontSize);
GOFoled.println(label + ":" + data);
}
void doDisplay()
{
GOFoled.display();
}
void clearDisplay()
{
GOFoled.clearDisplay();
GOFoled.setCursor(0, 0);
}
int getActualDistance()
{
int distanceSum = 0;
for (byte i=0;i<10;i++) {
distanceSum += ultrasonic.Ranging(CM);
}
return distanceSum / 10;
}
int getDistance()
{
return map(analogRead(timerPot), 0, 1024, 0, 200);
}
int getTimer()
{
return map(analogRead(distancePot), 0, 1024, 0, 20);
}
void lockScreen()
{
Serial.println("pressing");
Keyboard.press(KEY_LEFT_CTRL);
delay(10);
Keyboard.press(KEY_LEFT_ALT);
delay(10);
Keyboard.write('l');
delay(10);
Keyboard.releaseAll();
}
Finally connect the arduino the computer using the usb cable, and upload the sketch into the arduino.
Step 3: Using the DeviceWhen the arduino is connected to the computer it will continuously monitor the distance in front of the sensor and send a "lock" screen key combination to the computer if the distance increases.
The device has some configurations:
1. Normal distance, the distance can be configured using the variable resistor connected to the A0. The distance is also displayed on the OLED. When the distance will increase with 25% from the one that is set a countdown will begin
2. Timeout (countdown). The timeout in seconds is also configurable from the resistor connected to the A1. When the timeout expires the lock command will be sent
3. Lock key combination. The default lock key combination is set up to work for Ubuntu Linux 18 (CTRL+ALT+L). To change the combination you need to modify your sketch according to your operation system:
4. Timeout and distance protection. Because this is a device that emulates the keyboard it's a good idea to have a mechanism of deactivating the keyboard functionality. In my sketch i've chosen that the timeout and distance must be greater then "1". (you can modify that in the code if you like)
Locate and change the "lockScreen()" function
void lockScreen()
{
Serial.println("pressing");
Keyboard.press(KEY_LEFT_CTRL);
delay(10);
Keyboard.press(KEY_LEFT_ALT);
delay(10);
Keyboard.write('l');
delay(10);
Keyboard.releaseAll();
}
For a full list of arduino special keys, check here: https://www.arduino.cc/en/Reference/KeyboardModifi...
Step 4: Other ApproachesBefore this implementation i've considered some other implementations too:
1. Infrared thermometer (MLX90614 https://www.sparkfun.com/products/10740). An infrared thermometer is a device that measures temperature by analyzing infrared radiations emitted by an object at a distance. I had one lying around and I thought maybe I can detect the difference in temperature in front of the computer.
I've hooked it up, but the temperature difference was very small (when I was in front or not) 1-2 degrees and I thought it couldn't be so reliable
2. PIR sensor. (https://www.sparkfun.com/products/13285) This cheap sensors are marketed as "motion sensors" but they really detect changes in infrared radiation so in theory it could work, when a person leaves the computer the sensor would detect that.. Also these sensors have a build in timeout and sensitivity knobs. So i've hooked one up and played with it but it seems that the sensor it's not made for a close range (it has a wide angle), it gave all kinds of false alerts.
3. Face detection using the webcam. This option seemed very interesting, as I played with this computer field in my other projects like: https://github.com/danionescu0/robot-camera-platfo... and https://github.com/danionescu0/image-processing-pr...
This was piece of cake! But there were some drawbacks: the laptop camera couldn't be used for other purposes when the program was running, and some computer resources would be required for that. So i've dropped this idea too.
If you have more ideas about how this could be done please share them, thanks!
Comments