这是我在 github 中的代码。点击【这里】https://github.com/bearer1024/cryptographyEmail
用户每次都无法通过 verifyLogin,即使给出了正确的 .pub 和 .prv key 。 我很确定问题与签名有关。但我不知道如何解决。
她是我在客户端的运行输出: java MailClient localhost 1111 承载
客户端中,签名长度为:256
假
登录失败
以下是服务器端的运行输出:
java 邮件服务器 1111
欢迎...
在服务器端,签名长度为:256
验证 clientid 是否为:bearer
服务器位置2
客户端登录失败
客户端承载登录失败。
客户端登录代码:
// connect to server
Socket s = new Socket(host,port);
DataInputStream dis = new DataInputStream(s.getInputStream());
DataOutputStream dos = new DataOutputStream(s.getOutputStream());
ObjectOutputStream oos = new ObjectOutputStream(s.getOutputStream());
oos.flush();
ObjectInputStream ois = new ObjectInputStream(s.getInputStream());
// TO DO: login
// these two lines are here just to make the supplied programs run without crashing.
// You may want to change them, and certainly add things after them
dos.writeUTF(userid);
String userPrivateKeyFileName = userid + ".prv";
// Get the key to create the signature
ObjectInputStream keyIn = new ObjectInputStream(new FileInputStream(userPrivateKeyFileName));
PrivateKey privateKey = (PrivateKey)keyIn.readObject();
keyIn.close();
// create timeStamp and random number
long t1 = (new Date()).getTime();
// ByteBuffer to convert to bytes later
ByteBuffer bb = ByteBuffer.allocate(16);
bb.putLong(t1);
bb.put(userid.getBytes());
// create signature, using timeStamp and random number as data
Signature sig = Signature.getInstance("SHA1withRSA");
sig.initSign(privateKey);
sig.update(bb.array());
byte[] signature = sig.sign();
// send data and signature
dos.writeLong(t1);
dos.writeInt(signature.length);
System.out.println("in the client,the length of signature is :"+signature.length);
dos.write(signature);
dos.flush();
boolean answer = dis.readBoolean();
System.out.println(answer);
服务器验证签名代码:
public static boolean verifyLogin(DataInputStream dis, String userid) throws Exception {
// TO DO
// receive data and signature
long t1 = dis.readLong();
//double q1 = dis.readDouble();
int length = dis.readInt();
System.out.println("in the server,the length of signature is:"+length);
byte[] signature = new byte[length];
System.out.println("verifying for clientid is:"+userid);
dis.readFully(signature);
System.out.println("Server position2");
// ByteBuffer to convert to bytes later
ByteBuffer bb = ByteBuffer.allocate(16);
bb.put(userid.getBytes());
bb.putLong(t1);
// should actually retrieve the appropriate key file using the received user name. For simplicity, hardcoded here
String userPublicKeyFileName = userid + ".pub";
ObjectInputStream keyIn = new ObjectInputStream(new FileInputStream(userPublicKeyFileName));
PublicKey publicKey = (PublicKey)keyIn.readObject();
keyIn.close();
// verify signature
Signature sig = Signature.getInstance("SHA1withRSA");
sig.initVerify(publicKey);
sig.update(bb.array());
// verify timeSpan
// server local timeStamp
long t2 = (new Date()).getTime();
long timeSpan = t2 - t1;
boolean timeFresh = false;
if (timeSpan < 60000)
timeFresh = true;
//final check
/*if (sig.verify(signature)&&timeFresh){
System.out.println("Client logged in");
return true;}
else{
System.out.println("Client failed to log in");
return false;}*/
if (sig.verify(signature)){
System.out.println("signature is right");
if(timeFresh){
System.out.println("timespan is fresh");
}
return true;}
else{
System.out.println("Client failed to log in");
return false;}
}
最佳答案
是的,这是一个愚蠢的错误,因为我使用了datainputstream和dataoutputstream,导致客户端输出序列和服务器输入序列应该相同。
// ByteBuffer to convert to bytes later
ByteBuffer bb = ByteBuffer.allocate(16);
bb.put(userid.getBytes());
bb.putLong(t1);
这个bug不太容易发现,因为我使用了bb.array()。哈哈。
关于java - 编写一个简单的邮件客户端和服务器,使用签名进行用户认证,验证签名,用户登录失败,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/35930001/