主函数
实现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 中
// 引用任何所需的附加头文件,而不是在此文件中引用