1. 程式人生 > >c++ 簡單的實現橢圓曲線加密演算法

c++ 簡單的實現橢圓曲線加密演算法

橢圓曲線演算法

橢圓曲線密碼體制來源於對橢圓曲線的研究,所謂橢圓曲線指的是由韋爾斯特拉斯(Weierstrass)方程:
y2+a1xy+a3y=x3+a2x2+a4x+a6 (1)
所確定的平面曲線。其中係數ai(I=1,2,…,6)定義在某個域上,可以是有理數域、實數域、複數域,還可以是有限域GF(pr),橢圓曲線密碼體制中用到的橢圓曲線都是定義在有限域上的。
橢圓曲線上所有的點外加一個叫做無窮遠點的特殊點構成的集合連同一個定義的加法運算構成一個Abel群。在等式
mP=P+P+…+P=Q (2)
中,已知m和點P求點Q比較容易,反之已知點Q和點P求m卻是相當困難的,這個問題稱為橢圓曲線上點群的離散對數問題。橢圓曲線密碼體制正是利用這個困難問題設計而來。

公鑰演算法是基於數學函式(如單向陷門函式),公鑰密碼體制根據其所依據的難題一般分為三類:大整數分解問題類、離散對數問題類、橢圓曲線類。

本文是在素域Zp上的,以Menezes-Vanstone形式的橢圓加密演算法。

在素域上的曲線函式為

y^2 = x ^ 3 +a*  x + b      a,b為小於p的非負數,且 4*a^3+ 27*b^2 != 0

對於在素域上的加法中,對於所有的點P,Q 屬於E(Zp),有加法規則:

1。P + O = O + P = P ,P + (-P) = O;

O為橢圓曲線上的零點或者稱為無限遠的點,但是O在橢圓曲線的加法域上。

2.加法的分配率和結合律,對於s,t 屬於Zp,有(s + t )* P = s * P + t* P;

3.對於 P = (x1,y1),Q = (x2,y2) ,並且 P != - Q,則P + Q=(x3,y3),

x3 = k^2 - x1 -x2;

y3 = k*(x1-x3) - y1;

k = (y2-y1)/(x2-x1)   if P != Q;

k = (3x1^2 + a)/(2*y1) if P == Q;

橢圓曲線在素域上的運算用到除法,而在除法的規則是a / b = c mod p 即計算 a x b^-1 = c mod p ,其中 b^-1為b的乘法逆元, 即 b x b^-1 = 1 mod p。對於乘法逆元,當b與p互素時,存在唯一解,而這裡p是一個素數,且b不可能為1,則肯定有解。對於求乘法逆元,一般使用歐幾里德演算法,如下:

int getX_1(int x,int mod){
	int Q,X1,X2,X3,Y1,Y2,Y3,T1,T2,T3;
	X1 = 1;
	X2 = 0;
	X3 = mod;
	Y1 = 0;
	Y2 = 1;
	Y3 = (x%mod + mod) %mod;//獲得正整數
	while(Y3 != 1){ 
		Q = X3 / Y3;
		T1 = X1 - Q * Y1;
		T2 = X2 - Q * Y2;
		T3 = X3 - Q * Y3;
		X1 = Y1;
		X2 = Y2;
		X3 = Y3;
		Y1 = T1;
		Y2 = T2;
		Y3 = T3;
	}
	return Y2;
}


乘法運算規則:
1. 對於任意 k 屬於 Zp,有 k * P = P + ..... + P (k個P相加)
2. 對於任意 s,t 屬於 Zp,有 s *(t *P) = (s*t)*P

對於Menezes-Vanstone的橢圓加密演算法:
1. 產生金鑰,
任選一個整數k ,0<k<p ,為私鑰,在曲線上任選一點 A ,並計算 B = k*A ,公鑰為(A,,B)。其中又可稱A為基鑰,對於最小整數n以使 n* A = O ,則n稱為週期,要是週期為素數,且為一個較大值才合理。
2.加密過程:
令明文為 M = (m1,m2),M可以不是曲線E上的點。計算得到密文(C1,C2),其中任選一個數屬於Zp:
C1 = r * A;;
Y= (y1,y2) = r * B;
C2 = (C21,C22) = (y1 * m1 mod p,y2* m2 mod p)
3 解密過程;
計算Z = (z1,z2) = k*C1;計算明文 M = (C21 * z1^-1 mod p, C22 * z2 ^ -1 mod p).

c++中的模運算,當有負數存在時無法達到正確結果,簡直是坑,如 -1 % 2,在使用vs2012進行測試,會返回-1,而不是1. c++中模運算結果的符號和被除數的符號一致。
引數選取:選取 p = 127,曲線函式為: y^2 = x^3 + 5* x + 37, a = 5 ,b= 37, r = 7.選取私鑰 k = 9選取一個點A為(11,4)則 B = k*A = (120,41)
則原始碼如下,這裡直接對char進行加密,效果不佳

#include "stdafx.h"
#include <string>
#include <iostream>
using namespace std;
const int k = 9;
const int a = 5;
const int b = 37;
const int p = 127;
const int r =7;

int getX_1(int x,int mod){
	int Q,X1,X2,X3,Y1,Y2,Y3,T1,T2,T3;
	X1 = 1;
	X2 = 0;
	X3 = mod;
	Y1 = 0;
	Y2 = 1;
	Y3 = (x%mod + mod) %mod;//獲得正整數
	while(Y3 != 1){ 
		Q = X3 / Y3;
		T1 = X1 - Q * Y1;
		T2 = X2 - Q * Y2;
		T3 = X3 - Q * Y3;
		X1 = Y1;
		X2 = Y2;
		X3 = Y3;
		Y1 = T1;
		Y2 = T2;
		Y3 = T3;
	}
	return Y2;
}//獲得其乘法逆元

struct point{
	int x;
	int y;
};
point A,B;//公鑰
typedef pair<point,point> twopoint;
bool operator == (point pa,point pb){
	return pa.x == pb.x && pa.y == pb.y;
}
point operator + (point pa , point pb){
	int k;
	
	if(pa == pb)
		k = ((3 * pa.x * pa.x + a) * getX_1(2* pa.y ,p)) % p ;//必須使用正整數。這裡pa.y的值不能取0.
	//當取0時,這就不能進行這個計算了,因為 pa = -pb了,則,應該進行一個判斷。但是,這樣的結果是 O,是不在橢圓曲線上的,不能進行輸出的值。
	//這裡是有一個週期數在,對於容易一個基值的也就是先給出的A來說,它有一個週期n,使nA = O,而這裡所有引數的選取值
	//都小於n,使其不會達到O,保證了不會出錯,應該是這樣吧。。。
	else
		k = (pb.y - pa.y) * getX_1(pb.x - pa.x , p) %p;
		point c;
		c.x = (k*k - pa.x -pb.x) %p;
		c.y = (k * (pa.x - c.x) - pa.y)%p ;
		c.x = (c.x + p) %p; 
		c.y = (c.y + p) %p; 
		
		return c;
}
point operator * (point &b,int n){
		point q = b;
		n = n -1;
		for(int i = 1 ; i < n;i++){
			q = q + b ;
		}
		return q;
}
twopoint ECodePoint(point m){
	point c1,c2;
	c1 = A * r ;
	point Y = B * r ;
	c2.x = Y.x * m.x % p ;
	c2.y = Y.y * m.y % p ;
	return twopoint(c1,c2);
}
point DCodePoint(twopoint t){
	point Z = t.first * k;
	point m;
	m.x = t.second.x * getX_1(Z.x,p) % p ;
	m.y = t.second.y * getX_1(Z.y,p) % p ;
	return m;
}
string ECode(string input){//明文的輸入是一個string型別,但是單個的操作應該是對單個的字元char轉換成的int型別進行計算
	string output = "";
	point M;
	twopoint C;
	for(int i =0; i < input.length();i++){
		M.x = i;
		M.y = input[i];
		C = ECodePoint(M);
		output += (char)C.first.x ;
		output += (char)C.first.y ;
		output += (char)C.second.x ;
		output += (char)C.second.y ;
	}

	return output;
}
string DCode(string input){
	string output = "";
	point M;
	twopoint C;
	if(input.length()%4 != 0)
		return "錯誤輸入";//因為密文肯定是4的倍數,如果不是,肯定出錯了。
	for(int i = 0;i < input.length();){
		C.first.x = input[i++];
		C.first.y = input[i++];
		C.second.x = input[i++];
		C.second.y = input[i++];
		M = DCodePoint(C);
		output += (char)M.y;
	}
	return output;
}

int main()
{
	A.x = 11;
	A.y = 4;
	B = A*k;
	string s = "";
	//加密簡單,隨便輸入點東西就可以加密了,但是解密不行啊,隨便輸入肯定是錯誤的結果,
	//程式肯定會出錯,所以,只支援對之前加密的結果進行解密。
	cout<<"使用在素域上的曲線 y^2 = x^3 + 5*x +37   ,使用Menezes-Vanstone的演算法:"<<endl;
	cout<<"在素域p=127上,私鑰為k=9,公鑰A(11,4),B(120,41),對明文字串直接轉換為int進行加密"<<endl;
	cout<<"請輸入要加密的內容:"<<endl;
	cin>>s;
	cout<<"密文如下:"<<"\r\n";
	s = ECode(s);
	cout<<s<<endl;
	cout<<"對之前密文解密,得到明文如下(由於輸入密文不正確絕對會使這個程式出錯,所以只能解密絕對安全的密文):"<<"\r\n";
	s = DCode(s);
	cout<<s<<"\r\n"<<"完成"<<endl;
	cin>>s;
	return 0;
}

相關推薦

c++ 簡單實現橢圓曲線加密演算法

橢圓曲線演算法 橢圓曲線密碼體制來源於對橢圓曲線的研究,所謂橢圓曲線指的是由韋爾斯特拉斯(Weierstrass)方程: y2+a1xy+a3y=x3+a2x2+a4x+a6 (1) 所確定的平面曲線。其中係數ai(I=1,2,…,6)定義在某個域上,可以是有理數域、實數域

簡單橢圓曲線加密演算法(ECC)示例(MATLAB實現

摘要 本文主要是使用MATLAB演示橢圓曲線加密演算法(ECC)的加密/解密過程,內容包括金鑰、公鑰生成,以及通過加密並解密一個簡單數字的過程來描述其使用方法。 本文實際是對以下兩篇文章的一個MATLAB實現,並且提供了兩個實用的MATLAB工具函式以便在閱

橢圓曲線加密演算法SM2在Android用Java呼叫實現

        SM2基於ECC,ECC(Elliptic Curves Cryptography)加密演算法是一種公鑰加密演算法,與主流的RSA演算法相比,ECC演算法可以使用較短的金鑰達到相同的安全程度。近年來,人們對ECC的認識已經不再處於研究階段,開始逐步進入實際應用

ECC橢圓曲線加密演算法

橢圓曲線加密也是一種公鑰加密演算法,和RSA與離散對數一樣,它也是基於一個數學求解的難題,並且它的難度比RSA和離散對數都要大,它基於的數字難題就是求取定義在橢圓曲線上的離散對數的求取難題,對於這個難題的描述比大數分解和離散對數要稍微複雜一些,不過它也還算比較形

橢圓曲線加密演算法

  橢圓曲線密碼學(Elliptic curve cryptography),簡稱ECC,是一種建立公開金鑰加密的演算法,也就是非對稱加密。類似的還有RSA,ElGamal演算法等。ECC被公認為在給定金鑰長度下最安全的加密演算法。比特幣中的公私鑰生成以及簽名演算法ECDSA都是基於ECC的。下面簡單介紹E

橢圓曲線加密演算法的證書

網上介紹openssl建立RSA演算法的證書很多,但是建立橢圓曲線證書的少。即使這些介紹橢圓曲線的,都不對,創建出來的證書無法使用。 最終基於該開源工具成功建立了: http://sourceforge.net/projects/xca/

c實現功能(8)簡單實現文字的加密

#include <stdio.h> #include <string.h> //實現對檔案的加密函式 void encode(char *s){ while (*s) { (*s)++; s++; }

go實現橢圓曲線加解密、簽名驗證演算法(go ecdsa庫的運用),及生成比特幣地址過程講解、base58實現

go實現橢圓曲線加解密、簽名驗證演算法(go ecdsa庫的運用),及生成比特幣地址過程講解、BASE58實現 前言 本文主要講解使用Go的ecdsa庫實現橢圓曲線加解密、簽名、驗證演算法,同時通過公鑰生成比特幣地址,具體程式碼邏輯參考bitcoin0

A*尋路演算法C++簡單實現

2007/8/13 17:26:59 #include <iostream> #include <ctime> #include <list> #include <algorithm> #include <cassert&

谷歌百度以圖搜圖 "感知雜湊演算法" C#簡單實現

/// <summary> /// 感知雜湊演算法 /// </summary> public class ImageComparer { /// <summary> /// 獲取圖片的Hashcode /// &

python實現橢圓曲線加密

col sha2 -s emp for in spa 屬於 質數分解 app 我也看得雲裏霧裏, 但是ECC和RSA並列為非對稱加密雙雄, 還是很有必要了解一下的。 RSA是用質數分解,ECC是用離散的橢圓方程解,安全度更高。 而且,這個ECC的加法乘法規則,和普通

A*尋路演算法C++簡單實現

參考文章: A*尋路演算法是遊戲中常用的AI演算法,這裡用C++簡單實現了一下演算法,便於理解。 搜尋區域 如圖所示簡易地圖, 其中綠色方塊的是起點 (用 A 表示), 中間藍色的是障礙物, 紅色的方塊 (用 B 表示) 是目的地. 為了可以用一個二

[轉] A*尋路算法C++簡單實現

track pos endpoint 障礙 close math.h 不存在 rec 節點 參考文章: http://www.policyalmanac.org/games/aStarTutorial.htm 這是英文原文《A*入門》,最經典的講解,有demo演示 ht

[數據結構(二)]七種排序算法的C++簡單實現

末尾 技術分享 下標 ima http 直接 wap temp 部分 一.冒泡排序(Bubble Sort) 基本思想:兩兩比較相鄰記錄的關鍵字,如果反序則交換,直到沒有反序的記錄為止。 //冒泡排序 void BubbleSort(int *p, int lengt

Hbuilder開發app實戰-識歲05-Crypto.js實現各種js加密演算法

前言 js加密,應該說做js開發的很少接觸到這一塊,因為很多時候都是做加密,很少有前端做加密的, 很榮幸我接觸過兩次,找到了crypto.js,很好的東西,可以實現各種js加密。 吐槽 吐槽下前端做加密,一般來說前端做加密這需求是很少的,極少的, 我卻碰到了兩次,

雙向連結串列簡單實現--資料結構與演算法紀錄片第一記

  從這個月開始得準備春招的東西,所以打算重新學習資料結構與演算法,以後的部落格就以這個為主。   今天是線性結構中的雙向連結串列。   程式碼實現與測試:   DoubleLinkNode:  package linear.doublelink;/** * @Description: 連結串列節點結

(排序演算法)linux c語言實現二分插入排序演算法(簡化版本的插入排序演算法

 二分插入演算法是在已經排序好的序列裡插入一個元素,是穩定的演算法,關鍵詞是折中。 比如說我要在12345678910裡插入一個3,那麼我先看看中間的數比3大,還是比3小,要是比3大,我就去後一半,如果是比3小,我就去前一半,現在進入某個一半後,再做如此操作,最後將其他的元素依次往後挪

單鏈表的C語言實現及插入刪除演算法

什麼是單鏈表?   由於順序表在插入和刪除是需要做大量的元素移動工作,而且需要連續的物理空間,因此其缺點是十分明顯的,為了解決這一問題,不需要預先分配連續的記憶體地址空間、插入刪除元素不需要做大量移動工作的連結串列出現了。但解決問題的同時也擁有自己的缺點,即不能隨機存取。   在連結串列中,每個

60行c++簡單實現中綴表示式轉字尾

中綴表示式轉字尾表示式演算法 使用棧進行輔助 對於符號±/(),定義為/優先順序為2,’(’(左括號)優先順序為3,右括號’)'優先順序最低為0 對於一個表示式 如果當前字元為數字: 輸出到輸出佇列中; 否則當前字元是運算子號或

超級瑪麗遊戲 C 簡單實現

分享一下我老師大神的人工智慧教程!零基礎,通俗易懂!http://blog.csdn.net/jiangjunshow 也歡迎大家轉載本篇文章。分享知識,造福人民,實現我們中華民族偉大復興!