让我解释一下我的问题
我想覆盖Socket和ServerSocket类,以便以这种方式加密我的消息:
1)客户端将随机生成的对称密钥(AES算法)发送到服务器
2)之后,客户端和服务器可以通过使用此密钥加密其消息进行通信
3)为了交换对称密钥,客户端使用服务器的公钥(RSA算法)对其进行加密
我覆盖Socket和ServerSocket,因此当客户端打开Socket时,它会自动发送由服务器公钥加密的对称密钥。服务器读取流中的前128个字节,对其进行解码,并构建对称密钥。 这部分似乎有效。我使用Wireshark检查通信:数据包是加密的,接收的对称密钥是否正确传递。 为了保证透明地使用我的套接字,我重写 getInputStream 和 getOutputStream 方法,返回 CipheredInputStream 和 ChiperedOutputStream
它现在不起作用。当我尝试让OutputStream发送数据时,程序会通过指令,但它并不重要(我通过Wireshark检查并且没有发送数据包)。
这是ServerSocket的代码:
public class SecureServerSocket extends ServerSocket {
public SecureServerSocket(int port) throws IOException {
super(port);
}
public Socket accept() throws IOException {
SecureSocket s = new SecureSocket();
implAccept(s);
SecretKey seckey;
InputStream is = s.getInputStream();
byte[] tmp = new byte[128]; //128: length of the key
int i = 0;
while (i < 128) {
tmp[i] = (byte) (is.read() & 0x000000FF);
++i;
}
byte[] mess = EncryptionManager.rsaDecryptPrivate(tmp);
seckey = new SecretKeySpec(mess, "AES");
try {
s.setkey(seckey);
} catch (InvalidKeyException | NoSuchAlgorithmException
| NoSuchPaddingException e) {
e.printStackTrace();
}
return s;
}
}
这是Socket的代码:
public class SecureSocket extends Socket {
private SecretKey seckey;
private InputStream in = null;
private OutputStream out = null;
private CipherInputStream cin = null;
private CipherOutputStream cout = null;
public SecureSocket() throws IOException {
}
public SecureSocket(String address, int port) throws UnknownHostException,
IOException, NoSuchAlgorithmException, NoSuchPaddingException,
InvalidKeyException {
super(address, port);
if (out == null) {
this.out = super.getOutputStream();
}
if (in == null) {
this.in = super.getInputStream();
}
KeyGenerator keyGen = KeyGenerator.getInstance("AES");
SecureRandom random = new SecureRandom();
keyGen.init(random);
seckey = keyGen.generateKey();
byte[] mess = EncryptionManager.rsaEncryptPublic(seckey.getEncoded());
// writing the initial message with the AES encryption key
out.write(mess);
// Initialization of the Cipher streams
Cipher cipherEn = Cipher.getInstance("AES");
cipherEn.init(Cipher.ENCRYPT_MODE, seckey);
Cipher cipherDc = Cipher.getInstance("AES");
cipherDc.init(Cipher.DECRYPT_MODE, seckey);
cout = new CipherOutputStream(out, cipherEn);
cin = new CipherInputStream(in, cipherDc);
}
public InputStream getInputStream() throws IOException {
if (cin == null)
return super.getInputStream();
return cin;
}
public OutputStream getOutputStream() throws IOException {
if (cout == null)
return super.getOutputStream();
return cout;
}
public synchronized void close() throws IOException {
OutputStream o = getOutputStream();
o.flush();
super.close();
}
public void setkey(SecretKey seckey) throws NoSuchAlgorithmException,
NoSuchPaddingException, InvalidKeyException, IOException {
this.seckey = seckey;
Cipher cipherEn = Cipher.getInstance("AES");
cipherEn.init(Cipher.ENCRYPT_MODE, seckey);
cout = new CipherOutputStream(super.getOutputStream(), cipherEn);
Cipher cipherDc = Cipher.getInstance("AES");
cipherDc.init(Cipher.DECRYPT_MODE, seckey);
cin = new CipherInputStream(super.getInputStream(), cipherDc);
}
}
我无法弄清问题在哪里。谢谢!
答案 0 :(得分:0)
问题是密码需要特定数量的数据(例如128位)才能正确加密。如果您发送文件,那没问题,因为关闭流时将发送文件的最后几位。
但是,您需要填充进行网络通信。您可以为Cipher实例指定一个:
Cipher cipherEnOrDe = Cipher.getInstance("AES/CBC/PKCS5Padding"); //for example, check documentation for more
使用填充,一旦调用flush()方法,Cipher将能够发送您的数据(无论何时您都希望发送某些内容,您应该这样做。)
注意:如果您的客户使用公钥分发,您的应用程序将是安全的。否则,您无法确定是否首先连接到正确的服务器。任何人都可以创建公钥。