Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

how to encrypt and decrypt data between php and android

These are my classes used in order to encrypt and decrypt data between a php based server and an android application.

Sometimes the php decrypt class does not work:

For example when I encrypt "abc" or "zdf" or "091360532561524369510" in android, the php class could not decrypt the encrypted data from the android client side.

Can you please check these classes? java class:

import java.security.NoSuchAlgorithmException;

import javax.crypto.Cipher;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;

public class ApiCrypter
{
    private String iv= "0123456789012345";
    private String secretkey= "9876543210987654";
    private IvParameterSpec ivspec;
    private SecretKeySpec keyspec;
    private Cipher cipher;

    public ApiCrypter()
    {
        ivspec = new IvParameterSpec(iv.getBytes());
        keyspec = new SecretKeySpec(secretkey.getBytes(), "AES");

        try {
            cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        } catch (NoSuchPaddingException e) {
            e.printStackTrace();
        }
    }

    public byte[] encrypt(String text) throws Exception
    {
        if(text == null || text.length() == 0) {
            throw new Exception("Empty string");
        }
        byte[] encrypted = null;
        try {
            cipher.init(Cipher.ENCRYPT_MODE, keyspec, ivspec);
            encrypted = cipher.doFinal(text.getBytes("UTF-8"));
        }
        catch (Exception e) {
            throw new Exception("[encrypt] " + e.getMessage());
        }
        return encrypted;
    }

    public byte[] decrypt(String code) throws Exception
    {
        if(code == null || code.length() == 0) {
            throw new Exception("Empty string");
        }
        byte[] decrypted = null;
        try {
            cipher.init(Cipher.DECRYPT_MODE, keyspec, ivspec);
            decrypted = cipher.doFinal(hexToBytes(code));
        }
        catch (Exception e) {
            throw new Exception("[decrypt] " + e.getMessage());
        }
        return decrypted;
    }

    public static String bytesToHex(byte[] data)
    {
        if (data==null) {
            return null;
        }
        int len = data.length;
        String str = "";
        for (int i=0; i<len; i++) {
            if ((data[i]&0xFF)<16) {
                str = str + "0" + java.lang.Integer.toHexString(data[i]&0xFF);
            }
            else {
                str = str + java.lang.Integer.toHexString(data[i]&0xFF);
            }
        }
        return str;
    }

    public static byte[] hexToBytes(String str) {
        if (str==null) {
            return null;
        }
        else if (str.length() < 2) {
            return null;
        }
        else {
            int len = str.length() / 2;
            byte[] buffer = new byte[len];
            for (int i=0; i<len; i++) {
                buffer[i] = (byte) Integer.parseInt(str.substring(i*2,i*2+2),16);
            }
            return buffer;
        }
    }
}

PHP class :

<?php
class ApiCrypter
{
    private $iv  = '0123456789012345';
    private $key = '9876543210987654';

    public function __construct() 
    {
    }

    public function encrypt($str)
    { 
        $str = $this->pkcs5_pad($str);   
        $iv = $this->iv; 
        $td = mcrypt_module_open('rijndael-128', '', 'cbc', $iv); 
        mcrypt_generic_init($td, $this->key, $iv);
        $encrypted = mcrypt_generic($td, $str); 
        mcrypt_generic_deinit($td);
        mcrypt_module_close($td); 
        return bin2hex($encrypted);
    }

    public function decrypt($code)
    { 
        $code = $this->hex2bin($code);
        $iv = $this->iv; 
        $td = mcrypt_module_open('rijndael-128', '', 'cbc', $iv); 
        mcrypt_generic_init($td, $this->key, $iv);
        $decrypted = mdecrypt_generic($td, $code); 
        mcrypt_generic_deinit($td);
        mcrypt_module_close($td); 
        $ut =  utf8_encode(trim($decrypted));
        return $this->pkcs5_unpad($ut);
    }

    protected function hex2bin($hexdata)
    {
        $bindata = ''; 
        for ($i = 0; $i < strlen($hexdata); $i += 2) {
            $bindata .= chr(hexdec(substr($hexdata, $i, 2)));
        } 
        return $bindata;
    } 

    protected function pkcs5_pad ($text)
    {
        $blocksize = 16;
        $pad = $blocksize - (strlen($text) % $blocksize);
        return $text . str_repeat(chr($pad), $pad);
    }

    protected 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);
    }
}
?>
like image 315
X Fa Avatar asked Nov 08 '22 08:11

X Fa


1 Answers

A couple of things:

  1. Your IVs should be distinct per message and unpredictable; never hard-coded.
  2. Don't use mcrypt in PHP.

This is the easiest way to solve your problem:

  1. Get libsodium in both languages. If you upgrade your PHP to 7.2 or newer, you should get the Sodium extension automatically (unless your OS vendor is doing something wrong).
  2. Use crypto_secretbox() (or the equivalent API in your language) to encrypt, crypto_secretbox_open() to decrypt.

This is simpler than learning the proper way to fuss about with CBC mode, Initialization Vectors, padding schemes, RNGs, and ciphertext integrity.

like image 165
Scott Arciszewski Avatar answered Nov 14 '22 22:11

Scott Arciszewski