/// <summary> /// Copies the in-memory configuration to the stored configuration file. /// </summary> /// <param name="pin">The personal identification number (PIN) to use as an encryption key.</param> public static void Save(int pin) => TSM.RunSafe(() => { using (var s = Application.Context.OpenFileOutput(FILE_NAME, FileCreationMode.Private)) using (var w = new BinaryWriter(s)) { w.Write(FILE_VERSION); w.Write(Address); w.Write(ConnectionTargets.Length); foreach (var t in ConnectionTargets) { w.Write(t.Serialize()); } w.Write(Contacts.Length); foreach (var c in Contacts) { w.Write(c.Address); w.WriteString472(c.Name); } w.Write(Recents.Length); foreach (var r in Recents) { w.Write(r.Address); w.Write(r.Timestamp.Ticks); } var aes = WinRTCrypto.SymmetricKeyAlgorithmProvider.OpenAlgorithm(SymmetricAlgorithm.AesCbcPkcs7); var sha = WinRTCrypto.HashAlgorithmProvider.OpenAlgorithm(HashAlgorithm.Sha512); var bk = sha.HashData(BitConverter.GetBytes(pin)); using (var ms = new MemoryStream()) { /*using (var es = new EncryptedStream(ms, key)) * using (var ws = new WrapperStream(ms)) * using (var cs = new CryptoStream(ws, WinRTCrypto.CryptographicEngine.CreateEncryptor(aes.CreateSymmetricKey(key)), CryptoStreamMode.Write))*/ using (var cw = new BinaryWriter(ms)) { cw.Write(bk); cw.Write(VerificationKeys.Length); foreach (var k in VerificationKeys) { w.Write(k.Address); w.Write(k.PrivateKey.Length); w.Write(k.PrivateKey); w.Write(k.PublicKey.Length); w.Write(k.PublicKey); } } var key = bk; var data = ms.ToArray(); for (int i = 0; i < data.Length / 64 + 1; ++i) { key = sha.HashData(key); for (int j = 0; j < 64 && (i < data.Length / 64 || j < data.Length % 64); ++j) { data[i * 64 + j] ^= key[j]; } } w.Write(data.Length); w.Write(data); } } });
/// <summary> /// Resets the in-memory configuration. /// </summary> /// <param name="address">The address of the new configuration.</param> public static void Reset(ErebusAddress address) => TSM.RunSafe(() => { Address = address; ConnectionTargets = new IConnectionTarget[0]; Contacts = new Contact[0]; Recents = new RecentEntry[0]; VerificationKeys = new KeyPair[0]; });
/// <summary> /// Resets the in-memory configuration and saves it to disk with the specified PIN. /// </summary> /// <param name="address">The address of the new configuration.</param> /// <param name="pin">The personal identification number (PIN) to use as an encryption key.</param> public static void Configure(ErebusAddress address, int pin) => TSM.RunSafe(() => { Reset(address); Save(pin); });
/// <summary> /// Reloads the in-memory configuration from the configuration file. /// </summary> /// <param name="pin">The personal identification number (PIN) to use as a decryption key.</param> public static void Reload(int pin) => TSM.RunSafe(() => { using (var s = Application.Context.OpenFileInput(FILE_NAME)) using (var r = new BinaryReader(s)) { var v = r.ReadUInt16(); if (v != FILE_VERSION) { throw new InvalidDataException($"Config file had version {v}; expected {FILE_VERSION}."); } Address = r.ReadErebusAddress(); ConnectionTargets = new IConnectionTarget[r.ReadInt32()]; for (int i = 0; i < ConnectionTargets.Length; ++i) { var t = r.ReadByte(); switch (t) { case 0: ConnectionTargets[i] = new TCPIPConnectionTarget(r.ReadString472(), r.ReadInt32()); break; case 1: ConnectionTargets[i] = new BluetoothConnectionTarget(r.ReadString472()); break; default: throw new InvalidDataException($"Config file had invalid connection target type {t}."); } } Contacts = new Contact[r.ReadInt32()]; for (int i = 0; i < Contacts.Length; ++i) { Contacts[i] = new Contact(r.ReadString472(), r.ReadErebusAddress()); } Recents = new RecentEntry[r.ReadInt32()]; for (int i = 0; i < Recents.Length; ++i) { Recents[i] = new RecentEntry(r.ReadErebusAddress(), new DateTime(r.ReadInt64())); } Log.RecordEvent(typeof(Configuration), "Attempting to decrypt encrypted portion of configuration file.", LogEntrySeverity.Info); var aes = WinRTCrypto.SymmetricKeyAlgorithmProvider.OpenAlgorithm(SymmetricAlgorithm.AesCbcPkcs7); var sha = WinRTCrypto.HashAlgorithmProvider.OpenAlgorithm(HashAlgorithm.Sha512); var bk = sha.HashData(BitConverter.GetBytes(pin)); var key = bk; var data = r.ReadBytes(r.ReadInt32()); for (int i = 0; i < data.Length / 64 + 1; ++i) { key = sha.HashData(key); for (int j = 0; j < 64 && (i < data.Length / 64 || j < data.Length % 64); ++j) { data[i * 64 + j] ^= key[j]; } } using (var ms = new MemoryStream(data)) /*using (var es = new EncryptedStream(ms, key)) * using (var ws = new WrapperStream(ms)) * using (var cs = new CryptoStream(ws, WinRTCrypto.CryptographicEngine.CreateDecryptor(aes.CreateSymmetricKey(key)), CryptoStreamMode.Read))*/ using (var cr = new BinaryReader(ms)) { if (!bk.SequenceEqual(cr.ReadBytes(64))) { throw new InvalidDataException("Incorrect PIN."); } VerificationKeys = new KeyPair[cr.ReadInt32()]; for (int i = 0; i < VerificationKeys.Length; ++i) { VerificationKeys[i] = new KeyPair(cr.ReadErebusAddress(), cr.ReadBytes(cr.ReadInt32()), cr.ReadBytes(cr.ReadInt32())); } } Log.RecordEvent(typeof(Configuration), "Decryption successful.", LogEntrySeverity.Info); } });