128-битное шифрование AES CBC с использованием Java и PHP
Недавно я использовал алгоритм AES CBC 128 в Java для шифрования данных. Теперь мне нужно перестроить этот алгоритм в PHP, но я понятия не имею, как, потому что алгоритмы PHP в Интернете дают разные результаты. Возможно ты можешь помочь мне.
Это Java-код для шифрования:
private SecretKeySpec secretKey;
private IvParameterSpec ivSpec;
public void setKey(String myKey) {
MessageDigest sha = null;
try {
byte[] key = myKey.getBytes("UTF-8");
sha = MessageDigest.getInstance("SHA-1");
key = sha.digest(key);
key = Arrays.copyOf(key, 16);
secretKey = new SecretKeySpec(key, "AES");
byte[] iv = new String("1010101010101010").getBytes("UTF-8");
ivSpec = new IvParameterSpec(iv);
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
}
public String encrypt(String strToEncrypt) {
try {
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
cipher.init(Cipher.ENCRYPT_MODE, secretKey, ivSpec);
return Base64.encode(cipher.doFinal(strToEncrypt.getBytes("UTF-8")));
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
public String decrypt(String strToDecrypt) {
try {
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
cipher.init(Cipher.DECRYPT_MODE, secretKey, ivSpec);
return new String(cipher.doFinal(Base64.decode(strToDecrypt)));
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
public static void main(String[] args) {
AESText aes = new AESText();
final String secretKey = "com.secure.test.projectjasdS/FjkGkGhkGjhG786Vjfg=tjGFGH";
aes.setKey(secretKey);
String originalString = "test set se ts et set s et se";
String encryptedString = aes.encrypt(originalString);
String decryptedString = aes.decrypt(encryptedString);
System.out.println("origin: " + originalString);
System.out.println("encrypted: " + encryptedString);
System.out.println("decrypted: " + decryptedString);
}
Это мой php код:
protected $key;
protected $method = 'AES-128-CBC';
protected $iv = '1010101010101010';
protected $option = OPENSSL_CIPHER_AES_128_CBC;
function __construct($key)
{
$this->key = $key;
}
public function encrypt($data) {
if (is_null($data)) {
return "Error " . INVALID_PARAMS_ENCRYPTIONS . ": Data is null ";
}
$enc = openssl_encrypt($data, $this->method, $this->key, $this->option, $this->iv);
return base64_encode($enc);
}
public function decrypt($data) {
if (is_null($data)) {
return "Error " . INVALID_PARAMS_ENCRYPTIONS . ": Data is null ";
}
$data = base64_decode($data);
$dec = openssl_decrypt($data, $this->method, $this->key, $this->option, $this->iv);
return $dec;
}
Когда я зашифровал данные из Java-шифрования, этот результат не может быть расшифрован при расшифровке Php.
Ребята, можете ли вы помочь мне с созданием сценария PHP, который возвращает те же результаты с Java-шифрованием?
1 ответ
На первый взгляд я вижу здесь три проблемы:
Во-первых: вы не используете тот же режим: в Java у вас есть AES/ECB/PKCS5Padding
тогда как ваш PHP использует AES-128-CBC
,
Второе: вы, вероятно, не используете одни и те же IV в коде Java и PHP (IV не имеют значения для ECB, но как только вы переключите Java на CBC, он вам понадобится):
У тебя есть $iv = '1010101010101010'
(который затем передается openssl) в вашем PHP, но ничего подобного в вашей Java.
По крайней мере, вам, вероятно, понадобится нечто подобное и в вашей Java-части:
cipher.init(Cipher.DECRYPT_MODE/ENCRYPT_MODE, secretKey, new IvParameterSpec(iv))
с iv
быть byte[]
содержащий ваши IV байты.
В-третьих: после решения вышеуказанных проблем заполнение может стать следующей проблемой: в спецификации Java-шифра упоминается PKCS5Padding
, Вы должны убедиться, что оба ваших коллег используют одно и то же.
редактирование: четвертое: еще одна проблема заключается в том, как вы получаете ключевые биты, которые будут использоваться. В java вы берете первые 16 байтов sha1-хеша, а в php вы просто передаете $key
в openssl. openssl может получить ключ шифрования другим способом.
При создании инструментов, связанных с криптографией, с использованием блочных шифров, всегда полезно вернуться к классике, такой как режим работы блочного шифра и заполнение в Википедии, чтобы понять, что происходит под капотом.