我使用下面的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中获得相同的正确加密字符串。
答案 0 :(得分:4)
我使用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希望你总是需要填充,而PHP则不然。所以Bouncy增加1..n个字节,而PHP增加0 ..(n-1)个字节,其中n是块大小(Rijndael-256/256为32个字节)。所以你可能不得不自己填充/取消填充;一定要测试边缘情况!