gpt4 book ai didi

c# - 为 SqlCipher 数据库存储加密 key 的正确方法

转载 作者:塔克拉玛干 更新时间:2023-11-02 08:33:09 25 4
gpt4 key购买 nike

我有一个 Xamarin 应用程序,并已设法将我的数据从我的服务器下载到我的设备。我还对其进行了设置,以便它可以使用 SqlCipher 加密 key 来加密数据。

我的问题是存储我用来加密此数据的 key 的正确位置在哪里?是给你的 KeyStore/KeyChain 吗?我应该使用哪些单声道类?

最佳答案

由于这个问题很受欢迎,我将发布我的实现:

PCL 界面

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

安卓

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

首先在Android应用的主activity中调用Create Store。 - 这可能会得到改进,并通过在保存和删除中检查 ks == null 并在为真时调用该方法来从界面中删除 CreateStrore()

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

工作人员

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

这是对 Xamarin.Auth 库 (Found Here) 的改编,但从 Xamarin.Auth 库中删除了依赖项以通过 PCL 中的接口(interface)提供跨平台使用。出于这个原因,我将其简化为只保存一个字符串。这可能不是最好的实现,但它适用于我的情况。随意扩展这个

关于c# - 为 SqlCipher 数据库存储加密 key 的正确方法,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/28429004/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com