java - 编写一个简单的邮件客户端和服务器,使用签名进行用户认证,验证签名,用户登录失败

标签 java sockets cryptography digital-signature digest-authentication

这是我在 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/

相关文章:

java - Java 中的字符流和字节流以及 C 中的 Char 与 Byte 有什么区别?

java - 使用 TCP/IP 在两台不同的计算机之间进行通信

security - 如何在我的设备上安装受信任的 CA 证书?

android - Android 上是否有 javax.smartcardio 类似物?

java - antlr 标识符名称与预定义函数名称相同导致 MismatchedTokenException

java - App Engine 数据存储 - 如何使用 Java 简单地存储和更新单个值?

java - Actionscript 覆盖扩展接口(interface)中的方法与 Java?

Java 客户端-服务器聊天应用程序获取 java.net.SocketException : Socket closed

javascript - 我可以通过 Javascript 建立套接字连接吗

javascript - 将 ECDSA PEM key 导入浏览器进行签名