So I have a specific problem in my code. It sometimes works, sometimes not and I have no idea why.
How it should work: Android encrypts a message using AES/CBC/PKCS5Padding with random IV and my secret key, converts encrypted message to base64 and sends it to server using POST method. Server converts message to binary form, decrypts it and appends smile to message. Next sends message back to Android. If message is empty, server sends me a "Empty" text.
How it works: I always receive data from server so connection is fine. Unfortunately I get 3 type of answers:
- My message with smile - that's OK
- "Empty..." text - but decrypt works somehow, no problem in PHP debug mode
- An error that my IV is too short - very rarely
A clue: I looked in base64 data and noticed that situation 2 appears when in base64 string is "+" char, but I don't know how it could help.
Android part to send data do server:
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 encrypt method:
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 file with my secret key also used in 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);
}
?>