Diffie-Hellman密钥交换与Elgamal公钥加密算法

Diffie-Hellman密钥交换

Diffie-Hellman的有效性是建立在计算离散对数很困难的这一基础上的。

算法:

第一步,选定一个素数q和它的原根a,并公开。

第二步,用户A和用户B分别选定私钥X_AX_B(X_A,X_B< q),并用公布的q和a分别计算

 \\Y_A = a^{X_A}mod\ q\\ Y_B = a^{X_B} mod\ q\\

Y_AY_B作为A和B的公钥向对方公开。

第三步,A和B通过对方公开的公钥Y分别通过下式计算得出K,K便成了双方约定的密钥。

对A:

       K=Y_B^{X_A} mod\ q

对B:

       K=Y_A^{X_B} mod\ q

原理:

拿A的密钥生成式来分析

\begin{align} K &= Y_B^{X_A} mod\ q \\ &= ({a^{X_B} mod \ q})^{X_A} mod\ q\\ &= a^{X_{B}X_{A}} mod \ q \\ &= a^{X_{A}X_{B}} mod \ q \\ &= ({a^{X_A} mod \ q})^{X_B} mod\ q \\ &= Y_A^{X_B} mod\ q \end{align}

可以看出双方的K是相等的,至此双方完成了密钥的交换

如果用群的语言来描述,可以看出DH是在群Z_q^*上做操作,其中q为素数,a为群Z_q^*的生成元。

 

Python代码实现:

# /DF.py

# 计算a^b mod p
def mod_exp(a, b, p):
    res = 1
    while (b):
        if b & 1:
            res = (res * a) % p
        b >>= 1
        a = (a * a) % p

    return res

# 通过给定的素数q、它的原根a、选定的私钥X
# 生成公钥Y
def generate_Y(q, a, X):
    return mod_exp(a, X, q)

# 通过给定的素数q、它的原根a、选定的私钥X以及对方的公钥Y
# 生成密钥K
def df(q, a, X, Y):
    return mod_exp(Y, X, q)

ElGamal密码体系

Elgamal是一种基于离散对数的公钥加密体制,与Diffie-Hellman密切相关。个人认为EG是基于DH的“密钥交换”而进行加密的,我也将ElGamal的加密算法分为 密钥交换 与 明文加密 两部分来理解。而其中,密钥交换部分采用的就是DF的方法。

算法:

加密:

用户A和用户B共同选择一个素数q,以及它的原根a。

用户A要做以下步骤:

1.随机生成整数X_A0<X_A<q-1), 作为A的私钥。

2.计算Y_A=a^{X_A} mod \ q

3.将三元组\{ q ,a,Y_A\}作为用户A的公钥,其他用户可通过此公钥对信息进行加密。

其他任何用户B通过A的公开密钥可以加密信息。

 

用户B要做以下步骤进行数据加密:

1.选择任意整数k \ (1\leq k \leq q-1)

2.计算密钥K = Y_a^{\ k} mod \ q

3.将信息表示为一个整数M\ (1\leq M\leq q-1).

4.计算C_M = KM\ mod\ q

5.计算C_K=a^k\ mod\ q

6.将完整密文(C_K,C_M)发送给用户A

解密:

用户A收到(C_K,C_M),按如下步骤进行解密:

1.计算K=C_M^{\ X_A}\ mod\ q

2.计算M = K^{-1}C_M\ mod\ q,得到明文。

 

以上便是ElGamal的完整算法。

乍一看,似乎不太能看得懂这算法是在干嘛,为什么最后发送的不只是加密后的密文,而是一个二元组?

仔细分析,正如加密过后得到的二元组,其实Elgamal的加密算法包含了两个部分。

A.密钥交换:

首先,用户A与B共享了素数q与其原根a。

用户A做了以下步骤:

1.随机生成整数X_A0<X_A<q-1), 作为A的私钥。

2.计算Y_A=a^{X_A} mod \ q,并把Y_A提供给了用户B。

 

用户B也做了以下步骤:

1.选择任意整数k \ (1\leq k \leq q-1)

2.计算C_K=a^k\ mod\ q,并把C_K提供给了用户A。

 

用户A通过计算K = C_K^{\ X_A}\ mod\ q得到K ,来解密信息

用户B通过计算K = Y_A^{\ k}\ mod\ q得到K, 来加密信息

眼熟吗?对,这就是上面讲的Diffie-Hellman密钥交换算法。要是还是看不出来,只需要将上述的k换成X_BC_K换成Y_B就与上面DH算法书写一模一样了。

既然用户A与B已经通过共享的信息确认了共享的密钥K,那么A和B就可以分别通过K来解密和加密信息了。

B.明文加密:

理解了密钥交换部分后,这一部分就显得很简单了。

用户B为了将明文加密,计算C_M = KM\ mod\ q,这便是明文的密文。

为了能让用户A顺利的解密信息,用户B需要提供有关密钥K的信息发送给用户A,而这信息就是上述的C_K。知道了C_K,用户A就能计算出密钥K的数值,从而可以通过密文C_M求出明文M.

这就是为什么用户B需要发送一个二元组(C_K,C_M)发送给A。

Python代码实现:

# /EG.py

from DF import df, mod_exp

# 扩展欧几里得算法
def egcd(x, y):
    a1, b1, c1 = 1, 0, x
    a2, b2, c2 = 0, 1, y
    while (c2):
      d = c1 // c2
      t1, t2, t3 = a1-d*a2, b1-d*b2, c1-d*c2
      a1, b1, c1, a2, b2, c2 = a2, b2, c2, t1, t2, t3

    return a1, b1, c1 # x模y的逆元 y模x的逆元 gcd(x, y)

# 求x的模p逆元
def inverse(x, p):
    if x < p:
        _, i, _ = egcd(p, x)

        return i if i > 0 else p + i
    else:
        i, _, _ = egcd(p, x)

        return i if i > 0 else p + i


#通过公钥三元组(q, a, Y)以及私钥X, 对明文M进行加密
def encrypt(q, a, Y, k, M):
    K = df(q, a, k, Y)
    CK = mod_exp(a, k, q)
    CM = (K * M) % q

    return (CK, CM)

#通过公钥三元组(q, a, Y)以及私钥X, 对密文D(CK, CM)进行加密
def decrypt(q, a, X, D):
    CK = D[0]
    CM = D[1]
    K = df(q, a, X, CK)
    M = (inverse(K, q) * CM) % q

    return M

def test(q, a, XA, k, M):
    print("原始明文为 M = ",M)
    YA = mod_exp(a, XA, q)
    D = encrypt(q, a, YA, k, M)
    print("加密得明文密文 D = ", D)
    m = decrypt(q, a, XA, D)
    print("解密得明文 M = ", m)

q = 19
a = 10
XA = 5

k = 6
M = 17

test(q, a, XA, k, M)

 

 

 

  • 2
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值