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

查看:133
本文介绍了Android中的加密相当于php的MCRYPT_RIJNDAEL_256的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述






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






现在尝试加密android,不同的加密字符串以下是android代码:






  public void enc(){
byte [] rawKey = getRawKey(my_key.getBytes());
SecretKeySpec skeySpec = new SecretKeySpec(rawKey,AES);
密码密码= 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();
返回原始;
}






有没有人可以帮助我我哪里错了?并且在android中也得到相同的加密字符串。

解决方案

我创建了一个 main 方法在Java中使用Bouncy Castle来显示代码示例中使用的 mcrypt_encrypt()的内部工作。



这主要是为了向其他开发者显示PHP的 mcrypt_encrypt()是一种非常危险的方法。它不会失败太多,但这是因为它在很久以前就停止了。例如,它添加或删除键中的值。它会在执行此操作时发出警告,但不会直接显示在代码中。

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

//只是一些常量
boolean ENCRYPT = true;
boolean DECRYPT = false;

//键是以PHP或字符串进行二进制(动态不是吗?),假设ASCII
byte [] givenKey = args [0] .getBytes(Charset .forName( ASCII));

//动态确定密钥大小,有人认为这是一个好主意...
//注意:如果密钥大小较大,PHP会发出警告,但将简单地使用
//最大的键大小否则
final int keysize;
if(givenKey.length< = 128 / Byte.SIZE){
keysize = 128;
} else if(givenKey.length< = 192 / Byte.SIZE){
keysize = 192;
} else {
keysize = 256;
}

//通过向解码密钥添加零字节创建256位密钥
byte [] keyData = new byte [keysize / Byte.SIZE];
System.arraycopy(givenKey,0,keyData,0,Math.min(givenKey.length,keyData.length));
KeyParameter key = new KeyParameter(keyData);

//创建256位块大小的Rijndael密码,这不是AES
BlockCipher rijndael = new RijndaelEngine(256);

//使用一个仅适用于不能以零值字节结尾的数据的填充方法
ZeroBytePadding c = new ZeroBytePadding();

//使用ECB模式加密,不应该使用
PaddedBufferedBlockCipher pbbc = new PaddedBufferedBlockCipher(rijndael,c);

//使用密钥初始化密码(不需要IV,这是ECB)
pbbc.init(ENCRYPT,key);

//创建一个纯文本字节数组
byte [] plaintext = args [1] .getBytes(Charset.forName(UTF8));

//为密文创建一个缓冲区
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);

//显示密文
System.out.println(new String(Hex.encode(ciphertext),Charset.forName(ASCII)));

//反转加密
pbbc.init(DECRYPT,key);
byte [] decryptpted = new byte [pbbc.getOutputSize(ciphertext.length)];
offset = 0;
offset + = pbbc.processBytes(ciphertext,0,ciphertext.length,decryptulated,offset);
offset + = pbbc.doFinal(解密,offset);

//这可能会正确打印出来,但实际上并不正确
System.out.println(new String(decrypted,Charset.forName(UTF8)));

//查看结尾处的零
System.out.println(new String(Hex.encode(decryptpted)),Charset.forName(UTF8)));

//所以让它有点短... PHP的方式
//注意在PHP中,字符串可能不包含一个空终止符
//在打印字符串之前添加它
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个字节)。所以你可能需要做自己的填充/打包;一定要测试边缘情况!


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!

这篇关于Android中的加密相当于php的MCRYPT_RIJNDAEL_256的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆