基于Java语言实现一次性动态口令算法
2021-05-10钟志贤包爱民申小琦
缪 蕊 ,钟志贤 ,刘 珺 ,包爱民 ,姜 维,申小琦
(1.昆明冶金高等专科学校网络管理与信息化部,云南 昆明 650033; 2.吉林省明日科技有限公司,吉林 长春 130000)
0 引 言
随着国家大力开展数字化经济,虚拟账号的数量呈指数上升,随之而来的就是与日俱增的数据安全问题。因为互联网有着极强的匿名性,所以服务商很难分辨当前进行远程操作的是客户本人还是冒名顶替的不法分子。为了保证电子商务交易安全和电子支付安全,服务商推出了多种身份验证方式。其中最常使用的是静态密码验证,用户通过输入用户名与密码进行身份认证,密码是静态的,可重复使用。但使用静态密码进行认证存在巨大风险,服务商为了维护这些密码以获得更高的安全性,需要耗费大量的人力、物力。用户会为了方便管理而使用弱密码或低强度密码(例如自己的电话号码、生日、楼栋号等)。这样的静态密码极易被盗用或破解。密码被盗用后,非法用户即可登录应用平台对用户数据进行肆意篡改,从而造成财产损失。
随着网络应用的复杂化、攻击手段的多样化,静态密码验证的安全缺陷也越来越明显,已经不再适用于安全性要求较高的网络应用系统。为了解决静态密码存在的缺陷,一次性动态口令的认证方式应运而生。但是,目前现有的一次性口令认证方案也并不十分完善,有的需要安装第三方插件,有的平台兼容性与可移植性较差,各种方案在执行性能和安全性能上还存在一定缺陷。设计更加完善的一次性口令认证方案,可以为更多的网络系统提供更加安全可靠的身份认证,保障用户在使用平台时的安全性、私密性。
本文将介绍基于Java语言的一次性动态口令算法,采用更加完善的认证,增强认证口令的随机性,做到真正的一次一密,并更加容易地部署到网络应用系统中。
1 动态口令的应用
在网络安全开展的早期,为了防止他人盗取数据,服务商提供“2套密码”服务:登录用一个密码,办理业务用另外一个密码。但很快这种方案也出现漏洞,不法分子只需同时捕捉到2套密码就可以非法窃取网络数据。之后服务商又推出了非常多的加密方案,银行作为金融机构,对于网络操作都十分敏感,所以银行对于身份验证的要求最为严格。
随着网络银行的业务开展,银行为了保证用户资金的安全性,要求用户在进行网络支付时,除了验证登录密码外,还要完成另一套验证操作。最早银行推出了口令卡业务,用户需到银行申请一个可刮擦、数字随机的二维矩阵卡,如图1所示。用户每次进行网络支付时,银行都会要求输入口令卡中指定行、列的数字,由此来验证用户真实身份。虽然口令卡用起来非常方便,但也存在着被盗取的安全隐患,并且口令卡上的密码数量有限,一旦用户刮完所有数字,就需要重新申请。
图1 工商银行口令卡Fig.1 ICBC password card
为了提高账户安全性,银行推出了网银盾业务,俗称U盾,如图2所示。这是一个写有固定加密程序的U盘,具有不可复制性,所以安全性极高。但U盾也存在一个缺陷,就是必须在已安装银行驱动程序的计算机上操作,对使用场景的要求极高。
所以U盾已成为网银加密的主要产品,但为了简化用户的操作过程,银行又推出了一次性动态口令令牌产品。这是一款小巧的自带电池、液晶屏的数码产品,通常液晶屏中会随机显示6个数字,这6个数字就是一次性动态口令,如图3所示。动态口令虽然是随机数字,但却和银行的服务器保持了一致性,用户在任意一台计算机上进行网络支付时,只需输入当前令牌显示的一次性口令就可以完成支付操作,这样就解除了使用场景的限制。
图2 建设银行一代网银U盾 图3 中国银行的动态口令令牌Fig.2 CCB generation I E-bank USBkey Fig.3 BOC dynamic password token
图4 QQ安全中心界面示意图Fig.4 QQ security center interface diagram
随着智能手机的普及,很多开发商将动态口令令牌由硬件产品转移到了智能手机软件上,这样极大地降低了推广成本。很多银行也将口令令牌功能转移到手机软件上,用户直接安装官方软件即可激活,无需再到柜台申请。除了银行以外,各大互联网公司也推出了各自的动态口令软件,例如图4所示的腾讯QQ安全中心软件。
2 一次性口令的原理
一次性口令也叫一次性密码(One Time Password,OTP)。OTP 的计算公式为:OTP(K,C) = Truncate[HMAC-SHA-1(K,C)],其中,K表示明文;C是加密算法对明文进行签名的秘钥;HMAC-SHA-1是从 SHA1 哈希函数构造的一种键控哈希算法加密算法,可以根据任意字符串生成一个160 位的哈希值;Truncate 是截取加密结果的方法。一次性口令的特点是用户可以根据服务商提供的动态口令程序生成的数字来输入动态口令,而且每个登录服务器的口令均只能使用一次,这样可使窃听者或黑客无法通过窃听和破解口令来伪造登录。同时利用单向散列函数的不可逆性,防止密码被窃听或破解后进行二次登录。
2.1 HOTP 基本原理
HOTP 的全称是HMAC-based One-Time Password,表示根据某一特定的事件及相同的种子值作为参数,通过哈希算法运算出一致的密码。
HOTP的计算公式为HOTP(K,C) = Truncate[HMAC-SHA-1(K,C)],其中,C是一个与事件同步的随机值,在HOTP的基础之上,将当前时间作为参数C,就发展出了TOTP算法。
2.2 TOTP 基本原理
TOTP的全称是Time-based One-time Password ,原理同HOTP一致,只是将其中的参数C变成了时间,计算公式为:TOTP(K,C) = Truncate[HMAC-SHA-1(K,C)]。
在Java语言中,时间戳可以采用System.currentTimeMillis()方法返回的当前时间毫秒数,这是一个long类型整数,每一次调用都会基于时间的不同而得到不同的数值。
公式中的K参数可以采用“用户唯一标志 + token”的方式拼接。用户的唯一标志可以是用户的身份证号、电话号、邮箱等,也可以是服务端提供用户的认证证书,例如电子证书号码、用户ID等。明文在加密之前要在末尾拼接token参数,这样可以极大地增加破译难度。token即盐值,其本身是一个无序、无语义的字符串,服务端和客户端每隔一段时间就更换并同步token参数,这样可以极大提高一次性口令的安全性。
获得6位一次性动态口令需要进行以下计算过程:
1)将K参数和C参数进行HmacSHA1加密,得到加密后的字节数组;
2)取出字节码数组的后4个字节;
3)为了加大加密算法的复杂度,翻转取出的4个字节的顺序;
4)按照翻转之后的顺序,将4个字节拼接成1个32位的整数;
5)截取此32位整数的最后6位数字,这6位数字就是算法生成的一次性动态口令。其计算过程如图5所示。
图5 计算动态口令的过程Fig.5 Dynamic password calculation process
3 Java代码的实现
3.1 运行环境
使用Java代码开发一次性动态口令算法,首先要实现HmacSHA1加密算法。JDK的javax.crypto包已提供了该算法的API。用Java编写的程序不但简洁、代码少,而且可读性较强。Java与平台无关,可移植性强,并自带丰富的网络类库,功能强大。基于以上原因,项目中选择采用Java来实现动态口令身份认证。
3.2 系统设计
本方案应用于学校智慧教室控制系统的教师身份认证,通过认证后,教师登录移动智能终端,并获得智慧教室设备的控制权限。
为方便教师使用,设计遵循以下原则:1)不需要在智慧教室控制端安装其它第三方组件,直接嵌入算法即可;2)可移植性高,兼容多种移动端设备;3)提供双向认证。
图6 基于时间同步身份认证原理图Fig.6 Identity authentication diagram based on the time synchronization
基于以上原则,本方案选择采用基于时间同步的身份认证。该技术的核心算法是单项散列函数,函数的输入参数是由“证书+盐值”拼接出的加密明文和当前时间的毫秒数(客户端和服务器需要校准为统一的时间),输出参数是长度固定的散列值。该散列值就可以作为用户身份的安全凭证。原理如图6所示。
该技术的核心算法是encrypt()方法,该方法的2个参数分别为由“证书+盐值”拼接出的加密明文和当前时间的毫秒数(客户端和服务器需要校准为统一的时间),返回值为经过HmacSHA1算法加密后得到的1个32位整数(可能是负数)。HmacSHA1是从SHA1哈希函数构造的一种键控哈希算法,很难找到逆向规律,所以加密安全性极高。前、后端在同一时间计算出的口令具有一致性,可以根据此口令作为用户的身份认证标志,前、后端的计算过程如图7所示。
图7 使用动态口令进行身份认证顺序Fig.7 Sequence diagram using the dynamic password for identity authentication
核心代码如下:
private static int encrypt(String encryptText, String encryptKey) {
try {
byte[] data = encryptKey.getBytes("UTF-8");
// 根据给定的字节数组构造一个密钥,第二参数指定一个密钥算法的名称
SecretKeysecretKey = new SecretKeySpec(data, "HmacSHA1");
Mac mac = Mac.getInstance("HmacSHA1");
mac.init(secretKey);// 密钥初始化
// 完成加密
byte ciphertext[] = mac.doFinal(encryptText.getBytes("UTF-8"));
int num = 0;// 待拼接数字
for (int i = 0; i< 4; i++) {// 取4个字节
// 将数组后4个字节顺序翻转并拼接成一个32位数字
num += ciphertext[ciphertext.length - 1 - i] << 8 * (3 - i);
}
return num;
} catch (InvalidKeyException e) {
e.printStackTrace();
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
}
return -1;
}
3.3 测 试
编写Test测试类,设定一个证书和一个token,获取当前毫秒数,将更新时间设定为 3 s,将拼接好的明文和时间进行加密,每隔 1 s 输出一次口令,查看运行结果,完整代码如下:
public class Test {
public static void main(String[] args) {
String certificate = "8898763578363844";// 证书或公钥
String token = "UWzwth6I";// 加密参数
String key = certificate + token;// 拼接加密内容
new Thread() {
public void run() {
while (true) {
try {
// 当前时间毫秒数
long time = System.currentTimeMillis();
// 打印随机口令,3 s更新
System.out.println(JTOTP.getPassword(key, time, 3));
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
};
}.start();
}
}
运行结果如下:
352081
352081
012760
012760
012760
192007
192007
192007
854810
854810
854810
经测试,即使代码在两台计算机上运行,只要计算机本地时间一致,就会得到同步的结果。如果修改了用户证书或token,动态口令就会立即改变。
4 结 语
本套代码可以直接用于基于Java语言开发的Android系统程序,在用户证书、token和本地时间一致的条件下,移动端得到的动态口令与服务器一致,运行速率快,可移植性高,能够满足智慧教室控制系统对教师身份认证的要求。