Example #1
0
        private static byte[] MakeSecretBytes(string secret, bool useHexEncoding, int degree)
        {
            if (useHexEncoding)
            {
                if (secret.Length > (degree / 4))
                {
                    Fatal("input string too long");
                }

                if (secret.Length < (degree / 4))
                {
                    Warning("input string too short, adding null padding on the left");
                }

                return(BigInteger.Parse(secret, NumberStyles.HexNumber).ToUnsignedBigEndianBytes());
            }
            else
            {
                if (secret.Length > (degree / 8))
                {
                    Fatal("input string too long");
                }

                foreach (char c in secret)
                {
                    if ((c < 32) || (c >= 127))
                    {
                        Warning("binary data detected, use -x mode instead");
                        break;
                    }
                }

                return(SecretEncoder.EncodeString(secret));
            }
        }
        private static void SplitFile()
        {
            // If your message is above 1K, you should use the hybrid approach of splitting the master secret
            // (which is the encryption key) and then use that to encrypt the file using OpenPGP and AES.

            // Here's an example of how to do this hybrid approach:

            // First, get a master secret of whatever size you want. 128 bits is plenty big and is a nice
            // balance of share sizes and security. However, to be fun, let's be super paranoid and go with
            // 256 bits (at the cost of bigger shares!)
            var masterPassword      = HexadecimalPasswordGenerator.GeneratePasswordOfBitSize(bitSize: 256);
            var masterPasswordBytes = SecretEncoder.ParseHexString(masterPassword);

            // As mentioned above, the threshold is the total number of shares that need to come together
            // to unlock the secret.
            const int threshold = 3;

            // Now we create a class to help us encrypt everything else:
            var splitSecret = SecretSplitter.SplitFile(masterPasswordBytes, threshold);

            // We can generate as many shares as we'd like knowing that 3 of them need to come together
            // to reconstruct the secret.
            const int totalShares = 5;
            var       shares      = splitSecret.GetShares(totalShares);

            // The textual representation is what you'd typically distribute:
            var sharesText = shares.Select(s => s.ToString()).ToList();

            // Remember that the shares are just mechanisms to distribute the master password. You still
            // need to distribute the encrypted file

            // Normally, you'd probably use the simpler method of
            // splitSecret.EncryptFile(inputPath, outputPath);

            // But this sample will use the more generic stream based version to keep everything in memory

            // Let's get a spot to store the encrypted output
            Stream encryptedStream;

            // First, let's make up a sample message of the numbers 1-1000
            // As mentioned before, normally you'd just use a simple file name with EncryptFile or an
            // existing stream:

            // The OpenPGP format stores the name of the file, so we provide that here. It can be whatever
            // you want
            const string fileNameInsideEncryptedContainer = "numbers.txt";

            using (var inputStream = new MemoryStream())
                using (var streamWriter = new StreamWriter(inputStream)) {
                    // Generate the numbers 1..1000 each on a single line
                    for (int i = 1; i <= 1000; i++)
                    {
                        streamWriter.WriteLine(i);
                    }

                    // we're done writing
                    streamWriter.Flush();

                    // Note that the size is bigger than 1250 bytes (the limit of splitting the message itself):
                    Debug.Assert(inputStream.Length > 1250);

                    // Now we can use the input. Reset its position to the start of the stream:
                    inputStream.Position = 0;

                    // Finally, encrypt the file. Save it with the filename metadata:
                    encryptedStream = splitSecret.Encrypt(inputStream, fileNameInsideEncryptedContainer);
                }

            // We can save the contents of outputStream wherever we'd like. It's encrypted.

            // Let's go ahead and decrypt it.

            // First, take the threshold number of shares to recover the master secret:
            var combinedSecret = SecretCombiner.Combine(sharesText.Take(threshold));

            // This metadata is present inside the encrypted file
            string   decryptedFileName;
            DateTime decryptedFileDateTime;

            using (var decryptedStream = combinedSecret.Decrypt(encryptedStream, out decryptedFileName, out decryptedFileDateTime))
                using (var decryptedStreamReader = new StreamReader(decryptedStream)) {
                    // For fun, verify the decrypted file is what we expect:

                    Debug.Assert(decryptedFileName == fileNameInsideEncryptedContainer);
                    for (int expectedNumber = 1; expectedNumber <= 1000; expectedNumber++)
                    {
                        var currentLineText   = decryptedStreamReader.ReadLine();
                        var currentLineNumber = Int32.Parse(currentLineText);
                        Debug.Assert(currentLineNumber == expectedNumber);
                    }

                    // Nothing left:
                    Debug.Assert(decryptedStreamReader.EndOfStream);
                }
        }
Example #3
0
        private void CreateSecretFileShares()
        {
            if (!TryVerifyThresholdValues())
            {
                return;
            }

            if (!File.Exists(txtSecretFilePath.Text))
            {
                ShowError("Secret file does not exist", "File Not Found");
                return;
            }

            if (String.IsNullOrEmpty(txtMasterKey.Text))
            {
                ShowError("A valid key is required to encrypt a file.", "Invalid Key Length");
                return;
            }

            byte[] keyBytes;
            if (!SecretEncoder.TryParseHexString(txtMasterKey.Text, out keyBytes))
            {
                ShowError("The key must contain all hexadecimal characters.", "Invalid Key Character");
                return;
            }

            SplitSecret splitSecret = SecretSplitter.SplitFile(keyBytes, (int)nudThreshold.Value);

            saveFileDialog.Filter           = DialogFilter;
            saveFileDialog.Title            = "Save Encrypted File";
            saveFileDialog.InitialDirectory = Path.GetDirectoryName(txtSecretFilePath.Text);
            saveFileDialog.FileName         = Path.GetFileName(Path.ChangeExtension(txtSecretFilePath.Text, ".splitsecret"));
            saveFileDialog.AddExtension     = true;

            ShowInfo("You'll now have to specify where to save the encrypted file.", "Specify Encrypted File Path");
            if (saveFileDialog.ShowDialog() != DialogResult.OK)
            {
                return;
            }

            splitSecret.EncryptFile(txtSecretFilePath.Text, saveFileDialog.FileName);

            var sb = new StringBuilder();

            sb.AppendLine("Here are your secret pieces that form the decryption key for the encrypted file located at:");
            sb.AppendLine(saveFileDialog.FileName);
            sb.AppendLine();
            int shareWidth = saveFileDialog.FileName.Length;

            foreach (var currentShare in splitSecret.GetShares((int)nudShares.Value))
            {
                string currentShareText = currentShare.ToString();
                sb.AppendLine(currentShareText);
                shareWidth = Math.Max(shareWidth, currentShareText.Length);
                sb.AppendLine();
            }

            SetWidthFromShareLength(shareWidth);

            sb.AppendLine("When distributing the secret pieces, remember to also make sure that you distribute the encrypted file. It's safe to email the encrypted file, but you should securely distribute the secret pieces (i.e. in person).");
            sb.AppendLine();
            sb.AppendLine("Make sure that each person knows that exactly " + ((int)nudThreshold.Value) + " pieces are required to reconstruct the file.");

            txtShares.Text   = sb.ToString();
            tabs.SelectedTab = tabRecover;
        }