所以我的代码中有一个特定的问题。它有时是有效的,有时不是,我不明白为什么。
如何运作:Android使用带有随机IV和我的密钥的AES / CBC / PKCS5Padding对邮件进行加密,将加密邮件转换为base64并使用POST方法将其发送到服务器。 服务器将消息转换为二进制形式,对其进行解密并将消息附加到消息中。接下来将消息发送回Android。如果消息为空,服务器会向我发送一个"空"文本。
工作原理:我总是从服务器接收数据,因此连接正常。不幸的是,我得到了3种答案:
线索:我查看了base64数据并发现当base64字符串为" +"时出现情况2 char,但我不知道它会如何帮助。
Android部分发送数据做服务器:
HttpURLConnection urlConnection;
String message = null;
String answer = null;
String data = "a piece of data";
try {
byte[] wynikByte = encrypt(data.getBytes("UTF-8"));
message = Base64.encodeToString(wynikByte, Base64.DEFAULT);
} catch (UnsupportedEncodingException ex){
Log.e("CRYPT", "Not working");
}
try {
// Connect to server
urlConnection = (HttpURLConnection) ((new URL(url).openConnection()));
urlConnection.setDoOutput(true);
urlConnection.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");
urlConnection.setRequestMethod("POST");
urlConnection.connect();
// Send to server
OutputStream outputStream = urlConnection.getOutputStream();
BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(outputStream, "UTF-8"));
writer.write("dane=" + message);
writer.close();
outputStream.close();
// Read answer
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(urlConnection.getInputStream(), "UTF-8"));
String line = null;
StringBuilder sb = new StringBuilder();
while ((line = bufferedReader.readLine()) != null) {
sb.append(line);
}
bufferedReader.close();
answer = sb.toString();
} catch (UnsupportedEncodingException | IOException ex) {
e.printStackTrace();
}
return message + "\n" + answer;
Android加密方法:
public static byte[] encrypt(byte[] plaintext) {
try {
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
SecretKey key = new SecretKeySpec(hexStringToByteArray(klucz2), "AES");
SecureRandom random = new SecureRandom();
byte iv[] = new byte[16];//generate random 16 byte IV AES is always 16bytes
random.nextBytes(iv);
IvParameterSpec ivspec = new IvParameterSpec(iv);
cipher.init(Cipher.ENCRYPT_MODE, key, ivspec);
byte[] encrypted = cipher.doFinal(plaintext);
byte[] ciphertext = new byte[iv.length + encrypted.length];
System.arraycopy(iv, 0, ciphertext, 0, iv.length);
System.arraycopy(encrypted, 0, ciphertext, iv.length, encrypted.length);
return ciphertext;
} catch (InvalidKeyException | NoSuchAlgorithmException
| NoSuchPaddingException
| IllegalBlockSizeException | InvalidAlgorithmParameterException
| BadPaddingException e) {
throw new IllegalStateException(
"CBC encryption with standard algorithm should never fail",
e);
}
}
带有我的密钥的PHP文件也在android app中使用:
<?php
if (isset($_POST['dane']))
{
$dane = $_POST['dane'];
$key = pack('H*', "73f826a001837efe6278b82789267aca");
$blocksize = mcrypt_get_block_size('rijndael_128', 'cbc');
$ciphertext = base64_decode($dane, $powodzenie);
$iv_size = mcrypt_get_iv_size(MCRYPT_RIJNDAEL_128, MCRYPT_MODE_CBC);
$iv_old = substr($ciphertext, 0, $iv_size);
$ciphertext = substr($ciphertext, $iv_size);
$plaintext = mcrypt_decrypt(MCRYPT_RIJNDAEL_128, $key, $ciphertext, MCRYPT_MODE_CBC, $iv_old);
$plaintext = pkcs5_unpad($plaintext);
if($plaintext == "")
{
echo "Empty...";
return;
}
$plaintext = $plaintext . " :)";
echo $plaintext;
} else {
echo "Dane is empty";
}
// PHP don't have pkcs5 methods to pad
function pkcs5_pad ($text, $blocksize)
{
$pad = $blocksize - (strlen($text) % $blocksize);
return $text . str_repeat(chr($pad), $pad);
}
// PHP don't have pkcs5 methods to unpad
function pkcs5_unpad($text)
{
$pad = ord($text{strlen($text)-1});
if ($pad > strlen($text)) return false;
if (strspn($text, chr($pad), strlen($text) - $pad) != $pad) return false;
return substr($text, 0, -1 * $pad);
}
?>
答案 0 :(得分:1)
您需要在标记的行之前正确编码message
字符串。是的,base64是7位安全的,但它也包含在表单编码数据中很重要的字符。 [+
和=
具体而言]
// Send to server
OutputStream outputStream = urlConnection.getOutputStream();
BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(outputStream, "UTF-8"));
writer.write("dane=" + message); // here
writer.close();
outputStream.close();
解决方案1将分别用+
和=
替换%2B
和%3D
。
解决方案2将切换到多部分编码。
我的偏好是解决方案2.实施起来需要做更多的工作,但是你可以获得更多的收益。