ELGamel 加密算法概述
ELGamel 是一种基于离散对数问题的公钥加密算法,由 Taher Elgamal 在 1985 年提出。它是 Diffie-Hellman 密钥交换协议的扩展,广泛应用于数字签名和加密场景。ELGamel 的安全性依赖于有限域上离散对数问题的计算难度。
ELGamel 密钥生成
选择一个大素数 ( p ) 和一个生成元 ( g )(即 ( g ) 是 ( \mathbb{Z}_p^* ) 的生成元)。 选择一个私钥 ( x ),满足 ( 1 \leq x \leq p-2 )。 计算公钥 ( y = g^x \mod p )。 公钥为 ( (p, g, y) ),私钥为 ( x )。
ELGamel 加密过程
假设明文为 ( m )(( 0 \leq m \leq p-1 )),选择一个随机数 ( k )(( 1 \leq k \leq p-2 ))。 计算密文的两部分:
- ( c_1 = g^k \mod p )
- ( c_2 = m \cdot y^k \mod p ) 密文为 ( (c_1, c_2) )。
ELGamel 解密过程
使用私钥 ( x ) 解密密文 ( (c_1, c_2) ): 计算 ( s = c_1^x \mod p )。 恢复明文 ( m = c_2 \cdot s^{-1} \mod p )。
ELGamel 安全性
ELGamel 的安全性依赖于离散对数问题的困难性。若攻击者无法从 ( g^k ) 或 ( g^x ) 中恢复 ( k ) 或 ( x ),则无法破解密文。为了确保安全性,素数 ( p ) 应足够大(通常至少 2048 位),且 ( g ) 应为大阶生成元。
ELGamel 应用场景
ELGamel 常用于混合加密系统,如与 AES 结合使用(用 ELGamel 加密 AES 密钥)。它还用于数字签名(如 DSA 算法)和多方安全协议中。
注意事项
- 实际应用中需使用更安全的随机数生成器和更大的密钥长度。
- 生成元 ( g ) 的选择需验证其是否为 ( \mathbb{Z}_p^* ) 的生成元。
- 明文 ( m ) 应通过编码方式映射到 ( \mathbb{Z}_p ),或使用混合加密方案。
ELGamel.h
cpp
#ifndef _ELGAMEL_H_
#define _ELGAMEL_H_
void Encryption(int m, int y, int g, int p, int *C1, int *C2);
int Decryption(int c2, int c1, int x, int p);
void Sign(int c1, int c2, int g, int p, int x, int *R1, int *S1, int *R2, int *S2);
int Vrfy(int y, int g, int r, int s, int m, int p);
#endif
ELGamel.cpp
cpp
#include "SDELGamel.h"
// 判断一个数是否为素数
// 输入一个数a
// 返回:如果a是素数,返回true ; 否则返回false
int Prime(int a)
{
for (int i = 2; i <= (a / 2); i++)
{
if ((a % i) == 0)
{
return 0;
}
}
return 1;
}
// 快速模幂运算
// 形式为 (a^b) mod c
// 输入 a 、b 和 c 因为要求a^b , 因此是长整数
// 返回 (a^b) mod c 计算结果
int modpow(long long a, long long b, int c)
{
int res = 1;
while (b > 0)
{
if (b & 1)
{
res = (res * a) % c;
}
b = b >> 1;
a = (a * a) % c;
}
return res;
}
// 求解乘法逆元
// 输入num 和 mod。 求num 在 mod 下的乘法逆元
// 返回num 在 mod 下的乘法逆元
int inverse(int num, int mod)
{
int a = num;
int b = mod;
int x = 0, x0 = 1;
int qt, temp;
while (b != 0)
{
qt = a / b;
temp = a % b;
a = b;
b = temp;
temp = x; x = x0 - qt * x; x0 = temp;
//temp = y; y = y0 - qt * y; y0 = temp;
}
if (x0 < 0)
{
x0 += mod;
}
return x0;
}
// ElGamal算法加密过程
// 输入公钥{g,y,p} , 明文m
// 返回密文对:C = {c1,c2} , 以数组形式
void Encryption(int m, int y, int g, int p, int *C1, int *C2)
{
long long temp;
//int c1, c2;
int k = 7;
*C1 = modpow(g, k, p);
temp = modpow(y, k, p);
*C2 = (m * temp) % p;
}
// ElGamal解密过程
// 输入密文对:{c1,c2} ,密钥d 以及公钥p
// 返回明文m
int Decryption(int c2, int c1, int x, int p)
{
int temp;
temp = modpow(c1, x, p);
long long temp1 = inverse(temp, p);
int m = (c2 * temp1) % p;
return m;
}
//ElGamal数字签名函数
void Sign(int c1, int c2, int g, int p, int x, int *R1, int *S1, int *R2, int *S2)
{
int k, k1;
long long temp;
int r1, r2, s1, s2;
k = 7;
int base = p - 1;
r1 = modpow(g, k, p);
temp = c1 - (long long)x * r1;
k1 = inverse(k, base);
s1 = (temp * k1) % base;
r2 = modpow(g, k, p);
temp = c2 - (long long)x * r2;
k1 = inverse(k, base);
s2 = (temp * k1) % base;
if (s1 < 0)
{
s1 = s1 + p - 1;
}
if (s2 < 0)
{
s2 = s2 + p - 1;
}
*R1 = r1;
*S1 = s1;
*R2 = r2;
*S2 = s2;
}
//数字签名验证函数
int Vrfy(int y, int g, int r, int s, int m, int p)
{
long long temp1, temp2;
long long i, j;
temp1 = modpow(y, r, p);
temp2 = modpow(r, s, p);
i = (temp1 * temp2) % p;
j = modpow(g, m, p);
if (i == j)
{
return 1;
}
else
{
return 0;
}
}
※说明:该代码仅实现了32位即int型密钥的加解密及签名验签,如果需要更大的密钥程度,需自行实现大整数的运算,建议实际生产时使用第三方库