aboutsummaryrefslogtreecommitdiffstats
path: root/Software/Visual_Studio/Tango.Synchronization/Local/LocalDBSynchronizer.cs
blob: 7e654c1613e418ff8d6ee0c5287c62eaca6b9c0b (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Tango.Synchronization.Local
{
    /// <summary>
    /// Represents an SQLite to SQLite file synchronizer.
    /// </summary>
    public class LocalDBSynchronizer
    {
        /// <summary>
        /// Synchronizes the specified master and slave SQLite files.
        /// </summary>
        /// <param name="masterSQLiteFile">The master SQLite file.</param>
        /// <param name="slaveSQLiteFile">The slave SQLite file.</param>
        /// <returns></returns>
        public static List<Diff> Synchronize(String masterSQLiteFile, String slaveSQLiteFile)
        {
            using (LocalDBComparer comparer = new LocalDBComparer(new SQLiteDataBase(masterSQLiteFile), new SQLiteDataBase(slaveSQLiteFile)))
            {
                var diffs = comparer.Compare();
                foreach (var diff in diffs)
                {
                    diff.Commit();
                }

                return diffs;
            }
        }

        /// <summary>
        /// Synchronizes the specified master and slave SQLite files asynchronously.
        /// </summary>
        /// <param name="masterSQLiteFile">The master SQLite file.</param>
        /// <param name="slaveSQLiteFile">The slave SQLite file.</param>
        /// <returns></returns>
        public static Task<List<Diff>> SynchronizeAsync(String masterSQLiteFile, String slaveSQLiteFile)
        {
            return Task.Factory.StartNew<List<Diff>>(() => { return Synchronize(masterSQLiteFile, slaveSQLiteFile); });
        }
    }
}
an> const int Keysize = 256; // This constant determines the number of iterations for the password bytes generation function. private const int DerivationIterations = 1000; /// <summary> /// Encrypts the specified plain text. /// </summary> /// <param name="plainText">The plain text.</param> /// <returns></returns> public static string Encrypt(string plainText) { // Salt and IV is randomly generated each time, but is preprended to encrypted cipher text // so that the same Salt and IV values can be used when decrypting. var saltStringBytes = Generate256BitsOfRandomEntropy(); var ivStringBytes = Generate256BitsOfRandomEntropy(); var plainTextBytes = Encoding.UTF8.GetBytes(plainText); using (var password = new Rfc2898DeriveBytes(ConvertSecureStringToString(passkey), saltStringBytes, DerivationIterations)) { var keyBytes = password.GetBytes(Keysize / 8); using (var symmetricKey = new RijndaelManaged()) { symmetricKey.BlockSize = 256; symmetricKey.Mode = CipherMode.CBC; symmetricKey.Padding = PaddingMode.PKCS7; using (var encryptor = symmetricKey.CreateEncryptor(keyBytes, ivStringBytes)) { using (var memoryStream = new MemoryStream()) { using (var cryptoStream = new CryptoStream(memoryStream, encryptor, CryptoStreamMode.Write)) { cryptoStream.Write(plainTextBytes, 0, plainTextBytes.Length); cryptoStream.FlushFinalBlock(); // Create the final bytes as a concatenation of the random salt bytes, the random iv bytes and the cipher bytes. var cipherTextBytes = saltStringBytes; cipherTextBytes = cipherTextBytes.Concat(ivStringBytes).ToArray(); cipherTextBytes = cipherTextBytes.Concat(memoryStream.ToArray()).ToArray(); memoryStream.Close(); cryptoStream.Close(); return Convert.ToBase64String(cipherTextBytes); } } } } } } /// <summary> /// Decrypts the specified cipher text. /// </summary> /// <param name="cipherText">The cipher text.</param> /// <returns></returns> public static string Decrypt(string cipherText) { // Get the complete stream of bytes that represent: // [32 bytes of Salt] + [32 bytes of IV] + [n bytes of CipherText] var cipherTextBytesWithSaltAndIv = Convert.FromBase64String(cipherText); // Get the saltbytes by extracting the first 32 bytes from the supplied cipherText bytes. var saltStringBytes = cipherTextBytesWithSaltAndIv.Take(Keysize / 8).ToArray(); // Get the IV bytes by extracting the next 32 bytes from the supplied cipherText bytes. var ivStringBytes = cipherTextBytesWithSaltAndIv.Skip(Keysize / 8).Take(Keysize / 8).ToArray(); // Get the actual cipher text bytes by removing the first 64 bytes from the cipherText string. var cipherTextBytes = cipherTextBytesWithSaltAndIv.Skip((Keysize / 8) * 2).Take(cipherTextBytesWithSaltAndIv.Length - ((Keysize / 8) * 2)).ToArray(); using (var password = new Rfc2898DeriveBytes(ConvertSecureStringToString(passkey), saltStringBytes, DerivationIterations)) { var keyBytes = password.GetBytes(Keysize / 8); using (var symmetricKey = new RijndaelManaged()) { symmetricKey.BlockSize = 256; symmetricKey.Mode = CipherMode.CBC; symmetricKey.Padding = PaddingMode.PKCS7; using (var decryptor = symmetricKey.CreateDecryptor(keyBytes, ivStringBytes)) { using (var memoryStream = new MemoryStream(cipherTextBytes)) { using (var cryptoStream = new CryptoStream(memoryStream, decryptor, CryptoStreamMode.Read)) { var plainTextBytes = new byte[cipherTextBytes.Length]; var decryptedByteCount = cryptoStream.Read(plainTextBytes, 0, plainTextBytes.Length); memoryStream.Close(); cryptoStream.Close(); return Encoding.UTF8.GetString(plainTextBytes, 0, decryptedByteCount); } } } } } } /// <summary> /// Generate256s the bits of random entropy. /// </summary> /// <returns></returns> private static byte[] Generate256BitsOfRandomEntropy() { var randomBytes = new byte[32]; // 32 Bytes will give us 256 bits. using (var rngCsp = new RNGCryptoServiceProvider()) { // Fill the array with cryptographically secure random bytes. rngCsp.GetBytes(randomBytes); } return randomBytes; } /// <summary> /// Converts the secure string to string. /// </summary> /// <param name="value">The value.</param> /// <returns></returns> private static String ConvertSecureStringToString(SecureString value) { IntPtr valuePtr = IntPtr.Zero; try { valuePtr = Marshal.SecureStringToGlobalAllocUnicode(value); return Marshal.PtrToStringUni(valuePtr); } finally { Marshal.ZeroFreeGlobalAllocUnicode(valuePtr); } } } }