使用 PHP mcrypt 加密,使用 Android 解密。这个解密对吗?

发布于 2024-11-26 06:25:09 字数 3866 浏览 1 评论 0原文

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

这是尝试解密的 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);
        }

如有任何帮助,我们将不胜感激:)

Am I doing it right or is there a mistake? The test program I'm still trying to implement is running without any exceptions or errors. But it's not doing the thing it has to do and I can't find the problem.

Here is the Android code that attempts to decrypt:

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;
    }

Here is the PHP code that encrypts:

$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);
        }

Any help will be appreciated :)

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

新雨望断虹 2024-12-03 06:25:09

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

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

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

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

首先:ECB 不是安全模式 - 特别是对于图像(尽管 JPG 可能没有 BMP 那么糟糕)。如果您决定更改为 CBC,请记住您需要通过将 IV, fx 添加到加密数据前面来传输它。但如果您想解密 CBC,则需要在 Cipher.getInstance() 调用中指明它(您当前使用 AES/CBC/PKCS5Padding)。

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

最后:使用 AES-256 进行加密。它使用 32 字节密钥。根据 mcrypt-documentation 如果密钥太,它会添加 \0s简短,因此您要么必须使用实际的 32 字节密钥,要么也将 \0 添加到 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);

You are trying to decrypt with a randomly generated key (adding a seed to a SecureRandom only supplements the random state). That is sure to fail.

If "MARTIN_123_MARTIN_123".getBytes() is your key (or rather: the first 16 bytes of it), you should just pass that directly to your decrypt-method:

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

Okay, from your comment, I can see that you are encrypting with PHP:mcrypt using AES-256/ECB/ZeroBytePadding (zero-byte padding is implicit with mcrypt).

First of all: ECB is not a safe mode - especially for images (though JPGs are probably not quite as bad as BMPs). If you decide to change to CBC, remember that you need to transmit the IV, f.x. by prepending it to the encrypted data. But if you want to decrypt CBC, you need to indicate it in your Cipher.getInstance()-call (you currently use AES/CBC/PKCS5Padding).

Zero-byte-padding is not really removable unless you know the length of the data. So you must either transmit the length or add PKCS#7 padding before encrypting the data.

Finally: you encrypt using AES-256. That uses a 32-byte key. According to the mcrypt-documentation it adds \0s if the key is too short, so you will either have to use an actual 32-byte key or add \0s to the Android-side, too.

Change your code to this on the Android side:

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;
}

And on the PHP side:

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);
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文