这个程序有相当大的问题,由于这个实验要交了,就没有往下做,交了个有问题的程序上去,要做的事是这样的:先构造一个64的全0的二进制字符串,然后用加盐后的密码作为密钥对这个数据块进行DES加密,将加密计算出的结果保存,将用户名,盐值,结果保存,然后用户验证的时候,先看用户存在不,存在的话就取相应的盐值和用户输入的密码用相同的方式加密,将结果与保存的结果比较,相同的话就验证成功。
然后自己没有用过什么密钥空间,什么密钥构造的类什么的,都是看的文档,自己摸索着用的那些方法,所以应该使用方式不太对,然后就是编码的时候,可能对什么字符,字节,之类的概念混乱,导致编码后总是不能得到以前的盐值,然后就会抛出异常,说Salt只能是8字节的……反正每次都提示这个错,而且都是在用户验证时,到输入密码后抛出的异常,有次很偶然居然顺利验证成功了,就截图写报告了,还有就是验证时取盐值输出时,后面有一大段空白……如果各位有时间能亲自运行下就能理解我的意思了……我强行加了substring(0,5),我不太明白默认的编码后的字符解码后怎么不一样了……
class PBECoder:口令管理信息的生成
class Base64:实现位串变换。
class Agen:实现用户注册,将用户名,盐值和加密后的信息保存在passwd.txt文本文件中
class Test:实验用户口令验证,从passwd.txt中取出用户名,与输入比较,如果存在,则提示用户未注册,若用户存在,则取出相应的盐值,然后提示输入密码,将输入密码与相应的盐值生成加密后的信息,与passwd.txt中保存的信息比较,如果相同则验证通过,如果不相同,则验证未通过。
注释部分为程序设计过程中用于测试结果的中间输出
class PBECoder:主要完成加密的操作
import java.security.Key;
import java.security.SecureRandom;
import javax.crypto.Cipher;
import javax.crypto.SecretKey;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.PBEKeySpec;
import javax.crypto.spec.PBEParameterSpec;
public abstract class PBECoder
{
public static final String ALGORITHM="PBEWITHMD5andDES";
public static final int ITERATION_COUNT=25;
private static Key toKey(String password)throws Exception
{
PBEKeySpec keySpec=
new PBEKeySpec(password.toCharArray());//带有一个密码的构造方法,导出一个密钥
SecretKeyFactory keyFactory=SecretKeyFactory.getInstance(ALGORITHM);//返回转换DES的秘密密钥工厂
SecretKey secretKey=keyFactory.generateSecret(keySpec);//密钥材料生成SecretKey对象
return secretKey;
}
public static byte[] encrypt(String password,byte[] salt)//加密算法
throws Exception{
Key key=toKey(password);
byte[] data={0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0};
PBEParameterSpec paramSpec=new PBEParameterSpec(salt,ITERATION_COUNT);//基于密码的加密法构造一个参数集合
Cipher cipher=Cipher.getInstance(ALGORITHM);//返回实现DESCipher 对象cipher.init(Cipher.ENCRYPT_MODE,key,paramSpec);//用密钥和一组算法参数初始化此 Cipher
return cipher.doFinal(data);
}//加密数据
public static byte[] returnsalt(String password,byte[] salt)
throws Exception{
Key key=toKey(password);
byte[] data={0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0};
PBEParameterSpec paramSpec=new PBEParameterSpec(salt,ITERATION_COUNT);//基于密码的加密法构造一个参数集合
return paramSpec.getSalt();
}
}
---------------------------------------------------------------------------------------------------------------------
class Base64:主要完成字符串与字节的转换:(用的网上找的代码)
import java.io.UnsupportedEncodingException;
public class Base64 {
private static char[] base64EncodeChars = new char[] {
'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H',
'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P',
'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X',
'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f',
'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n',
'o', 'p', 'q', 'r', 's', 't', 'u', 'v',
'w', 'x', 'y', 'z', '0', '1', '2', '3',
'4', '5', '6', '7', '8', '9', '+', '/' };
private byte []Array=new byte[10000];
private byte []dArray=new byte[10000];
private byte []d1Array=new byte[10000];
private char []decode=new char[10000];
private int length=0;
public String encode(String str) throws UnsupportedEncodingException //编码
{
StringBuffer buf=new StringBuffer();
int sign=0;
int b1,b2,b3;
Array=str.getBytes();
length=Array.length;
sign=length/3;
int j=0;
for(int i=0;i<sign;i++)
{
b1=Array[j++]&0xff;
b2=Array[j++]&0xff;
b3=Array[j++]&0xff;
buf.append(base64EncodeChars[b1>>>2]);
buf.append(base64EncodeChars[((b1&0x3)<<4|(b2&0xf0)>>>4)]);
buf.append(base64EncodeChars[((b2&0x0f)<<2)|((b3&0xc0)>>>6)]);
buf.append(base64EncodeChars[b3&0x3f]);
}
sign=length%3;
if(sign==0)
return buf.toString();
else if(sign==1)
{
b1=Array[j]&0xff;
buf.append(base64EncodeChars[b1>>>2]);
buf.append(base64EncodeChars[(b1&0x3)<<4]);
buf.append("==");
return buf.toString();
}
else
{
b1=Array[j]&0xff;
b2=Array[j+1]&0xff;
buf.append(base64EncodeChars[b1>>>2]);
buf.append(base64EncodeChars[(((b1&0x3)<<4)|((b2&0xf0)>>>4))]);
buf.append(base64EncodeChars[(b2&0x0f)<<2]);
buf.append("=");
return buf.toString();
}
}
public String decode(String str) throws UnsupportedEncodingException //解码
{
int k=0;
int b1,b2,b3,b4;
decode=str.toCharArray();
for(int i=0;i<decode.length;i++)
{
if(decode[i]!=-1)
dArray[i]=Search(decode[i]);
else
break;
}
int flag;
int j=0;
flag=decode.length/4;
for(int i=0;i<flag-1;i++)
{
b1=dArray[j++];
b2=dArray[j++];
b3=dArray[j++];
b4=dArray[j++];
d1Array[k++]=(byte)((b1<<2)|((b2&0x30)>>>4));
d1Array[k++]=(byte)((b2<<4)|((b3&0x3c)>>>2));
d1Array[k++]=(byte)((b3<<6)|b4);
}
if(dArray.length%4==0)
{
b1=dArray[j++];
b2=dArray[j++];
b3=dArray[j++];
b4=dArray[j++];
d1Array[k++]=(byte)((b1<<2)|((b2&0x30)>>>4));
d1Array[k++]=(byte)((b2<<4)|((b3&0x3c)>>>2));
d1Array[k++]=(byte)((b3<<6)|b4);
}
else if(dArray.length%4==2)
b1=dArray[j];
d1Array[k]=(byte)(b1<<2);
}
else
{
b1=dArray[j++];
b2=dArray[j++];
b3=dArray[j];
d1Array[k++]=(byte)((b1<<2)|((b2&0x30)>>>4));
d1Array[k]=(byte)((b2<<4)|((b3&0x3c)>>>2));
}
String tr=new String(d1Array);
return tr.toString();
}
public byte Search(char a)
{
byte i;
if(a=='=')
return -1;
for(i=0;i<64;i++)
{
if(base64EncodeChars[i]==a)
break;
}
return i;
}
}
---------------------------------------------------------------------------------------------------------------------
class Agen:主要实现用户注册,生成用户信息文本
import java.io.*;
import java.security.SecureRandom;
public class Agen
{
public static byte[] initSalt()throws Exception
{
SecureRandom random=new SecureRandom();//构造一个实现默认随机数算法的安全随机数生成器 (RNG)
return random.generateSeed(8);//返回给定的种子字节数量
}
public Agen(){}
public static void main(String[] args)throws Exception
{
System.out.println("注册新用户");
System.out.println("输入用户名");
BufferedReader Username=
new BufferedReader(new InputStreamReader(System.in));
String username=Username.readLine();
System.out.println("输入密码");
BufferedReader Passwd=
new BufferedReader(new InputStreamReader(System.in));
Agen agen=new Agen();
byte[] Salt=agen.initSalt()
String Salt2=new String(Salt);
/*System.out.println(Salt2);*/
Base64 base64=new Base64();
String passwd=Passwd.readLine();
/*System.out.println(passwd);
System.out.println(base64.encode(Salt2));
String sAL=base64.decode(base64.encode(Salt2));
System.out.println(sAL);*/
byte[] data=PBECoder.encrypt(passwd,Salt);
FileOutputStream fileout=new FileOutputStream(new File("E:/passwd.txt"));
fileout.write((username+":"+base64.encode(Salt2)+":"+base64.encode(new String(data))).getBytes());
}
}
---------------------------------------------------------------------------------------------------------------------
class Test:实现从txt中分离出用户名,盐值和生成的口令信息,进行身份验证
import java.io.*;
import java.security.SecureRandom;
public class Test
{
public static void main(String[] args)throws Exception
{
System.out.println("用户登陆");
System.out.println("输入用户名");
BufferedReader Username
=new BufferedReader(new InputStreamReader(System.in));
String username=Username.readLine();
BufferedReader in=new BufferedReader(new InputStreamReader(new FileInputStream(new File("E:/passwd.txt"))));
String save=in.readLine();
int userpos=save.indexOf(":");
String USER=save.substring(0,userpos);
boolean b1=USER.equals(username);
if(!b1)
System.out.println("用户未注册");
else
{
System.out.println("请输入密码");
BufferedReader Passwd
=new BufferedReader(new InputStreamReader(System.in));
String passwd=Passwd.readLine();
int saltpos=save.indexOf(":",userpos+1);
Base64 base64=new Base64();
String Sa=save.substring(userpos+1,saltpos);
/*System.out.println(Sa);
System.out.println(userpos);
System.out.println(saltpos);
System.out.println(Sa+Sa.length());*/
byte[] sal=Sa.getBytes();
/*System.out.println(sal);*/
String salt=base64.decode(Sa).substring(0,5);//这个不知道怎么弄。。。不是取6位吧……
/*System.out.println(salt);*/
byte[] SAL=salt.getBytes();
/*System.out.println(SAL);*/
byte[] data=PBECoder.encrypt(passwd,SAL);
String re=base64.encode(new String(data));
/*System.out.println(re);*/
int pwdpos=save.indexOf(":",saltpos);
String PWD=save.substring(saltpos+1,save.length());
boolean b2=re.equals(PWD);
if(!b2)
System.out.println("密码不正确");
else
System.out.println("验证成功");
}
}
}
首先在运行窗口依次编译PEBCoder.java,Agen.java,Test.java
编译成功后先运行Agen.class,进行用户注册,运行命令为java Agen,然后根据提示输入用户名和密码;
然后在制定目录下生成了passwd.txt,然后在运行窗口下运行Test.class,进行用户验证,运行命令为java Test,然后根据提示输入用户名,如果用户名已经注册了,则提示输入密码,如果密码输入正确则验证成功;如果用户名没有注册则提示用户未注册。
以下是对各种情况的实验结果:
验证成功:
以下为生成的用户信息文件:
以下是输出中间结果对程序的分析:(验证成功的情况)
用户注册信息:
你看那个Base64编码后的盐值下面那个就与上面那个不一样,多了个?,然后就不能还原到最初那个数组,其实那个-108,88,-119……我不知道用什么方式把它当做可打印的存进txt然后取出后还原……
与passwd.txt文件中保存的信息对比盐值,盐值正确保存:
验证用户信息:
重新生成的口令信息与文件中保存的文件信息一致,验证成功
本次项目的功能实现还有不完善的地方,目前只写了一个用户的身份验证,不过多用户的添加只需在写入文件的时候在文件末尾添加,只是要重新考虑从文件中分离用户名,盐值,口令信息的方法,此外,由于是第一次使用JAVA中一些基于口令的密钥空间和密钥工厂的方法,使用上可能存在不正确的地方,导致有的时候用户验证的时候出现错误