ElGamal加密算法

ElGamal算法是一種常見加密算法, 與Diffie-Hellman算法有密切關聯。

該算法安全性依賴于計算有限域上離散對數難題:求解離散對數(目前)是困難的,其逆運算指數運算簡單。

算法思路:
假設有2個用戶Alice 和 Bob,Bob欲使用ElGamal加密算法向Alice發送信息。
對于Alice,首先要選擇一個素數q, α是素數q的本原根。 [本原根的概念對應模q乘法群(需循環群)中的生成元。]

  • Alice產生一個XA, XA∈(1, q - 1)
  • 計算YA = αXA mod q
  • A的私鑰為XA, 公鑰為 {q, α, YA}

公鑰存在于某個可信公開中心目錄,任何用戶都可訪問

對于Bob, 首先去上述中心目錄訪問得Alice的公鑰 {q, α, YA}
然后將自己欲發送的明文M, (M ∈ [1, q - 1])洗干凈備好。

  • 選一個隨機整數k, k ∈ [1, q - 1]
  • 計算可解密自己密文的秘鑰 PrivateK = (YA)k mod q (即αXA*k mod q)
  • 將M加密成明文對(C1, C2) 其中
    C1 = αk mod q , C2 = PrivateK * M mod q
  • 明文對發送給Alice

Alice收到明文對:

  • PrivateK = (C1)XA mod q(即αk*XA mod q)
  • M = C2 * PrivateK-1 mod q

到這里..發現算法大多就是一些乘法,求冪之類的運算。剩下個關鍵內容就是如何尋找素數p的本原根,或者說如何找有限域GF(p)中的生成元。
我們在群這個概念里討論。
p是素數,令Zp = {1, 2, 3, ..., p - 1},因為考慮乘法,去掉了0元素。
2個定理:

  • Euler定理:設P和a是互素的兩個整數,則有aφ(p)=1 mod p
  • 拉格朗日定理: 設 G 是有限群, H 是 G 的子群,|H| 整除 |G|

回顧這樣2個概念:設G是群, a∈G, 使得等式ak = e成立的最小整數k稱為元素a的階。而群的階是指該群中的元素個數。值得留意的是,以某個生成元去生成某個子群,該子群的階就是該元素的階(當然了)。

因Zp中所有元素與p互素,由歐拉定理,Zp中所有元素的階不超過p-1,(因為群的階φ(p)是p-1,而至少有aφ(p)=1 mod p)。
對于Zp中的任一元素,以該元素為生成元形成的一個循環群,設為S(群S的階在數值上即該元素的階),根據群的封閉性可知S必然為Zp的子群,根據拉格朗日定理,可知Zp的元素的階必然是|Zp| (即p-1)的因子。

于是可以得到這樣一個結論:若有這樣一個元素a,其階為Ka, Ka是p-1的平凡因子(即因子1 或者因子p-1), 那么a或者是單位元,或者是生成元。 又知Zp的單位元是1,那么根據單位元的唯一性,可知若a非1,則a必為生成元。問題在于,p-1的因子可能很多,我們還不是得一個個去找到階是p-1的平凡因子的元素?

為此,我們構造一種特殊的素數,使得p-1的因子數量很少。取p - 1 = 2 * Q ,其中p是素數,Q也是素數。 因為Q是素數,因子僅1, Q。所以p - 1的因子只有 {1, 2, Q, p - 1}四個。
到此已經非常明朗,我們找到滿足上述條件的素數p,然后在Zp中尋找這樣一個元素a,a的階非2,非Q,即a^2 mod p != 1 && a^Q mod p != 1,若a又非單位元1,那么a必然是生成元。

留意Zp未必一定有生成元, 若1 到 (p - 1)經上述檢驗都不滿足, 考慮另取一個素數p。至于代碼實現上出現的問題:若mpz_probab_prime_p(tmp.mt, 6) == 1 改為 mpz_probab_prime_p(tmp.mt, 6) == 2,p一旦較大,程序運行速度很慢。取2為真素數檢驗,速度很慢,1為概率素數檢驗,速度快。

代碼實現

#include<bits/stdc++.h>
#include<gmp.h>
#include<gmpxx.h>
using namespace std;

#define mt get_mpz_t()
typedef mpz_class bn;

gmp_randstate_t rstate;

struct public_keys {
    // Big prime p, primitive root, Y = XA^(primitive root)
    bn p, pr, Y; 
    public_keys(bn _p = 0, bn _pr = 0, bn _Y = 0) : p(_p), pr(_pr), Y(_Y) {}
};

// Trusted third party  一個所有用戶可訪問的公開中心目錄
map<string, public_keys> ttp;    

// 返回start 到 end的一個隨機數
inline bn randNum(bn start, bn end) {
    bn tmp;
    mpz_urandomm(tmp.mt, rstate, bn(end + 1 - start).mt);
    return tmp + start;
}
// 返回 a^b mod n
inline bn aebmodn(bn a, bn b, bn n) {
    bn ret;
    mpz_powm(ret.mt, a.mt, b.mt, n.mt);
    return ret;
}
// 在2^bits范圍內生成一副公鑰,存于公開目錄中,記在name名下 返回私鑰
bn elgmal_keyGen(string name, unsigned long int bits) {
    bn p = 2, pr = -1, Y = -1, bounds = 2;
    mpz_pow_ui(bounds.mt, bounds.mt, bits);

    bool found = 0;
    while(1) {
        mpz_urandomm(p.mt, rstate, bounds.mt);
        mpz_nextprime(p.mt, p.mt);
        bn tmp = (p - 1) / 2;

        if (p < bounds && mpz_probab_prime_p(tmp.mt, 6) == 1) {
            // pr是1到p-1的一個數
            pr = randNum(1, p - 1);
            while (1) {
                // pr^tmp % p
                bn pexpn = aebmodn(pr, tmp, p);
                if (pr != 1 && (pr * pr) % p != 1 && pexpn != 1) {
                    found = 1;
                    break;
                }
                pr = (pr + 1) % p;
            }
        }
        if (found) break;
    }

    bn XA = randNum(2, p - 2);
    Y = aebmodn(pr, XA, p);
    ttp[name] = public_keys(p, pr, Y);
    return XA;
}

// 密文對(C1, C2)
struct cipher_text {
    bn c1, c2;
    cipher_text(bn _c1 = 0, bn _c2 = 0) : c1(_c1), c2(_c2) {}
};

/*
 * 根據公開中心目錄中name名下的公鑰 對明文m進行加密
 * 返回密文對(C1, C2)
 */
cipher_text elgamal_encrypt(string name, bn m) {
    public_keys pk = ttp[name];
    bn k = randNum(1, pk.p - 1);
    bn privateKey;
    mpz_powm(privateKey.mt, pk.Y.mt, k.mt, pk.p.mt);
    bn cipher1 = aebmodn(pk.pr, k, pk.p);
    bn cipher2 = (m * privateKey) % pk.p;
    return cipher_text(cipher1, cipher2);
}

// 根據在自己name名下的公鑰及 自己的秘鑰dk 解密密文對ct 返回明文
bn elgamal_decrypt(string name, bn dk, cipher_text ct) {
    public_keys pk = ttp[name];
    bn privateKey = aebmodn(ct.c1, dk, pk.p);
    bn k_inverse;
    mpz_invert(k_inverse.mt, privateKey.mt, pk.p.mt);
    return (ct.c2 * k_inverse) % pk.p;
}

int main() {
    gmp_randinit_mt(rstate);
    gmp_randseed_ui(rstate, time(NULL));
    // Alice初始化自己在中心的公鑰并得到自己的私鑰
    bn dk = elgmal_keyGen("Alice", 128);
    cout<<"Input the message: ";
    bn n; cin>>n;
    if (n > ttp["Alice"].p) cout<<"message's length is out of bounds\n"; 
    // Bob根據Alice用戶信息對明文n加密
    cipher_text ct = elgamal_encrypt("Alice", n);
    // Alice進行解密
    bn res = elgamal_decrypt("Alice", dk, ct);
    cout<<"decrypt   result : " <<res <<"\n";
    return 0;
}                             
示例
? ./ElGamal 
Input the message: 1024
decrypt   result : 1024

注:參考了這篇博客和LJF同學的討論..有不對請指正..

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 228,739評論 6 534
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 98,634評論 3 419
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 176,653評論 0 377
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,063評論 1 314
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 71,835評論 6 410
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 55,235評論 1 324
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,315評論 3 442
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,459評論 0 289
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 49,000評論 1 335
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 40,819評論 3 355
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 43,004評論 1 370
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,560評論 5 362
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,257評論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,676評論 0 26
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,937評論 1 288
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,717評論 3 393
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 48,003評論 2 374

推薦閱讀更多精彩內容

  • MD5的全稱是Message-Digest Algorithm 5,在90年代初由MIT的計算機科學實驗室和RSA...
    沒能唱給你的歌曲閱讀 980評論 2 6
  • 終端之間信息傳遞安全性的保證始終是業務的剛性需求。不同的加密算法針對不同的業務需求,因為公司是金融公司性質,又不是...
    語歌閱讀 2,830評論 0 5
  • 一、SSL協商 由于非對稱加密的速度比較慢,所以它一般用于密鑰交換,雙方通過公鑰算法協商出一份密鑰,然后通過對稱加...
    自我陶醉閱讀 2,644評論 1 1
  • RSA是第一個比較完善的公開密鑰算法,它既能用于加密,也能用于數字簽名。RSA以它的三個發明者Ron Rivest...
    暗物質閱讀 1,717評論 0 0
  • 姓名:于川皓 學號:16140210089 轉載自:https://baike.baidu.com/item/RS...
    道無涯_cc76閱讀 2,584評論 0 1