private void LoadMetaDataFromFile(string filePath) { try { int metaSize; byte[] metaSizeBytes = new byte[4]; FileStream metaSizeStream = new FileStream(filePath, FileMode.Open); metaSizeStream.Read(metaSizeBytes, 0, 4); metaSizeStream.Close(); metaSize = BitConverter.ToInt32(metaSizeBytes, 0); byte[] faesMetaData = new byte[metaSize]; FileStream faesMeta = new FileStream(filePath, FileMode.Open); faesMeta.Read(faesMetaData, 0, metaSize); faesMeta.Close(); try { if (metaSize < 7) { LoadLegacyMetaDataFromFile(filePath); } else { ushort faesIdentifierSize; byte[] faesIdentifierSizeBytes = new byte[2]; Array.Copy(faesMetaData, 4, faesIdentifierSizeBytes, 0, 2); faesIdentifierSize = BitConverter.ToUInt16(faesIdentifierSizeBytes, 0); byte[] faesIdentifierBytes = new byte[faesIdentifierSize]; Array.Copy(faesMetaData, 6, faesIdentifierBytes, 0, Convert.ToInt32(faesIdentifierSize)); if (CryptUtils.ConvertBytesToString(faesIdentifierBytes) != CryptUtils.GetCryptIdentifier()) { LoadLegacyMetaDataFromFile(filePath); } else { InitWithBytes(faesMetaData); } } } catch (IOException) { Logging.Log("File is already open in another program!", Severity.ERROR); } catch (Exception) { LoadLegacyMetaDataFromFile(filePath); } } catch (Exception) { LoadLegacyMetaDataFromFile(filePath); } }
/// <summary> /// Encrypts the selected file using the given password /// </summary> /// <param name="metaData">Formatted Metadata used at the start of a file</param> /// <param name="inputFilePath">File path for unencrypted file</param> /// <param name="outputFilePath">File path for encrypted file</param> /// <param name="encryptionPassword">Encryption Password</param> /// <param name="percentComplete">Percent completion of the encryption process</param> /// <returns>If the encryption was successful</returns> internal bool Encrypt(byte[] metaData, string inputFilePath, string outputFilePath, string encryptionPassword, ref decimal percentComplete) { byte[] salt = _specifiedSalt ?? CryptUtils.GenerateRandomSalt(); byte[] passwordBytes = Encoding.UTF8.GetBytes(encryptionPassword); const int keySize = 256; const int blockSize = 128; Rfc2898DeriveBytes key = new Rfc2898DeriveBytes(passwordBytes, salt, 51200); RijndaelManaged AES = new RijndaelManaged { KeySize = keySize, BlockSize = blockSize, Padding = PaddingMode.PKCS7, Key = key.GetBytes(keySize / 8), IV = key.GetBytes(blockSize / 8), Mode = CipherMode.CBC }; FileStream outputDataStream = new FileStream(outputFilePath, FileMode.Create); outputDataStream.Write(metaData, 0, metaData.Length); outputDataStream.Write(salt, 0, salt.Length); CryptoStream crypto = new CryptoStream(outputDataStream, AES.CreateEncryptor(), CryptoStreamMode.Write); FileStream inputDataStream = new FileStream(inputFilePath, FileMode.Open); byte[] buffer = new byte[FileAES_Utilities.GetCryptoStreamBuffer()]; int read; long expectedComplete = metaData.Length + AES.KeySize + AES.BlockSize; Logging.Log("Beginning writing encrypted data...", Severity.DEBUG); while ((read = inputDataStream.Read(buffer, 0, buffer.Length)) > 0) { try { percentComplete = Math.Ceiling((decimal)((Convert.ToDouble(outputDataStream.Length) / Convert.ToDouble(expectedComplete)) * 100)); if (percentComplete > 100) { percentComplete = 100; } } catch { // ignored } crypto.Write(buffer, 0, read); } Logging.Log("Finished writing encrypted data.", Severity.DEBUG); inputDataStream.Close(); crypto.Close(); outputDataStream.Close(); return(true); }
/// <summary> /// Gets the Password Hint /// </summary> /// <returns>Password Hint stored in MetaData</returns> public string GetPasswordHint() { if (_passwordHint != null) { //Removes the old padding character used in older FAES versions, as well as any newlines or special chars. I wish I wasn't stupid and actually zero-padded + checked for special characters in older v1.1.x versions... return(CryptUtils.ConvertBytesToString(_passwordHint).TrimEnd('\n', '\r', '¬', '�')); } else { return("No Password Hint Set"); } }
/// <summary> /// Gets the Compression Method used to compress the encrypted file /// </summary> /// <returns>Compression Mode Type</returns> public string GetCompressionMode() { if (_compressionMode != null) { string converted = CryptUtils.ConvertBytesToString(_compressionMode); if (!String.IsNullOrEmpty(converted)) { return(converted); } } return("LGYZIP"); }
/// <summary> /// Converts variables into easy-to-manage method calls to create a byte array for metadata /// </summary> /// <param name="checksumHashType">Type of checksum used to generate the file hash</param> /// <param name="originalFileHash">File hash of the original file (checksum generated using previous hash type)</param> /// <param name="passwordHint">A password hint for the password used to encrypt the file</param> /// <param name="compressionModeUsed">Compression mode used to compress the file</param> /// <param name="originalFileName">The name of the original file</param> public DynamicMetadata(Checksums.ChecksumType checksumHashType, byte[] originalFileHash, string passwordHint, string compressionModeUsed, string originalFileName) { _faesIdentifier = CryptUtils.ConvertStringToBytes(CryptUtils.GetCryptIdentifier()); _hashType = CryptUtils.ConvertChecksumTypeToBytes(checksumHashType); _originalFileHash = originalFileHash; _encryptionTimestamp = BitConverter.GetBytes((long)(DateTime.UtcNow - new DateTime(1970, 1, 1, 0, 0, 0)).TotalSeconds); _passwordHint = CryptUtils.ConvertStringToBytes(passwordHint.TrimEnd('\n', '\r')); _encryptionVersion = CryptUtils.ConvertStringToBytes(FileAES_Utilities.GetVersion()); _compressionMode = CryptUtils.ConvertStringToBytes(compressionModeUsed); _originalFileName = CryptUtils.ConvertStringToBytes(originalFileName); _totalMetadataSize = (4 + 2 + _faesIdentifier.Length + 2 + _hashType.Length + 2 + _originalFileHash.Length + 2 + _encryptionTimestamp.Length + 2 + _passwordHint.Length + 2 + _encryptionVersion.Length + 2 + _compressionMode.Length + 2 + _originalFileName.Length); }
/// <summary> /// Gets the Version of FAES used to encrypt the file /// </summary> /// <returns>FAES Version</returns> public string GetEncryptionVersion() { if (_encryptionVersion != null) { string ver = CryptUtils.ConvertBytesToString(_encryptionVersion); if (ver.Contains("DEV")) { return(ver.Split('_')[0]); } return(ver); } return("Unknown version!"); }
/// <summary> /// Checks the metadata to see if the file can be decrypted /// </summary> /// <param name="filePath">Path to file (Compatibility)</param> /// <returns>If the file can be decrypted</returns> public bool IsDecryptable(string filePath) { if (_usingCompatibilityMode) { return(new LegacyCrypt().IsDecryptable(filePath)); } else if (_dynamicMetadata.GetFaesIdentifier() == CryptUtils.GetCryptIdentifier()) { return(true); } else { return(false); } }
/// <summary> /// Gets the data at the current offset /// </summary> /// <param name="offset">Offset from the beginning of the metadata</param> /// <param name="totalSize">Total metadata size</param> /// <returns>Data at the current offset</returns> private byte[] LoadDynamicMetadataChunk(ref int offset, ref int totalSize) { if (offset < totalSize) { int origOffset = offset; // Saves the starting offset byte[] chunkSizeBytes = new byte[2]; // chunkSize's are always 2 bytes (ushort) Array.Copy(_metaData, offset, chunkSizeBytes, 0, 2); // Gets the size of the next chunk (the data chunk) from the chunkSize ushort chunkSize = BitConverter.ToUInt16(chunkSizeBytes, 0); // Size of the data chunk byte[] metaDataChunk = new byte[chunkSize]; offset += 2; // Increase offset to be past the chunkSize chunk Array.Copy(_metaData, offset, metaDataChunk, 0, chunkSize); // Gets the data (for the size of the data chunk) from the metadata offset += chunkSize; // Increase offset to be past the data chunk Logging.Log(String.Format("MetaData | Size: {0}, Converted: {2}, InitialOffset: {3}, FinalOffset: {4}, Raw: {1}", chunkSize, BitConverter.ToString(metaDataChunk), CryptUtils.ConvertBytesToString(metaDataChunk), origOffset, offset), Severity.DEBUG); return(metaDataChunk); // Return the data from the data chunk } else { throw new IndexOutOfRangeException("Metadata cannot be found at this offset!"); // Something is f****d, this shouldn't happen. Corrupted file? } }
/// <summary> /// Gets the FAES Identifier /// </summary> /// <returns>Gets the FAES Identifier stored in MetaData</returns> public string GetFaesIdentifier() { return(CryptUtils.ConvertBytesToString(_faesIdentifier)); }
/// <summary> /// Gets the Original Filename /// </summary> /// <returns>Gets the Original Filename stored in MetaData</returns> public string GetOriginalFileName() { return(CryptUtils.ConvertBytesToString(_originalFileName)); }
/// <summary> /// Gets the Checksum Hash Type used to hash the original file /// </summary> /// <returns>The original hash type</returns> public Checksums.ChecksumType GetHashType() { return(CryptUtils.ConvertBytesToChecksumType(_hashType)); }
/// <summary> /// Automatically adds a Metadata Chunk byte array to a FAESv3 Metadata structure /// </summary> /// <param name="src">Metadata Chunk</param> /// <param name="dst">FAESv3 Metadata structure</param> /// <param name="offset">Current offset</param> private void MetaDataBlockCopy(byte[] src, ref byte[] dst, ref int offset) { ushort chunkSize = Convert.ToUInt16(src.Length); // Size of the data chunk (to store within the chunkSize) int origOffset = offset; Array.Copy(BitConverter.GetBytes(chunkSize), 0, dst, offset, 2); // Store the data chunk size (size of the data within the data chunk) offset += 2; // Increase offset to be past the chunkSize chunk Array.Copy(src, 0, dst, offset, src.Length); // Store the data chunk data offset += src.Length; // Increase offset to be past the data chunk Logging.Log(String.Format("MetaData | Size: {0}, Converted: {2}, InitialOffset: {3}, FinalOffset: {4}, Raw: {1}", chunkSize, BitConverter.ToString(src), CryptUtils.ConvertBytesToString(src), origOffset, offset), Severity.DEBUG); }