Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/sockets/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java:通过套接字发送后公钥不同_Java_Sockets_Cryptography - Fatal编程技术网

Java:通过套接字发送后公钥不同

Java:通过套接字发送后公钥不同,java,sockets,cryptography,Java,Sockets,Cryptography,我正在尝试通过Java中的套接字连接发送公钥。虽然我非常清楚Java为这类活动提供了SSL功能,但这是一个uni分配;我不能使用Java实现 服务器对其公钥进行编码,并通过套接字连接将其传输到客户端。当客户端接收到密钥并对其进行解码时,它看起来就不同了。不仅如此,客户机接收的数据与服务器发送的数据似乎不同。我相信,当我尝试使用此密钥加密用户名和密码时,这会给我带来问题 可使用以下代码再现此问题: 客户: public class TestClient { /** * @par

我正在尝试通过Java中的套接字连接发送公钥。虽然我非常清楚Java为这类活动提供了SSL功能,但这是一个uni分配;我不能使用Java实现

服务器对其公钥进行编码,并通过套接字连接将其传输到客户端。当客户端接收到密钥并对其进行解码时,它看起来就不同了。不仅如此,客户机接收的数据与服务器发送的数据似乎不同。我相信,当我尝试使用此密钥加密用户名和密码时,这会给我带来问题

可使用以下代码再现此问题:

客户:

public class TestClient {

    /**
     * @param args
     */
    public static void main(String[] args) {

        final int sPort = 4321;

        Socket sock = null;
        Key serverPubKey = null;
        BufferedReader clientIn = null;

        // Initialise server connection
        try{
            sock = new Socket(InetAddress.getLocalHost(), sPort);
            clientIn = new BufferedReader(new InputStreamReader(sock.getInputStream()));
        } catch (UnknownHostException e) {
            System.out.println("Unknown host.");
            System.exit(1);
        } catch  (IOException e) {
            System.out.println("No I/O");
            System.exit(1);
        }

        // Get server pub key
        try{
            int len = Integer.parseInt(clientIn.readLine());
            byte[] servPubKeyBytes = new byte[len];
            sock.getInputStream().read(servPubKeyBytes,0,len);
            System.out.println(servPubKeyBytes);
            X509EncodedKeySpec ks = new X509EncodedKeySpec(servPubKeyBytes);
            KeyFactory kf = KeyFactory.getInstance("RSA");
            serverPubKey = kf.generatePublic(ks);
            System.out.println(serverPubKey.getEncoded());
        } catch (IOException e) {
            System.out.println("Error obtaining server public key 1.");
            System.exit(0);
        } catch (NoSuchAlgorithmException e) {
            System.out.println("Error obtaining server public key 2.");
            System.exit(0);
        } catch (InvalidKeySpecException e) {
            System.out.println("Error obtaining server public key 3.");
            System.exit(0);
        }

    }

}
public class TestClient {

    /**
     * @param args
     */
    public static void main(String[] args) {

        final int sPort = 4321;

        Socket sock = null;
        Key serverPubKey = null;

        // Initialise server connection
        try{
            sock = new Socket(InetAddress.getLocalHost(), sPort);
        } catch (UnknownHostException e) {
            System.out.println("Unknown host.");
            System.exit(1);
        } catch  (IOException e) {
            System.out.println("No I/O");
            System.exit(1);
        }

        // Get server pub key
        try{
            byte[] lenb = new byte[4];
            sock.getInputStream().read(lenb,0,4);
            ByteBuffer bb = ByteBuffer.wrap(lenb);
            int len = bb.getInt();
            System.out.println(len);
            byte[] servPubKeyBytes = new byte[len];
            sock.getInputStream().read(servPubKeyBytes);
            System.out.println(DatatypeConverter.printHexBinary(servPubKeyBytes));
            X509EncodedKeySpec ks = new X509EncodedKeySpec(servPubKeyBytes);
            KeyFactory kf = KeyFactory.getInstance("RSA");
            serverPubKey = kf.generatePublic(ks);
            System.out.println(DatatypeConverter.printHexBinary(serverPubKey.getEncoded()));
        } catch (IOException e) {
            System.out.println("Error obtaining server public key 1.");
            System.exit(0);
        } catch (NoSuchAlgorithmException e) {
            System.out.println("Error obtaining server public key 2.");
            System.exit(0);
        } catch (InvalidKeySpecException e) {
            System.out.println("Error obtaining server public key 3.");
            System.exit(0);
        }   
    }   
}
服务器:

public class TestServer {

    public static void main(String[] args) {
        final int servPort = 4321;
        final int RSAKeySize = 1024;
        final String newline = "\n";

        Key pubKey = null;
        ServerSocket cServer = null;
        Socket cClient = null;
        PrintWriter cOut = null;

        // Initialise RSA
        try{
            KeyPairGenerator RSAKeyGen = KeyPairGenerator.getInstance("RSA");
            RSAKeyGen.initialize(RSAKeySize);
            KeyPair pair = RSAKeyGen.generateKeyPair();
            pubKey = pair.getPublic();
        } catch (GeneralSecurityException e) {
            System.out.println(e.getLocalizedMessage() + newline);
            System.out.println("Error initialising encryption. Exiting.\n");
            System.exit(0);
        }

        // Initialise socket connection
        try{
            cServer = new ServerSocket(servPort); 
            cClient = cServer.accept();
            cOut = new PrintWriter(cClient.getOutputStream(), true);
        } catch (IOException e) {
            System.out.println("Error initialising I/O.\n");
            System.exit(0);
        }

        // Send public key
        try {
            cOut.println(pubKey.getEncoded().length);
            System.out.println(pubKey.getEncoded());
            cClient.getOutputStream().write(pubKey.getEncoded());
            cClient.getOutputStream().flush();
        } catch (IOException e) {
            System.out.println("I/O Error");
            System.exit(0);
        }

    }

}
public class TestServer {

    public static void main(String[] args) {
        final int servPort = 4321;
        final int RSAKeySize = 1024;
        final String newline = "\n";

        Key pubKey = null;
        ServerSocket cServer = null;
        Socket cClient = null;

        // Initialise RSA
        try{
            KeyPairGenerator RSAKeyGen = KeyPairGenerator.getInstance("RSA");
            RSAKeyGen.initialize(RSAKeySize);
            KeyPair pair = RSAKeyGen.generateKeyPair();
            pubKey = pair.getPublic();
        } catch (GeneralSecurityException e) {
            System.out.println(e.getLocalizedMessage() + newline);
            System.out.println("Error initialising encryption. Exiting.\n");
            System.exit(0);
        }

        // Initialise socket connection
        try{
            cServer = new ServerSocket(servPort); 
            cClient = cServer.accept();
        } catch (IOException e) {
            System.out.println("Error initialising I/O.\n");
            System.exit(0);
        }

        // Send public key
        try {
        System.out.println(DatatypeConverter.printHexBinary(pubKey.getEncoded()));
            ByteBuffer bb = ByteBuffer.allocate(4);
            bb.putInt(pubKey.getEncoded().length);
            cClient.getOutputStream().write(bb.array());
            cClient.getOutputStream().write(pubKey.getEncoded());
            cClient.getOutputStream().flush();
        } catch (IOException e) {
            System.out.println("I/O Error");
            System.exit(0);
        }

    }

}
这可能很简单,只要告诉我我的密钥不是X509编码的,但是这似乎是从文件中恢复密钥的方式(也读取为字节),所以我不明白为什么它不能工作

提前非常感谢您的帮助/建议


编辑:问题已解决,请参阅Jeffrey的回答。修改(工作)代码作为响应发布。

在实际代码中,我强烈建议不要以这种方式直接使用加密类。如果可能,请使用。

也就是说,我看到的错误是,您将
InputStreamReader
访问与下面的原始
InputStream
混合。
InputStreamReader
读取的字节数可能比您在
readLine
中要求的要多-编写它的目的几乎是假设它拥有底层的
InputStream
,因此可以在缓冲块中提前读取

引述:

每次调用InputStreamReader的read()方法之一都可能 导致从基础字节输入读取一个或多个字节 流动要实现字节到字符的高效转换, 从底层流中提前读取的字节数可能比实际读取的字节数多 必须满足当前读取操作


除了Jeffrey所解释的作者和输出流的混合之外,以下内容也可能存在问题:

sock.getInputStream().read(servPubKeyBytes,0,len);
InputStream.read的JavaDoc文件:

从输入流中读取一定数量的字节,并将它们存储到缓冲区数组b中。实际读取的字节数作为整数返回。此方法将一直阻止,直到输入数据可用、检测到文件结尾或引发异常为止。 如果b的长度为零,则不读取字节,返回0;否则,将尝试读取至少一个字节。如果由于流位于文件末尾而没有可用字节,则返回值-1;否则,至少读取一个字节并将其存储到b中

读取的第一个字节存储在元素b[0]中,下一个字节存储在元素b[1]中,依此类推。读取的字节数最多等于b的长度。设k为实际读取的字节数;这些字节将存储在元素b[0]到b[k-1]中,使元素b[k]到b[b.length-1]不受影响

也就是说,
read()。如果知道有更多字节,则应反复调用
read
,直到所有数据都已读取,例如:

for (int p = 0; p < len; ) {
    int read = in.read(servPubKeyBytes, p, len - p);
    if (read == -1) {
        throw new RuntimeException("Premature end of stream");
    }
    p += read;
}
for(int p=0;p
首先,感谢大家的帮助,非常感谢!还有12个小时就要到期了,我开始担心了,我想从这里一帆风顺:)

无论如何,修订后的守则:

服务器:

public class TestServer {

    public static void main(String[] args) {
        final int servPort = 4321;
        final int RSAKeySize = 1024;
        final String newline = "\n";

        Key pubKey = null;
        ServerSocket cServer = null;
        Socket cClient = null;
        PrintWriter cOut = null;

        // Initialise RSA
        try{
            KeyPairGenerator RSAKeyGen = KeyPairGenerator.getInstance("RSA");
            RSAKeyGen.initialize(RSAKeySize);
            KeyPair pair = RSAKeyGen.generateKeyPair();
            pubKey = pair.getPublic();
        } catch (GeneralSecurityException e) {
            System.out.println(e.getLocalizedMessage() + newline);
            System.out.println("Error initialising encryption. Exiting.\n");
            System.exit(0);
        }

        // Initialise socket connection
        try{
            cServer = new ServerSocket(servPort); 
            cClient = cServer.accept();
            cOut = new PrintWriter(cClient.getOutputStream(), true);
        } catch (IOException e) {
            System.out.println("Error initialising I/O.\n");
            System.exit(0);
        }

        // Send public key
        try {
            cOut.println(pubKey.getEncoded().length);
            System.out.println(pubKey.getEncoded());
            cClient.getOutputStream().write(pubKey.getEncoded());
            cClient.getOutputStream().flush();
        } catch (IOException e) {
            System.out.println("I/O Error");
            System.exit(0);
        }

    }

}
public class TestServer {

    public static void main(String[] args) {
        final int servPort = 4321;
        final int RSAKeySize = 1024;
        final String newline = "\n";

        Key pubKey = null;
        ServerSocket cServer = null;
        Socket cClient = null;

        // Initialise RSA
        try{
            KeyPairGenerator RSAKeyGen = KeyPairGenerator.getInstance("RSA");
            RSAKeyGen.initialize(RSAKeySize);
            KeyPair pair = RSAKeyGen.generateKeyPair();
            pubKey = pair.getPublic();
        } catch (GeneralSecurityException e) {
            System.out.println(e.getLocalizedMessage() + newline);
            System.out.println("Error initialising encryption. Exiting.\n");
            System.exit(0);
        }

        // Initialise socket connection
        try{
            cServer = new ServerSocket(servPort); 
            cClient = cServer.accept();
        } catch (IOException e) {
            System.out.println("Error initialising I/O.\n");
            System.exit(0);
        }

        // Send public key
        try {
        System.out.println(DatatypeConverter.printHexBinary(pubKey.getEncoded()));
            ByteBuffer bb = ByteBuffer.allocate(4);
            bb.putInt(pubKey.getEncoded().length);
            cClient.getOutputStream().write(bb.array());
            cClient.getOutputStream().write(pubKey.getEncoded());
            cClient.getOutputStream().flush();
        } catch (IOException e) {
            System.out.println("I/O Error");
            System.exit(0);
        }

    }

}
客户:

public class TestClient {

    /**
     * @param args
     */
    public static void main(String[] args) {

        final int sPort = 4321;

        Socket sock = null;
        Key serverPubKey = null;
        BufferedReader clientIn = null;

        // Initialise server connection
        try{
            sock = new Socket(InetAddress.getLocalHost(), sPort);
            clientIn = new BufferedReader(new InputStreamReader(sock.getInputStream()));
        } catch (UnknownHostException e) {
            System.out.println("Unknown host.");
            System.exit(1);
        } catch  (IOException e) {
            System.out.println("No I/O");
            System.exit(1);
        }

        // Get server pub key
        try{
            int len = Integer.parseInt(clientIn.readLine());
            byte[] servPubKeyBytes = new byte[len];
            sock.getInputStream().read(servPubKeyBytes,0,len);
            System.out.println(servPubKeyBytes);
            X509EncodedKeySpec ks = new X509EncodedKeySpec(servPubKeyBytes);
            KeyFactory kf = KeyFactory.getInstance("RSA");
            serverPubKey = kf.generatePublic(ks);
            System.out.println(serverPubKey.getEncoded());
        } catch (IOException e) {
            System.out.println("Error obtaining server public key 1.");
            System.exit(0);
        } catch (NoSuchAlgorithmException e) {
            System.out.println("Error obtaining server public key 2.");
            System.exit(0);
        } catch (InvalidKeySpecException e) {
            System.out.println("Error obtaining server public key 3.");
            System.exit(0);
        }

    }

}
public class TestClient {

    /**
     * @param args
     */
    public static void main(String[] args) {

        final int sPort = 4321;

        Socket sock = null;
        Key serverPubKey = null;

        // Initialise server connection
        try{
            sock = new Socket(InetAddress.getLocalHost(), sPort);
        } catch (UnknownHostException e) {
            System.out.println("Unknown host.");
            System.exit(1);
        } catch  (IOException e) {
            System.out.println("No I/O");
            System.exit(1);
        }

        // Get server pub key
        try{
            byte[] lenb = new byte[4];
            sock.getInputStream().read(lenb,0,4);
            ByteBuffer bb = ByteBuffer.wrap(lenb);
            int len = bb.getInt();
            System.out.println(len);
            byte[] servPubKeyBytes = new byte[len];
            sock.getInputStream().read(servPubKeyBytes);
            System.out.println(DatatypeConverter.printHexBinary(servPubKeyBytes));
            X509EncodedKeySpec ks = new X509EncodedKeySpec(servPubKeyBytes);
            KeyFactory kf = KeyFactory.getInstance("RSA");
            serverPubKey = kf.generatePublic(ks);
            System.out.println(DatatypeConverter.printHexBinary(serverPubKey.getEncoded()));
        } catch (IOException e) {
            System.out.println("Error obtaining server public key 1.");
            System.exit(0);
        } catch (NoSuchAlgorithmException e) {
            System.out.println("Error obtaining server public key 2.");
            System.exit(0);
        } catch (InvalidKeySpecException e) {
            System.out.println("Error obtaining server public key 3.");
            System.exit(0);
        }   
    }   
}

可以通过套接字通过对象发送公钥 例如,我们可以编写一个类作为框架,如下所示:

import java.io.Serializable;
public class Frame implements Serializable {
    byte[] data;

}
在客户端,只需定义框架和套接字,然后写入:

Frame frame = new Frame();
frame.data = thePublicKey.getEncoded();
toServer.writeObject(frame);
在服务器端解码公钥:

Frame frame = fromClient.readObject();
byte[] pubKey = frame.data;                 
X509EncodedKeySpec ks = new X509EncodedKeySpec(pubKey);
KeyFactory = KeyFactory.getInstance("RSA");
thepublicKey = kf.generatePublic(ks);

“我强烈建议不要以这种方式直接使用密码学类”我理解这一点,也不会这样做,除非我认为我的作业的目的更多的是证明理解,而不是编写一个安全的程序。非常感谢您的回复,我将有一个剧本,让您知道我的进展。值得一提的是,编写HTTP处理器(服务器或客户端)时也会遇到同样的问题。我以前必须编写InputStreamReader的一个特殊的无缓冲变体,以便在不消耗任何实体体字节的情况下读取标题。如果可以使用其他标准JDK类,则可以将密钥作为单行文本传输。具有用于在base64或“十六进制二进制”格式的字节数组和字符串之间转换的实用函数。这应该比自定义混合文本/二进制输入流更容易实现。@user990403请以新答案发布。你甚至可以通过这种方式获得一些选票:-)@JeffreyHantin出于某种原因,我又遇到了这个问题(我不记得我是怎么来到这里的)。我只是想再次说声谢谢;我发布了相当多的代码,而你花时间阅读并理解了它。非常感谢:)为什么您的代码有“System.out.println(pubKey.getEncoded())”这样的语句?PrintStream.println不会对字节[]执行任何特殊操作,因此只会打印类似以下内容的内容[B@10b62c9“(大致意思是“内存位置0x010B62C9处的字节[]”)。我这样问是因为您说“客户端接收的数据与服务器发送的数据不同”,我希望上面的语句不是你如何确定的。@ruakh”我希望上面的语句不是你如何确定的“不幸的是,这正是我正在做的。我几乎是一个java处女,实际上,我假设它正在做一些神奇的类型转换到一个字符数组或字符串中,将“new string(pubKey.getEncoded())“请帮助我确定发送/接收的数据是否相同?据我所知,字节数组可能无法正确编码,但如果它们相等,我至少可以大致假定情况是这样,然后尝试enc