En teoria els algorismes de xifrat són genèrics i independents del llenguatge de programació. En la realitat sempre hi ha sorpreses. Ja vaig haver de patir per una altra interoperabilitat similar entre PL/SQL i Java, així que anava avisat.
Per xifrar i desxifrar des de Java es fa amb la Java Cryptography Architecture (JCA). Cal indicar l'algorisme i el tipus de padding, i sel·leccionar i una clau i un vector d'inicialització.
Per fer-ho des de PHP cal fer servir el mòdul mcrypt. En funció del sistema operatiu cal revisar que estigui instal·lat el mòdul (revisant el
phpinfo
) i mirar quins ciphers i modes són actius.Caldrà triar un algorisme de xifrat que sigui vàlid als dos entorns i nosaltres vam triar compartir el resultat en format hexadecimal. També és important triar la mida de la clau i del vector d'incialització. Per encriptació de 128-bits la clau ha de ser de 16 bytes i per 256-bits de 32 bytes.
El problema entre els dos llenguatges és com tracten el padding, el farcit de caràcters fins arribar a la mida de cadena correcta. Mcrypt sempre farceix amb \0 (null) i no pas amb espais.
Jugant amb trims i NoPaddings de Java s'aconsegueix la màgia. Nosaltres vam triar encriptació amb AES de 128 bits.
El xifrat a Java es fa així:
import javax.crypto.Cipher;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
...
private String padString(String source) {
char paddingChar = ' ';
int size = 16;
int padLength = size - source.length() % size;
for (int i = 0; i < padLength; i++) {
source += paddingChar;
}
return source;
}
public String encrypt(String text) {
String encrypted = null;
try {
cipher = Cipher.getInstance("AES/CBC/NoPadding");
} catch (Exception e) {
logger.error("Error creating cipher instance", e);
}
try {
SecretKeySpec keySpec = new SecretKeySpec(key.getBytes(), "AES");
IvParameterSpec ivSpec = new IvParameterSpec(iv.getBytes());
if (cipher != null) {
cipher.init(Cipher.ENCRYPT_MODE, keySpec, ivSpec);
byte[] res = cipher.doFinal(padString(text).getBytes());
encrypted = asHex(res);
}
} catch (Exception e) {
logger.error("Error ciphering", e);
}
return encrypted;
}
El desxifrat a PHP el fem així:
function decrypt($param) {
$cipher = mcrypt_module_open(MCRYPT_RIJNDAEL_128, '', MCRYPT_MODE_CBC, '');
$key128 = '0123456789ABCDEF';
$iv = 'FEDCBA9876543210';
$decrypted = mcrypt_decrypt(MCRYPT_RIJNDAEL_128, $key128, hex2bin($param), MCRYPT_MODE_CBC, $iv);
$decrypted = trim($decrypted);
return $decrypted;
}
No comments:
Post a Comment