【问题标题】:Xamarin.android- how to make encryption/decryption of images fasterXamarin.android-如何更快地对图像进行加密/解密
【发布时间】:2018-06-26 15:26:07
【问题描述】:

我希望用户从图库中选择图像/视频并在我的应用中保护他们的图像。为此,我加密了这些图像。对图像的加密工作正常(我想是的!)。 8MB 图像需要 1.5 到 2 秒。但是视频呢?视频可能以 GB 为单位。所以会花很多时间。即使在加密/解密中,我也必须对每个图像执行操作,这可能会导致内存问题。 This 链接帮助我实现了这一目标。

如果您看到,ES 文件浏览器还提供图像/视频的加密和解密。并在几秒钟内完成 GB 的操作。那么我能知道这些人使用哪种技术/算法吗?

或者即使我使用自己的方式,有什么技巧可以让它更快吗?还是有任何其他方法使用户无法访问文件?更改 MIME 类型会起作用吗?

即使我更改扩展名或通过添加隐藏它。在文件名之前,用户仍然可以在某些文件资源管理器中查看图像。

实际上对于xamarin,我没有找到任何与加密解密文件相关的帖子/博客。他们提供的只是字符串上的解决方案。

如果有人指导我解决这个问题,我将不胜感激。

编辑

您好,@Joe Lv,正如我所说,我尝试了您的方法,加密速度慢,但解密速度非常快。所以我实现了与加密事物相同的解密技术。它有效!但我想知道这是否有效。

现在我的加密方法如下所示:

public void encrypt(string filename)
    {

        // Here you read the cleartext.
        try
        {
            File extStore = Environment.GetExternalStoragePublicDirectory(Environment.DirectoryMovies);
            startTime = System.DateTime.Now.Millisecond;
            Android.Util.Log.Error("Encryption Started", extStore + "/" + filename);

            // This stream write the encrypted text. This stream will be wrapped by
            // another stream.
        //    createFile(filename, extStore);
        //    System.IO.FileStream fs=System.IO.File.OpenRead(extStore + "/" + filename);
      //      FileOutputStream fos = new FileOutputStream(extStore + "/" + filename + ".aes", false);

            FileInputStream fis = new FileInputStream(filepath);


            FileOutputStream fos = new FileOutputStream(filepath, false);
            System.IO.FileStream fs = System.IO.File.OpenWrite(filepath + filename);
            // Create cipher

            // Length is 16 byte
            Cipher cipher = Cipher.GetInstance("AES/CBC/PKCS5Padding");
            byte[] raw = System.Text.Encoding.Default.GetBytes(sKey);
            SecretKeySpec skeySpec = new SecretKeySpec(raw, "AES");
            IvParameterSpec iv = new IvParameterSpec(System.Text.Encoding.Default.GetBytes(ivParameter));//
            cipher.Init(CipherMode.EncryptMode, skeySpec, iv);

            // Wrap the output stream
           // CipherInputStream cis = new CipherInputStream(fs, cipher);
            CipherOutputStream cos = new CipherOutputStream(fs, cipher);

            // Write bytes
            int b;
            byte[] d = new byte[512 * 1024];
            while ((b = fis.Read(d)) != -1)
            {
                cos.Write(d, 0, b);
            }
            // Flush and close streams.
            fos.Flush();
            fos.Close();
            cos.Close();
   fis.Close();

            stopTime = System.DateTime.Now.Millisecond;
            Android.Util.Log.Error("Encryption Ended", extStore + "/5mbtest/" + filename + ".aes");
            Android.Util.Log.Error("Time Elapsed", ((stopTime - startTime) / 1000.0) + "");
        }
        catch (Exception e)
        {
            Android.Util.Log.Error("lv",e.Message);
        }

    }

【问题讨论】:

  • 图片为什么不用ThreadPoolExecutor加密呢?
  • 你可以使用CipherOutputStream来解密文件。
  • 我认为 ES 文件浏览器可能只是打开一个线程来加密/解密并在 UI 线程中显示结果,所以实际上工作线程很慢,这只是一个猜测。
  • 这是使用 android keystore 解释的一种方法:appliedcodelog.com/2021/07/…

标签: c# android encryption xamarin.android


【解决方案1】:

我没有找到任何与加密解密文件相关的帖子/博客

您可以使用CipherOutputStreamCipherInputStream 来实现它。

这是我的测试demo,你可以试试,你需要将一个名为videoplayback.mp4的视频文件推送到你的手机中,路径为/storage/sdcard/Movies,这样你就可以直接测试我的代码了。

using Android.App;
using Android.Widget;
using Android.OS;
using Javax.Crypto.Spec;
using Java.Lang;
using Java.IO;
using Javax.Crypto;
using System.Text;

namespace EncryTest
{
    [Activity(Label = "EncryTest", MainLauncher = true)]
    public class MainActivity : Activity
    {
        long stopTime, startTime;
        private string sKey = "0123456789abcdef";//key,
        private string ivParameter = "1020304050607080";
        protected override void OnCreate(Bundle savedInstanceState)
        {
            base.OnCreate(savedInstanceState);

            // Set our view from the "main" layout resource
            SetContentView(Resource.Layout.Main);

            encrypt("videoplayback.mp4");
            decrypt("videoplayback.mp4");
        }

        public void encrypt(string filename)
        {

            // Here you read the cleartext.
            try
            {
                File extStore = Environment.GetExternalStoragePublicDirectory(Environment.DirectoryMovies);
                startTime = System.DateTime.Now.Millisecond;
                Android.Util.Log.Error("Encryption Started", extStore + "/" + filename);

                // This stream write the encrypted text. This stream will be wrapped by
                // another stream.
                createFile(filename, extStore);
                System.IO.FileStream fs=System.IO.File.OpenRead(extStore + "/" + filename);
                FileOutputStream fos = new FileOutputStream(extStore + "/" + filename + ".aes", false);

                // Length is 16 byte
                Cipher cipher = Cipher.GetInstance("AES/CBC/PKCS5Padding");
                byte[] raw = System.Text.Encoding.Default.GetBytes(sKey);
                SecretKeySpec skeySpec = new SecretKeySpec(raw, "AES");
                IvParameterSpec iv = new IvParameterSpec(System.Text.Encoding.Default.GetBytes(ivParameter));//
                cipher.Init(CipherMode.EncryptMode, skeySpec, iv);

                // Wrap the output stream
                CipherInputStream cis = new CipherInputStream(fs, cipher);
                // Write bytes
                int b;
                byte[] d = new byte[1024 * 1024];
                while ((b = cis.Read(d)) != -1)
                {
                    fos.Write(d, 0, b);
                }
                // Flush and close streams.
                fos.Flush();
                fos.Close();
                cis.Close();
                stopTime = System.DateTime.Now.Millisecond;
                Android.Util.Log.Error("Encryption Ended", extStore + "/5mbtest/" + filename + ".aes");
                Android.Util.Log.Error("Time Elapsed", ((stopTime - startTime) / 1000.0) + "");
            }
            catch (Exception e)
            {
                Android.Util.Log.Error("lv",e.Message);
            }

        }


        private void createFile(string filename, File extStore)
        {
            File file = new File(extStore + "/" + filename + ".aes");

            if (filename.IndexOf(".") != -1)
            {
                try
                {
                    file.CreateNewFile();
                }
                catch (IOException e)
                {
                    // TODO Auto-generated catch block
                    Android.Util.Log.Error("lv",e.Message);
                }
                Android.Util.Log.Error("lv","file created");
            }
            else
            {
                file.Mkdir();
                Android.Util.Log.Error("lv","folder created");
            }

            file.Mkdirs();
        }
        public void decrypt(string filename)
        {
            try
            {

                File extStore = Environment.GetExternalStoragePublicDirectory(Environment.DirectoryMovies);
                Android.Util.Log.Error("Decryption Started", extStore + "");
                FileInputStream fis = new FileInputStream(extStore + "/" + filename + ".aes");

                createFile(filename, extStore);
                FileOutputStream fos = new FileOutputStream(extStore + "/" + "decrypted" + filename, false);
                System.IO.FileStream fs = System.IO.File.OpenWrite(extStore + "/" + "decrypted" + filename);
                // Create cipher

                Cipher cipher = Cipher.GetInstance("AES/CBC/PKCS5Padding");
                byte[] raw = System.Text.Encoding.Default.GetBytes(sKey);
                SecretKeySpec skeySpec = new SecretKeySpec(raw, "AES");
                IvParameterSpec iv = new IvParameterSpec(System.Text.Encoding.Default.GetBytes(ivParameter));//
                cipher.Init(CipherMode.DecryptMode, skeySpec, iv);

                startTime = System.DateTime.Now.Millisecond;
                CipherOutputStream cos = new CipherOutputStream(fs, cipher);
                int b;
                byte[] d = new byte[1024 * 1024];
                while ((b = fis.Read(d)) != -1)
                {
                    cos.Write(d, 0, b);
                }

                stopTime = System.DateTime.Now.Millisecond;

                Android.Util.Log.Error("Decryption Ended", extStore + "/" + "decrypted" + filename);
                Android.Util.Log.Error("Time Elapsed", ((stopTime - startTime) / 1000.0) + "");

                cos.Flush();
                cos.Close();
                fis.Close();
            }
            catch (Exception e)
            {
                Android.Util.Log.Error("lv", e.Message);
            }
        }
    }
}

视频仅供测试,你可以从其他路径获取视频文件,稍作改动即可。

关于路径/storage/sdcard/Movies,我觉得有图比较好理解

【讨论】:

  • 感谢@Joe Lv 的评论。实际上,我早些时候尝试了这种方法,并进行了一些更改。但是有一个问题,如果用户一次选择多张照片,比如说 5 张,那么 1 iv 就足以完成这 5 次加密吗?或者我必须为此生成 5 个静脉注射?使用这种方法,我能够加密但解密时出错。它说你必须提供 iv 才能解密,我怎么能记住 iv ?在全局变量或共享偏好中?我对 iv 感到困惑,所以我试图切换方法。再次感谢:)
  • 是的,生成 5 iv。将 iv 添加到文件名中。 getting error in decryption,你遇到了什么错误?
  • 嗨@Joe Lv。正如我提到的错误所说,“你必须提供 iv 来解密数据”实际上我不在工作地点,所以无法说出确切的错误。尝试了您的方法,但它在文件的同一位置加密文件。其实我想在不同的位置加密文件。为此,我使用了FileInputStreamCipherOutPutStream。并反向解密,但使用它无法获得预期的结果。再次感谢:)
  • 您好,对FileInputStreamFileOutputStream 进行更多研究就足以理解您的代码。它按预期工作。但还有一个问题,您的解密方法(使用 CypherOutputStream)比加密快得多。所以我在加密中也使用了相同的技术。而且它也加快了速度。你能解释一下这两种方法有什么区别吗?
  • ByI want encrypted file at different location,你只需要改变文件的路径,或者你可以告诉我你的文件在哪里。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-10-12
  • 1970-01-01
  • 1970-01-01
  • 2013-06-25
  • 2017-09-13
相关资源
最近更新 更多