C++实现RC4加密算法

主函数

实现RC4的字符串加密与文件加密算法

// streamcipher.cpp : 定义控制台应用程序的入口点。
//

#include "stdafx.h"
#include "RC4.h"
#include "LSFR.h"
#include <iostream> //cout,cin, endl
#include <cstdio>  //C 标准库 strlen
#include <string>  //std::string
#include<stdio.h>

void testLFSR16() { //测试16级移位寄存器(由本原多项式产生)

	int C[16] = { 0,0,1,0, 0,0,0,0, 0,0,0,1, 0,0,0,1 }; //注意:最后一个一定不能为0,即C[n]=1 为什么
	LSFR lfsr16(C, 16); //按指定的系数构造线性反馈移位寄存器

	int a[16] = { 1,0,1,0, 0,1,1,0, 0,0,0,0, 1,1,1,0 }; //设置寄存器的值
	lfsr16.SetA(a);
	//以下输出255个寄存器的值,即 a1,a2,..., a255

	//16个一组地进行输出
	int j = 0;
	for (int i = 0; i < 65536; i++) {
		std::cout << lfsr16.out();//输出
		j++;
		if (j == 16) {
			j = 0;
			std::cout << std::endl;//输出
		}
	}

}
//测试RC4
void testRc4a(){
	char *key = "this is Rc4's key for RC4 Encript test.这里是RC4的密钥,用于测试用!";
	int len = strlen(key);
	RC4 rc4;  //声明一个RC4对象
	rc4.SetKey(key,len); //设置密钥

	//using namespace  std; 若有此句,则不用写std::
	//以下输入两个文件名:
	std::string strSrc,strDes; //两个文件名
	std::cout << "源文件名称: ";
	std::cin.ignore();
	std::getline (std::cin,strSrc);

	std::cout << "加密后文件名称: ";
	std::getline (std::cin,strDes);

	//加密文件
	bool bOk = rc4.EncryptFile(strSrc.c_str(),strDes.c_str());

	std::cout << (bOk? "OK cipher!" : "Err cipher!") << std::endl;

	//以下主要是想在调度环境下,进行暂停!
	int p=0;
	std::cout << "please input a integer to Exit!" << std::endl;
	std::cin >> p; 
}
void testRc4b() {
	char* key = "this is Rc4's key for RC4 Encript test.这里是RC4的密钥,用于测试用!";
	int len = strlen(key);
	RC4 rc4;  //声明一个RC4对象
	rc4.SetKey(key, len); //设置密钥

	//using namespace  std; 若有此句,则不用写std::
	//以下输入两个文件名:
	std::string strSrc, strDes; //两个文件名
	std::cout << "源文件名称: ";
	std::cin.ignore();
	std::getline(std::cin, strSrc);
	std::cout << "解密后文件名称: ";
	std::getline(std::cin, strDes);

	//加密文件
	bool bOk = rc4.EncryptFile(strSrc.c_str(), strDes.c_str());

	std::cout << (bOk ? "OK decipher!" : "Err decipher!") << std::endl;

	//以下主要是想在调度环境下,进行暂停!
	int p = 0;
	std::cout << "please input a integer to Exit!" << std::endl;
	std::cin >> p;
}


void testLFSR8(){

	//本原多项式:8,4,3,2,1  p(x)=x^8+x^4+x^3+x^2+x^1+1
	int C[8]={1,1,1,1,0,0,1,1}; //注意:最后一个一定不能为0,即C[n]=1 为什么
	LSFR lfsr8(C,8); //按指定的系数构造线性反馈移位寄存器

	int a[8]={1,0,0,1,0,0,1,1}; //设置寄存器的值
	lfsr8.SetA(a);
	//以下输出255个寄存器的值,即 a1,a2,..., a255
	int j = 0;
	for (int i = 0; i < 256; i++){
		std::cout<<lfsr8.out();//输出
		j++ ;
		if (j == 8){
			j = 0; 
			std::cout<<std::endl;//输出
		}

	} 

}


void TestRc4String() {
	char* key = "this is Rc4's key for RC4 Encript test.这里是RC4的密钥,用于测试用!";
	int len = strlen(key);
	
	RC4 rc4;  //声明一个RC4对象
	rc4.SetKey(key, len); //设置密钥
	std::string m;
    std::cout << "输入明文字符串: ";
	std::cin.ignore();
	std::getline(std::cin, m);
	std::cout << m<<std::endl;
	char* c = new char[100];
	char* m2 = new char[100];
	bool bOk=rc4.EncryptString(m.c_str(), c);
	std::cout << (bOk ? "加密成功!" : "加密失败!") << std::endl;
	printf("密文为");
	printf(c);
	printf("\n");
	rc4.Ini();
	bool bOk2 = rc4.EncryptString(c,m2);
	std::cout << (bOk2 ? "解密成功!" : "解密失败!") << std::endl;
	printf("明文为");
	printf(m2);
	printf("\n");
	



	int p;
	std::cin >> p;
}

int _tmain(int argc, _TCHAR* argv[])
{
    std::cout << "RC4加密:请选择加密字符串或流文件:"<<std::endl;
	std::cout << "1、加密解密字符串 2、加密流文件 3、解密流文件" << std::endl;
	int a;
	std::cin >> a;
	if (a == 1) {
		TestRc4String();
		int p;
		std::cin >> p;
	}
	else if (a == 2) {
		testRc4a(); //测试RC4
	}
	else if (a == 3) {
		testRc4b();
	}
		
	
	return 0;
}

头文件

1、线性移位寄存器LFSR

#pragma once
class LSFR
{
public:
	LSFR(int *C, int n); // 以初始参数,构造一个n级线性移位寄存器
	~LSFR(void);         // 由于是动态分配内存(系统C及寄存器),故在析构函数中进行释放
private:
	
	int n;  // n级
	int* C; // 反馈系统,教科书为C[1]-C[n],
	        // 为了和教科书一致,分配内在时 c=new int[n+1],
	        // 以便获得C[1]-C[n], 而C[0]
	int* a; // 寄存器 a[n]-a[1]
public:
	void SetA(int *a);
	int out(void);
};


2、RC4

#pragma once
/*  RC4流密码
    author:huchaoju@163.com
	date:2021-12-12
*/
class RC4
{
public:
	RC4(void);
	RC4(char* k, int len);//
	~RC4(void);


private:

	unsigned char  m_i, m_j; //两个变量,用于在密钥流(这里是字节)产生过程中两个i,j
			   //为避免和临时变量i,j混淆,这里加入了前缀m_, 意即(member) 成员_xxx
			   //在密钥调度算法中进行初始化,之所以声明为unsigned char, 为了程序方便
	unsigned char S[256]; //S表,要初始化为S[i]=i
	unsigned char K[256]; //密钥,当密钥长度<256时,要重复填入
	void KSA();//密钥调度算法 key-scheduling algorithm, i.e. KSA

public:
	void SetKey(char* k, int len); //设置密钥
	void Ini(void);// 在加、解密之前进行初始化:即进行密钥调度!
	unsigned char Get(void);//获取密钥流的一个字节

	//源文件(srcFileName)加密成目标文件(desFileName)
	bool EncryptFile(const char* srcFileName, const char* desFileName);
	bool EncryptString(const char* m,char* c);
};


3、stdafx.h : 标准系统包含文件的包含文件

#pragma once

#include "targetver.h"

#include <stdio.h>
#include <tchar.h>



// TODO: 在此处引用程序需要的其他头文件

4、 SDKDDKVer.h: 定义可用的最高版本的 Windows 平台。

#pragma once
// 如果要为以前的 Windows 平台生成应用程序,请包括 WinSDKVer.h,并将
// WIN32_WINNT 宏设置为要支持的平台,然后再包括 SDKDDKVer.h。

#include <SDKDDKVer.h>

RC4和LFSR类函数的实现

1、LFSR类函数:LFSR.cpp

#include "StdAfx.h"
#include "LSFR.h"


LSFR::LSFR(int *C, int n)
{
	this->n = n; //类成员变量this->n, 被赋予n
	this->C = new int[n+1]; //反馈系数,多申请了一个,目的:教科书式的采用C[1]-C[n]
	a = new int[n+1]; //寄存器,多申请了一个,目的:教科书式的采用a[1]-a[n]
	
	for (int i =0 ; i < n; i++)
	{
		this->C[i+1] = C[i];
	}
}

LSFR::~LSFR(void)
{
	//释放内存
	delete[] C;
	delete[] a; 
}

//设置寄存器的初始值
void LSFR::SetA(int *a){
	for (int i=0; i<n; i++){
		this->a[i+1] = a[i]; //没错:按照教科书式的表示,类中表示的是a[1]-a[n]
	}
}


int LSFR::out(void)
{	
	int an1=0;  //An+1, 下标n+1
	//以下计算:An+1=a1Cn⊕a2Cn-1⊕...⊕anC1
	for (int i = 1; i <= n; i++)
	{
		an1 ^= a[i] * C[n-i+1]; 
	}

	//a[n]->a[n-1]->...->a[1](->a[0])
	//进行移位!
	for (int i = 0; i <= n; i++){
		a[i] = a[i+1];
	}

	a[n] = an1; //将计算的值存入a[n]

	return a[0];
}

2、RC4类函数:RC4.cpp

#include "StdAfx.h"
#include "RC4.h"
#include <utility>  //std::swap
#include <iostream> // std::cout
#include <fstream> //std::ifstream, std::ofstream
typedef unsigned char BYTE;

RC4::RC4(void)
{
}

RC4::RC4(char *key, int len)
{
	SetKey(key,len);
}


RC4::~RC4(void)
{
}

void RC4::SetKey(char *key, int len){
	
	//重复将密钥填入K数组,并:
	int j = 0; 
	for(int i = 0; i < 256; i++){
		K[i] = key[j];
		if(j == len){
			j = 0; 
		}
	}
	//上面语句也可以为以下形式:
	/*
	for(int i=0; i<256; i++){
		K[i]=key[i%len];
	}
	*/
}

//密钥调度算法
void RC4::KSA(){
	for (int i = 0; i <256; i++) //初始化S[0]-S[255]
	{
		S[i] = i; // 即为 S[i] = (unsigned char)i;
	}
	//在初始化完了K[0]-K[255]后调用,或在新的加密开始时进行调用。

	int j = 0; 
	for (int i = 0; i < 256; i++)
	{
		j = (j + S[i] + K[i]) % 256;
		std::swap(S[i], S[j]);
	}
	m_i = m_j = 0; 

}


// 在加、解密之前进行初始化:即进行密钥调度!
void RC4::Ini(void)
{
	KSA();
}


unsigned char RC4::Get(void)
{
	//注:m_i,m_j为成员变量,已在KSA()中进行了初始化
	//由于m_i声明为unsigned char, 即 m_i在0-255中增一循环,i.e. m_i=(m_i+1) % 256;
	m_i++; 
	m_j += m_j + S[m_j]; //i.e. m_j = (m_j+S[m_j]) % 256; 
	std::swap(S[m_i], S[m_j]);
	unsigned t = S[m_i] + S[m_j]; //i.e. t=S[m_i]+S[m_j] mod 256; 
	return S[t]; //返回一个字节作为密钥流的一部分
}


bool RC4::EncryptFile(const char *srcFileName, const char* desFileName)
{
	std::ifstream is (srcFileName, std::ifstream::binary);
	if (!is) return false; //为读打开文件失败,则返回

	std::ofstream os (desFileName,std::ofstream::binary);
	if (!os){//为写打开目标失败,则返回
		is.close();
		return false; 
	}
	//获取文件长度:
	is.seekg (0, is.end);    // 定位到文件尾部
	int length = is.tellg(); // 取得文件长度
	is.seekg (0, is.beg);    // 再定位到文件头 
	// 分配内存
	char* buffer = new char [length];
	is.read (buffer,length); // 一次性将文件读入缓冲区,这里是明文plainText
	is.close(); //文件使用完毕,关掉!

	//以下准备加密的密文缓冲区,由于是流密码,不需要填充,因此:密文长度与明文长度一致
	char* cipher =  new char [length];
	KSA();//密钥调度,即加密归零,也即 this->Ini();
	//逐字节XOR
	for (int i=0; i < length; i++){
		char ki=Get(); //获取密钥(流的一个字节);
		cipher[i] = buffer[i] ^ ki; //XOR
	}

	//将密文写入文件
	os.write (cipher,length);
	os.close(); //将目标文件关闭!
	
	//将动态分配的内在释放:
	delete[] buffer;
	delete[] cipher;
	return true;
}
bool RC4::EncryptString(const char* m,char* c) {
	Ini();
	int n = strlen(m);
	for (int i = 0; i < n; i++) {
		char key = Get();
		c[i] = m[i] ^ key;
	}
	c[n] = 0;
	return true;
}

3、 stdafx.cpp : 只包括标准包含文件的源文件


// streamcipher.pch 将作为预编译头
// stdafx.obj 将包含预编译类型信息

#include "stdafx.h"

// TODO: 在 STDAFX.H 中
// 引用任何所需的附加头文件,而不是在此文件中引用

  • 5
    点赞
  • 29
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值