利用RSA算法實現文件加密(C++)

瞭解

    說道加密算法就不得不提起:對稱加密算法和非對稱加密加密算法

    對稱加密算法:甲方選某擇一種加密規則,對信息進行加密。乙方使用同一種規則,對信息進行解密。由於加密和解密使用同樣規則(簡稱“密鑰”),因此被稱爲“對稱加密算法”

    這種加密模式有一個最大的弱點:甲方必須把加密規則告訴乙方否則無法解密。那麼保存和傳遞密鑰就成爲了另一個重要問題

   非對稱加密算法:可以在不直接傳遞密鑰的 情況下,完成解密。加密和解密 可以使用不同的規則,只要這兩種規則之間存在某種對應關係即可,這樣就避免了直接傳遞密鑰。這種新的加密模式 被稱爲"非對稱加密算法"。

  • 乙方生成兩把密鑰(公鑰和私鑰)。公鑰是公開的,任何人都可以獲得,私鑰則是保密的。
  • 甲方獲取乙方的公鑰,然後用它對信息加密。
  • 乙方得到加密後的信息,用私鑰解密。

  如果公鑰加密的信息只有私鑰解得開,只要私鑰不泄露,就可以保證安全


RSA加解密公式

  • 加密:公鑰(E,N)             密文=(明文^E) mod N
  • 解密:密鑰(D,N)          明文=(密文^D) mod N

RSA的安全基於大數分解的難度。公鑰和私鑰是一對大素數的函數。從一個公鑰和密文恢復出明文的難度,等價於分解兩個大素數之積

主要用到的公式:

  1. 互質數:公約數只有1的兩個數
  2. 歐拉函數:φ(mn)=φ(m)φ(n)=(m-1)x(n-1)
  3. 歐拉定理:如果兩個正整數a和n互質,則n的歐拉函數φ(n)可以讓等式  成立
  4. 模反元素(逆元):根據歐拉定理,如果兩個正整數a和n互質,那麼一定可以找到整數b,使得ab-1可以被n整除或者ab%n=1,b就叫做a的模反元素

RSA密鑰產生的過程

  1. 隨機選擇兩個不相等的質數p和q。
  2. 計算p和q的乘積n,n=pq。
  3. 計算n的歐拉函數φ(n)。
  4. 隨機選擇一個整數e,條件是1<e<φ(n),並且e與φ(n)互質。
  5. 計算e對於φ(n)的模反元素d,使de=1 mod φ(n)        ——(de)modφ(n)=1
  6. 產生公鑰(e,n)。私鑰(d,n)

舉例

  1. 選擇p=3,q=11.
  2. n=pq=33.
  3. φ(n)=(p-1)x(q-1)=20.
  4. 選擇e=3,e與φ(n)互質
  5. (de)mod φ(n)=(d*3)mod*20,d=7
  6. 公鑰(3,33),私鑰(7,33)

在瞭解RSA加密算法後,下面開始實際的代碼編寫
      運行環境windows平臺下vs2013

 設計過程:

  • 利用rand()函數產生隨機數,並獲得兩個素數
  • 兩個素數的乘積產生n,根據歐拉函數求出φ(n)
  • 求明文,根據互質的性質,從(1 < e < φ(n))之間隨機選取一個數使得e與乘積值互質
  • 求密文,根據歐拉定理((de)mod φ(n) = 1)
  • 產生公鑰(e,n),私鑰(d,n)
  • 根據加密公式對字符串、文件內容加密
  • 根據解密公式對字符串、文件內容解密

源代碼

RSA.h

#pragma once
#include <iostream>
#include <vector>
#include <string>
#include <time.h>
#include <fstream>

struct Key{
	//公鑰(public_key, share_key)
	long long share_key;
	long long public_key;
	//私鑰(private_key, share_key)
	long long private_key;
};

class RSA{
public:
	RSA();
	Key GetKey() {
		return _key;
	}
	//給文件進行加密
	void Ecrept(const char* plain_file_in, const char* ecrept_file_out,
		long public_key, long share_key);
	void DEcrept(const char* plain_file_in, const char* ecrept_file_out,
		long private_key, long share_key);

	//對字符串進行加密
	std::vector<long> Ecrept(std::string& str_in, long public_key, long share_key);
	std::string DEcrept(std::vector<long>& ecrept_str, long private_key, long share_key);

	//打印加密之後的信息
	void PrintInfo(std::vector<long>& ecrept_str);
private:
	//產生素數
	long ProducePrime();
	//判斷一個數是否是素數
	bool IsPrime(long prime);
	//產生所有的key值
	void ProduceKeys();
	//求share_kay
	long ProduceShareKey(long prime1, long prime2);
	//根據歐拉函數求乘積
	long ProduceOrla(long prime1, long prime2);
	//求public_key
	long ProducePublicKey(long orla);
	//判斷兩個數之間的最大公約是否爲1
	long ProduceGcd(long public_key, long orla);
	//求private_key
	long ProducePrivateKey(long public_key, long orla);
	//加密單個信息
	long Ecrept(long msg, long key, long share_key);
private:
	Key _key;
};

RSA.cpp

#include "RSA.h"

RSA::RSA() {
	ProduceKeys();
}

//給文件進行加密與解密
void RSA::Ecrept(const char* plain_file_in, const char* ecrept_file_out,
	long public_key, long share_key){
	std::ifstream fin(plain_file_in);
	std::ofstream fout(ecrept_file_out, std::ofstream::app);
	if (!fin.is_open()){
		std::cout << "open file failed" << std::endl;
		return;
	}
	//一次讀取文件大小,但是有可能因爲文件過大,無法進行加密
	//fin.seekg(0, fin.end);
	//long fsize = fin.tellg();
	//按塊讀取,逐段加密
	const int NUM = 256;
	char buf[NUM];
	long buf_out[NUM];
	int cur_num;
	while (!fin.eof()){
		fin.read(buf, NUM);
		//當前所讀取的字節數
		cur_num = fin.gcount();
		for (int i = 0; i < cur_num; ++i){
			buf_out[i] = Ecrept((long)buf[i], public_key, share_key);
		}
		fout.write((char*)buf_out, cur_num * sizeof(long));
	}
	fin.close();
	fout.close();
}
void RSA::DEcrept(const char* plain_file_in, const char* ecrept_file_out,
	long private_key, long share_key){
	std::ifstream fin(plain_file_in);
	std::ofstream fout(ecrept_file_out, std::ofstream::app);
	if (!fin.is_open()){
		std::cout << "open file failed" << std::endl;
		return;
	}
	//一次讀取文件大小,但是有可能因爲文件過大,無法進行加密
	//fin.seekg(0, fin.end);
	//long fsize = fin.tellg();
	//按塊讀取,逐段加密
	const int NUM = 256;
	long buf[NUM];
	char buf_out[NUM];
	int cur_num;
	while (!fin.eof()){
		fin.read((char*)buf, NUM * sizeof(long));
		//當前所讀取的字節數
		cur_num = fin.gcount();
		cur_num /= sizeof(long);
		for (int i = 0; i < cur_num; ++i){
			buf_out[i] = (char)Ecrept((long)buf[i], private_key, share_key);
		}
		fout.write(buf_out, cur_num);
	}
	fin.close();
	fout.close();
}

//對字符串進行加密與解密
std::vector<long> RSA::Ecrept(std::string& str_in, long public_key, long share_key) {
	std::vector<long> vecout;
	for (const auto& e : str_in){
		vecout.push_back(Ecrept(e, public_key, share_key));
	}
	return vecout;
}
std::string RSA::DEcrept(std::vector<long>& ecrept_str, long private_key, long share_key) {
	std::string strout;
	for (const auto& e : ecrept_str){
		strout.push_back((char)Ecrept(e, private_key, share_key));
	}
	return strout;
}

//打印加密之後的信息
void RSA::PrintInfo(std::vector<long>& ecrept_str) {
	for (const auto& e : ecrept_str){
		std::cout << e << " ";
	}
	std::cout << std::endl;
}

//加密單個信息,模冪運算
long RSA::Ecrept(long msg, long key, long share_key){
	long msg_out = 1;
	long a = msg;
	long b = key;
	int c = share_key;
	while (b){
		if (b & 1){
			//msg_out = (A0*A1...Ai...An) % c
			msg_out = (msg_out * a) % c;
		}
		b >>= 1;
		a = (a * a) % c;
	}
	return msg_out;
}

//產生素數,隨機產生兩個素數
long RSA::ProducePrime()
{
	srand(time(nullptr));
	long prime = 0;
	while (1){
		prime = rand() % 50 + 2;
		if (IsPrime(prime))
			break;
	}
	return prime;
}

//判斷一個數是否是素數
bool RSA::IsPrime(long prime) {
	if (prime < 2)
		return false;
	for (int i = 2; i < sqrt(prime); ++i){
		if (prime % i == 0)
			return false;
	}
	return true;
}

//產生所有的key值
void RSA::ProduceKeys() {
	//選擇兩個不相等的素數
	long prime1 = ProducePrime();
	long prime2 = ProducePrime();
	while (prime1 == prime2)
		prime2 = ProducePrime();
	_key.share_key = ProduceShareKey(prime1, prime2);
	long orla = ProduceOrla(prime1, prime2);
	_key.public_key = ProducePublicKey(orla);
	_key.private_key = ProducePrivateKey(_key.public_key, orla);
}

//求share_kay
long RSA::ProduceShareKey(long prime1, long prime2) {
	return prime1 * prime2;
}

//根據歐拉函數求乘積
long RSA::ProduceOrla(long prime1, long prime2) {
	return (prime1 - 1) * (prime2 - 1);
}

//求public_key,隨機選擇一個數, 1 < public_key < orla,public_key,oala互質
long RSA::ProducePublicKey(long orla) {
	long public_key;
	srand(time(nullptr));
	while (1){
		public_key = rand() % orla;
		if (public_key > 1 && ProduceGcd(public_key, orla) == 1)
			break;
	}
	return public_key;
}

//判斷兩個數之間的最大公約是否爲1
long RSA::ProduceGcd(long public_key, long orla) {
	long residual;
	while (residual = public_key % orla){
		public_key = orla;
		orla = residual;
	}
	return orla;
}

//求private_key
long RSA::ProducePrivateKey(long public_key, long orla) {
	//(public_key * private_key) % orla == 1
	long private_key = orla / public_key;
	while (1){
		if ((public_key * private_key) % orla == 1)
			break;
		++private_key;
	}
	return private_key;
}

測試部分

#include "RSA.h"

void TestString() {
	RSA rsa;
	Key key = rsa.GetKey();
	std::string strin;
	std::cout << "輸入加密信息" << std::endl;
	std::cin >> strin;
	std::vector<long> strecrept = rsa.Ecrept(strin, key.public_key, key.share_key);
	std::string strout = rsa.DEcrept(strecrept, key.private_key, key.share_key);
	std::cout << "加密信息" << std::endl;
	rsa.PrintInfo(strecrept);
	std::cout << "解密信息" << std::endl;
	std::cout << strout << std::endl;
}

//void TestFile() {
//	RSA rsa;
//	Key key = rsa.GetKey();
//	rsa.Ecrept("plain.txt", "ecrept.out.txt", key.public_key, key.share_key);
//	rsa.DEcrept("ecrept.out.txt", "decrept.out.txt", key.private_key, key.share_key);
//}

int main() {
	TestString();
	//TestFile();
	system("pause");
	return 0;
}

運行結果

 字符串加解密:

     

 文件加解密:

 

 


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章