php - Android中的加密相当于php的MCRYPT_RIJNDAEL_256

标签 php android encryption

我正在使用下面的 php 代码进行加密:


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

现在尝试在 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 中也获得相同正确的加密字符串。

最佳答案

我使用 Bouncy CaSTLe 在 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。后来我发现,Bouncy CaSTLe 和 PHP 在这方面是有区别的:Bouncy CaSTLe 期望你总是需要 pad,而 PHP 则不需要。所以 Bouncy 添加 1..n 字节,而 PHP 添加 0..(n-1) 字节,其中 n 是 block 大小(Rijndael-256/256 为 32 字节)。因此,您可能必须自己进行填充/取消填充;一定要测试边缘情况!

关于php - Android中的加密相当于php的MCRYPT_RIJNDAEL_256,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/18101545/

相关文章:

android - 多线程处理程序与 ThreadPoolExecutor

java - GNU Crypto Encrypt 返回空白字符串

python - 无法在 python 中的 AES.MODE_CTR 密码中使用 256 位计数器

javascript - Parse.com 云代码 RSA 验证 - Android 应用内购买验证

php - 如何连接mysql的两个表并将多行连接成一个单元格?

php - 用于打开电子邮件的 Bootstrap 按钮

PHPExcel - 合并单元格的动态行高

android - 无法更改操作栏中的图标颜色

android - 如何使用与文本颜色不同的颜色在 TextView 中为文本添加下划线?

php - 如何通过在htaccess中重写来删除部分URL