【问题标题】:Encrypting with PHP mcrypt, decrypting with Android. Is this decryption right?用 PHP mcrypt 加密,用 Android 解密。这个解密对吗?
【发布时间】:2011-10-13 10:44:36
【问题描述】:

我做得对还是有错误?我仍在尝试实施的测试程序正在运行,没有任何异常或错误。但它没有做它必须做的事情,我找不到问题。

这是尝试解密的 Android 代码:

private static final int IO_BUFFER_SIZE = 4 * 1024;
@Override
public void onCreate(Bundle savedInstanceState){
    super.onCreate(savedInstanceState);
    setContentView(R.layout.main);

            try {
                AssetManager am = this.getAssets();
                InputStream is = am.open("2000_1.jpg_encrypted"); // get the encrypted image from assets folder

                ByteArrayOutputStream baos = new ByteArrayOutputStream();  
                byte[] b = new byte[IO_BUFFER_SIZE];  
                int read;  
                while ((read = is.read(b)) != -1) {  //convert inputstream to bytearrayoutputstream
                    baos.write(b, 0, read);
                }                           
                //START
                long start = System.currentTimeMillis()/1000L; // start

                //byte[] keyStart = "MARTIN_123_MARTIN_123".getBytes();  // specific key value 
                KeyGenerator kgen = KeyGenerator.getInstance("AES/CBC/PKCS5Padding");   //aes
                SecureRandom sr = SecureRandom.getInstance("SHA1PRNG");
                //sr.setSeed(keyStart);
                kgen.init(128, sr); 
                //SecretKey skey = kgen.generateKey();
                //byte[] key = skey.getEncoded();    

                byte[] key = "MARTIN_123_MARTIN_123".getBytes("UTF-8");
                byte[] iv = "1234567890123456".getBytes("UTF-8");
                byte[] decryptedData = decrypt(key, iv, b);


                //END
                long end = System.currentTimeMillis()/1000L;    // end
                Log.d("TEST","Time start "+ String.valueOf(start)); //showing the strat in ms
                Log.d("TEST","Time end "+ String.valueOf(end));     //showing the end in ms

                Bitmap bitmap = BitmapFactory.decodeByteArray(decryptedData , 0, decryptedData .length);    //decoding bytearrayoutputstream to bitmap
                //String filepath = Environment.getExternalStorageDirectory()+"bitmap";
                FileOutputStream fos = new FileOutputStream("sdcard/DCIM/100ANDRO");
                fos.write(decryptedData);
                fos.close();

                is.close(); // close the inputstream
                baos.close(); // close the bytearrayoutputstream
            }
            catch(Exception e){
                e.fillInStackTrace();
            }
        } 

        //decrypt
        private byte[] decrypt(byte[] raw, byte[] iv, byte[] encrypted) throws Exception {
      SecretKeySpec skeySpec = new SecretKeySpec(raw, "AES");
      Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
      IvParameterSpec ivspec = new IvParameterSpec(iv);         
      cipher.init(Cipher.DECRYPT_MODE, skeySpec, ivspec);
      byte[] decrypted = cipher.doFinal(encrypted);

      return decrypted;
    }

这是加密的 PHP 代码:

$folder = $this->getConfiguration()->getAppRootDir() . '/temp_encryption_testing/';

$files = array(
        '007FRAMESUPERIOR.jpg',
        '2000_1.jpg',
        'APLICACIONdescargaliga.jpg',
        'APPCOMMENTS.pdf',
        'AUDIOVISUALFOTO02.jpg'
        );
$iv_size = mcrypt_get_iv_size(MCRYPT_RIJNDAEL_256, MCRYPT_MODE_ECB);
        $iv = mcrypt_create_iv($iv_size, MCRYPT_RAND);
        $key = "MARTIN_123_MARTIN_123";
foreach($files as $file)
{
            $input_file = $folder . $file;
$text = file_get_contents($input_file);
            //$text = "Meet me at 11 o'clock behind the monument.";
            echo strlen($text) . "\n";
$crypttext = mcrypt_encrypt(MCRYPT_RIJNDAEL_256, $key, $text, MCRYPT_MODE_ECB, $iv);
            echo strlen($crypttext) . "\n";
            file_put_contents($input_file . '_encrypted', $crypttext);
        }

任何帮助将不胜感激:)

【问题讨论】:

  • 我让这个问题更容易找到。希望你没事。

标签: php android encryption cryptography mcrypt


【解决方案1】:

您正在尝试使用随机生成的密钥进行解密(将种子添加到 SecureRandom 只会补充随机状态)。那肯定会失败。

如果 "MARTIN_123_MARTIN_123".getBytes() 是您的密钥(或者更确切地说:它的前 16 个字节),您应该直接将其传递给您的解密方法:

byte[] decryptedData = decrypt(keyStart,b);

好的,从您的评论中,我可以看到您正在使用 AES-256/ECB/ZeroBytePadding 使用 PHP:mcrypt 进行加密(mcrypt 隐含零字节填充)。

首先:ECB 不是一种安全模式 - especially for images(尽管 JPG 可能不如 BMP 糟糕)。如果您决定更改为 CBC,请记住您需要传输 IV,f.x。通过将其添加到加密数据中。但是如果你想解密CBC,你需要在你的Cipher.getInstance()-call中注明(你目前使用AES/CBC/PKCS5Padding)。

除非您知道数据的长度,否则零字节填充实际上是不可移除的。因此,您必须在加密数据之前传输长度或添加 PKCS#7 填充。

最后:您使用 AES-256 进行加密。它使用一个 32 字节的密钥。根据mcrypt-documentation,如果密钥太短,它会添加 \0s,因此您要么必须使用实际的 32 字节密钥,要么也将 \0s 添加到 Android 端。

在 Android 端将您的代码更改为:

byte[] key = "MARTIN_123456789".getBytes("UTF-8");
byte[] iv = "1234567890123456".getBytes("UTF-8");
byte[] decryptedData = decrypt(key, iv, b);

private byte[] decrypt(byte[] raw, byte[] iv, byte[] encrypted) throws Exception {
  SecretKeySpec skeySpec = new SecretKeySpec(raw, "AES");
  Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
  IvParameterSpec ivspec = new IvParameterSpec(iv);         
  cipher.init(Cipher.DECRYPT_MODE, skeySpec, ivspec);
  byte[] decrypted = cipher.doFinal(encrypted);

  return decrypted;
}

在 PHP 方面:

function addpadding($string, $blocksize = 16){
    $len = strlen($string);
    $pad = $blocksize - ($len % $blocksize);
    $string .= str_repeat(chr($pad), $pad);
    return $string;
}

$key = "MARTIN_123456789";
$iv = "1234567890123456"
$crypttext = mcrypt_encrypt(MCRYPT_RIJNDAEL_128, $key, addpadding($text), MCRYPT_MODE_CBC, $iv);

【讨论】:

  • 我的密钥只是“MARTIN_123_MARTIN_123”。那么我需要在哪里添加呢?你能帮帮我吗?
  • @Android:小更新。如果这不起作用,请添加一些有关数据如何加密的信息。
  • @Android:再次更新。恐怕您的代码有很多 问题。我的建议是使用 AES/CBC/PKCS5Padding 和 32 字节密钥对其进行实际加密(然后您的 Android 代码几乎是正确的)。
  • 我理解你说的一些事情。实际上这个应用程序只是为了测试 AES 的速度。你能告诉我我的代码需要改变什么吗,因为我很新在加密/解密中,我仍然不确定如何才能把事情做好。真的很感激!
  • 所以基本上我更新了我的问题的更改,但是我在 sdcard 中找不到解密的图像,并且 Log.d 没有出现在我的 LogCat 中。有什么建议可以解决这些问题吗?
猜你喜欢
  • 2015-11-10
  • 2013-12-28
  • 2014-02-24
  • 2013-04-14
  • 2011-01-24
  • 2012-07-27
  • 2014-09-12
  • 2014-06-28
  • 2011-01-27
相关资源
最近更新 更多