【发布时间】:2020-03-23 18:52:42
【问题描述】:
所以我正在尝试制作一个 Web 套接字,该套接字发送将被编码为 base64 然后使用 AES 加密的数据,生成的字节数组将通过套接字和服务器之间的流发送。这工作正常,直到我尝试发出某个命令给我BadPaddingException。所有使用Cryptographer 类的代码都使用完全相同的类和相同的秘密。
websockets 对每个连接都有线程来读取和写入数据。所有这些线程都使用同一个 cyptographer。
在连接线程中解密结果时给我异常的函数在名为MessageSender的类中这样编写,解密sendFile()的结果时会发生异常强>:
package com.company.client.workers;
import com.company.security.Cryptographer;
import java.io.File;
import java.io.IOException;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.nio.file.Files;
import java.util.Base64;
public class MessageSender {
private PrintWriter writer;
private OutputStream outputStream;
private Cryptographer cryptographer;
public MessageSender(OutputStream outputStream) {
this.outputStream = outputStream;
this.writer = new PrintWriter(this.outputStream);
cryptographer = new Cryptographer();
}
/**
* Sends a message to the PrintWriter.
* @param message to send.
*/
public void send(String message) {
try {
String b64 = Base64.getEncoder().encodeToString(message.getBytes());
byte[] bytes = cryptographer.getData(b64.getBytes(), 0);
outputStream.write(bytes, 0, bytes.length);
} catch (IOException e) {
e.printStackTrace();
}
}
/**
* Send a file over the server.
* @param receiver to send to
* @param path location of file
*/
public void sendFile(String receiver, String path) {
File file = new File(path);
try {
byte[] bytes = Files.readAllBytes(file.toPath());
// The encrypted result of this will throw the exception once the server tries to decrypt it.
String message = "SFC " + receiver + " " + bytes.length + " " + getFileName(path);
send(message);
outputStream.write(cryptographer.getData(bytes, 0), 0, bytes.length);
} catch (IOException e) {
e.printStackTrace();
}
}
private String getFileName(String path) {
String[] parts = path.split("/");
return parts[parts.length-1];
}
}
以下运行函数将从输入流(这是套接字)读取数据。它还将调用密码学家类来加密和解密数据,这是同一个类,也将在客户端使用一个单独的实例。在此异常的情况下,IsReceiving 仍设置为 false。这是Cryptographer 类:
package com.company.security;
import javax.crypto.*;
import javax.crypto.spec.SecretKeySpec;
import java.security.InvalidKeyException;
import java.security.Key;
import java.security.NoSuchAlgorithmException;
import java.util.Base64;
public class Cryptographer {
private Key secretKey;
public Cryptographer() {
byte[] secret = new byte[16]; // 128 bit is 16 bytes, and AES accepts 16 bytes, and a few others.
byte[] secretBytes = "secret".getBytes();
System.arraycopy(secretBytes, 0, secret, 0, secretBytes.length);
secretKey = new SecretKeySpec(secret, "AES");
}
/**
* Get data from either encryption and decryption.
* @param data to encrypt or decrypt
* @param mode 0 to encrypt en other numbers to decrypt
* @return result data as byte array format.
*/
public byte[] getData(byte[] data, int mode) {
Cipher c;
try {
c = Cipher.getInstance("AES");
} catch (NoSuchAlgorithmException | NoSuchPaddingException e) {
e.printStackTrace();
return null;
}
try {
if(mode == 0) { // 0 is encrypt mode.
c.init(Cipher.ENCRYPT_MODE, secretKey);
} else { // other numbers are decrypt mode.
c.init(Cipher.DECRYPT_MODE, secretKey);
}
} catch (InvalidKeyException e) {
e.printStackTrace();
return null;
}
try {
return c.doFinal(data);
} catch (IllegalBlockSizeException | BadPaddingException e) {
e.printStackTrace();
return null;
}
}
/**
* Decode base64 byte array.
* @param encoded encoded byte array
* @return decoded string
*/
public String decodeBaseToString(byte[] encoded) {
return new String(Base64.getDecoder().decode(encoded));
}
/**
* Decode base64 byte array.
* @param encoded encoded byte array
* @return decoded byte array
*/
public byte[] decodeBaseToBytes(byte[] encoded) {
return Base64.getDecoder().decode(encoded);
}
/**
* Encode byte array to base64.
* @param source array to encode
* @return encoded base64 byte array
*/
public byte[] encodeBase(byte[] source) {
return Base64.getEncoder().encode(source);
}
}
异常堆栈跟踪:
javax.crypto.BadPaddingException: Given final block not properly padded. Such issues can arise if a bad key is used during decryption.
at java.base/com.sun.crypto.provider.CipherCore.unpad(CipherCore.java:975)
at java.base/com.sun.crypto.provider.CipherCore.fillOutputBuffer(CipherCore.java:1056)
at java.base/com.sun.crypto.provider.CipherCore.doFinal(CipherCore.java:853)
at java.base/com.sun.crypto.provider.AESCipher.engineDoFinal(AESCipher.java:446)
at java.base/javax.crypto.Cipher.doFinal(Cipher.java:2208)
at com.company.security.Cryptographer.getData(Cryptographer.java:48)
at com.company.client.Reader.run(Reader.java:45)
at java.base/java.lang.Thread.run(Thread.java:835)
Exception in thread "Thread-3" java.lang.NullPointerException
at java.base/java.lang.String.<init>(String.java:623)
at com.company.client.Reader.run(Reader.java:47)
at java.base/java.lang.Thread.run(Thread.java:835)
加密适用于所有其他命令,并且当我不在sendFile() 中包含文件名时它也适用。我在这里做错了什么?
【问题讨论】:
标签: java encryption aes