java实现DES加解密算法

来源:互联网 发布:高清网络摄像机方案 编辑:程序博客网 时间:2024/05/22 06:08

以下是我用java实现的DES算法,实现中可能存在一点问题自己没空去找,但我觉得DES的算法过程肯定没错!现在暂时没时间去找到底是哪里的问题,有空再瞧瞧自己的代码喽!

makekey.java是生成密钥以及子密钥


import java.util.Random;


public class makekey {
 Random rand=new Random();
 byte[] skey=new byte[64];
 static byte[][] key=new byte[16][48];
 static byte[] lun={1,1,2,2,2,2,2,2,1,2,2,2,2,2,2,1};
 static byte[] keyex={13,16,10,23,0,4,2,27,14,5,20,9,
         22,18,11,3,25,7,15,6,26,19,12,1,
         40,51,30,36,46,54,29,39,50,44,32,47,
         43,48,38,55,33,52,45,41,49,35,28,31};
 byte[] keyzuoyou=new byte[56];
 byte[] keyyou=new byte[28];
 byte[] keyzuo=new byte[28];
public makekey(){//
 findskey();////
 cutskey(keyzuoyou);////
 makesonkey();//??////
}
public void makesonkey(){//产生16个子密钥
 for(int l=0;l<16;l++){
  cut();
  xhzlkey(keyzuo,lun[l]);
  xhzlkey(keyyou,lun[l]);
  he();
  huodzmy(keyzuoyou,key[l]);
 }
 
}
public void huodzmy(byte[] byt,byte[] zmy){
 for(int k=0;k<zmy.length;k++)
  zmy[k]=byt[keyex[k]];
}
public void cut(){//将56位密钥分成左右各28位的密钥用于循环左移
 for(int l=0;l<28;l++)
  keyzuo[l]=keyzuoyou[l];
    for(int k=28,n=0;k<56;k++){
     keyyou[n]=keyzuoyou[k];
     n++;
    }
}
public void xhzlkey(byte[] byt,int num){//实现循环左移
 byte[] temp=new byte[num];
 for(int k=0;k<num;k++)
  temp[k]=byt[k];
 for(int l=0;l<byt.length-num;l++){
  byt[l]=byt[l+num];
 }
 for(int m=byt.length-1,g=num-1;g>=0;g--)
  {
  byt[m]=temp[g];
  m--;
  }
 //outzmy(byt);///test
}
public void he(){//将经过循环左移后的左右各28位密钥合并
 for(int l=0;l<28;l++)
  keyzuoyou[l]=keyzuo[l];
    for(int k=28,n=0;n<28;n++){
     keyzuoyou[k]=keyyou[n];
     k++;
    }
}
public static void outzmy(byte[] byt){//用于显示子密钥的代码
 System.out.println("$$");
for(int p=0;p<byt.length;p++)
{
 if(p%8==0)
  System.out.print("\n");
 System.out.print(byt[p]);
}
}
/*public void outckey(byte[] byt){
 for(int k=1;k<=byt.length;k++){
  if((k-1)%7==0)
   System.out.print("\n");
  System.out.print(byt[k-1]);
 }
}*/
public void cutskey(byte[] byt){//去掉无用的校验位得到56位的有用初始化的key
   for(int i=0,l=0;i<64;i++){
    if((i+1)%8==0)
     continue;
    byt[l]=skey[i];
    l++;
   }
}
public void findskey(){//产生随机的64位密钥,包含8位校验位
 for(int i=0;i<64;i++){
  if((i+1)%8==0){
   int k=i,l=k-7,num=0;
   while(k>=l){
    if(skey[k]==1)
     num++;
    k--;
   }
   if(num%2==0)
    skey[i]=1;
   else
    skey[i]=0;
   continue;
   
  }
  skey[i]=(byte)rand.nextInt(2);
 }
 /*for(int p=0;p<64;p++)
 {
  if(p%8==0)
   System.out.print("\n");
  System.out.print(skey[p]);
 }*/
}

/*public static void main(String[] args) {
 // TODO Auto-generated method stub
 new makekey();
}*/
}

mingwen.java是加解密过程中明文对应的处理逻辑


public class mingwen {
static byte[] mingex={57,49,41,33,25,17,9,1,59,51,43,35,27,19,11,3,
  61,53,45,37,29,21,13,5,63,55,47,39,31,23,15,7,
  56,48,40,32,24,16,8,0,58,50,42,34,26,18,10,2,
  60,52,44,36,28,20,12,4,62,54,46,38,30,22,14,6};//初次置换用到的转换表
static byte[] exxming={39,7,47,15,55,23,63,31,38,6,46,14,54,22,62,30,
  37,5,45,13,53,21,61,29,36,4,44,12,52,20,60,28,
  35,3,43,11,51,19,59,27,34,2,42,10,50,18,58,26,
  33,1,41,9,49,17,57,25,32,0,40,8,48,16,56,24};//最后置换用到的转换表
public static byte[] mingwenex(byte[] byt,byte[] exming,boolean ischu){//初次和最后用到的转换实现
 if(ischu)
 for(int j=0;j<byt.length;j++)
  exming[j]=byt[mingex[j]];
 else
  for(int j=0;j<byt.length;j++)
   exming[j]=byt[exxming[j]];
 return exming;//
}
public static byte[] cutmingzuo(byte[] byt,byte[] mingzuo){//初次分割明文用到该功能
 for(int k=0;k<mingzuo.length;k++)
  mingzuo[k]=byt[k];
 return mingzuo;//
}
public static byte[] cutmingyou(byte[] byt,byte[] mingyou){//初次分割明文用到该功能
 for(int v=32;v<byt.length;v++)
  mingyou[v-32]=byt[v];
 return mingyou;//
}
public static byte[] heming(byte[] mingzuo,byte[] mingyou,byte[] byt){//最后用于合并16轮变换后的密文
   for(int b=0;b<mingzuo.length;b++)
    byt[b]=mingzuo[b];
   for(int y=0;y<mingyou.length;y++)
    byt[32+y]=mingyou[y];
   return byt;//
}
public static byte[] getmingyou(byte[] byt,byte[] mingyou){//将明文右半部分扩展成48位的mingyou
 int num=0,k=0,b=0;
 while(num<8){
  for(int i=k+1,m=b;i<5+k;i++,m++)
   mingyou[i]=byt[m];
  num++;
  k+=6;b+=4;
 }
 for(int g=3,n=6;g<=27;g+=4,n+=6)
  mingyou[n]=byt[g];
 for(int b1=4,c=5;b1<=28;b1+=4,c+=6)
  mingyou[c]=byt[b1];
 mingyou[0]=byt[31];
 mingyou[47]=byt[0];
 return mingyou;//
}

}
jiajiem.java是DES加解密过程的逻辑功能实现


public class jiajiem {
 byte[] phe={15,6,19,20,28,11,27,16,0,14,22,25,4,17,30,9,1,7,23,13,31,26,2,8,18,12,29,5,21,10,3,24};

 byte[] shimingwen=new byte[64];//初始要加密的64位明文串
 byte[] tempming=new byte[64];//经过16轮操作后合并的中间密文串
 byte[] miwen=new byte[64];//最终得到的密文
 byte[] mingzuo=new byte[32];//用于保存操作过程产生的32左明文
 byte[] mingtemp=new byte[32];//一轮完后用于保存交换左右明文的中间量
 byte[] sout=new byte[32];//用于保存经过S盒后的输出
 byte[] pout=new byte[32];//用于保存经过P盒后的输出
 byte[] mingyou=new byte[32];//用于保存操作过程产生的32右明文
 byte[] mingyouex=new byte[48];//用于保存操作过程产生的扩展的48位右明文
 byte[] miwenuse=new byte[64];//need it to co
 public jiajiem(byte[] mingwenbyt,boolean isen){
 if(isen)
  en(mingwenbyt);
 else
  co(mingwenbyt);
}
 public void co(byte[] mingwenbyt){
  System.out.println("现在是在解密!");//
  int num=0;
  fuzhi(mingwen.mingwenex(mingwenbyt,shimingwen, true),shimingwen);//初次的简单明文置换操作
  fuzhi(mingwen.cutmingzuo(shimingwen, mingzuo),mingzuo);//将明文分割成左右明文
  fuzhi(mingwen.cutmingyou(shimingwen, mingyou),mingyou);//将明文分割成左右明文
  while(num<16){
  fuzhi(mingwen.getmingyou(mingyou, mingyouex),mingyouex);//扩展32位的右明文为48位用于和子密钥进行异或
  fuzhi(xor(makekey.key[15-num],mingyouex),mingyouex);
  fuzhi(S(mingyouex,sout),sout);
  fuzhi(P(sout,pout),pout);
  fuzhi(mingyou,mingtemp);
  fuzhi(xor(mingzuo,pout),pout);
  fuzhi(pout,mingyou);///
  fuzhi(mingtemp,mingzuo);
  num++;//so
 }
  fuzhi(mingwen.heming(mingzuo, mingyou,tempming),tempming);
  fuzhi(mingwen.mingwenex(tempming,miwen,false),miwen);//第二次的简单中间密文置换操作
  fuzhi(outmiwen(miwen),miwenuse);//为了输出解密后的字符串
 }
 public void en(byte[] mingwenbyt){
  System.out.println("现在是在加密!");//
  int num=0;
  fuzhi(mingwen.mingwenex(mingwenbyt,shimingwen, true),shimingwen);//初次的简单明文置换操作
  fuzhi(mingwen.cutmingzuo(shimingwen, mingzuo),mingzuo);//将明文分割成左右明文
  fuzhi(mingwen.cutmingyou(shimingwen, mingyou),mingyou);//将明文分割成左右明文
  while(num<16){
  fuzhi(mingwen.getmingyou(mingyou, mingyouex),mingyouex);//扩展32位的右明文为48位用于和子密钥进行异或
  fuzhi(xor(makekey.key[num],mingyouex),mingyouex);
  fuzhi(S(mingyouex,sout),sout);
  fuzhi(P(sout,pout),pout);
  fuzhi(mingyou,mingtemp);
  fuzhi(xor(mingzuo,pout),pout);
  fuzhi(pout,mingyou);//
  fuzhi(mingtemp,mingzuo);
  num++;//so
  }
  fuzhi(mingwen.heming(mingzuo, mingyou,tempming),tempming);
  fuzhi(mingwen.mingwenex(tempming,miwen,false),miwen);//第二次的简单中间密文置换操作
  fuzhi(outmiwen(miwen),miwenuse);//为了解密方便
 }
 public static byte[] outmiwen(byte[] byt){
  for(int k=0;k<byt.length;k++)
   System.out.print(byt[k]);
  return byt;
 }
public void fuzhi(byte[] from,byte[] to){
 for(int h=0;h<from.length;h++)
  to[h]=from[h];
}
public void fuzhif(byte[] from,byte[] to,int num){
 for(int h=num;h<num+4;h++)
  to[h]=from[h];
}
public byte[] xor(byte[] zmy,byte[] youmw){//实现子密钥和右明文的异或操作,同时实现左明文和经过p盒置换的右明文串进行置换
 for(int i=0;i<zmy.length;i++){
  if(zmy[i]==youmw[i])
   youmw[i]=0;
  else
   youmw[i]=1;
 }
 return youmw;
}
public byte[] S(byte[] xorming,byte[] pming){//实现s的操作,将其转换到p盒前的状态
 int num=0,k=0,m=0;
 byte hang,lie;
 while(num<8){
  hang=(byte)(2*(xorming[k])+xorming[k+5]);
  lie=(byte)(Math.pow(2,3)*xorming[k+1]+Math.pow(2,2)*xorming[k+2]+2*xorming[k+3]+xorming[k+4]);
  fuzhif(erjztobyt(s[num][hang][lie],pming,m),pming,m);///4important
  k+=6;//
  m+=4;
  num++;
 }
 //makekey.outzmy(pming);///test find the pming is have shu ju;
 return pming;//
}
public byte[] P(byte[] pqian,byte[] phou){
 for(int h=0;h<pqian.length;h++)
  phou[h]=pqian[phe[h]];
 return phou;//
}
public byte[] erjztobyt(byte byt,byte[] bb,int num){//从num开始的下标将所得到的的二进制数分别复制到bb
 int xx=3,k=0;
 while(xx>=0){
  if(Math.pow(2, xx)>byt){
   bb[num+k]=0;
   xx--;
   k++;
  }
  else if(Math.pow(2,xx)<byt){
   bb[num+k]=1;
   byt-=Math.pow(2,xx);
   xx--;
   k++;
  }
  else{
   bb[num+k]=1;
   xx--;
   while(xx>=0){///
    k++;
    bb[num+k]=0;
    xx--;
   }
  }
 }
 return bb;
}
byte[][][] s={
  {
 {14,4,13,1,2,15,11,8,3,10,6,12,5,9,0,7},

 {0,15,7,4,14,2,13,1,10,6,12,11,9,5,3,8},

 {4,1,14,8,13,6,2,11,15,12,9,7,3,10,5,0},

 {15,12,8,2,4,9,1,7,5,11,3,14,10,0,6,13}},
   {
 {15,1,8,14,6,11,3,4,9,7,2,13,12,0,5,10},

 {3,13,4,7,15,2,8,14,12,0,1,10,6,9,11,5},

 {0,14,7,11,10,4,13,1,5,8,12,6,9,3,2,15},

 {13,8,10,1,3,15,4,2,11,6,7,12,0,5,14,9}},
   {
 {10,0,9,14,6,3,15,5,1,13,12,7,11,4,2,8},

 {13,7,0,9,3,4,6,10,2,8,5,14,12,11,15,1},

 {13,6,4,9,8,15,3,0,11,1,2,12,5,10,14,7},

 {1,10,13,0,6,9,8,7,4,15,14,3,11,5,2,12}},
   {
 {7,13,14,3,0,6,9,10,1,2,8,5,11,12,4,15},

 {13,8,11,5,6,15,0,3,4,7,2,12,1,10,14,9},

 {10,6,9,0,12,11,7,13,15,1,3,14,5,2,8,4},

 {3,15,0,6,10,1,13,8,9,4,5,11,12,7,2,14}},
   {
 {2,12,4,1,7,10,11,6,8,5,3,15,13,0,14,9},

 {14,11,2,12,4,7,13,1,5,0,15,10,3,9,8,6},

 {4,2,1,11,10,13,7,8,15,9,12,5,6,3,0,14},

 {11,8,12,7,1,14,2,13,6,15,0,9,10,4,5,3}},
   {
 {12,1,10,15,9,2,6,8,0,13,3,4,14,7,5,11},

 {10,15,4,2,7,12,9,5,6,1,13,14,0,11,3,8},

 {9,14,15,5,2,8,12,3,7,0,4,10,1,13,11,6},

 {4,3,2,12,9,5,15,10,11,14,1,7,6,0,8,13}},
   {
 {4,11,2,14,15,0,8,13,3,12,9,7,5,10,6,1},

 {13,0,11,7,4,9,1,10,14,3,5,12,2,15,8,6},

 {1,4,11,13,12,3,7,14,10,15,6,8,0,5,9,2},

 {6,11,13,8,1,4,10,7,9,5,0,15,14,2,3,12}},
   {
 {13,2,8,4,6,15,11,1,10,9,3,14,5,0,12,7},

 {1,15,13,8,10,3,7,4,12,5,6,11,0,14,9,2},

 {7,11,4,1,9,12,14,2,0,6,10,13,15,3,5,8},

 {2,1,14,7,4,10,8,13,15,12,9,0,3,5,6,11}}};

}
Main.java是程序的入口

import java.util.Scanner;

import java.util.Scanner;


public class Main {
 Scanner scan=new Scanner(System.in);
 String code;
 makekey key=new makekey();//产生子密钥
 public Main(){
  System.out.println("请输入要加密的字符串!");
  code=scan.nextLine();
  while(code.charAt(0)!='0'){
   String str=strtoerjz(code);
   byte[] byt=new byte[str.length()];
   for(int k=0;k<byt.length;k++)
    byt[k]=(byte)(str.charAt(k)-'0');
   System.out.println("加密前其对应的unicode码(二进制)是:\n"+str);
   System.out.println("加密后其对应的二进制是:\n");
   jiajiem jia=new jiajiem(byt,true);
   System.out.println("\n解密后对应的二进制是:\n");
   jiajiem jie=new jiajiem(jia.miwenuse,false);
   System.out.println("\n解密得到的二进制转换成字符串是:"+erjztostr(jie.miwenuse));///$$
   System.out.println("\n请输入要加密的字符串!");
   code=scan.nextLine();
  }
 }
public String erjztostr(byte[] byt){
 System.out.println();
  String str="";short temp=0;
  for(int i=0,num=0;i<byt.length;i++){
   temp+=Math.pow(2,15-i+num)*byt[i];
   if((i+1)%16==0){
    str+=(char)temp;
    //System.out.println(temp);///
    temp=0;
    num+=16;
   }
  }
  return str;
  
 }
public String strtoerjz(String str){
 short temp;
 byte shiliu=15;
 String erjz="";
 for(int i=0;i<str.length();i++){
  temp=(short)str.charAt(i);
  while(shiliu>=0){
   if(Math.pow(2,shiliu)<temp){
    erjz+='1';
    temp-=Math.pow(2, shiliu);
    shiliu--;
   }
   else if(Math.pow(2, shiliu)>temp){
    erjz+='0';
    shiliu--;
   }
   else{
    erjz+='1';
    shiliu--;
    while(shiliu>0){
     erjz+='0';
     shiliu--;
    }
   }
  }
  shiliu=15;
 }
 return erjz;
}
 public static void main(String[] args) {
  // TODO Auto-generated method stub
new Main();

 }

}


运行截图:

注:由于DES一次只能加密一个64位的块,而java中一个字符占16位,所以刚好是4个字符构成一次加解密要的64位,本程序中只考虑了一次4位字符的加解密情况,如果想一下加解密很多的字符请在Main.java中做相应改动!