瞭解
說道加密算法就不得不提起:對稱加密算法和非對稱加密加密算法
對稱加密算法:甲方選某擇一種加密規則,對信息進行加密。乙方使用同一種規則,對信息進行解密。由於加密和解密使用同樣規則(簡稱“密鑰”),因此被稱爲“對稱加密算法”
這種加密模式有一個最大的弱點:甲方必須把加密規則告訴乙方否則無法解密。那麼保存和傳遞密鑰就成爲了另一個重要問題
非對稱加密算法:可以在不直接傳遞密鑰的 情況下,完成解密。加密和解密 可以使用不同的規則,只要這兩種規則之間存在某種對應關係即可,這樣就避免了直接傳遞密鑰。這種新的加密模式 被稱爲"非對稱加密算法"。
- 乙方生成兩把密鑰(公鑰和私鑰)。公鑰是公開的,任何人都可以獲得,私鑰則是保密的。
- 甲方獲取乙方的公鑰,然後用它對信息加密。
- 乙方得到加密後的信息,用私鑰解密。
如果公鑰加密的信息只有私鑰解得開,只要私鑰不泄露,就可以保證安全
RSA加解密公式
- 加密:公鑰(E,N) 密文=(明文^E) mod N
- 解密:密鑰(D,N) 明文=(密文^D) mod N
RSA的安全基於大數分解的難度。公鑰和私鑰是一對大素數的函數。從一個公鑰和密文恢復出明文的難度,等價於分解兩個大素數之積
主要用到的公式:
- 互質數:公約數只有1的兩個數
- 歐拉函數:φ(mn)=φ(m)φ(n)=(m-1)x(n-1)
- 歐拉定理:如果兩個正整數a和n互質,則n的歐拉函數φ(n)可以讓等式 成立
- 模反元素(逆元):根據歐拉定理,如果兩個正整數a和n互質,那麼一定可以找到整數b,使得ab-1可以被n整除或者ab%n=1,b就叫做a的模反元素
RSA密鑰產生的過程
- 隨機選擇兩個不相等的質數p和q。
- 計算p和q的乘積n,n=pq。
- 計算n的歐拉函數φ(n)。
- 隨機選擇一個整數e,條件是1<e<φ(n),並且e與φ(n)互質。
- 計算e對於φ(n)的模反元素d,使de=1 mod φ(n) ——(de)modφ(n)=1
- 產生公鑰(e,n)。私鑰(d,n)
舉例
- 選擇p=3,q=11.
- n=pq=33.
- φ(n)=(p-1)x(q-1)=20.
- 選擇e=3,e與φ(n)互質
- (de)mod φ(n)=(d*3)mod*20,d=7
- 公鑰(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;
}
運行結果
字符串加解密:
文件加解密: