Xamarin.iOS / Akavache - 带有自定义EncryptionProvider的加密缓存 [英] Xamarin.iOS / Akavache - Encrypted Cache with custom EncryptionProvider

查看:289
本文介绍了Xamarin.iOS / Akavache - 带有自定义EncryptionProvider的加密缓存的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个Xamarin.iOS应用程序,它使用Akavache缓存数据并减少不必要的服务器请求数据的数量。使用 BlobCache.LocalMachine ,一切都按预期工作得很好,喜欢它。

I have a Xamarin.iOS app that is using Akavache to cache data and reduce the number on unnecessary requests to the server for data. Everything is working great as expected using BlobCache.LocalMachine, love it.

现在我想确保加密时的静态数据。从在线研究和阅读文档,我发现默认实现并没有实际加密iOS上的缓存,我实际上需要提供 IEncryptionProvider 的自定义实现。

Now I would like to make sure that the data at rest in encrypted. From researching this and reading documentation online I saw that the default implementation doesn't actually encrypt the cache on iOS and that I actually need to provide a custom implementation of IEncryptionProvider.

我遵循了这篇文章: http://kent-boogaart.com/blog/password-protected-encryption-provider-for-akavache

从这个主题: https://github.com/akavache/Akavache/issues/190

结束了这个实现:

    public interface IPasswordProtectedEncryptionProvider : IEncryptionProvider
    {
        void SetPassword(string password);
    }

    public sealed class MyEncryptionProvider : IPasswordProtectedEncryptionProvider
    {
        static readonly byte[] salt = Encoding.ASCII.GetBytes("dVBZMQWyFRcJOIas");
        readonly IScheduler scheduler;
        readonly SymmetricAlgorithm symmetricAlgorithm;
        ICryptoTransform decryptTransform;
        ICryptoTransform encryptTransform;

        public MyEncryptionProvider()
        {
            scheduler = BlobCache.TaskpoolScheduler ?? throw new ArgumentNullException(nameof(scheduler), "Scheduler instance is null");
            symmetricAlgorithm = new RijndaelManaged();
            var securePassword = "kadhaskdhsakhaskjdhaskjdhaskdjashdkjahkfghkjhew";
            SetPassword(securePassword);
        }

        public void SetPassword(string password)
        {
            if(password == null)
               throw new ArgumentNullException(nameof(password), "password can't be null");

            var derived = new Rfc2898DeriveBytes(password, salt);
            var bytesForKey = symmetricAlgorithm.KeySize / 8;
            var bytesForIV = symmetricAlgorithm.BlockSize / 8;
            symmetricAlgorithm.Key = derived.GetBytes(bytesForKey);
            symmetricAlgorithm.IV = derived.GetBytes(bytesForIV);
            decryptTransform = symmetricAlgorithm.CreateDecryptor(symmetricAlgorithm.Key, symmetricAlgorithm.IV);
            encryptTransform = symmetricAlgorithm.CreateEncryptor(symmetricAlgorithm.Key, symmetricAlgorithm.IV);
        }

        public IObservable<byte[]> DecryptBlock(byte[] block)
        {
            if (block == null)
            {
                throw new ArgumentNullException(nameof(block), "block can't be null");
            }

            if (decryptTransform == null)
            {
                return Observable.Throw<byte[]>(new InvalidOperationException("You must call SetPassword first."));
            }

            return Observable.Start(() => InMemoryTransform(block, decryptTransform), scheduler);
        }

        public IObservable<byte[]> EncryptBlock(byte[] block)
        {
            if (block == null)
            {
                throw new ArgumentNullException(nameof(block), "block can't be null");
            }

            if (encryptTransform == null)
            {
                return Observable.Throw<byte[]>(new InvalidOperationException("You must call SetPassword first."));
            }

            return Observable.Start(() => InMemoryTransform(block, encryptTransform), scheduler);
        }

        static byte[] InMemoryTransform(byte[] bytesToTransform, ICryptoTransform transform)
        {
            using (var memoryStream = new MemoryStream())
            {
                using (var cryptoStream = new CryptoStream(memoryStream, transform, CryptoStreamMode.Write))
                {
                    cryptoStream.Write(bytesToTransform, 0, bytesToTransform.Length);
                }

                return memoryStream.ToArray();
            }
        }
    }

我像这样注册这个实现:
Locator.CurrentMutable.RegisterConstant(new MyEncryptionProvider(),typeof(IEncryptionProvider)); 在调用 BlobCache.Secure

I register this implementation like this: Locator.CurrentMutable.RegisterConstant(new MyEncryptionProvider(), typeof(IEncryptionProvider)); before calling BlobCache.Secure

我看到 EncryptBlock DecryptBlock 当我在该安全缓存上使用 .GetOrFetchObject 时被调用。到现在为止还挺好。

And I see the EncryptBlock and DecryptBlock being called when I use .GetOrFetchObject on that secure cache. So far so good.

我遇到的问题是尝试使用 Newtonsoft 中的此错误进行反序列化时失败:

The problem I run into is that it fails when trying to Deserialize with this error from Newtonsoft:

{Newtonsoft.Json.JsonReaderException: Read past end of current container context. Path ''.
  at Newtonsoft.Json.Bson.BsonReader.ReadNormal () [0x0013c] in <c19705166c7c4a608e182e859c4de6d2>:0 
  at Newtonsoft.Json.Bson.BsonReader.Read () [0x00033] in <c19705166c7c4a608e182e859c4de6d2>:0 
  at Newtonsoft.Json.JsonReader.ReadAndAssert () [0x00000] in <c19705166c7c4a608e182e859c4de6d2>:0 
  at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.CreateObject (Newtonsoft.Json.JsonReader reader, System.Type objectType, Newtonsoft.Json.Serialization.JsonContract contract, Newtonsoft.Json.Serialization.JsonProperty member, Newtonsoft.Json.Serialization.JsonContainerContract containerContract, Newtonsoft.Json.Serialization.JsonProperty containerMember, System.Object existingValue) [0x000b6] in <c19705166c7c4a608e182e859c4de6d2>:0 
  at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.CreateValueInternal (Newtonsoft.Json.JsonReader reader, System.Type objectType, Newtonsoft.Json.Serialization.JsonContract contract, Newtonsoft.Json.Serialization.JsonProperty member, Newtonsoft.Json.Serialization.JsonContainerContract containerContract, Newtonsoft.Json.Serialization.JsonProperty containerMember, System.Object existingValue) [0x0006d] in <c19705166c7c4a608e182e859c4de6d2>:0 
  at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.Deserialize (Newtonsoft.Json.JsonReader reader, System.Type objectType, System.Boolean checkAdditionalContent) [0x000db] in <c19705166c7c4a608e182e859c4de6d2>:0 
  at Newtonsoft.Json.JsonSerializer.DeserializeInternal (Newtonsoft.Json.JsonReader reader, System.Type objectType) [0x00053] in <c19705166c7c4a608e182e859c4de6d2>:0 
  at Newtonsoft.Json.JsonSerializer.Deserialize (Newtonsoft.Json.JsonReader reader, System.Type objectType) [0x00000] in <c19705166c7c4a608e182e859c4de6d2>:0 
  at Newtonsoft.Json.JsonSerializer.Deserialize[T] (Newtonsoft.Json.JsonReader reader) [0x00000] in <c19705166c7c4a608e182e859c4de6d2>:0 
  at Akavache.Sqlite3.SQLitePersistentBlobCache.DeserializeObject[T] (System.Byte[] data) [0x00074] in <67aced6c5c1a4c15b03e120d7300429d>:0 
--- End of stack trace from previous location where exception was thrown ---
  at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw () [0x0000c] in /Library/Frameworks/Xamarin.iOS.framework/Versions/10.12.0.20/src/mono/mcs/class/referencesource/mscorlib/system/runtime/exceptionservices/exceptionservicescommon.cs:151 
  at System.Reactive.PlatformServices.ExceptionServicesImpl.Rethrow (System.Exception exception) [0x00006] in <427ee2007f4d40bb9d3f1fcd73e9b750>:0 
  at System.Reactive.ExceptionHelpers.ThrowIfNotNull (System.Exception exception) [0x0000d] in <ab76b1b1678341d69f8fc2c1f68d0bf5>:0 
  at System.Reactive.Subjects.AsyncSubject`1[T].GetResult () [0x00039]

当使用 BlobCache.LocalMachine 缓存相同的对象时,相同的数据结构ure成功存储如下:

When the same object is cached using the BlobCache.LocalMachine the same data structure is successfully stored like this:

[
  {
    "Name": "John Smith",
    "Date": "2017-04-03T20:00:00-04:00",
    "Number1": -8820768.6192349959,
    "Number2": -25540081.8275,
    "Number3": -0.0045255076670528034,
    "Number4": 0.0457761358483606,
    "RelatedObjects": [],
    "LastUpdateTime": "2017-04-04T17:36:06.247-04:00"
  }
]

我在这里缺少什么?非常沮丧,真的希望有人看到我不是的东西。感谢您的帮助。

What am I missing here? Very frustrated, really hoping someone sees something I am not. Thanks for your help.

推荐答案

借助本文中的示例: Xamarin.iOS / Akavache工作示例

我能够得到这个问题得到解决,示例解决方案中显示了一个工作示例: https:// github.com/dmitrysamuylov/xamarin-ios-akavache-secure-example

I was able to get this problem resolved and a working example is shown in the sample solution here: https://github.com/dmitrysamuylov/xamarin-ios-akavache-secure-example

希望将来帮助某人

这篇关于Xamarin.iOS / Akavache - 带有自定义EncryptionProvider的加密缓存的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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