Skip to content

Instantly share code, notes, and snippets.

@trinnguyen
Last active September 20, 2020 11:39
Show Gist options
  • Save trinnguyen/4b2a5cb3c82f041b309e094250aa0a7b to your computer and use it in GitHub Desktop.
Save trinnguyen/4b2a5cb3c82f041b309e094250aa0a7b to your computer and use it in GitHub Desktop.
File encryption with Tink iOS
using System;
using System.Diagnostics;
using Foundation;
using Tink;
namespace TnnCrypto
{
public class FileCrypto
{
private readonly ITINKAead _aead;
public FileCrypto(string keyname)
{
// register
RegisterAead();
// create
_aead = InitAead(keyname);
}
public bool Encrypt(string srcPath, string dstPath)
{
using (NSData data = NSData.FromFile(srcPath))
{
NSData associatedData = NSData.FromString(dstPath, NSStringEncoding.UTF8);
NSData cipherData = _aead.Encrypt(data, associatedData, out NSError error);
if (error != null || cipherData == null)
{
Debug.WriteLine(error?.LocalizedFailureReason ?? "");
return false;
}
cipherData.Save(dstPath, NSDataWritingOptions.FileProtectionCompleteUntilFirstUserAuthentication, out error);
if (error != null)
{
Debug.WriteLine(error.LocalizedFailureReason);
return false;
}
return true;
}
}
public NSData Decrypt(string cipherPath)
{
using (NSData data = NSData.FromFile(cipherPath))
{
NSData associatedData = NSData.FromString(cipherPath, NSStringEncoding.UTF8);
NSData plain = _aead.Decrypt(data, associatedData, out NSError error);
if (plain == null || error != null)
{
Debug.WriteLine(error?.LocalizedFailureReason ?? "");
return null;
}
return plain;
}
}
private static ITINKAead InitAead(string keyName)
{
TINKKeysetHandle handle = LoadOrCreateKey(keyName);
ITINKAead aead = TINKAeadFactory.PrimitiveWithKeysetHandle(handle, out NSError error);
if (error != null)
throw new Exception($"Failed to create Aead: {error.LocalizedFailureReason}");
return aead;
}
private static TINKKeysetHandle LoadOrCreateKey(string keyName)
{
TINKKeysetHandle handle = LoadFromKeychain(keyName);
if (handle != null)
return handle;
// create new and store
var tpl = new TINKAeadKeyTemplate(TINKAeadKeyTemplates.Aes256Gcm, out NSError error);
if (error != null)
throw new Exception($"Failed to create key: {keyName}");
handle = new TINKKeysetHandle(tpl, out error);
if (error != null)
throw new Exception($"Failed to create key: {keyName}");
if (!handle.WriteToKeychainWithName(keyName, false, out error))
throw new Exception($"Failed to store key to iOS keychain: {keyName}");
return handle;
}
private static void RegisterAead()
{
var config = new TINKAeadConfig(out NSError error);
if (error != null)
{
Debug.WriteLine(error.LocalizedFailureReason);
throw new Exception("Failed to initialize Tink: " + error.LocalizedFailureReason);
}
TINKConfig.RegisterConfig(config, out error);
if (error != null)
{
Debug.WriteLine(error.LocalizedFailureReason);
throw new Exception("Failed to initialize Tink: " + error.LocalizedFailureReason);
}
}
private static TINKKeysetHandle LoadFromKeychain(string keysetName)
{
try
{
TINKKeysetHandle handleStore = new TINKKeysetHandle(keysetName, out NSError error);
if (error == null)
return handleStore;
Debug.WriteLine(error.LocalizedFailureReason);
return null;
}
catch
{
return null;
}
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment