再也不用输入密码了(持续的传奇)
制作这个由Arduino驱动的设备,它集成了触摸屏和蓝牙,您将再也不必输入密码。
引言
这是我的展示文章,希望您喜欢并从中获得信息。
首先,我知道我的极端标题(永不输入密码)让很多人觉得夸张。但这就是它的乐趣所在。
而且,它真的不仅仅是夸张。一点也不。如果您真的制作了这个设备,您确实再也不必输入密码了。您也不必再记忆密码或凭空编造密码。稍后会详述。
首先,成品设备的照片
首先,让我向您展示我正在使用的Arduino驱动设备,这样我就再也不必输入密码了。
我知道!它很漂亮,不是吗?所有那些美妙的电线!(仅数据线就有8根。呼……)形式遵循功能,您知道的,这个东西确实效果很好。它确实解决了我的问题。
它做什么?
- 它将通过蓝牙接收您的密码,并将其输入到您的计算机中(用于解锁屏幕或登录)。
- 它允许您输入设置的PIN码,然后它将您的密码输入到您的计算机中(用于解锁屏幕或登录)。
- 由于该设备被计算机简单地视为一个键盘,因此无需在计算机上安装任何驱动程序。这太神奇了。这也意味着您可以在Linux、Mac或Windows上使用它,而无需进行任何更改。只需将其插入USB端口即可。
在YouTube上观看它的实际演示
我创建了两个YouTube视频来展示该设备如何解锁我的计算机。
- 观看它通过蓝牙解锁我的计算机:https://youtu.be/5kqBRNTcLLg(在新标签页中打开)
- 观看它在我输入PIN码后解锁我的计算机:https://youtu.be/kkcDFU1JiLI(新标签页)
解决CTRL-ALT-DEL以显示登录
我甚至解决了计算机处于“屏幕保护程序”状态的挑战,此时尚未显示登录文本框。该设备可以将**CTRL-ALT-DEL**发送到您的系统以显示登录。如果您使用的是蓝牙,那么在您走到计算机旁时就可以解锁您的计算机。
我讨厌密码:我相信您也一样
这一切的开始是因为我讨厌密码。我真的讨厌。我讨厌记住它们。我讨厌编造它们。我讨厌在小设备(手机等)上只用拇指输入它们。如果我可以告诉您我和我妻子就某个银行账户的密码争论过多少次(“……不要再输错了,否则我们会被锁定的!!!”),您就会真正理解了。
有一天,我注意到您可以对任何数据进行哈希处理。我在这里CP上写了一篇关于它的文章(销毁所有密码:再也不用记住密码[^]),该文章在一周内获得了超过250,000次观看(现在超过374K次)。哇!这是因为每个人都讨厌密码。但并非所有人都相信我的方法。没关系。我只是喜欢解决问题的方法让我思考一些有趣的想法。
必须在所有平台上可用
那时我决定为自己创建这个东西。没有比创建可用的原型并开始使用它更好的方法来测试一个想法了。但是,如果我要说服其他人使用它,那么**它必须在所有平台上可用**(Android、Windows、iOS、Web)。这花了我一段时间,但我做到了,并将其写成了一篇文章,并通过Github(和CP)将所有代码开源了。请参阅用户讨厌密码(我们都是用户):再也不用记住密码[^],这样您就可以获得Android、iOS、Web和/或WinForm代码。
我每天都使用它,但有一件事需要解决
我每天都使用它,而且一天多次。一旦您使用它,您就会想为什么以前要输入密码。但是,有一件事有点烦人。
如果我没有携带手机或其他运行C'YaPass的设备,我就无法解锁我的计算机(因为密码长达64个字符,我记不住)。
需要解决的烦人问题
如果我有手机,我只需运行Android C'YaPass,生成密码并通过蓝牙发送,我的计算机就会解锁。但这有点麻烦。当我坐到电脑前时,我不想掏出手机和所有那些繁琐的步骤*(WOTD)。
*冗长而复杂的程序
Arduino解决方案的梦想
由于我已经有了这个Arduino设备,它可以(通过蓝牙)为我输入密码,我知道我应该能够简单地添加一个数字键盘之类的东西,它允许我输入一个4或5位数的PIN码,然后设备会为我输入我的长密码,我的计算机就会解锁。
但是,我该怎么做呢?
我知道我可以添加一个数字键盘,但我想要更炫的东西,而且我想尝试使用触摸屏。我开始四处查看,发现您可以花大约16美元购买一个TFT 320x240触摸屏。
工作原理摘要
如果您观看了YouTube视频(上方),您就知道它基本上是如何工作的,但我还创建了一个图形概述,应该能让您快速了解我的设备的作用。
保存按钮:您需要一种方法将密码保存到设备中,以便它可以为您输入。我选择使用Arduino的EEPROM(电擦除可编程只读存储器)。一旦您保存了密码,当您输入正确的PIN码时,Arduino就会将该密码输入到您计算机的登录框中。
发送按钮:当您输入了有效的PIN码后,按下此按钮,Arduino将检查其是否有效,然后将之前存储在EEPROM中的密码输入到登录框中。
PIN码按钮:PIN码按钮允许您随时更改PIN码。当然,第一次使用C'YaPass键盘时,您需要设置值。按下按钮,输入您的4位PIN码,即可开始使用。
CAD按钮:CAD按钮会将**CTRL-ALT-DEL**序列发送到您的计算机,以显示登录文本框,或者如果您已经登录,它将锁定您的计算机。
组件列表
您需要四样主要的东西来构建和运行此项目
- Arduino Pro Micro - SparkFun的原始Pro Micro售价20美元,但您可以从Gikfun购买一个仅售7.98美元的克隆品(https://amzn.to/2Ki4kqr)。或者,您可以一次购买几个,价格会更便宜(购买5个@6美元/个https://amzn.to/2Im66VK)。
- 320x240 TFT **触摸屏**(https://amzn.to/2tpPKXp)- 一个非常好的触摸屏,并且得到了制造商的良好支持。
- HC-05蓝牙模块(https://amzn.to/2lAbuf3)
- USB电缆 - USB 2.0 A公头到Micro B(https://amzn.to/2tA48eX)- 因此您可以将C'YaPass键盘连接到计算机。设备的所有电源都来自您的USB端口。
如果您想制作像我一样的原型,您还需要
- 连接线 - 我买了这套非常漂亮的实心芯连接线,非常适合爱好制作:(https://amzn.to/2Ki9y5i)
- 面包板 - 我购买了多套这样的(https://amzn.to/2Kf4tdX)
现在,让我们谈谈我在开发此项目时发现的一些有趣的事情。
为什么使用Arduino Pro Micro?
我们使用的是Pro Micro板而不是Arduino Nano,因为Pro Micro(又名Leonardo)使用不同的ATmega微控制器:32u4,而不是ATmega328P(Nano、Uno和其他许多板子使用的)。
32u4有什么特别之处?
32u4支持Arduino IDE提供的键盘和鼠标库,并且硬件支持HID(人类接口设备)标准,因此当您将其连接到计算机时,计算机将立即将其识别为键盘和/或鼠标。这就是为什么让这个Arduino为您在计算机上输入如此容易的原因。
Arduino为您输入
这是按下屏幕上的[CAD]按钮时运行的代码。
if (b == 14){
Keyboard.press(KEY_LEFT_CTRL);
Keyboard.press(KEY_LEFT_ALT);
Keyboard.write(KEY_DELETE);
Keyboard.release(KEY_LEFT_ALT);
Keyboard.release(KEY_LEFT_CTRL);
Keyboard.write(KEY_RETURN);
}
b
变量简单地保存了按下的屏幕按钮的整数值。
Keyboard.press()
、Keyboard.release()
和Keyboard.write()
方法都由Keyboard.h库提供,该库与32u4微控制器协同工作。
press()
方法被计算机识别为就像在真实键盘上按下按键一样。像这样使用press()
和release()
允许我们模拟按下和释放所有三个按键(**ctrl-alt-del**),然后write()
方法发送一个<ENTER>
(也称为回车)。
想象一下,您现在可以用它做多少事情!使用32u4微控制器非常容易。
触摸屏代码
现在,触摸屏代码非常直接。它由Elegoo(TFT触摸屏制造商)在其很棒的网站上提供。他们提供了一个不错的基本Arduino程序,可以处理按钮的绘制和按钮按下时的事件。
我采用了该代码并根据我的需求进行了修改。我还将代码分解为函数,以处理可重复的代码。如果您将本文的下载内容与Elegoo的代码^进行比较,您会发现我做了很多更改。
屏幕保护程序:我不确定TFT屏幕图像烧伤
如果您知道Arduino Sketch的设置方式,您会记得它们基本上会无限循环执行loop()
方法。
如果loop()
结束,那么Arduino程序也就结束了。这类似于旧的Windows SDK消息循环^,您的程序中的所有内容都在其中发生。
好的,在那个loop()
中是绘制屏幕上的按钮和文本框的代码。然而,我想让屏幕在不使用时显示为空白。我认为这可以防止按钮图像烧坏屏幕(如果这是必需的,我不确定),而且我认为这样您就不必一直看到那个东西亮着。
我添加了一些代码,用于检查屏幕上次触摸是否已超过10秒,如果超过了,它将用黑色方框填充屏幕。但是,如果屏幕是黑色的,并且您触摸了它,那么屏幕应该为您绘制按钮。
if ((millis() - lastTimeTouched) > 10000){
if (!needsRefresh){
tft.fillScreen(BLACK);
// main screen only needs redraw if the screen save has enabled
needsRefresh=true;
}
}
else{
if (needsRefresh){
DrawMainScreen();
needsRefresh=false;
// set the touched point to 0,0 so no button will be mapped
// since we do not want a button press when the screen had been blank
p.x = 0;
p.y = 0;
}
}
millis()
方法是一个Arduino库方法,它返回Arduino程序启动以来的毫秒数(unsigned int
)。我只需在用户触摸屏幕时更新lastTimeTouched
(unsigned int
)。每当用户触摸屏幕超过10秒时,我就会调用tft
库方法fillScreen()
并用预定义的黑色值填充它。
我修复的一个bug
起初,代码会在每次循环时用黑色填充屏幕,因为我没有设置一个标志来表示它已经被填充过了。这使得触摸屏对新触摸的响应非常慢,无法再次绘制带有按钮的主屏幕,因此我添加了标志,现在它非常灵敏。
PIN码:存储在EEProm中
接下来我做的有趣的事情是允许用户创建自己的PIN码并将其存储在EEPROM中。提供的库很容易读写EEPROM。但是,您必须自己管理内存,这意味着决定要写入哪个地址以及要写入多少字节。
暂时为4位PIN
目前,我只做一个4位PIN。我将此4位PIN存储在EEPROM地址0(零)处。
哦,对了,EEPROM内存大约可以写入10,000次,所以非常适合这类事情。即使我们每天更改一次PIN码,我们也可以使用27年。此外,EEPROM的量有限,但有1024字节,这对我们来说绰绰有余。4位PIN码只需要4个字节。稍后您将看到我们还存储了您希望CYaPassKeyPad
输入的密码到登录文本框,但那也只有64个字节(用于64个字符的密码)。
我只做一个4位PIN,并且我还没有(尚未)强制您验证旧PIN来更改为新PIN。我将尽快实现该代码并在完成时发布。
现在,当您单击**[PIN#]**按钮时,程序将读取您在键盘上输入的接下来的4位数字,并在顶部文本框中显示它们,然后将它们保存到字节数组中。当您输入第4位数字时,程序将自动清除文本框,并将数字写入EEPROM,从地址0开始。
这是处理数字按钮的代码。
if ((b >= 3) && (b < 14) && (b != 12)) {
if (textfield_i < TEXT_LEN) {
textfield[textfield_i] = buttonlabels[b][0];
textfield_i++;
textfield[textfield_i] = 0; // zero terminate
if (isPinChanging){
if (textfield_i-1 < 4){
pinValue[textfield_i-1] = buttonlabels[b][0];
}
if (textfield_i >= 4){
isPinDone = true;
writePinToEEProm();
ClearTextField();
}
}
}
}
当您按下**[PIN#]**按钮时,isPinChanging
标志被设置为true
。这意味着在loop()
中的每次迭代中,当用户按下数字按钮时,该值将被保存在pinValue
字节数组中,以便我们可以将其写入EEPROM。当用户按下第4位数字时,将运行以下代码将数据保存到EEPROM。
void writePinToEEProm(){
if (isPinDone){
for (int i = 0;i < 4;i++){
EEPROM.write(i, pinValue[i]);
}
isPinDone = false;
}
isPinChanging = false;
}
我只需迭代从0到3的EEPRom地址,并为每个地址写入一个字节(数字键盘值)。
验证用户输入的正确PIN码
一旦PIN码设置好,之后当用户尝试使用PIN码解锁计算机时,程序将从EEPRom读取字节并与最终值进行比较,以确保PIN码正确。
以下方法获取用户在按下**[发送]**按钮之前输入的PIN码,然后读取EEPROM以确定它是否匹配,并向调用者返回一个布尔值,以告知它是否应该为用户输入密码并解锁计算机。
bool verifyPinValue(String pinAttempt){
String pin = "";
for (int i = 0; i<4;i++){
byte value = EEPROM.read(i);
pin+= (char)value;
}
if (pin == pinAttempt){
return true;
}
else{
return false;
}
}
您可以看到我再次使用EEPROM.read()
来迭代前4个字节。该值与用户的输入进行比较,并返回布尔值。
再一点:EEProm再次解决了问题
最后,在使用CYaPass键盘之前还需要完成另一件事。用户的密码也必须存储在EEPRom中,这样当用户输入正确的PIN码时,设备就可以将密码输入到Windows屏幕的登录框中。
现在,我需要允许用户将其密码存储在EEPRom中。首先,请注意存储在EEPRom中的此值将以明文形式存储,但目前我并不担心,因为这是一个物理设备。
我们必须考虑密码长度
由于您的密码可能长度不同,并且我们必须将字节数写入EEPROM,然后稍后将其读出,因此我们还必须将密码长度写入EEPROM。我们必须这样做,因为当我们检索密码时,我们需要知道何时停止从EEPROM读取字节。EEPROM内存可以初始化为任何值,因此无法知道内存中的内容是否是您想要的值。
我设置了两个#DEFINED
值
#define PASSWORD_LENGTH 100 // writing password size as a byte at RAM address 100
#define PASSWORD_BEGIN 101 // writing password as bytes begin at address 101
这样我就可以清晰地引用写入密码长度(地址100)和密码第一个字节写入EEProm的地址。
这样,稍后,如果您的密码有17个字符,我就会读取存储在地址100的值,然后知道我需要从地址101开始读取,然后仅读取第一个字节之后的接下来的16个字节。
这有点棘手,因为您必须自己完成所有工作,但我将其放入了一个易于调用的好函数中。
String readPwdFromEEProm(){
byte pwdLength = EEPROM.read(PASSWORD_LENGTH);
String pwd = "";
for (byte i = 0; i<pwdLength;i++){
pwd += (char)EEPROM.read(PASSWORD_BEGIN + i);
}
return pwd;
}
如何存储密码?
现在,我已经使其工作,您只需执行以下操作即可将密码存储在EEPROM中。
- 按下CYaPass键盘上的**[保存]**按钮。此时,程序正在等待来自蓝牙设备的数据输入。
- 运行Android CYaPass应用程序(与CYaPass键盘配对)并按应用程序中的发送按钮。
- CYaPass键盘将接收字节,并将其存储在EEPROM内存中。
- 它会在键盘上显示一个小的输出语句,说“Got Serial”。
- 再次按下**[保存]**按钮,表示您不再向设备发送要保存在EEPROM中的数据。
再一点
实际上还有另一种方法可以存储您想要的任何密码(而不是CYaPass应用程序生成的密码——尽管您仍然需要CYaPass Android应用程序)。
您只需在Android手机上输入密码,然后选择它并复制到剪贴板即可。
完成后,切换到CYaPass应用程序并按[发送]按钮(带向上箭头的圆圈)。执行此操作时,CYaPass会将剪贴板上的任何内容通过蓝牙发送。这将将其写入CYaPass键盘。
输入密码的终结?
您可能不认为这是输入密码的终结,但希望您同意这是朝着正确方向迈出的一步。我每天都在我的台式机上使用它,而且非常喜欢。
但是,希望您能看到,这篇文章不仅仅是关于销毁密码(尽管我确实想销毁所有密码)。它关于思考如何利用这些强大、小巧、廉价且功耗低的Arduino设备来做一些新事情。
也许您在这里看到的东西会激发您的想象力,并为您提供建造下一个伟大事物的动力。
继续学习,继续建造。
接线图
我忘记添加接线图了。它看起来有点复杂,但实际上很简单。只需按照下图进行连接,然后通过USB端口供电即可。
历史
- 2018-06-24:首次发布