Эквивалент Java для шифрования/дешифрования PHP Triple DES ECB

У меня есть функция PHP ниже, которую я хочу реализовать на Java, но мне не повезло, я не могу получить тот же результат:

function encryptText( $plainText, $key )
{
    $mcopen = mcrypt_module_open (MCRYPT_TripleDES, "", MCRYPT_MODE_ECB,"");
    $iv = mcrypt_create_iv (mcrypt_enc_get_iv_size ($mcopen), MCRYPT_RAND);
    $td = mcrypt_module_open('tripledes', '', 'ecb', '');
    $cryptedHash = '';

    if (mcrypt_generic_init($td, $key, $iv) != -1)
    {
        $cryptedHash = mcrypt_generic($td, $plainText);
        mcrypt_generic_deinit($td);
        mcrypt_module_close($td);
    }
    return base64_encode($cryptedHash);
 }

Это мой код Java, найденный здесь:

public static String encrypt(String message, String key) throws Exception {
    final MessageDigest md = MessageDigest.getInstance("md5");
    final byte[] digestOfPassword = md.digest(key.getBytes("utf-8"));
    final byte[] keyBytes = Arrays.copyOf(digestOfPassword, 24);
    for (int j = 0, k = 16; j < 8;) {
        keyBytes[k++] = keyBytes[j++];
    }

    final SecretKey keyz = new SecretKeySpec(keyBytes, "DESede");
    final IvParameterSpec iv = new IvParameterSpec(new byte[8]);
    final Cipher cipher = Cipher.getInstance("DESede/CBC/PKCS5Padding");
    cipher.init(Cipher.ENCRYPT_MODE, keyz, iv);

    final byte[] plainTextBytes = message.getBytes("utf-8");
    final byte[] cipherText = cipher.doFinal(plainTextBytes);
    final String encodedCipherText = new   sun.misc.BASE64Encoder().encode(cipherText);

    return encodedCipherText;
}

person Mustapha K.    schedule 13.09.2015    source источник


Ответы (2)


У вас есть пара проблем.

  • Поскольку вы хотите использовать режим ECB, вам необходимо указать режим ECB. CBC - это другой режим.

  • Вы не запускаете свой ключ через MD5 в коде PHP, поэтому вам не следует делать это в Java.

  • Блочному шифру в режиме ECB или CBC требуется дополнение для шифрования произвольных сообщений. Mcrypt по умолчанию использует нулевое заполнение, но вы указываете заполнение PKCS#5 в Java. Поскольку поставщики Sun по умолчанию не реализуют ZeroPadding, вам нужно будет либо реализовать его самостоятельно, указав «NoPadding» и внедрив заполнение нулями, либо использовать поставщика BouncyCastle: Cipher.getInstance("DESede/ECB/ZeroPadding", "BC").


Другие соображения:

Никогда не используйте режим ECB. Это не семантически безопасно. Если вы дважды зашифруете одно и то же сообщение одним и тем же ключом, злоумышленник может легко увидеть, что вы снова зашифровали одно и то же сообщение (или одну и ту же часть сообщения).

person Artjom B.    schedule 13.09.2015
comment
Спасибо за этот ответ. Постараюсь выполнить ваши рекомендации. Для режима ECB я знаю, что он не очень безопасен, но это то, что на самом деле реализовано на стороне php (партнер). - person Mustapha K.; 14.09.2015

Решено, решение:

public static String cryptBC(String data, String key) throws Exception{
    Security.addProvider(new org.bouncycastle.jce.provider.BouncyCastleProvider());
    byte[] input = data.getBytes();
    byte[] keyBytes = key.getBytes() ;   
    SecretKeySpec skey = new SecretKeySpec(keyBytes, "DESede");
    Cipher cipher = Cipher.getInstance("DESede/ECB/NoPadding", "BC");

    if(input.length % 8 != 0){ 
        byte[] padded = new byte[input.length + 8 - (input.length % 8)];
        System.arraycopy(input, 0, padded, 0, input.length);
        input = padded;
    }
    System.out.println("input : " + new String(input));
    cipher.init(Cipher.ENCRYPT_MODE, skey);
    byte[] cipherText = new byte[cipher.getOutputSize(input.length)];
    int ctLength = cipher.update(input, 0, input.length, cipherText, 0);
    ctLength += cipher.doFinal(cipherText, ctLength);

    return new String(Base64.encodeBase64(cipherText));
}
person Mustapha K.    schedule 16.09.2015