所以我正在制作一个将安全消息发送到指定IP地址的应用程序。我使用AES来加密消息,这部分工作得很好。我可以加密消息,也可以在发送消息之前解密它。但是,当我试图解密从服务器接收到的消息时,我无法解密它。它以加密的形式显示。
我得到这个错误"java.lang. "NumberFormatException:无效int:"ne",我认为这可能与字符编码或其他东西有关?当字符串通过网络发送时,它是否以任何方式被改变?
以下是可能与问题相关的代码片段。
public static String encrypt(String seed, String cleartext)
throws Exception {
byte[] rawKey = getRawKey(seed.getBytes());
byte[] result = encrypt(rawKey, cleartext.getBytes());
return toHex(result);
}
public static String decrypt(String seed, String encrypted)
throws Exception {
byte[] rawKey = getRawKey(seed.getBytes());
byte[] enc = toByte(encrypted);
byte[] result = decrypt(rawKey, enc);
return new String(result);
}
public static byte[] toByte(String hexString) {
int len = hexString.length() / 2;
byte[] result = new byte[len];
for (int i = 0; i < len; i++)
result[i] = Integer.valueOf(hexString.substring(2 * i, 2 * i + 2),
16).byteValue();
return result;
}
public static String toHex(byte[] buf) {
if (buf == null)
return "";
StringBuffer result = new StringBuffer(2 * buf.length);
for (int i = 0; i < buf.length; i++) {
appendHex(result, buf[i]);
}
return result.toString();
}
这是我为要显示的消息进行解密的地方。
while (!goOut) {
if (dataInputStream.available() > 0) {
incoming = dataInputStream.readUTF();
if(encrypt == true) {
try{
msgLog += AESHelper.decrypt(seed,incoming);
} catch (Exception e) {
e.printStackTrace();
}
} else msgLog += incoming;
MainActivity.this.runOnUiThread(new Runnable() {
@Override
public void run() {
chatMsg.setText(msgLog);
}
});
这是在加密消息:
OnClickListener buttonEncryptOnClickListener = new OnClickListener() {
public void onClick(View v) {
if (chatClientThread == null) {
return;
}
if (editTextSay.getText().toString().equals("")) {
return;
}
if(!editTextSay.getText().toString().equals("")){
String message = editTextSay.getText().toString();
encrypt = true;
int secLvl = Integer.parseInt(editTextSecurity.getText().toString());
String encryptedMsg;
try {
encryptedMsg = AESHelper.encrypt(seed, message);
textEncryptedmsg.setText(encryptedMsg);
textEncryptedmsg.setVisibility(View.VISIBLE);
} catch (Exception e) {
e.printStackTrace();
}
}
}
};
正在发送消息:
OnClickListener buttonSendOnClickListener = new OnClickListener() {
@Override
public void onClick(View v) {
if (editTextSay.getText().toString().equals("")) {
return;
}
if(chatClientThread==null){
return;
}
if (encrypt == true){
chatClientThread.sendMsg(textEncryptedmsg.getText().toString() + "n");
} else {
chatClientThread.sendMsg(editTextSay.getText().toString() + "n");
}
editTextSay.setText("");
textEncryptedmsg.setText("");
textDecryptedmsg.setText("");
encrypt = false;
incomingmsg.setVisibility(View.VISIBLE);
}
};
我假设您以十六进制编码的形式发送密文。DataInputStream#readUTF()
从流中读取单个Unicode字符。由于您发送的是十六进制字符,这将意味着可以由两个这样的Unicode字符构造单个密文字节。
问题是AES在块上操作。试图单独解密每个"半"字节是行不通的。
您需要将解密方法重写为
- 使用流解密或
- 读取整个密文并一次解密。
如果你想尝试流式解密,那么你基本上有两个选择:
- 使用
Cipher#update()
或 的偏移版本更新Cipher对象的内部缓冲区。 - 使用
CipherInputStream
下面是一个(伪代码)示例,在尝试解密之前读取整个内容:
StringBuilder incoming = new StringBuilder();
while (!goOut && ) {
incoming.append(dataInputStream.readUTF());
}
if(encrypt == true) {
try{
msgLog += AESHelper.decrypt(seed, incoming.toString());
} catch (Exception e) {
e.printStackTrace();
}
} else msgLog += incoming;
我找到了一个解决问题的方法,而不使用CipherInputStream
。每当我加密并发送消息时,加密/解密算法都不会解密从服务器接收到的消息。由于输出的加密消息与我发送的相同,因此我将传入的加密消息打印到TextView
中,然后将TextView
复制到String
中并对其进行解密,现在它运行得很好。
while (!goOut) {
if (dataInputStream.available() > 0) {
final String incoming = dataInputStream.readUTF();
MainActivity.this.runOnUiThread(new Runnable() {
@Override
public void run() {
incomingmsg.setText(incoming);
mustDecrypt = incomingmsg.getText().toString();
if (encrypt)
try {
mustDecrypt = AESHelper.decrypt(seed, mustDecrypt);
msgLog += mustDecrypt;
} catch (Exception e){
e.printStackTrace();
}
else msgLog += mustDecrypt;
chatMsg.setText(msgLog);
}
});
}