├── 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
--------------------------------------------------------------------------------