服务器将公钥加密数据发送到客户端,客户端也发送到服务器。
客户端解密很好。服务器端不是。
相同的解密程序似乎适用于Android,但是,它显然不在服务器端。
这是我的服务器端解密代码:
int bytesRead;
int current = 0;
FileOutputStream fos = null;
byte[] EncryptedClientAES = new byte[10000];
InputStream is = clientSocket.getInputStream();
fos = new FileOutputStream("ClientAESFile");
BufferedOutputStream bos = new BufferedOutputStream(fos);
bytesRead = is.read(EncryptedClientAES, 0, EncryptedClientAES.length);
current = bytesRead;
System.out.println("Size of read data: " + current);
bos.write(EncryptedClientAES, 0, current);
bos.flush();
bos.close();
fos.close();
clientSocket.close();
Cipher cipher = Cipher.getInstance("RSA");
cipher.init(Cipher.DECRYPT_MODE, privateKey);
byte[] decryptedAESKeyOfClient = null;
decryptedAESKeyOfClient = cipher.doFinal(EncryptedClientAES);
这失败, IllegalBlockSizeException 表示数据不应超过64个字节,这使得我将字节数组 EncryptedClientAES 的大小更改为 64 因为读取数据的大小也是 64 。继续使用它给了我 BadPaddingException ,但是,同样的程序适用于Android端。
以下是我从Android发送代码的加密数据:
SecureRandom secureRandom = new SecureRandom();
KeyGenerator kg = null;
kg = KeyGenerator.getInstance("AES");
kg.init(128, secureRandom);
SecretKey ClientSecretKey = kg.generateKey(); // Client AES is generated here.
String ServerModulus = ServerRSAPublicKey.substring(40, 194);
String ServerExponent = ServerRSAPublicKey.substring(214, 219);
BigInteger bigInteger = new BigInteger(ServerModulus, 10);
BigInteger bigInteger1 = new BigInteger(ServerExponent);
RSAPublicKeySpec rsaPublicKeySpec = new RSAPublicKeySpec(bigInteger, bigInteger1);
KeyFactory keyFactory = null;
try {
keyFactory = KeyFactory.getInstance("RSA");
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
}
RSAPublicKey publicKeyOfServer = null;
try {
assert keyFactory != null;
publicKeyOfServer = (RSAPublicKey) keyFactory.generatePublic(rsaPublicKeySpec);
} catch (InvalidKeySpecException e) {
e.printStackTrace();
}
Cipher c = null;
try {
c = Cipher.getInstance("RSA");
} catch (NoSuchPaddingException e) {
e.printStackTrace();
}
try {
assert c != null;
c.init(Cipher.ENCRYPT_MODE, publicKeyOfServer);
} catch (InvalidKeyException e) {
e.printStackTrace();
}
byte[] encryptedBytes = null;
try {
encryptedBytes = c.doFinal(ClientSecretKey.getEncoded());
} catch (IllegalBlockSizeException | BadPaddingException e) {
e.printStackTrace();
}
OutputStream outputStream;
outputStream = client.getOutputStream();
assert encryptedBytes != null;
outputStream.write(encryptedBytes, 0, encryptedBytes.length);
outputStream.flush();
outputStream.close();
client.close(); // closing the connection
我在Android端工作的解密代码是:
Socket client = new Socket("192.168.1.169", 4444);
int bytesRead;
int current = 0;
FileOutputStream fos;
byte[] EncryptedServerAES = new byte[100000];
InputStream is = client.getInputStream();
fos = new FileOutputStream("ServerAESKeyFile");
BufferedOutputStream bos = new BufferedOutputStream(fos);
bytesRead = is.read(EncryptedServerAES, 0, EncryptedServerAES.length);
current = bytesRead;
do {
bytesRead =
is.read(EncryptedServerAES, current, (EncryptedServerAES.length - current));
if (bytesRead >= 0) current += bytesRead;
} while (bytesRead > -1);
bos.write(EncryptedServerAES, 0, current);
bos.flush();
fos.close();
bos.close();
client.close(); // closing the connection
// try to decrypt and get AES key back.
BigInteger Modulus;
BigInteger publicExponent;
BigInteger privateExponent;
BigInteger primeP;
BigInteger primeQ;
BigInteger primeExpP;
BigInteger primeExpQ;
BigInteger crtCoeff;
Modulus = new BigInteger(ClientPrivateKey.substring(32, 161));
publicExponent = new BigInteger("10001");
privateExponent = new BigInteger(ClientPrivateKey.substring(198, 327));
primeP = new BigInteger(ClientPrivateKey.substring(334, 399));
primeQ = new BigInteger(ClientPrivateKey.substring(406, 471));
primeExpP = new BigInteger(ClientPrivateKey.substring(486, 551));
primeExpQ = new BigInteger(ClientPrivateKey.substring(566, 631));
crtCoeff = new BigInteger(ClientPrivateKey.substring(646, 711));
Cipher cipher = Cipher.getInstance("RSA");
// realise client's private key string as private key.
RSAPrivateCrtKeySpec rsaPrivateCrtKeySpec = new RSAPrivateCrtKeySpec(Modulus, publicExponent, privateExponent, primeP, primeQ, primeExpP, primeExpQ, crtCoeff);
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
RSAPrivateKey ClientPrivateKEY = null;
try {
ClientPrivateKEY = (RSAPrivateKey) keyFactory.generatePrivate(rsaPrivateCrtKeySpec);
} catch (InvalidKeySpecException e) {
e.printStackTrace();
}
try {
cipher.init(Cipher.DECRYPT_MODE, ClientPrivateKEY);
} catch (InvalidKeyException e) {
e.printStackTrace();
}
try {
decryptedAESKeyOfServer = cipher.doFinal(EncryptedServerAES);
} catch (IllegalBlockSizeException | BadPaddingException e) {
e.printStackTrace();
}
对于Android(客户端)方面的上述成功解密,服务器发送了此数据:
Cipher c = null;
try {
c = Cipher.getInstance("RSA");
} catch (NoSuchAlgorithmException | NoSuchPaddingException ex) {
Logger.getLogger(SecureServer.class.getName()).log(Level.SEVERE, null, ex);
}
{
try {
c.init(Cipher.ENCRYPT_MODE, publicKeyofClient);
} catch (InvalidKeyException ex) {
Logger.getLogger(SecureServer.class.getName()).log(Level.SEVERE, null, ex);
}
}
byte[] encryptedBytes = null;
{
try {
encryptedBytes = c.doFinal(ServerSecretKey.getEncoded());
} catch (IllegalBlockSizeException | BadPaddingException ex) {
Logger.getLogger(SecureServer.class.getName()).log(Level.SEVERE, null, ex);
}
}
OutputStream outputStream;
outputStream = clientSocket.getOutputStream();
outputStream.write(encryptedBytes, 0, encryptedBytes.length);
outputStream.flush();
outputStream.close();
clientSocket.close(); // closing the connection
这就是我在双方生成RSA密钥的方式:
secureRandom = new SecureRandom();
try {
keyPairGenerator = KeyPairGenerator.getInstance("RSA");
} catch (NoSuchAlgorithmException ex) {
Logger.getLogger(SecureServer.class.getName()).log(Level.SEVERE, null, ex);
}
keyPairGenerator.initialize(512, secureRandom);
keyPair = keyPairGenerator.generateKeyPair();
privateKey = (RSAPrivateKey) keyPair.getPrivate();
publicKey = (RSAPublicKey) keyPair.getPublic();
我想我在这里很蠢。
更新1 :
它仍然失败。
这是我的(Android)客户端加密代码:
Cipher ciphertest = null;
ciphertest = Cipher.getInstance("RSA/ECB/OAEPWithSHA-256AndMGF1Padding");
ciphertest.init(Cipher.ENCRYPT_MODE, publicKey);
byte[] encryptedBytes = null;
encryptedBytes = ciphertest.doFinal(Bytes_to_encrypt);
这是我的服务器端解密代码:
Cipher cipher = Cipher.getInstance("RSA/ECB/OAEPPadding");
OAEPParameterSpec oaepParams = new OAEPParameterSpec("SHA-256", "MGF1", new MGF1ParameterSpec("SHA-1"), PSource.PSpecified.DEFAULT);
cipher.init(Cipher.DECRYPT_MODE, privateKey, oaepParams);
byte[] decryptedAESKeyOfServer = null;
decryptedAESKeyOfServer = cipher.doFinal(EncryptedClientAES);
错误是 IllegalBlockSizeException (如果 decryptedAESKeyOfServer 的大小是随机大字节)或 BadPaddingException (如果 decryptedAESKeyOfServer 大小为256字节;从客户端接收的数据是这么多字节)。
更新2
客户端上从服务器读取空值的代码:
int bytesRead;
int current = 0;
FileOutputStream fos;
byte[] EncryptedServerAES = new byte[100000];
InputStream is = client.getInputStream();
fos = new FileOutputStream("ServerAESKeyFile");
BufferedOutputStream bos = new BufferedOutputStream(fos);
bytesRead = is.read(EncryptedServerAES, 0, EncryptedServerAES.length);
data_size = bytesRead; // data_size is 0.
Idk怎么样,但是,客户端仍在(尝试)解密它并且没有崩溃!。
我的堆栈跟踪:
06-15 15:18:03.619 23489-23927/com.avineshwar.secureclient W/System.err: java.io.FileNotFoundException: ServerAESKeyFile: open failed: EROFS (Read-only file system)
06-15 15:18:03.620 23489-23927/com.avineshwar.secureclient W/System.err: at libcore.io.IoBridge.open(IoBridge.java:456)
06-15 15:18:03.622 23489-23927/com.avineshwar.secureclient W/System.err: at java.io.FileOutputStream.<init>(FileOutputStream.java:87)
06-15 15:18:03.623 23489-23927/com.avineshwar.secureclient W/System.err: at java.io.FileOutputStream.<init>(FileOutputStream.java:127)
06-15 15:18:03.623 23489-23927/com.avineshwar.secureclient W/System.err: at java.io.FileOutputStream.<init>(FileOutputStream.java:116)
06-15 15:18:03.623 23489-23927/com.avineshwar.secureclient W/System.err: at com.avineshwar.secureclient.Part3$SendMessage.doInBackground(Part3.java:128)
06-15 15:18:03.623 23489-23927/com.avineshwar.secureclient W/System.err: at com.avineshwar.secureclient.Part3$SendMessage.doInBackground(Part3.java:115)
06-15 15:18:03.623 23489-23927/com.avineshwar.secureclient W/System.err: at android.os.AsyncTask$2.call(AsyncTask.java:292)
06-15 15:18:03.623 23489-23927/com.avineshwar.secureclient W/System.err: at java.util.concurrent.FutureTask.run(FutureTask.java:237)
06-15 15:18:03.623 23489-23927/com.avineshwar.secureclient W/System.err: at android.os.AsyncTask$SerialExecutor$1.run(AsyncTask.java:231)
06-15 15:18:03.623 23489-23927/com.avineshwar.secureclient W/System.err: at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1112)
06-15 15:18:03.623 23489-23927/com.avineshwar.secureclient W/System.err: at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:587)
06-15 15:18:03.623 23489-23927/com.avineshwar.secureclient W/System.err: at java.lang.Thread.run(Thread.java:818)
在 Part3.java 中,第115行只是一个空白行,我认为是对的引用:
private class SendMessage extends AsyncTask<Void, Void, Void> {
在 Part3.java 中,第128行:
InputStream is = client.getInputStream();