├── README.md ├── SecretSharing.sln └── SecretSharing ├── App.config ├── EntryPoint.cs ├── Helpers ├── Extensions.cs ├── HexConverter.cs └── Mod.cs ├── Polynoms ├── CoefficientsSolver.cs ├── LinearEquationsSystemSolver.cs ├── PolynomGenerator.cs ├── PolynomSolver.cs └── SystemGenerator.cs ├── Properties └── AssemblyInfo.cs ├── SecretEncryption ├── Encryption.cs ├── Encryption_Old.cs ├── KeyGenerator.cs └── SharesManager.cs ├── SecretSharing.csproj └── SecretSharing.exe /README.md: -------------------------------------------------------------------------------- 1 | # shamir-secret-sharing 2 | C# implementation of the cryptographic Shamir Secret Sharing Scheme 3 | 4 | MIT License 5 | 6 | Copyright (c) 2019 Anton Kolov 7 | 8 | Permission is hereby granted, free of charge, to any person obtaining a copy 9 | of this software and associated documentation files (the "Software"), to deal 10 | in the Software without restriction, including without limitation the rights 11 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 12 | copies of the Software, and to permit persons to whom the Software is 13 | furnished to do so, subject to the following conditions: 14 | 15 | The above copyright notice and this permission notice shall be included in all 16 | copies or substantial portions of the Software. 17 | 18 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 21 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 22 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 23 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 24 | SOFTWARE. 25 | -------------------------------------------------------------------------------- /SecretSharing.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio 14 4 | VisualStudioVersion = 14.0.23107.0 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SecretSharing", "SecretSharing\SecretSharing.csproj", "{8C416B50-2C7D-48D0-A8C5-E19AECCF8C88}" 7 | EndProject 8 | Global 9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 10 | Debug|Any CPU = Debug|Any CPU 11 | Release|Any CPU = Release|Any CPU 12 | EndGlobalSection 13 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 14 | {8C416B50-2C7D-48D0-A8C5-E19AECCF8C88}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 15 | {8C416B50-2C7D-48D0-A8C5-E19AECCF8C88}.Debug|Any CPU.Build.0 = Debug|Any CPU 16 | {8C416B50-2C7D-48D0-A8C5-E19AECCF8C88}.Release|Any CPU.ActiveCfg = Release|Any CPU 17 | {8C416B50-2C7D-48D0-A8C5-E19AECCF8C88}.Release|Any CPU.Build.0 = Release|Any CPU 18 | EndGlobalSection 19 | GlobalSection(SolutionProperties) = preSolution 20 | HideSolutionNode = FALSE 21 | EndGlobalSection 22 | EndGlobal 23 | -------------------------------------------------------------------------------- /SecretSharing/App.config: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /SecretSharing/EntryPoint.cs: -------------------------------------------------------------------------------- 1 | namespace SecretSharing 2 | { 3 | using SecretEncryption; 4 | using Polynoms; 5 | using Helpers; 6 | using System; 7 | 8 | class EntryPoint 9 | { 10 | public static void Main() 11 | { 12 | Console.WriteLine("1: Split\n2: Combine"); 13 | string choice = Console.ReadLine(); 14 | 15 | if (choice == "1") 16 | { 17 | Console.WriteLine("Players: "); 18 | string playerStr = Console.ReadLine(); 19 | 20 | Console.WriteLine("Required: "); 21 | string requiredStr = Console.ReadLine(); 22 | 23 | Console.WriteLine("Message:"); 24 | string message = Console.ReadLine(); 25 | 26 | int players = int.Parse(playerStr); 27 | int required = int.Parse(requiredStr); 28 | 29 | int polynomsCount = 3; 30 | 31 | var byteKey = KeyGenerator.GenerateKey(polynomsCount * 16); 32 | var key = KeyGenerator.GenerateDoubleBytesKey(byteKey); 33 | var hexKey = KeyGenerator.GetHexKey(key); 34 | 35 | var encrypted = Encryption.Encrypt(message, hexKey); 36 | 37 | Console.WriteLine("\nEncrypted message:\n{0}", encrypted); 38 | 39 | Console.WriteLine("\nShares: "); 40 | 41 | var splitted = SharesManager.SplitKey(key, players, required); 42 | for (int i = 0; i < splitted.Length; i++) 43 | { 44 | Console.WriteLine(splitted[i]); 45 | } 46 | Console.WriteLine(); 47 | } 48 | else if (choice == "2") 49 | { 50 | 51 | Console.WriteLine("Encrypted message: "); 52 | string message = Console.ReadLine(); 53 | 54 | Console.WriteLine("Number of shares: "); 55 | string sharesCountStr = Console.ReadLine(); 56 | int sharesCount = int.Parse(sharesCountStr); 57 | 58 | 59 | var shares = new string[sharesCount]; 60 | 61 | for (int i = 0; i < sharesCount; i++) 62 | { 63 | Console.WriteLine("Share {0}:", i + 1); 64 | shares[i] = Console.ReadLine(); 65 | } 66 | 67 | var generatedKey = SharesManager.CombineKey(shares); 68 | var hexKey = KeyGenerator.GetHexKey(generatedKey); 69 | 70 | var decrypted = Encryption.Decrypt(message, hexKey); 71 | Console.WriteLine("\nDecrypted message:"); 72 | Console.WriteLine(decrypted); 73 | Console.WriteLine(); 74 | } 75 | 76 | var a = Console.ReadLine(); 77 | } 78 | } 79 | } 80 | -------------------------------------------------------------------------------- /SecretSharing/Helpers/Extensions.cs: -------------------------------------------------------------------------------- 1 | namespace SecretSharing.Helpers 2 | { 3 | using System; 4 | 5 | public static class Extensions 6 | { 7 | public static T[] GetRow(this T[,] matrix, int index) 8 | { 9 | int matrixWidth = matrix.GetLength(1); 10 | 11 | T[] result = new T[matrixWidth]; 12 | 13 | for (int i = 0; i < matrixWidth; i++) 14 | { 15 | result[i] = matrix[index, i]; 16 | } 17 | 18 | return result; 19 | } 20 | 21 | public static void SetRow(this T[,] matrix, int index, T[] row) 22 | { 23 | if (row.Length > matrix.Length) 24 | { 25 | throw new ArgumentException("The row size must not be biger than the destination row."); 26 | } 27 | 28 | for (int i = 0; i < row.Length; i++) 29 | { 30 | matrix[index, i] = row[i]; 31 | } 32 | } 33 | 34 | public static void SwapRows(this T[,] matrix, int firstIndex, int secondIndex) 35 | { 36 | var tempRow = matrix.GetRow(firstIndex); 37 | matrix.SetRow(firstIndex, matrix.GetRow(secondIndex)); 38 | matrix.SetRow(secondIndex, tempRow); 39 | } 40 | 41 | public static void Divide(this double[] row, int index, double value) 42 | { 43 | if (value == 0) 44 | { 45 | throw new System.ArgumentException("You can't devide by 0."); 46 | } 47 | for (int i = index; i < row.Length; i++) 48 | { 49 | row[i] /= value; 50 | } 51 | } 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /SecretSharing/Helpers/HexConverter.cs: -------------------------------------------------------------------------------- 1 | namespace SecretSharing.Helpers 2 | { 3 | using System.Text; 4 | using System; 5 | 6 | public class HexConverter 7 | { 8 | public static string NumbersArrToHexString(uint[] arr, char separator) 9 | { 10 | StringBuilder sb = new StringBuilder(); 11 | for (int i = 0; i < arr.Length; i++) 12 | { 13 | sb.Append(arr[i].ToString("X")); 14 | if (i != arr.Length - 1) 15 | { 16 | sb.Append(separator); 17 | } 18 | } 19 | 20 | return sb.ToString(); 21 | } 22 | 23 | public static uint[] HexStringToNumbersArr(string str, char separator) 24 | { 25 | var strArr = str.Split(separator); 26 | var res = new uint[strArr.Length]; 27 | 28 | for (int i = 0; i < strArr.Length; i++) 29 | { 30 | res[i] = (uint)Convert.ToInt32(strArr[i], 16); 31 | } 32 | 33 | return res; 34 | } 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /SecretSharing/Helpers/Mod.cs: -------------------------------------------------------------------------------- 1 | namespace SecretSharing.Helpers 2 | { 3 | public static class Mod 4 | { 5 | public const uint MOD = 2147483647; 6 | 7 | public static ulong PowMod(ulong value, ulong exp, ulong mod) 8 | { 9 | if (exp == 0) return 1; 10 | if (exp == 1) return value % MOD; 11 | 12 | ulong res = PowMod(value, exp / 2, mod); 13 | res *= res; 14 | res %= MOD; 15 | 16 | if ((exp & 1) == 1) 17 | { 18 | res *= value; 19 | res %= mod; 20 | } 21 | 22 | return res; 23 | } 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /SecretSharing/Polynoms/CoefficientsSolver.cs: -------------------------------------------------------------------------------- 1 | namespace SecretSharing.Polynoms 2 | { 3 | public class CoefficientsSolver 4 | { 5 | public static ushort[] GetCoefficients(uint[,,] points) 6 | { 7 | int polynomsCount = points.GetLength(0); 8 | int pointsCount = points.GetLength(1); 9 | var coefficients = new ushort[polynomsCount]; 10 | 11 | var currentPoints = new uint[pointsCount, 2]; 12 | 13 | var systemMatrix = new ulong[polynomsCount, polynomsCount + 1]; 14 | var solved = new ulong[polynomsCount]; 15 | 16 | for (int i = 0; i < polynomsCount; i++) 17 | { 18 | for (int j = 0; j < pointsCount; j++) 19 | { 20 | currentPoints[j, 0] = points[i, j, 0]; 21 | currentPoints[j, 1] = points[i, j, 1]; 22 | } 23 | 24 | systemMatrix = SystemGenerator.GenerateSystemMatrixWithFiniteField(currentPoints); 25 | solved = LinearEquationsSystemSolver.SolveWithFiniteField(systemMatrix); 26 | 27 | coefficients[i] = (ushort)solved[0]; 28 | } 29 | 30 | return coefficients; 31 | } 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /SecretSharing/Polynoms/LinearEquationsSystemSolver.cs: -------------------------------------------------------------------------------- 1 | namespace SecretSharing.Polynoms 2 | { 3 | using Helpers; 4 | using System; 5 | 6 | class LinearEquationsSystemSolver 7 | { 8 | public static ulong[] SolveWithFiniteField(ulong[,] matrix) 9 | { 10 | int n = matrix.GetLength(0); 11 | 12 | for (int i = 0; i < n; i++) 13 | { 14 | // Search for maximum in this column 15 | ulong maxEl = matrix[i, i]; 16 | int maxRow = i; 17 | for (int k = i + 1; k < n; k++) 18 | { 19 | if (matrix[k, i] > maxEl) 20 | { 21 | maxEl = matrix[k, i]; 22 | maxRow = k; 23 | } 24 | } 25 | 26 | // Swap maximum row with current row (column by column) 27 | for (int k = i; k < n + 1; k++) 28 | { 29 | ulong tmp = matrix[maxRow, k]; 30 | matrix[maxRow, k] = matrix[i, k]; 31 | matrix[i, k] = tmp; 32 | } 33 | 34 | // Make all rows below this one 0 in current column 35 | for (int k = i + 1; k < n; k++) 36 | { 37 | ulong factor = (matrix[k, i] * Mod.PowMod(matrix[i, i], Mod.MOD - 2, Mod.MOD)) % Mod.MOD; 38 | 39 | for (int j = i; j < n + 1; j++) 40 | { 41 | if (i == j) 42 | { 43 | matrix[k, j] = 0; 44 | } 45 | else 46 | { 47 | matrix[k, j] += Mod.MOD - (factor * matrix[i, j]) % Mod.MOD; 48 | matrix[k, j] %= Mod.MOD; 49 | } 50 | } 51 | } 52 | } 53 | 54 | // Solve equation Ax=b for an upper triangular matrix A 55 | var coefficients = new ulong[n]; 56 | 57 | for (int i = n - 1; i >= 0; i--) 58 | { 59 | coefficients[i] = (matrix[i, n] * Mod.PowMod(matrix[i, i], Mod.MOD - 2, Mod.MOD)) % Mod.MOD; 60 | 61 | for (int k = i - 1; k >= 0; k--) 62 | { 63 | matrix[k, n] += Mod.MOD - (matrix[k, i] * coefficients[i]) % Mod.MOD; 64 | matrix[k, n] %= Mod.MOD; 65 | } 66 | } 67 | 68 | return coefficients; 69 | } 70 | 71 | public static int[] SolveWithoutFiniteField(double[,] matrix) 72 | { 73 | int n = matrix.GetLength(0); 74 | 75 | for (int i = 0; i < n; i++) 76 | { 77 | // Search for maximum in this column 78 | double maxEl = Math.Abs(matrix[i, i]); 79 | int maxRow = i; 80 | for (int k = i + 1; k < n; k++) 81 | { 82 | if (Math.Abs(matrix[k, i]) > maxEl) 83 | { 84 | maxEl = Math.Abs(matrix[k, i]); 85 | maxRow = k; 86 | } 87 | } 88 | 89 | // Swap maximum row with current row (column by column) 90 | for (int k = i; k < n + 1; k++) 91 | { 92 | double tmp = matrix[maxRow, k]; 93 | matrix[maxRow, k] = matrix[i, k]; 94 | matrix[i, k] = tmp; 95 | } 96 | 97 | // Make all rows below this one 0 in current column 98 | for (int k = i + 1; k < n; k++) 99 | { 100 | double factor = matrix[k, i] / matrix[i, i]; 101 | for (int j = i; j < n + 1; j++) 102 | { 103 | if (i == j) 104 | { 105 | matrix[k, j] = 0; 106 | } 107 | else 108 | { 109 | matrix[k, j] -= factor * matrix[i, j]; 110 | } 111 | } 112 | } 113 | } 114 | 115 | 116 | // Solve equation Ax=b for an upper triangular matrix A 117 | var coefficients = new double[n]; 118 | 119 | for (int i = n - 1; i >= 0; i--) 120 | { 121 | coefficients[i] = matrix[i, n] / matrix[i, i]; 122 | 123 | for (int k = i - 1; k >= 0; k--) 124 | { 125 | matrix[k, n] -= matrix[k, i] * coefficients[i]; 126 | } 127 | } 128 | 129 | var result = new int[n]; 130 | for (int i = 0; i < n; i++) 131 | { 132 | result[i] = Convert.ToInt32(coefficients[i]); 133 | } 134 | return result; 135 | } 136 | } 137 | } 138 | -------------------------------------------------------------------------------- /SecretSharing/Polynoms/PolynomGenerator.cs: -------------------------------------------------------------------------------- 1 | namespace SecretSharing.Polynoms 2 | { 3 | using System; 4 | using Helpers; 5 | 6 | class PolynomGenerator 7 | { 8 | public static uint lowerXBound = 1; 9 | public static uint upperXBound = Mod.MOD - 1; 10 | 11 | private static Random rand = new Random(); 12 | 13 | public static ushort[] GenerateWholeNumbers(int count) 14 | { 15 | var result = new ushort[count]; 16 | 17 | for (int i = 0; i < count; i++) 18 | { 19 | result[i] = (ushort)(rand.Next(ushort.MinValue, ushort.MaxValue)); 20 | } 21 | 22 | return result; 23 | } 24 | 25 | public static ushort[,] GeneratePolynomsMatrix(ushort[] key, int count, int power) 26 | { 27 | var matrix = new ushort[count, power + 1]; 28 | 29 | var currentCoefficients = new ushort[power + 1]; 30 | 31 | for (int i = 0; i < count; i++) 32 | { 33 | currentCoefficients = GenerateWholeNumbers(power + 1); 34 | currentCoefficients[0] = key[i]; 35 | matrix.SetRow(i, currentCoefficients); 36 | } 37 | 38 | return matrix; 39 | } 40 | 41 | public static uint GetRandomX(uint lowerBond, uint upperBond) 42 | { 43 | uint thirtyBits = (uint)rand.Next(1 << 30); 44 | uint twoBits = (uint)rand.Next(1 << 2); 45 | return (thirtyBits << 2) | twoBits; 46 | } 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /SecretSharing/Polynoms/PolynomSolver.cs: -------------------------------------------------------------------------------- 1 | namespace SecretSharing.Polynoms 2 | { 3 | using Helpers; 4 | 5 | class PolynomSolver 6 | { 7 | 8 | public static uint SolveWithFiniteField(ushort[] coefficients, ulong x) 9 | { 10 | ulong y = 0; 11 | 12 | for (int i = 0; i < coefficients.Length; i++) 13 | { 14 | y += (coefficients[i] * Mod.PowMod(x, (ulong)(coefficients.Length - i - 1), Mod.MOD)) % Mod.MOD; 15 | y %= Mod.MOD; 16 | } 17 | 18 | return (uint)y; 19 | } 20 | 21 | //public static int SolveWithoutFiniteField(int[] coefficients, int x) 22 | //{ 23 | // int y = 0; 24 | 25 | // for (int i = 0; i < coefficients.Length; i++) 26 | // { 27 | // y += coefficients[i] * Convert.ToInt32(Math.Pow(x, coefficients.Length - i - 1)); 28 | // } 29 | 30 | // return y; 31 | //} 32 | 33 | public static uint[,] GetRandomPoints(ushort[] coefficients, int count) 34 | { 35 | var pointsArr = new uint[count, 2]; 36 | var point = new uint[2]; 37 | 38 | for (int i = 0; i < count; i++) 39 | { 40 | pointsArr[i, 0] = PolynomGenerator.GetRandomX(PolynomGenerator.lowerXBound, PolynomGenerator.upperXBound); 41 | pointsArr[i, 1] = SolveWithFiniteField(coefficients, pointsArr[i, 0]); 42 | 43 | for (int j = 0; j < i; j++) 44 | { 45 | // ensure random point 46 | if (pointsArr[i, 0] == pointsArr[j, 0]) 47 | { 48 | i--; 49 | } 50 | } 51 | } 52 | 53 | return pointsArr; 54 | } 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /SecretSharing/Polynoms/SystemGenerator.cs: -------------------------------------------------------------------------------- 1 | namespace SecretSharing.Polynoms 2 | { 3 | using Helpers; 4 | 5 | class SystemGenerator 6 | { 7 | public static ulong[,] GenerateSystemMatrixWithFiniteField(uint[,] points) 8 | { 9 | int pointsCount = points.GetLength(0); 10 | 11 | var matrix = new ulong[pointsCount, pointsCount + 1]; 12 | 13 | for (int i = 0; i < pointsCount; i++) 14 | { 15 | var currentX = (ulong)points[i, 0]; 16 | for (int j = 0; j < pointsCount; j++) 17 | { 18 | matrix[i, j] = Mod.PowMod(currentX, (ulong)(pointsCount - j - 1), Mod.MOD); 19 | } 20 | matrix[i, pointsCount] = points[i, 1]; 21 | } 22 | 23 | return matrix; 24 | } 25 | 26 | //public static double[,] GenerateSystemMatrixWithoutFiniteField(int[,] points) 27 | //{ 28 | // int pointsCount = points.GetLength(0); 29 | 30 | // var matrix = new double[pointsCount, pointsCount + 1]; 31 | 32 | // for (int i = 0; i < pointsCount; i++) 33 | // { 34 | // var currentX = points[i, 0]; 35 | // for (int j = 0; j < pointsCount; j++) 36 | // { 37 | // matrix[i, j] = (double)Math.Pow(currentX, pointsCount - j - 1); 38 | // } 39 | // matrix[i, pointsCount] = points[i, 1]; 40 | // } 41 | 42 | // return matrix; 43 | //} 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /SecretSharing/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.CompilerServices; 3 | using System.Runtime.InteropServices; 4 | 5 | // General Information about an assembly is controlled through the following 6 | // set of attributes. Change these attribute values to modify the information 7 | // associated with an assembly. 8 | [assembly: AssemblyTitle("SecretSharing")] 9 | [assembly: AssemblyDescription("")] 10 | [assembly: AssemblyConfiguration("")] 11 | [assembly: AssemblyCompany("")] 12 | [assembly: AssemblyProduct("SecretSharing")] 13 | [assembly: AssemblyCopyright("Copyright © 2015")] 14 | [assembly: AssemblyTrademark("")] 15 | [assembly: AssemblyCulture("")] 16 | 17 | // Setting ComVisible to false makes the types in this assembly not visible 18 | // to COM components. If you need to access a type in this assembly from 19 | // COM, set the ComVisible attribute to true on that type. 20 | [assembly: ComVisible(false)] 21 | 22 | // The following GUID is for the ID of the typelib if this project is exposed to COM 23 | [assembly: Guid("8c416b50-2c7d-48d0-a8c5-e19aeccf8c88")] 24 | 25 | // Version information for an assembly consists of the following four values: 26 | // 27 | // Major Version 28 | // Minor Version 29 | // Build Number 30 | // Revision 31 | // 32 | // You can specify all the values or you can default the Build and Revision Numbers 33 | // by using the '*' as shown below: 34 | // [assembly: AssemblyVersion("1.0.*")] 35 | [assembly: AssemblyVersion("1.0.0.0")] 36 | [assembly: AssemblyFileVersion("1.0.0.0")] 37 | -------------------------------------------------------------------------------- /SecretSharing/SecretEncryption/Encryption.cs: -------------------------------------------------------------------------------- 1 | // 2 | 3 | // This sample code is provided "AS IS" with no warranties, 4 | // and confers no rights. 5 | // 6 | // ATTENTION: This sample is designed to be more of a 7 | // tutorial rather than something you can copy and paste in 8 | // the production code! 9 | // 10 | 11 | 12 | 13 | using System; 14 | using System.IO; 15 | using System.Security.Cryptography; 16 | 17 | // 18 | // Sample encrypt/decrypt functions 19 | // Parameter checks and error handling 20 | // are ommited for better readability 21 | // 22 | 23 | public class Encryption 24 | { 25 | // Encrypt a byte array into a byte array using a key and an IV 26 | public static byte[] Encrypt(byte[] clearData, byte[] Key, byte[] IV) 27 | { 28 | // Create a MemoryStream to accept the encrypted bytes 29 | MemoryStream ms = new MemoryStream(); 30 | 31 | // Create a symmetric algorithm. 32 | // We are going to use Rijndael because it is strong and 33 | // available on all platforms. 34 | // You can use other algorithms, to do so substitute the 35 | // next line with something like 36 | // TripleDES alg = TripleDES.Create(); 37 | Rijndael alg = Rijndael.Create(); 38 | 39 | // Now set the key and the IV. 40 | // We need the IV (Initialization Vector) because 41 | // the algorithm is operating in its default 42 | // mode called CBC (Cipher Block Chaining). 43 | // The IV is XORed with the first block (8 byte) 44 | // of the data before it is encrypted, and then each 45 | // encrypted block is XORed with the 46 | // following block of plaintext. 47 | // This is done to make encryption more secure. 48 | 49 | // There is also a mode called ECB which does not need an IV, 50 | // but it is much less secure. 51 | alg.Key = Key; 52 | alg.IV = IV; 53 | 54 | // Create a CryptoStream through which we are going to be 55 | // pumping our data. 56 | // CryptoStreamMode.Write means that we are going to be 57 | // writing data to the stream and the output will be written 58 | // in the MemoryStream we have provided. 59 | CryptoStream cs = new CryptoStream(ms, 60 | alg.CreateEncryptor(), CryptoStreamMode.Write); 61 | 62 | // Write the data and make it do the encryption 63 | cs.Write(clearData, 0, clearData.Length); 64 | 65 | // Close the crypto stream (or do FlushFinalBlock). 66 | // This will tell it that we have done our encryption and 67 | // there is no more data coming in, 68 | // and it is now a good time to apply the padding and 69 | // finalize the encryption process. 70 | cs.Close(); 71 | 72 | // Now get the encrypted data from the MemoryStream. 73 | // Some people make a mistake of using GetBuffer() here, 74 | // which is not the right way. 75 | byte[] encryptedData = ms.ToArray(); 76 | 77 | return encryptedData; 78 | } 79 | 80 | // Encrypt a string into a string using a password 81 | // Uses Encrypt(byte[], byte[], byte[]) 82 | 83 | public static string Encrypt(string clearText, string Password) 84 | { 85 | // First we need to turn the input string into a byte array. 86 | byte[] clearBytes = 87 | System.Text.Encoding.Unicode.GetBytes(clearText); 88 | 89 | // Then, we need to turn the password into Key and IV 90 | // We are using salt to make it harder to guess our key 91 | // using a dictionary attack - 92 | // trying to guess a password by enumerating all possible words. 93 | PasswordDeriveBytes pdb = new PasswordDeriveBytes(Password, 94 | new byte[] {0x49, 0x76, 0x61, 0x6e, 0x20, 0x4d, 95 | 0x65, 0x64, 0x76, 0x65, 0x64, 0x65, 0x76}); 96 | 97 | // Now get the key/IV and do the encryption using the 98 | // function that accepts byte arrays. 99 | // Using PasswordDeriveBytes object we are first getting 100 | // 32 bytes for the Key 101 | // (the default Rijndael key length is 256bit = 32bytes) 102 | // and then 16 bytes for the IV. 103 | // IV should always be the block size, which is by default 104 | // 16 bytes (128 bit) for Rijndael. 105 | // If you are using DES/TripleDES/RC2 the block size is 106 | // 8 bytes and so should be the IV size. 107 | // You can also read KeySize/BlockSize properties off 108 | // the algorithm to find out the sizes. 109 | byte[] encryptedData = Encrypt(clearBytes, 110 | pdb.GetBytes(32), pdb.GetBytes(16)); 111 | 112 | // Now we need to turn the resulting byte array into a string. 113 | // A common mistake would be to use an Encoding class for that. 114 | //It does not work because not all byte values can be 115 | // represented by characters. 116 | // We are going to be using Base64 encoding that is designed 117 | //exactly for what we are trying to do. 118 | return Convert.ToBase64String(encryptedData); 119 | 120 | } 121 | 122 | // Encrypt bytes into bytes using a password 123 | // Uses Encrypt(byte[], byte[], byte[]) 124 | 125 | public static byte[] Encrypt(byte[] clearData, string Password) 126 | { 127 | // We need to turn the password into Key and IV. 128 | // We are using salt to make it harder to guess our key 129 | // using a dictionary attack - 130 | // trying to guess a password by enumerating all possible words. 131 | PasswordDeriveBytes pdb = new PasswordDeriveBytes(Password, 132 | new byte[] {0x49, 0x76, 0x61, 0x6e, 0x20, 0x4d, 133 | 0x65, 0x64, 0x76, 0x65, 0x64, 0x65, 0x76}); 134 | 135 | // Now get the key/IV and do the encryption using the function 136 | // that accepts byte arrays. 137 | // Using PasswordDeriveBytes object we are first getting 138 | // 32 bytes for the Key 139 | // (the default Rijndael key length is 256bit = 32bytes) 140 | // and then 16 bytes for the IV. 141 | // IV should always be the block size, which is by default 142 | // 16 bytes (128 bit) for Rijndael. 143 | // If you are using DES/TripleDES/RC2 the block size is 8 144 | // bytes and so should be the IV size. 145 | // You can also read KeySize/BlockSize properties off the 146 | // algorithm to find out the sizes. 147 | return Encrypt(clearData, pdb.GetBytes(32), pdb.GetBytes(16)); 148 | 149 | } 150 | 151 | // Encrypt a file into another file using a password 152 | public static void Encrypt(string fileIn, 153 | string fileOut, string Password) 154 | { 155 | 156 | // First we are going to open the file streams 157 | FileStream fsIn = new FileStream(fileIn, 158 | FileMode.Open, FileAccess.Read); 159 | FileStream fsOut = new FileStream(fileOut, 160 | FileMode.OpenOrCreate, FileAccess.Write); 161 | 162 | // Then we are going to derive a Key and an IV from the 163 | // Password and create an algorithm 164 | PasswordDeriveBytes pdb = new PasswordDeriveBytes(Password, 165 | new byte[] {0x49, 0x76, 0x61, 0x6e, 0x20, 0x4d, 166 | 0x65, 0x64, 0x76, 0x65, 0x64, 0x65, 0x76}); 167 | 168 | Rijndael alg = Rijndael.Create(); 169 | alg.Key = pdb.GetBytes(32); 170 | alg.IV = pdb.GetBytes(16); 171 | 172 | // Now create a crypto stream through which we are going 173 | // to be pumping data. 174 | // Our fileOut is going to be receiving the encrypted bytes. 175 | CryptoStream cs = new CryptoStream(fsOut, 176 | alg.CreateEncryptor(), CryptoStreamMode.Write); 177 | 178 | // Now will will initialize a buffer and will be processing 179 | // the input file in chunks. 180 | // This is done to avoid reading the whole file (which can 181 | // be huge) into memory. 182 | int bufferLen = 4096; 183 | byte[] buffer = new byte[bufferLen]; 184 | int bytesRead; 185 | 186 | do 187 | { 188 | // read a chunk of data from the input file 189 | bytesRead = fsIn.Read(buffer, 0, bufferLen); 190 | 191 | // encrypt it 192 | cs.Write(buffer, 0, bytesRead); 193 | } while (bytesRead != 0); 194 | 195 | // close everything 196 | 197 | // this will also close the unrelying fsOut stream 198 | cs.Close(); 199 | fsIn.Close(); 200 | } 201 | 202 | // Decrypt a byte array into a byte array using a key and an IV 203 | public static byte[] Decrypt(byte[] cipherData, 204 | byte[] Key, byte[] IV) 205 | { 206 | // Create a MemoryStream that is going to accept the 207 | // decrypted bytes 208 | MemoryStream ms = new MemoryStream(); 209 | 210 | // Create a symmetric algorithm. 211 | // We are going to use Rijndael because it is strong and 212 | // available on all platforms. 213 | // You can use other algorithms, to do so substitute the next 214 | // line with something like 215 | // TripleDES alg = TripleDES.Create(); 216 | Rijndael alg = Rijndael.Create(); 217 | 218 | // Now set the key and the IV. 219 | // We need the IV (Initialization Vector) because the algorithm 220 | // is operating in its default 221 | // mode called CBC (Cipher Block Chaining). The IV is XORed with 222 | // the first block (8 byte) 223 | // of the data after it is decrypted, and then each decrypted 224 | // block is XORed with the previous 225 | // cipher block. This is done to make encryption more secure. 226 | // There is also a mode called ECB which does not need an IV, 227 | // but it is much less secure. 228 | alg.Key = Key; 229 | alg.IV = IV; 230 | 231 | // Create a CryptoStream through which we are going to be 232 | // pumping our data. 233 | // CryptoStreamMode.Write means that we are going to be 234 | // writing data to the stream 235 | // and the output will be written in the MemoryStream 236 | // we have provided. 237 | CryptoStream cs = new CryptoStream(ms, 238 | alg.CreateDecryptor(), CryptoStreamMode.Write); 239 | 240 | // Write the data and make it do the decryption 241 | cs.Write(cipherData, 0, cipherData.Length); 242 | 243 | // Close the crypto stream (or do FlushFinalBlock). 244 | // This will tell it that we have done our decryption 245 | // and there is no more data coming in, 246 | // and it is now a good time to remove the padding 247 | // and finalize the decryption process. 248 | cs.Close(); 249 | 250 | // Now get the decrypted data from the MemoryStream. 251 | // Some people make a mistake of using GetBuffer() here, 252 | // which is not the right way. 253 | byte[] decryptedData = ms.ToArray(); 254 | 255 | return decryptedData; 256 | } 257 | 258 | // Decrypt a string into a string using a password 259 | // Uses Decrypt(byte[], byte[], byte[]) 260 | 261 | public static string Decrypt(string cipherText, string Password) 262 | { 263 | // First we need to turn the input string into a byte array. 264 | // We presume that Base64 encoding was used 265 | byte[] cipherBytes = Convert.FromBase64String(cipherText); 266 | 267 | // Then, we need to turn the password into Key and IV 268 | // We are using salt to make it harder to guess our key 269 | // using a dictionary attack - 270 | // trying to guess a password by enumerating all possible words. 271 | PasswordDeriveBytes pdb = new PasswordDeriveBytes(Password, 272 | new byte[] {0x49, 0x76, 0x61, 0x6e, 0x20, 0x4d, 0x65, 273 | 0x64, 0x76, 0x65, 0x64, 0x65, 0x76}); 274 | 275 | // Now get the key/IV and do the decryption using 276 | // the function that accepts byte arrays. 277 | // Using PasswordDeriveBytes object we are first 278 | // getting 32 bytes for the Key 279 | // (the default Rijndael key length is 256bit = 32bytes) 280 | // and then 16 bytes for the IV. 281 | // IV should always be the block size, which is by 282 | // default 16 bytes (128 bit) for Rijndael. 283 | // If you are using DES/TripleDES/RC2 the block size is 284 | // 8 bytes and so should be the IV size. 285 | // You can also read KeySize/BlockSize properties off 286 | // the algorithm to find out the sizes. 287 | byte[] decryptedData = Decrypt(cipherBytes, 288 | pdb.GetBytes(32), pdb.GetBytes(16)); 289 | 290 | // Now we need to turn the resulting byte array into a string. 291 | // A common mistake would be to use an Encoding class for that. 292 | // It does not work 293 | // because not all byte values can be represented by characters. 294 | // We are going to be using Base64 encoding that is 295 | // designed exactly for what we are trying to do. 296 | return System.Text.Encoding.Unicode.GetString(decryptedData); 297 | } 298 | 299 | // Decrypt bytes into bytes using a password 300 | // Uses Decrypt(byte[], byte[], byte[]) 301 | 302 | public static byte[] Decrypt(byte[] cipherData, string Password) 303 | { 304 | // We need to turn the password into Key and IV. 305 | // We are using salt to make it harder to guess our key 306 | // using a dictionary attack - 307 | // trying to guess a password by enumerating all possible words. 308 | PasswordDeriveBytes pdb = new PasswordDeriveBytes(Password, 309 | new byte[] {0x49, 0x76, 0x61, 0x6e, 0x20, 0x4d, 310 | 0x65, 0x64, 0x76, 0x65, 0x64, 0x65, 0x76}); 311 | 312 | // Now get the key/IV and do the Decryption using the 313 | //function that accepts byte arrays. 314 | // Using PasswordDeriveBytes object we are first getting 315 | // 32 bytes for the Key 316 | // (the default Rijndael key length is 256bit = 32bytes) 317 | // and then 16 bytes for the IV. 318 | // IV should always be the block size, which is by default 319 | // 16 bytes (128 bit) for Rijndael. 320 | // If you are using DES/TripleDES/RC2 the block size is 321 | // 8 bytes and so should be the IV size. 322 | 323 | // You can also read KeySize/BlockSize properties off the 324 | // algorithm to find out the sizes. 325 | return Decrypt(cipherData, pdb.GetBytes(32), pdb.GetBytes(16)); 326 | } 327 | 328 | // Decrypt a file into another file using a password 329 | public static void Decrypt(string fileIn, 330 | string fileOut, string Password) 331 | { 332 | 333 | // First we are going to open the file streams 334 | FileStream fsIn = new FileStream(fileIn, 335 | FileMode.Open, FileAccess.Read); 336 | FileStream fsOut = new FileStream(fileOut, 337 | FileMode.OpenOrCreate, FileAccess.Write); 338 | 339 | // Then we are going to derive a Key and an IV from 340 | // the Password and create an algorithm 341 | PasswordDeriveBytes pdb = new PasswordDeriveBytes(Password, 342 | new byte[] {0x49, 0x76, 0x61, 0x6e, 0x20, 0x4d, 343 | 0x65, 0x64, 0x76, 0x65, 0x64, 0x65, 0x76}); 344 | Rijndael alg = Rijndael.Create(); 345 | 346 | alg.Key = pdb.GetBytes(32); 347 | alg.IV = pdb.GetBytes(16); 348 | 349 | // Now create a crypto stream through which we are going 350 | // to be pumping data. 351 | // Our fileOut is going to be receiving the Decrypted bytes. 352 | CryptoStream cs = new CryptoStream(fsOut, 353 | alg.CreateDecryptor(), CryptoStreamMode.Write); 354 | 355 | // Now will will initialize a buffer and will be 356 | // processing the input file in chunks. 357 | // This is done to avoid reading the whole file (which can be 358 | // huge) into memory. 359 | int bufferLen = 4096; 360 | byte[] buffer = new byte[bufferLen]; 361 | int bytesRead; 362 | 363 | do 364 | { 365 | // read a chunk of data from the input file 366 | bytesRead = fsIn.Read(buffer, 0, bufferLen); 367 | 368 | // Decrypt it 369 | cs.Write(buffer, 0, bytesRead); 370 | 371 | } while (bytesRead != 0); 372 | 373 | // close everything 374 | cs.Close(); // this will also close the unrelying fsOut stream 375 | fsIn.Close(); 376 | } 377 | } -------------------------------------------------------------------------------- /SecretSharing/SecretEncryption/Encryption_Old.cs: -------------------------------------------------------------------------------- 1 | namespace SecretSharing.SecretEncryption 2 | { 3 | using System.Security.Cryptography; 4 | using System; 5 | 6 | public class Encryption_Old 7 | { 8 | private static byte[] IV = new byte[8] { 1, 2, 3, 4, 5, 6, 7, 8 }; 9 | 10 | public static string Encrypt(string text, byte[] key) 11 | { 12 | byte[] plaintextbytes = System.Text.Encoding.ASCII.GetBytes(text); 13 | AesCryptoServiceProvider aes = new AesCryptoServiceProvider(); 14 | // aes.BlockSize = 128; 15 | ////aes.KeySize = 256; 16 | aes.Key = key; 17 | //aes.IV = IV; 18 | aes.Padding = PaddingMode.None; 19 | aes.Mode = CipherMode.CBC; 20 | ICryptoTransform crypto = aes.CreateEncryptor(aes.Key, aes.IV); 21 | byte[] encrypted = crypto.TransformFinalBlock(plaintextbytes, 0, plaintextbytes.Length); 22 | crypto.Dispose(); 23 | 24 | return Convert.ToBase64String(encrypted); 25 | } 26 | 27 | public static string Decrypt(string encrypted, byte[] key) 28 | { 29 | byte[] encryptedbytes = Convert.FromBase64String(encrypted); 30 | AesCryptoServiceProvider aes = new AesCryptoServiceProvider(); 31 | // aes.BlockSize = 128; 32 | aes.KeySize = 256; 33 | aes.Key = key; 34 | //aes.IV = IV; 35 | aes.Padding = PaddingMode.None; 36 | aes.Mode = CipherMode.CBC; 37 | ICryptoTransform crypto = aes.CreateDecryptor(aes.Key, aes.IV); 38 | byte[] secret = crypto.TransformFinalBlock(encryptedbytes, 0, encryptedbytes.Length); 39 | crypto.Dispose(); 40 | 41 | return System.Text.Encoding.ASCII.GetString(secret); 42 | } 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /SecretSharing/SecretEncryption/KeyGenerator.cs: -------------------------------------------------------------------------------- 1 | namespace SecretSharing.SecretEncryption 2 | { 3 | using System; 4 | using Helpers; 5 | 6 | class KeyGenerator 7 | { 8 | private static Random rand = new Random(); 9 | 10 | public static byte[] GenerateKey(int bitsLength) 11 | { 12 | if (bitsLength % 8 != 0) 13 | { 14 | throw new ArgumentException("The bits length must be able to be divided by 8."); 15 | } 16 | 17 | int bytesLength = bitsLength / 8; 18 | var key = new byte[bytesLength]; 19 | rand.NextBytes(key); 20 | 21 | return key; 22 | } 23 | 24 | public static ushort[] GenerateDoubleBytesKey(byte[] arr) 25 | { 26 | if (arr.Length % 2 != 0) 27 | { 28 | throw new ArgumentException("The array length must be even."); 29 | } 30 | 31 | int length = arr.Length; 32 | var result = new ushort[length / 2]; 33 | 34 | ushort el1, el2; 35 | for (int i = 0; i < length / 2; i++) 36 | { 37 | el1 = (ushort)(arr[2 * i]<<8); 38 | el2 = arr[2 * i + 1]; 39 | 40 | result[i] = (ushort)(el1+ el2); 41 | } 42 | 43 | return result; 44 | } 45 | 46 | public static string GetHexKey(ushort[] key) 47 | { 48 | var newKey = new uint[key.Length]; 49 | for (int i = 0; i < key.Length; i++) 50 | { 51 | newKey[i] = key[i]; 52 | } 53 | return HexConverter.NumbersArrToHexString(newKey, '-'); 54 | } 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /SecretSharing/SecretEncryption/SharesManager.cs: -------------------------------------------------------------------------------- 1 | namespace SecretSharing.SecretEncryption 2 | { 3 | using System; 4 | using Polynoms; 5 | using Helpers; 6 | 7 | public class SharesManager 8 | { 9 | public static string[] SplitKey(ushort[] key, int players, int required) 10 | { 11 | int keyLengthInBits = key.Length * 16; 12 | int polynomsCount = key.Length; 13 | 14 | var polynoms = PolynomGenerator.GeneratePolynomsMatrix(key, polynomsCount, required - 1); 15 | 16 | //Console.WriteLine("Generated matrix:"); 17 | //for (int i = 0; i < polynoms.GetLength(0); i++) 18 | //{ 19 | // for (int j = 0; j < polynoms.GetLength(1); j++) 20 | // { 21 | // Console.Write("{0} ", polynoms[i, j]); 22 | // } 23 | // Console.WriteLine(); 24 | //} 25 | 26 | var playerPoints = new uint[players, polynomsCount, 2]; 27 | var currentPolynomPoints = new uint[players, 2]; 28 | var currentPolynom = new ushort[required]; 29 | 30 | for (int i = 0; i < polynomsCount; i++) 31 | { 32 | currentPolynom = polynoms.GetRow(i); 33 | currentPolynomPoints = PolynomSolver.GetRandomPoints(currentPolynom, players); 34 | for (int j = 0; j < players; j++) 35 | { 36 | playerPoints[j, i, 0] = currentPolynomPoints[j, 0]; 37 | playerPoints[j, i, 1] = currentPolynomPoints[j, 1]; 38 | } 39 | } 40 | 41 | //for (int i = 0; i < playerPoints.GetLength(0); i++) 42 | //{ 43 | // for (int j = 0; j < playerPoints.GetLength(1); j++) 44 | // { 45 | // Console.Write("({0}, {1}) ", playerPoints[i, j, 0], playerPoints[i, j, 1]); 46 | // } 47 | // Console.WriteLine(); 48 | //} 49 | 50 | var geneneratedHexes = new string[players]; 51 | 52 | var currentPlayerPoints = new uint[polynomsCount * 2]; 53 | var counter = 0; 54 | for (int i = 0; i < playerPoints.GetLength(0); i++) 55 | { 56 | for (int j = 0; j < playerPoints.GetLength(1); j++) 57 | { 58 | currentPlayerPoints[counter] = playerPoints[i, j, 0]; 59 | counter++; 60 | currentPlayerPoints[counter] = playerPoints[i, j, 1]; 61 | counter++; 62 | } 63 | counter = 0; 64 | geneneratedHexes[i] = HexConverter.NumbersArrToHexString(currentPlayerPoints, '-'); 65 | //Console.WriteLine(geneneratedHexes[i]); 66 | //Console.WriteLine(); 67 | } 68 | 69 | return geneneratedHexes; 70 | } 71 | 72 | public static ushort[] CombineKey(string[] playerPoints) 73 | { 74 | var polynomsCount = (playerPoints[0].Split('-').Length - 1) / 2 + 1; 75 | var required = playerPoints.Length; 76 | 77 | var convertedPoints = new uint[polynomsCount, required, 2]; 78 | 79 | var testingPlayersPoints = new uint[polynomsCount]; 80 | var counter = 0; 81 | 82 | var currentPlayerPoints = new uint[polynomsCount]; 83 | 84 | for (int i = 0; i < required; i++) 85 | { 86 | currentPlayerPoints = HexConverter.HexStringToNumbersArr(playerPoints[i], '-'); 87 | 88 | for (int j = 0; j < polynomsCount; j++) 89 | { 90 | convertedPoints[j, i, 0] = currentPlayerPoints[counter]; 91 | counter++; 92 | convertedPoints[j, i, 1] = currentPlayerPoints[counter]; 93 | counter++; 94 | } 95 | counter = 0; 96 | } 97 | 98 | //for (int i = 0; i < convertedPoints.GetLength(0); i++) 99 | //{ 100 | // for (int j = 0; j < convertedPoints.GetLength(1); j++) 101 | // { 102 | // Console.Write("({0}, {1})", convertedPoints[i, j, 0], convertedPoints[i, j, 1]); 103 | // } 104 | // Console.WriteLine(); 105 | //} 106 | 107 | var testingSolved = CoefficientsSolver.GetCoefficients(convertedPoints); 108 | 109 | return testingSolved; 110 | } 111 | } 112 | } 113 | -------------------------------------------------------------------------------- /SecretSharing/SecretSharing.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | Debug 6 | AnyCPU 7 | {8C416B50-2C7D-48D0-A8C5-E19AECCF8C88} 8 | Exe 9 | Properties 10 | SecretSharing 11 | SecretSharing 12 | v4.6.1 13 | 512 14 | true 15 | 16 | 17 | 18 | AnyCPU 19 | true 20 | full 21 | false 22 | bin\Debug\ 23 | DEBUG;TRACE 24 | prompt 25 | 4 26 | 27 | 28 | AnyCPU 29 | pdbonly 30 | true 31 | bin\Release\ 32 | TRACE 33 | prompt 34 | 4 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 73 | -------------------------------------------------------------------------------- /SecretSharing/SecretSharing.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/koloff/shamir-secret-sharing/3a1c12ae900bc6203ebf3da144e5e9f26c139938/SecretSharing/SecretSharing.exe --------------------------------------------------------------------------------