2015-02-10 11 views
9

Bir Xamarin uygulamasına sahibim ve verilerimi sunucumdan aygıtıma karşıdan yüklemeyi başardınız. Verileri şifrelemek için SqlCipher Şifreleme anahtarını alabilmesi için ayarlamayı da yaptım.SqlCipher veritabanı için şifreleme anahtarını saklamanın doğru yolu

Sorum şu: Bu verileri şifrelemek için kullandığım anahtarımı depolamak için doğru konum nerede? Bu size KeyStore/KeyChain mi? Hangi mono sınıfları kullanmayı düşünmeliyim?

+0

onun github repository

diğer bilgiler de bulmak örneği var. [Keychain için Mono örneği] (https://github.com/xamarin/monotouch-samples/tree/master/Keychain) – Wizche

+0

Ve ayrıca bir [KeyStore için Mono örneği] (https://github.com/escfrya/Locator/ blob/3297318c781aabc67b6d303cddaa792af2dcf6c4/Xamarin.Auth/Xamarin.Auth.Android/AndroidAccountStore.cs) – Wizche

+0

@Wizche Android mono örneğini inceledim ve nuget Xamarin.Auth kullanıyor gibi görünüyor. Çünkü benim PCL'imdeki Xamarin.Auth 'a başvuramam, bu da PCL'den gelen yöntemleri bağımlılık enjeksiyonu kullanan bir arayüz üzerinden kullanamayacağım anlamına geliyor. Bu nedenle Xamarin – user1

cevap

7

nedeniyle bu benim uygulanmasını göndermek için gidiyorum bu sorunun popülerlik:

PCL arayüzü

public interface IAuth 
{ 
    void CreateStore(); 
    IEnumerable<string> FindAccountsForService(string serviceId); 
    void Save(string pin,string serviceId); 
    void Delete(string serviceId); 
} 

Android

public class IAuthImplementation : IAuth 
{ 
    Context context; 
    KeyStore ks; 
    KeyStore.PasswordProtection prot; 

    static readonly object fileLock = new object(); 

    const string FileName = "MyProg.Accounts"; 
    static readonly char[] Password = null; 

    public void CreateStore() 
    { 

     this.context = Android.App.Application.Context; 

     ks = KeyStore.GetInstance(KeyStore.DefaultType); 

     prot = new KeyStore.PasswordProtection(Password); 

     try 
     { 
      lock (fileLock) 
      { 
       using (var s = context.OpenFileInput(FileName)) 
       { 
        ks.Load(s, Password); 
       } 
      } 
     } 
     catch (Java.IO.FileNotFoundException) 
     { 
      //ks.Load (null, Password); 
      LoadEmptyKeyStore(Password); 
     } 
    } 

    public IEnumerable<string> FindAccountsForService(string serviceId) 
    { 
     var r = new List<string>(); 

     var postfix = "-" + serviceId; 

     var aliases = ks.Aliases(); 
     while (aliases.HasMoreElements) 
     { 
      var alias = aliases.NextElement().ToString(); 
      if (alias.EndsWith(postfix)) 
      { 
       var e = ks.GetEntry(alias, prot) as KeyStore.SecretKeyEntry; 
       if (e != null) 
       { 
        var bytes = e.SecretKey.GetEncoded(); 
        var password = System.Text.Encoding.UTF8.GetString(bytes); 
        r.Add(password); 
       } 
      } 
     } 
     return r; 
    } 

    public void Delete(string serviceId) 
    { 
     var alias = MakeAlias(serviceId); 

     ks.DeleteEntry(alias); 
     Save(); 
    } 

    public void Save(string pin, string serviceId) 
    { 
     var alias = MakeAlias(serviceId); 

     var secretKey = new SecretAccount(pin); 
     var entry = new KeyStore.SecretKeyEntry(secretKey); 
     ks.SetEntry(alias, entry, prot); 

     Save(); 
    } 

    void Save() 
    { 
     lock (fileLock) 
     { 
      using (var s = context.OpenFileOutput(FileName, FileCreationMode.Private)) 
      { 
       ks.Store(s, Password); 
      } 
     } 
    } 

    static string MakeAlias(string serviceId) 
    { 
     return "-" + serviceId; 
    } 

    class SecretAccount : Java.Lang.Object, ISecretKey 
    { 
     byte[] bytes; 
     public SecretAccount(string password) 
     { 
      bytes = System.Text.Encoding.UTF8.GetBytes(password); 
     } 
     public byte[] GetEncoded() 
     { 
      return bytes; 
     } 
     public string Algorithm 
     { 
      get 
      { 
       return "RAW"; 
      } 
     } 
     public string Format 
     { 
      get 
      { 
       return "RAW"; 
      } 
     } 
    } 

    static IntPtr id_load_Ljava_io_InputStream_arrayC; 

    void LoadEmptyKeyStore(char[] password) 
    { 
     if (id_load_Ljava_io_InputStream_arrayC == IntPtr.Zero) 
     { 
      id_load_Ljava_io_InputStream_arrayC = JNIEnv.GetMethodID(ks.Class.Handle, "load", "(Ljava/io/InputStream;[C)V"); 
     } 
     IntPtr intPtr = IntPtr.Zero; 
     IntPtr intPtr2 = JNIEnv.NewArray(password); 
     JNIEnv.CallVoidMethod(ks.Handle, id_load_Ljava_io_InputStream_arrayC, new JValue[] 
      { 
       new JValue (intPtr), 
       new JValue (intPtr2) 
      }); 
     JNIEnv.DeleteLocalRef(intPtr); 
     if (password != null) 
     { 
      JNIEnv.CopyArray(intPtr2, password); 
      JNIEnv.DeleteLocalRef(intPtr2); 
     } 
    } 

Çağrı Store'un oluştur önce Android uygulamasının ana etkinliği. - Bu muhtemelen geliştirilmiş ve Kaydet ks == boş olmadığını denetleme ve silin ve yöntemini çağırarak arayüzünden CreateStrore() kaldırmak olabilir doğrudur

iOS

public class IAuthImplementation : IAuth 
{ 
    public IEnumerable<string> FindAccountsForService(string serviceId) 
    { 
     var query = new SecRecord(SecKind.GenericPassword); 
     query.Service = serviceId; 

     SecStatusCode result; 
     var records = SecKeyChain.QueryAsRecord(query, 1000, out result); 

     return records != null ? 
      records.Select(GetAccountFromRecord).ToList() : 
      new List<string>(); 
    } 

    public void Save(string pin, string serviceId) 
    { 
     var statusCode = SecStatusCode.Success; 
     var serializedAccount = pin; 
     var data = NSData.FromString(serializedAccount, NSStringEncoding.UTF8); 

     // 
     // Remove any existing record 
     // 
     var existing = FindAccount(serviceId); 

     if (existing != null) 
     { 
      var query = new SecRecord(SecKind.GenericPassword); 
      query.Service = serviceId; 

      statusCode = SecKeyChain.Remove(query); 
      if (statusCode != SecStatusCode.Success) 
      { 
       throw new Exception("Could not save account to KeyChain: " + statusCode); 
      } 
     } 

     // 
     // Add this record 
     // 
     var record = new SecRecord(SecKind.GenericPassword); 
     record.Service = serviceId; 
     record.Generic = data; 
     record.Accessible = SecAccessible.WhenUnlocked; 

     statusCode = SecKeyChain.Add(record); 

     if (statusCode != SecStatusCode.Success) 
     { 
      throw new Exception("Could not save account to KeyChain: " + statusCode); 
     } 
    } 

    public void Delete(string serviceId) 
    { 
     var query = new SecRecord(SecKind.GenericPassword); 
     query.Service = serviceId; 

     var statusCode = SecKeyChain.Remove(query); 

     if (statusCode != SecStatusCode.Success) 
     { 
      throw new Exception("Could not delete account from KeyChain: " + statusCode); 
     } 
    } 

    string GetAccountFromRecord(SecRecord r) 
    { 
     return NSString.FromData(r.Generic, NSStringEncoding.UTF8); 
    } 

    string FindAccount(string serviceId) 
    { 
     var query = new SecRecord(SecKind.GenericPassword); 
     query.Service = serviceId; 

     SecStatusCode result; 
     var record = SecKeyChain.QueryAsRecord(query, out result); 

     return record != null ? GetAccountFromRecord(record) : null; 
    } 

    public void CreateStore() 
    { 
     throw new NotImplementedException(); 
    } 
} 

WP

eğer
public class IAuthImplementation : IAuth 
{ 
    public IEnumerable<string> FindAccountsForService(string serviceId) 
    { 
     using (var store = IsolatedStorageFile.GetUserStoreForApplication()) 
     { 
      string[] auths = store.GetFileNames("MyProg"); 
      foreach (string path in auths) 
      { 
       using (var stream = new BinaryReader(new IsolatedStorageFileStream(path, FileMode.Open, FileAccess.Read, FileShare.Read, store))) 
       { 
        int length = stream.ReadInt32(); 
        byte[] data = stream.ReadBytes(length); 

        byte[] unprot = ProtectedData.Unprotect(data, null); 
        yield return Encoding.UTF8.GetString(unprot, 0, unprot.Length); 
       } 
      } 
     } 
    } 

    public void Save(string pin, string serviceId) 
    { 
     byte[] data = Encoding.UTF8.GetBytes(pin); 
     byte[] prot = ProtectedData.Protect(data, null); 

     var path = GetAccountPath(serviceId); 

     using (var store = IsolatedStorageFile.GetUserStoreForApplication()) 
     using (var stream = new IsolatedStorageFileStream(path, FileMode.Create, FileAccess.Write, FileShare.None, store)) 
     { 
      stream.WriteAsync(BitConverter.GetBytes(prot.Length), 0, sizeof(int)).Wait(); 
      stream.WriteAsync(prot, 0, prot.Length).Wait(); 
     } 
    } 

    public void Delete(string serviceId) 
    { 
     var path = GetAccountPath(serviceId); 
     using (var store = IsolatedStorageFile.GetUserStoreForApplication()) 
     { 
      store.DeleteFile(path); 
     } 
    } 

    private string GetAccountPath(string serviceId) 
    { 
     return String.Format("{0}", serviceId); 
    } 

    public void CreateStore() 
    { 
     throw new NotImplementedException(); 
    } 
} 

Bu, Xamarin.Auth kitaplığının (Found Here) bir uyarlamasıdır ancak çapraz plat sağlamak için Xamarin.Auth kitaplığından bağımlılığı kaldırır. PCL'deki arayüz üzerinden form kullanımı. Bu nedenle sadece bir dizeyi kaydetmek için basitleştirdim. Bu muhtemelen en iyi uygulama değil ama benim durumumda çalışıyor. Bu

+0

Bunu paylaştığınız için teşekkürler, sadece ilginizi çekmiyor pimi nasıl ele alıyorsunuz? Bu kullanıcı girilen değer mi? Bu değeri nerede saklıyorsun? Tekrar teşekkürler. – Jammer

+0

@Jammer evet pin kullanıcının girilen değeridir. Bu kod, Android'deki 'KeyStore'daki değeri, iOS'ta' KeyChain' ve WP'de 'IsolatedStorage'daki değerleri saklar, hepsi temelde aynı şeydir ve 3'ü şifreli hale getirerek – user1

+0

güvenliğini sağlar.Şu anda benzer bir şey yapıyorum. Sorum, bu iğneyi depolayıp saklamayacağınız ya da istediğiniz zaman sorulup sorulmadığı hakkındaydı. – Jammer

2

üzerinde genişletmek için çekinmeyin. Bu mantığı iOs, Android ve Windows Phone için kapsülleyen KeyChain.NET adında bir nuget paketi vardır.

Açık kaynaklı ve ben en iyi seçenek Android için iOS ve anahtar deposu için Anahtarlık olduğunu biliyoruz gibi Bildiğim kadarıyla bu blog post

İlgili konular