这次是RC6加解密算法。RC6继承了RC5的优点,在加密过程中不需要查表,加上算法中的乘法运算可以用平方代替,所以该算法对内存要求极低,这使得RC6适合在单片机上实现。至于RC6的安全性,对RC6最为有效的攻击是强力攻击。但由于分组长度和密钥都至少是128bit,穷举法并不可行。对20轮的RC6,用线性分析法至少需要2^155个明文,用查分分析法至少需要2^238个明文。
RC6分组长度为128bit,使用了4个寄存器,并使用32bit的整数模乘运算,用于加强扩散特性。RC6更精确的表示是RC6-w/r/b,其中字长为w bit,r为加密轮数,b为加密密钥用字节表示的长度。通常令w=32,r=20,b=16(24,32)。
加密过程:(把128bit明文放入4个32bit的寄存器A、B、C、D中)
B=B+S[0] (S为密钥)
D=D+S[1]
for i=1 to r do
t=ROL(B*(2B+1),log2w)
u=ROL(D*(2D+1),log2w)
A=ROL(A⊕t,u)+S[2i]
C=ROL(C⊕u,t)+S[2i+1]
(A,B,C,D)=(B,C,D,A)
A=A+S[2r+2]
C=C+S[2r+3]
A、B、C、D即为密文。
解密过程:(把128bit密文放入4个32bit的寄存器A、B、C、D中)
C=C-S[2r+3]
A=A-S[2r+2]
for i=r down to 1 do
(A,B,C,D)=(D,A,B,C)
u=ROL(D*(2D+1),log2w)
t=ROL(B*(2B+1),log2w)
C=ROR(C-S[2i+1],t)⊕u
A=ROR(A-S[2i],u)⊕t
D=D-S[1]
B=B-S[0]
A、B、C、D即为明文。
密钥扩展方案:(在密钥扩展中用到两个常数P、Q,P=0xB7E15163,Q=0x9E3779B9。
首先,将用户密钥输入到c个w比特字的L[0],...,L[c-1]阵列,若不够,用0字节填充,其中c为8b/w的整数部分)
个人理解:每个L阵列可以存放4个字符,即若c为4时,密钥密钥最长为16个字符。
S[0]=P
for i=1 to 2r+3 do
S[i]=S[i-1]+Q
用户密钥混合到S中
A=B=i=j=0
v=3*max{c,2r+4}
for s=1 to v do循环体循环v次
A=S[i]=ROL(S[i]+A+B,3)
B=L[j]=ROL(L[j]+A+B,A+B)
i=(i+1)mod(2r+4)
j=(j+1)modc
输出S[0],S[1],...,S[2r+3]即为子密钥
个人心得:1、将需要处理的数据统一当做十六进制运算,输入字符的asc码可以通过位移运算处理成十六进制
2、int型和unsigned int最高都可以存放0xffffffff,但前者的第一位(二进制)表示正负,后者才是真正的0xffffffff
3、<<和>>表示左移和右移(二进制,十进制的话相当于乘上2的n次方),是不循环的!左移末尾补0,右移前端补1!
(这些都是这次编程中困扰过我的问题,对这些概念不清楚或者解密逆不回去的童鞋也请留意一下哦~)
下面贴一波代码
#include
#include
#include
const unsigned int r=20;
const unsigned int w=32;
const unsigned int b=16;
const unsigned int c=4;
const unsigned int p=0xb7e15163;
const unsigned int q=0x9e3779b9;
unsigned int moveleft(unsigned int x,unsigned int y);
unsigned int moveright(unsigned int x,unsigned int y);
void keyextend(unsigned int *s,unsigned int *l);
void encryp(unsigned int *A,unsigned int *B,unsigned int *C,unsigned int *D,unsigned int *S);
void decryp(unsigned int *A,unsigned int *B,unsigned int *C,unsigned int *D,unsigned int *S);
unsigned int moveleft(unsigned int x,unsigned int y)
{
unsigned int i,temp;
if(y/32!=0)
y=y%32;
for (i=0; i>31)&0x00000001);
}
return x;
}
unsigned int moveright(unsigned int x,unsigned int y)
{
unsigned int i,temp;
if(y/32!=0)
y=y%32;
for (i=0; i>1;
x=(x&0x7fffffff)+(temp<<31);
}
return x;
}
void keyextend(unsigned int *s,unsigned int *l)
{
unsigned int i,j,k,a,b;
s[0]=p;
for (i=1; i<=43; i++)
s[i]=s[i-1]+q;
a=0;
b=0;
i=0;
j=0;
for (k=1; k<=132; k++)
{
s[i]=s[i]+a+b;
s[i]=moveleft(s[i],3);
a=s[i];
l[j]=l[j]+a+b;
l[j]=moveleft(l[j],(a+b));
b=l[j];
i=(i+1)%44;
j=(j+1)%4;
}
}
void encryp(unsigned int *A,unsigned int *B,unsigned int *C,unsigned int *D,unsigned int *S)
{
int i,j,t,u,temp;
*B=*B+S[0];
*D=*D+S[1];
j=(unsigned int)(log(w)/log(2));
for (i=1; i<=r; i++)
{
t=moveleft(((*B)*(2*(*B)+1)),j);
u=moveleft(((*D)*(2*(*D)+1)),j);
temp=moveleft(((*A)^t),u);
*A=temp+S[2*i];
temp=moveleft(((*C)^u), t);
*C=temp+S[2*i+1];
temp=*A;
*A=*B;
*B=*C;
*C=*D;
*D=temp;
}
*A=*A+S[2*r+2];
*C=*C+S[2*r+3];
}
void decryp(unsigned int *A,unsigned int *B,unsigned int *C,unsigned int *D,unsigned int *S)
{
unsigned int i,j,u,t,temp;
j=(unsigned int)(log(w)/log(2));
*C=*C-S[2*r+3];
*A=*A-S[2*r+2];
for (i=r; i>=1; i--)
{
temp=*D;
*D=*C;
*C=*B;
*B=*A;
*A=temp;
u=moveleft(((*D)*(2*(*D)+1)),j);
t=moveleft(((*B)*(2*(*B)+1)),j);
temp=moveright(((*C)-S[2*i+1]),t);
*C=temp^u;
temp=moveright(((*A)-S[2*i]), u);
*A=temp^t;
}
*D=*D-S[1];
*B=*B-S[0];
}
int main()
{
int ch;
unsigned int A,B,C,D,S[2*r+4],L[c]={0};
char plaintxt[16]={0},key[c*4],ciphertxt[16]; //plaintxt接收明文,key接收用户密钥,cipertxt存放解密后明文
unsigned int i,j,temp,keylong;
char g;
printf("请输入选择:1.文件读写(从a.txt里读出明文,把密文写入b.txt,解密后写入c.txt) 2.键盘读入文件 \n");
scanf("%d",&ch);
getchar();//缓冲回车符
if(ch==1)
{
FILE *fp1;
fp1=fopen("/Users/air/Documents/a.txt","r");
if (!fp1) {
printf("wrong1");
return 0;
}
for(i=0;i<16;i++)
{
g=fgetc(fp1);
if (g==' ')
g=fgetc(fp1);
else if(g=='\n'||g==EOF)
{
break;
}
plaintxt[i]=g;
}
fclose(fp1);
}
else
{
printf("请输入明文\n");
for(i=0;i<16;i++)
{
g=getchar();
if (g==' ')
g=getchar();
else if(g=='\n')
break;
plaintxt[i]=g;
}
if(i==16)
getchar(); //缓冲回车符
}
printf("请输入密钥\n");
for(i=0;i<16;i++)
{
g=getchar();
if (g==' ') {
g=getchar();
}
else if (g=='\n')
break;
key[i]=g;
}
keylong=i;
j=0;
for (i=0; i>24)&0xff;
ciphertxt[1]=((A&0xff0000)>>16)&0xff;
ciphertxt[2]=((A&0xff00)>>8)&0xff;
ciphertxt[3]=A&0xff;
ciphertxt[4]=((B&0xff000000)>>24)&0xff;
ciphertxt[5]=((B&0xff0000)>>16)&0xff;
ciphertxt[6]=((B&0xff00)>>8)&0xff;
ciphertxt[7]=B&0xff;
ciphertxt[8]=((C&0xff000000)>>24)&0xff;
ciphertxt[9]=((C&0xff0000)>>16)&0xff;
ciphertxt[10]=((C&0xff00)>>8)&0xff;
ciphertxt[11]=C&0xff;
ciphertxt[12]=((D&0xff000000)>>24)&0xff;
ciphertxt[13]=((D&0xff0000)>>16)&0xff;
ciphertxt[14]=((D&0xff00)>>8)&0xff;
ciphertxt[15]=D&0xff;
if(ch==1)
{
FILE *fp3;
fp3=fopen("/Users/air/Documents/c.txt", "w");
if(!fp3)
{
printf("wrong3");
return 0;
}
for(i=0;i<16;i++)
{
if(ciphertxt[i]==0)
break;
fprintf(fp3,"%c",ciphertxt[i]);
}
fclose(fp3);
}
else
{
printf("解密后:\n");
for(i=0;i<16;i++)
{
if(ciphertxt[i]==0)
{
printf("\n");
break;
}
printf("%c",ciphertxt[i]);
}
}
return 0;
}
运行截图:
a.txt
b.txt
c.txt
键盘读入明文加解密
注:1、明文接收时我把空格处理掉了,如果需要空格请自行改相关部分
2、明文和密文可以不足需要的长度,但如果超过也没影响,反正没接收。。
3、这篇代码是在Xcode上写的,搬到其他编译器可能会出现水土不服,比如初始化数组长度时会报错,把const那部分改成define或者写死数据应该就能解决了,吧。。