Last active
September 20, 2020 11:39
-
-
Save trinnguyen/4b2a5cb3c82f041b309e094250aa0a7b to your computer and use it in GitHub Desktop.
File encryption with Tink iOS
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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