安卓系统中的加密相当于php'的MCRYPT_RIJNDAEL_256[英] Encryption in Android equivalent to php's MCRYPT_RIJNDAEL_256

本文是小编为大家收集整理的关于安卓系统中的加密相当于php'的MCRYPT_RIJNDAEL_256的处理/解决方法,可以参考本文帮助大家快速定位并解决问题,中文翻译不准确的可切换到English标签页查看源文。

问题描述

我正在使用以下PHP代码进行加密:


$enc_request = base64_encode(
    mcrypt_encrypt(MCRYPT_RIJNDAEL_256, 
                 $this->_app_key, 
                 json_encode($request_params), 
                 MCRYPT_MODE_ECB)
);

现在试图加密In Android并获取不同的加密字符串.以下是Android代码:


public void enc(){
    byte[] rawKey = getRawKey("my_key".getBytes());
    SecretKeySpec skeySpec = new SecretKeySpec(rawKey, "AES");
    Cipher cipher = Cipher.getInstance("AES");
    cipher.init(Cipher.ENCRYPT_MODE, skeySpec);
    byte[] encrypted = cipher.doFinal("my_message".getBytes());
    String result=Base64.encodeToString(encrypted, Base64.DEFAULT);
}

private static byte[] getRawKey(byte[] seed) throws Exception {
    KeyGenerator kgen = KeyGenerator.getInstance("AES");
    SecureRandom sr = SecureRandom.getInstance("SHA1PRNG");
    sr.setSeed(seed);
    kgen.init(256, sr); 
    SecretKey skey = kgen.generateKey();
    byte[] raw = skey.getEncoded();
    return raw;
}

任何人都可以帮助我,我错了吗?并在Android中获得相同正确的加密字符串.

推荐答案

我已经使用弹性城堡在Java中创建了main方法,以显示代码样本中使用的mcrypt_encrypt()的内部工作.

这主要是向其他开发人员表明,PHP的mcrypt_encrypt()是一种非常危险的使用方法.它不会失败,但这是因为它继续很久以前就应该停止的地方.例如,它添加或删除从密钥中的值.它在执行此操作时会发出警告,但不会直接显示在代码中.

public static void main(String[] args) throws DataLengthException, IllegalStateException, InvalidCipherTextException {

    // just some constants
    boolean ENCRYPT = true;
    boolean DECRYPT = false;

    // the key is either in binary in PHP or a string (dynamic isn't it?), lets assume ASCII
    byte[] givenKey = args[0].getBytes(Charset.forName("ASCII"));

    // determine the key size dynamically, somebody thought this was a good idea...
    // NOTE: PHP will emit a warning if the key size is larger, but will simply use the
    // largest key size otherwise
    final int keysize;
    if (givenKey.length <= 128 / Byte.SIZE) {
        keysize = 128;
    } else if (givenKey.length <= 192 / Byte.SIZE) {
        keysize = 192;
    } else {
        keysize = 256;
    }

    // create a 256 bit key by adding zero bytes to the decoded key
    byte[] keyData = new byte[keysize / Byte.SIZE];
    System.arraycopy(givenKey, 0, keyData, 0, Math.min(givenKey.length, keyData.length));
    KeyParameter key = new KeyParameter(keyData);

    // create a Rijndael cipher with 256 bit block size, this is not AES
    BlockCipher rijndael = new RijndaelEngine(256);

    // use a padding method that only works on data that cannot end with zero valued bytes
    ZeroBytePadding c = new ZeroBytePadding();

    // use ECB mode encryption, which should never be used
    PaddedBufferedBlockCipher pbbc = new PaddedBufferedBlockCipher(rijndael, c);

    // initialize the cipher using the key (no need for an IV, this is ECB)
    pbbc.init(ENCRYPT, key);

    // create a plain text byte array
    byte[] plaintext = args[1].getBytes(Charset.forName("UTF8"));

    // create a buffer for the ciphertext
    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);

    // show the ciphertext
    System.out.println(new String(Hex.encode(ciphertext), Charset.forName("ASCII")));

    // reverse the encryption
    pbbc.init(DECRYPT, key);
    byte[] decrypted = new byte[pbbc.getOutputSize(ciphertext.length)];
    offset = 0;
    offset += pbbc.processBytes(ciphertext, 0, ciphertext.length, decrypted, offset);
    offset += pbbc.doFinal(decrypted, offset);

    // this will probably print out correctly, but it isn't actually correct
    System.out.println(new String(decrypted, Charset.forName("UTF8")));

    // check out the zero's at the end
    System.out.println(new String(Hex.encode(decrypted), Charset.forName("UTF8")));

    // so lets make it a bit shorter... the PHP way
    // note that in PHP, the string may *not* contain a null terminator
    // add it yourself before printing the string
    System.out.println(new String(decrypted, Charset.forName("UTF8")).replaceAll("\\x00+$", ""));
}

警告:上面的代码包含ZeroBytePadding.后来,我发现在这方面有弹性城堡和PHP之间存在差异:Boncy Castle期望您始终必须加路,而PHP则没有.因此,弹性添加了1..n字节,而PHP添加0 ..(n-1)字节,其中n是块大小(Rijndael-256/256的32个字节).因此,您可能必须自己做填充/取消附件;确保测试边缘情况!

本文地址:https://www.itbaoku.cn/post/102562.html

问题描述

I am using the below php code for encryption:


$enc_request = base64_encode(
    mcrypt_encrypt(MCRYPT_RIJNDAEL_256, 
                 $this->_app_key, 
                 json_encode($request_params), 
                 MCRYPT_MODE_ECB)
);

Now trying to encrypt the in android and getting the different encrypted string. Below is the android code:


public void enc(){
    byte[] rawKey = getRawKey("my_key".getBytes());
    SecretKeySpec skeySpec = new SecretKeySpec(rawKey, "AES");
    Cipher cipher = Cipher.getInstance("AES");
    cipher.init(Cipher.ENCRYPT_MODE, skeySpec);
    byte[] encrypted = cipher.doFinal("my_message".getBytes());
    String result=Base64.encodeToString(encrypted, Base64.DEFAULT);
}

private static byte[] getRawKey(byte[] seed) throws Exception {
    KeyGenerator kgen = KeyGenerator.getInstance("AES");
    SecureRandom sr = SecureRandom.getInstance("SHA1PRNG");
    sr.setSeed(seed);
    kgen.init(256, sr); 
    SecretKey skey = kgen.generateKey();
    byte[] raw = skey.getEncoded();
    return raw;
}

Could any one help me, where I am wrong? And get same correct encrypted string in android too.

推荐答案

I've created a main method in Java using Bouncy Castle to show the inner workings of mcrypt_encrypt() used in your code sample.

This is mainly to show other developers that PHP's mcrypt_encrypt() is a very dangerous method to use. It won't fail much, but that is because it rather continues where it should have stopped long ago. For instance, it adds or removes values from the key. It emits a warning when it does do this, but it won't directly show in the code.

public static void main(String[] args) throws DataLengthException, IllegalStateException, InvalidCipherTextException {

    // just some constants
    boolean ENCRYPT = true;
    boolean DECRYPT = false;

    // the key is either in binary in PHP or a string (dynamic isn't it?), lets assume ASCII
    byte[] givenKey = args[0].getBytes(Charset.forName("ASCII"));

    // determine the key size dynamically, somebody thought this was a good idea...
    // NOTE: PHP will emit a warning if the key size is larger, but will simply use the
    // largest key size otherwise
    final int keysize;
    if (givenKey.length <= 128 / Byte.SIZE) {
        keysize = 128;
    } else if (givenKey.length <= 192 / Byte.SIZE) {
        keysize = 192;
    } else {
        keysize = 256;
    }

    // create a 256 bit key by adding zero bytes to the decoded key
    byte[] keyData = new byte[keysize / Byte.SIZE];
    System.arraycopy(givenKey, 0, keyData, 0, Math.min(givenKey.length, keyData.length));
    KeyParameter key = new KeyParameter(keyData);

    // create a Rijndael cipher with 256 bit block size, this is not AES
    BlockCipher rijndael = new RijndaelEngine(256);

    // use a padding method that only works on data that cannot end with zero valued bytes
    ZeroBytePadding c = new ZeroBytePadding();

    // use ECB mode encryption, which should never be used
    PaddedBufferedBlockCipher pbbc = new PaddedBufferedBlockCipher(rijndael, c);

    // initialize the cipher using the key (no need for an IV, this is ECB)
    pbbc.init(ENCRYPT, key);

    // create a plain text byte array
    byte[] plaintext = args[1].getBytes(Charset.forName("UTF8"));

    // create a buffer for the ciphertext
    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);

    // show the ciphertext
    System.out.println(new String(Hex.encode(ciphertext), Charset.forName("ASCII")));

    // reverse the encryption
    pbbc.init(DECRYPT, key);
    byte[] decrypted = new byte[pbbc.getOutputSize(ciphertext.length)];
    offset = 0;
    offset += pbbc.processBytes(ciphertext, 0, ciphertext.length, decrypted, offset);
    offset += pbbc.doFinal(decrypted, offset);

    // this will probably print out correctly, but it isn't actually correct
    System.out.println(new String(decrypted, Charset.forName("UTF8")));

    // check out the zero's at the end
    System.out.println(new String(Hex.encode(decrypted), Charset.forName("UTF8")));

    // so lets make it a bit shorter... the PHP way
    // note that in PHP, the string may *not* contain a null terminator
    // add it yourself before printing the string
    System.out.println(new String(decrypted, Charset.forName("UTF8")).replaceAll("\\x00+$", ""));
}

Warning: the above code contains ZeroBytePadding. I later discovered that there is a difference between Bouncy Castle and PHP in this respect: Bouncy Castle expects that you always have to pad, while PHP doesn't. So Bouncy adds 1..n bytes while PHP adds 0..(n-1) bytes, where n is the block size (32 bytes for Rijndael-256/256). So you may have to do the padding/unpadding yourself; be sure to test the edge cases!