Мне нужно кодировать строку в Java и PHP, где результат должен быть одинаковым.
Даны следующие условия:
String to encode: 201412181656005P443m2Q1R9A7f5r3e1z08642
<?php
class Cipher
{
private $securekey, $iv;
function __construct($textkey)
{
$this->securekey = $textkey;
$this->iv = mcrypt_create_iv(32);
}
function encryptR($input)
{
$enc = mcrypt_encrypt(MCRYPT_RIJNDAEL_128, $this->securekey, $input, MCRYPT_MODE_ECB, $this->iv);
return base64_encode($enc);
}
function decryptR($input)
{
return trim(mcrypt_decrypt(MCRYPT_RIJNDAEL_128, $this->securekey, base64_decode($input), MCRYPT_MODE_ECB, $this->iv));
}
}
$raw_text = '201412181656005P443m2Q1R9A7f5r3e1z08642';
$secretKey = '5P443m2Q1R9A7f5r3e1z08642';
$cipher = new Cipher($secretKey);
$encrypted = $cipher->encryptR($raw_text);
?>
encrypted = encrypt("201412181656005P443m2Q1R9A7f5r3e1z08642","5P443m2Q1R9A7f5r3e1z08642");
public class Crypt {
private final String characterEncoding = "UTF-8";
private final String cipherTransformation = "AES/ECB/PKCS5Padding";
private final String aesEncryptionAlgorithm = "AES";
public byte[] decrypt(byte[] cipherText, byte[] key) throws Exception
{
Cipher cipher = Cipher.getInstance(cipherTransformation);
SecretKeySpec secretKeySpecy = new SecretKeySpec(key, aesEncryptionAlgorithm);
cipher.init(Cipher.DECRYPT_MODE, secretKeySpecy);
cipherText = cipher.doFinal(cipherText);
return cipherText;
}
public byte[] encrypt(byte[] plainText, byte[] key) throws Exception
{
Cipher cipher = Cipher.getInstance(cipherTransformation);
SecretKeySpec secretKeySpec = new SecretKeySpec(key, aesEncryptionAlgorithm);
cipher.init(Cipher.ENCRYPT_MODE, secretKeySpec);
plainText = cipher.doFinal(plainText);
return plainText;
}
private byte[] getKeyBytes(String key) throws UnsupportedEncodingException{
byte[] keyBytes= new byte[16];
byte[] parameterKeyBytes= key.getBytes(characterEncoding);
System.arraycopy(parameterKeyBytes, 0, keyBytes, 0, Math.min(parameterKeyBytes.length, keyBytes.length));
return keyBytes;
}
@SuppressLint("NewApi")
public String encrypt(String plainText, String key) throws Exception {
byte[] plainTextbytes = plainText.getBytes(characterEncoding);
byte[] keyBytes = getKeyBytes(key);
// Log.i("iv", ""+keyBytesIV);
return Base64.encodeToString(encrypt(plainTextbytes,keyBytes), Base64.DEFAULT);
}
@SuppressLint("NewApi")
public String decrypt(String encryptedText, String key) throws Exception {
byte[] cipheredBytes = Base64.decode(encryptedText, Base64.DEFAULT);
byte[] keyBytes = getKeyBytes(key);
return new String(decrypt(cipheredBytes, keyBytes), characterEncoding);
}
}
Я изменил отступы от NoPadding
в PKCS5Padding
Это правильно? Я не уверен, потому что если вы посмотрите на код PHP. Не было указано никакого отступа (мое собственное предположение, основанное на синтаксисе).
Прочитай это документ относительно заполнения (No Padding). Должно быть, было связано с проблемой.
Похоже, ваша версия PHP использует AES-128, который по определению использует 128-битные (16-байтовые) ключи. Однако похоже, что вы передали в 25-байтном ключе (5P443m2Q1R9A7f5r3e1z08642
), что я не уверен, что делает PHP, когда это происходит.
Метод getKeyBytes () вашей версии Java возвращает только первые 16 байтов предоставленного ключа, поэтому он шифруется только этим.
Попробуйте усечь ключ в вашей версии PHP до 5P443m2Q1R9A7f5r
и вы получите тот же результат. За исключением конечной части, которая может отличаться. В этот момент проблема будет заключаться в дополнительном заполнении. Вы можете применить pkcs5_pad
Функция PHP на вашем открытом тексте, так что она соответствует вашей версии Java.
Все, что сказал, если это было только для учебных целей, это нормально. В противном случае для фактического использования важно, чтобы вы не используйте режим шифрования ECB.
Я изменился byte[] keyBytes= new byte[16];
в byte[] keyBytes= new byte[32];
в getKeyBytes
метод то работал нормально.