概述

由Leslie Lamport教授于上世纪80年代发明,但是随着公钥加密技术、SSH等其他密码协议的普及,S/KEY已经逐步被废弃,取而代之的是双因素认证

S/KEY协议主要是用于身份认证,用于对类Unix操作系统进行身份验证,尤其是一些不受信任的公共计算机上,用户不希望在这些计算机上保存长期密码,因此用户的密码以一个临时字符串和递减计数器表示,以形成一次一密

S/KEY身份认证解决方案可以有效解决重放攻击,而且每个密码只用一次,对于密钥监听是无效的

由于临时字符串在递减计数器归零前不会改变,因此其可以按照顺序计算好并跟随用户携带,或者用户也可以将这个临时字符串和计数器用临时计算机计算,以生成一次性密码,并在网络上以明文形式传输给服务端,此时相当于一个挑战-响应机制

OpenSSH 1.2.2版以来,OpenSSH还实现了S/KEY,常见的实现称为OPIE

原理

协议步骤

S/KEY协议主要分为下列四个步骤


  1. 用户与服务端协商一个密钥$k$,这个密钥可以由服务端提供,也可以由用户提供,但是需要确保该密钥保密,如果密钥泄露,则意味S/KEY被攻破
  2. 用户与服务端协商使用的Hash函数$H$和计数器值$n$
  3. 用户按顺序计算$n-1$个Hash值$H_i(i=1,2,3,...,n-1)$,其中$H_1=H(k \ || \ 1)$,$H_2=H(H_1 \ || \ 2)$,...,$H_i=H(H_{i-1} \ || \ i)$,其中第$i$个Hash值为上一个Hash值$H_{i-1}$拼接上当前的计数器$i$,计算完毕后按逆序排列这$n-1$个Hash值并保存,也即用户保存$\{H_{n-1},H_{n-2},...,H_2,H_1\}$,同时删除初始密钥
  4. 服务端按照同样的方法计算Hash值,与用户不同的是,服务端需要计算$n$个Hash值,但是仅保存计数器值$n$和最后一个Hash值,也即服务端保存$(H_n,n)$,同时删除初始密钥,如下图所示


协议执行

用户有这么多的Hash值,每个Hash值都作为每一次登录使用的口令,具体的执行流程如下


  1. 用户从Hash值列表中取出第一个值$H_{n-1}$,将其作为口令$pw$,并连同自己的账号$un$发送给服务端
  2. 服务端收到用户的账号$un$,先到对应的文件中找到账号$un$对应的秘密值$(H_n,n)$,若计数器$n$为零,则拒绝用户登录
  3. 服务端根据用户发送的口令$pw$,计算$h=H(pw \ || \ n) $
  4. 比较$h$与保存的秘密值$H_{n}$,若两者相等,则验证通过,允许用户登录,同时用$pw$替换原来的$H_n$并将秘密值中的计数器减少1,也即用户登录成功时服务端保存$(pw,n-1)$,用户则删除Hash值列表的第一个值$H_{n-1}$
  5. 若两者不相等,验证不通过,终止连接
  6. 用户每次登录时都使用列表中的第一个Hash值,用完后则无法登录,需要重新和服务器协商

正确性

对于请求登陆的用户,服务端计算$h=H(pw \ || \ n) =H(H_{n-1} \ || \ n)=H_n$,若$pw=H_{n-1}$,则根据之前介绍的的协议原理,一定有$h==H_n$,从而验证通过,此时服务器保存$(pw,n-1)$,用户则删除$H_{n-1}$,也即实际上服务端保存的是$(H_{n-1},n-1)$,用户此时的第一个Hash值为$H_{n-2}$

对于下一次登陆的用户,其第一个Hash值为$H_{n-2}$,按照之前的流程,由于此时服务端保存的值为$(H_{n-1},n-1)$,根据协议原理,若发送的口令为$H_{n-2}$,则可以通过验证,此时用户删除$H_{n-2}$,服务端也更新秘密值为$(H_{n-2},n-2)$

重复上述步骤,直到用户密钥用完或服务端计数器降为0

具体的流程图如下

安全性

需要确保密钥安全,不能防止MITM