Мне нужно получить доступ к некоторым данным, которые использовали шифрование PHP. Шифрование PHP похоже на это.
base64_encode(mcrypt_encrypt(MCRYPT_RIJNDAEL_256, md5($cipher), $text, MCRYPT_MODE_ECB));
В качестве значения $ text они передают значение функции time (), которое будет отличаться при каждом вызове метода. Я реализовал это в Java. Как это,
public static String md5(String string) {
byte[] hash;
try {
hash = MessageDigest.getInstance("MD5").digest(string.getBytes("UTF-8"));
} catch (NoSuchAlgorithmException e) {
throw new RuntimeException("Huh, MD5 should be supported?", e);
} catch (UnsupportedEncodingException e) {
throw new RuntimeException("Huh, UTF-8 should be supported?", e);
}
StringBuilder hex = new StringBuilder(hash.length * 2);
for (byte b : hash) {
int i = (b & 0xFF);
if (i < 0x10) hex.append('0');
hex.append(Integer.toHexString(i));
}
return hex.toString();
}
public static byte[] rijndael_256(String text, byte[] givenKey) throws DataLengthException, IllegalStateException, InvalidCipherTextException, IOException{
final int keysize;
if (givenKey.length <= 192 / Byte.SIZE) {
keysize = 192;
} else {
keysize = 256;
}
byte[] keyData = new byte[keysize / Byte.SIZE];
System.arraycopy(givenKey, 0, keyData, 0, Math.min(givenKey.length, keyData.length));
KeyParameter key = new KeyParameter(keyData);
BlockCipher rijndael = new RijndaelEngine(256);
ZeroBytePadding c = new ZeroBytePadding();
PaddedBufferedBlockCipher pbbc = new PaddedBufferedBlockCipher(rijndael, c);
pbbc.init(true, key);
byte[] plaintext = text.getBytes(Charset.forName("UTF8"));
byte[] ciphertext = new byte[pbbc.getOutputSize(plaintext.length)];
int offset = 0;
offset += pbbc.processBytes(plaintext, 0, plaintext.length, ciphertext, offset);
offset += pbbc.doFinal(ciphertext, offset);
return ciphertext;
}public static String encrypt(String text, String secretKey) throws Exception {byte[] givenKey = String.valueOf(md5(secretKey)).getBytes(Charset.forName("ASCII"));
byte[] encrypted = rijndael_256(text,givenKey);
return new String(Base64.encodeBase64(encrypted));
}
Я сослался на этот ответ при создании метода MCRYPT_RIJNDAEL_256. «Шифрование в Android эквивалентно MCRYPT_RIJNDAEL_256 php
«Я использовал кодек Apache для Base64. Вот как я вызываю функцию шифрования,
long time= System.currentTimeMillis()/1000;
String encryptedTime = EncryptionUtils.encrypt(String.valueOf(time), secretkey);
Проблема иногда в том, что вывод не похож на PHP, но иногда он работает нормально.
Я думаю, что мой метод MCRYPT_RIJNDAEL_256 ненадежен.
Я хочу знать, где я ошибся, и найти надежный метод, чтобы я всегда мог получить зашифрованную строку, аналогичную PHP.
Проблема, вероятно, заключается в ZeroBytePadding
, Один из Bouncy всегда добавляет / удаляет по крайней мере один байт со значением ноль (например, PKCS5Padding, от 1 до 16 байтов заполнения), но один из PHP только дополняет, пока не встретится граница первого блока (от 0 до 15 байтов заполнения). Я обсуждал это с Дэвидом из легиона Bouncy Castle, но заполнение нулевым байтом PHP крайне плохо подходит для того, как Bouncy выполняет заполнение, поэтому в настоящее время вам придется делать это самостоятельно и использовать шифр без заполнения.
Конечно, в качестве реального решения, переписать часть PHP, чтобы использовать AES (MCRYPT_RIJNDAEL_128
), Шифрование в режиме CBC, аутентификация HMAC, реальная функция получения ключа на основе пароля (PBKDF, например, PBKDF2 или bcrypt) и PKCS # 7-совместимое дополнение вместо этого небезопасного, несовместимого кода. В качестве альтернативы, перейдите на совместимость с OpenSSL или известный формат защищенного контейнера.
Других решений пока нет …