问题描述
我正在使用以下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个字节).因此,您可能必须自己做填充/取消附件;确保测试边缘情况!
问题描述
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!