同态加密登陆

在服务器日常登录过程中,一般是前端传输账号和密码到服务器,然后服务器对账号密码进行校验。但在这个过程中有两个问题,假设传输过程中信息被截获(或者打印日志然后日志泄漏等操作),可能导致密码泄漏。如果服务器数据泄漏,也会导致密码泄漏。一般来说我们服务器中存储的是密码的sha256,这样可以解决服务器数据泄漏的问题,但是传输过程中的问题没有解决(前端hash再传输是无效的,因为这样做hash后的值等效于密码)。我们希望提出一种方案,同时满足传输过程中信息任意泄漏,服务器数据任意泄漏,也可以保证密码的安全。

想法来源:

同态加密允许加密一个值,并使用加密后的值进行运算。实现同态加密有多种方式,这里简单介绍一个简要例子

选择一个自然数作为基数(这个基数需要具备一些特定的属性),将基数记为g,用 g去加密一个值,即g为底数,需要加密的值为指数。比如,我们要加密一个数值 3,取 g为 5:

$$ 5^3=125 $$

125是 3 加密过后的值,如果我们把需要加密的值E(3)乘2,我们就可以给加密后的值(125)提高两个阶数,

$$ 125^2=15265=(5^3)^2=5^{2*3}=5^6 $$

同样,我们可以通过除法来使加密值相减,例如 5−3:

$$ {5^5}/{5^3}=5^{5-3}=5^2=25 $$

我们可以看出,同态加密可以实现加、减、乘操作

$m为素数,g是m的原根之一,m数量级约 2^{256},令 h(x) = {g^{x}}\bmod{m},定义 h(x)*h(y) = g^{x\ast y}\bmod{m}$

在登录的时候,前端需要使用两个信息,1是密码本身,2是一些现场信息,比如当前时间戳、设备信息、当前浏览器、想要登录的服务器id、后端给的保证登录不可复用token等,我们称这部分信息为前端info。后端生成数据的时候需要一个salt,这个数据可以是一个保密的随机数。

简单来说,我们需要使用三个数据。令sm=密码的sha256,sf=前端info的sha256,ss=后端salt的sha256,

当用户注册的时候,后端拿到sm和ss,计算出 $hsmss=h(sm)*h(ss)=g^{sm\ast{ss}}\bmod{m}$存入数据库,同时丢弃sm。此时后端能拿到的数据有:ss、g、m、hsmss。

当用户想要登录时,前端有sm和sf,计算出$hsmsf=h(sm)*h(sf)=g^{sm\ast{sf}}\bmod{m}$。把hsmsf和sf传入后端(实际上应该传sf的原文,因为后端需要校验时间戳等,这里为了简化使用sf)

此时后端已知hsmss、sf、hsmsf、ss,可以校验

$$ hsmss^{sf} == hsmsf^{ss}(\bmod{m}) => g^{(sm\ast ss)\ast sf}==g^{(sm\ast sf)\ast ss}(\bmod{m}) $$

如果相等则密码正确,否则密码错误。

我们可以验证这个方案是否满足需求,假设我们在多机部署,其中一台机器后端数据库泄漏,同时某用户在登录过程中传输的所有信息也泄漏了(例如登录信息打印在日志上,日志泄漏了),此时攻击者是否可以用这些信息登录别的服务器。

为了简化问题,我们列出攻击者实际可以拿到的数据:g、m、ss、hsmss、hsmsf1、sf1(攻击者需要再次登录,被截获的登录的sf为sf1,攻击者登录为sf2)。攻击者需要做的是在不知道sm的情况下,构造出hsmsf2。

$hsmsf2=(g^{sm})^{sf2}\bmod{m}或(g^{sf2})^{sm}\bmod{m}$ 所以攻击者需要计算出$g^{sm}\bmod{m}或sm\bmod{m}$

而 $hsmss=(g^{sm})^{ss}\bmod{m}$

我们可以将问题再次简化

$m为素数,g是m的原根之一。h=g^{a * b}\bmod{m},t=g^{a * c}\mod{m},(a,b,c,g,m数量级都是2^{256})$

问在已知h,b,c,g,m的情况下,是否存在非枚举的方法可以求出t.

走到这步我们很高兴的可以说这个问题是不存在有限时间内的解的,因为证明密码的强度一般是将问题转化成公认的已知困难问题,比如离散对数问题,而这个问题本身就是离散对数问题。

离散对数问题:https://zhuanlan.zhihu.com/p/523658036

代码实现思路参考:

这个库已经提供了m和g的值,以及大整数运算,稍加修改即可

直接贴个m和g:

1
2
3
21888242871839275222246405745257275088548364400416034343698204186575808495617

7