/// <summary> /// Decrypts the selected file using the given password /// </summary> /// <param name="inputFile">Encrypted File</param> /// <param name="password">Password to decrypt the file</param> /// <param name="percentComplete">Percent of completion</param> /// <returns>If the decryption was successful</returns> internal bool Decrypt(string inputFile, string password, ref decimal percentComplete) { byte[] passwordBytes = Encoding.UTF8.GetBytes(password); FileStream fsCrypt = new FileStream(inputFile, FileMode.Open); fsCrypt = DecryptModeHandler(fsCrypt, out byte[] hash, out byte[] salt, out byte[] faesCBCMode, out byte[] faesMetaData, out var cipher); const int keySize = 256; const int blockSize = 128; Rfc2898DeriveBytes key = new Rfc2898DeriveBytes(passwordBytes, salt, 50000); RijndaelManaged AES = new RijndaelManaged { KeySize = keySize, BlockSize = blockSize, Key = key.GetBytes(keySize / 8), IV = key.GetBytes(blockSize / 8), Padding = PaddingMode.PKCS7, Mode = cipher }; try { CryptoStream cs = new CryptoStream(fsCrypt, AES.CreateDecryptor(), CryptoStreamMode.Read); string outputName = Path.ChangeExtension(inputFile, FileAES_Utilities.ExtentionUFAES); try { FileStream fsOut = new FileStream(outputName, FileMode.Create); File.SetAttributes(outputName, FileAttributes.Hidden); byte[] buffer = new byte[FileAES_Utilities.GetCryptoStreamBuffer()]; long expectedComplete = fsCrypt.Length + hash.Length + salt.Length + faesCBCMode.Length + faesMetaData.Length + AES.KeySize + AES.BlockSize; try { int read; Logging.Log("Beginning writing decrypted data...", Severity.DEBUG); while ((read = cs.Read(buffer, 0, buffer.Length)) > 0) { try { percentComplete = Math.Ceiling((decimal)((Convert.ToDouble(fsOut.Length) / Convert.ToDouble(expectedComplete)) * 100)); if (percentComplete > 100) { percentComplete = 100; } } catch { Logging.Log("Percentage completion calculation failed!", Severity.WARN); } fsOut.Write(buffer, 0, read); } Logging.Log("Finished writing decrypted data.", Severity.DEBUG); } catch { fsOut.Close(); } cs.Close(); fsOut.Close(); fsCrypt.Close(); if (Checksums.ConvertHashToString(hash) != Checksums.ConvertHashToString(Checksums.GetSHA1(outputName))) { Logging.Log("Invalid Checksum detected! Assuming password is incorrect.", Severity.DEBUG); FileAES_IntUtilities.SafeDeleteFile(outputName); return(false); } Logging.Log("Valid Checksum detected!", Severity.DEBUG); return(true); } catch { cs.Close(); fsCrypt.Close(); return(false); } } catch (CryptographicException) { fsCrypt.Close(); return(false); } }
/// <summary> /// Decrypts the selected file using the given password /// </summary> /// <param name="faesMetaData">Formatted Metadata used at the start of a file</param> /// <param name="inputFilePath">File path for encrypted file</param> /// <param name="outputFilePath">File path for unencrypted file</param> /// <param name="encryptionPassword">Encryption Password</param> /// <param name="percentComplete">Percent completion of the encryption process</param> /// <returns>If the decryption was successful</returns> internal bool Decrypt(MetaData faesMetaData, string inputFilePath, string outputFilePath, string encryptionPassword, ref decimal percentComplete) { CipherMode cipher = CipherMode.CBC; byte[] metaData = new byte[faesMetaData.GetLength()]; byte[] salt = new byte[32]; byte[] passwordBytes = Encoding.UTF8.GetBytes(encryptionPassword); FileStream inputDataStream = new FileStream(inputFilePath, FileMode.Open); inputDataStream.Read(metaData, 0, faesMetaData.GetLength()); inputDataStream.Read(salt, 0, salt.Length); const int keySize = 256; const int blockSize = 128; Rfc2898DeriveBytes key = new Rfc2898DeriveBytes(passwordBytes, salt, 51200); RijndaelManaged AES = new RijndaelManaged { KeySize = blockSize, BlockSize = 128, Key = key.GetBytes(keySize / 8), IV = key.GetBytes(blockSize / 8), Padding = PaddingMode.PKCS7, Mode = cipher }; try { CryptoStream crypto = new CryptoStream(inputDataStream, AES.CreateDecryptor(), CryptoStreamMode.Read); FileStream outputDataStream = new FileStream(outputFilePath, FileMode.Create); try { byte[] buffer = new byte[FileAES_Utilities.GetCryptoStreamBuffer()]; long expectedComplete = salt.Length + AES.KeySize + AES.BlockSize; try { Logging.Log("Beginning writing decrypted data...", Severity.DEBUG); int read; while ((read = crypto.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 } outputDataStream.Write(buffer, 0, read); } Logging.Log("Finished writing decrypted data.", Severity.DEBUG); } catch { outputDataStream.Close(); } crypto.Close(); outputDataStream.Close(); inputDataStream.Close(); bool doesHashMatch = false; switch (faesMetaData.GetHashType()) { case Checksums.ChecksumType.SHA1: doesHashMatch = Checksums.CompareHash(faesMetaData.GetOrigHash(), Checksums.GetSHA1(outputFilePath)); break; case Checksums.ChecksumType.SHA256: doesHashMatch = Checksums.CompareHash(faesMetaData.GetOrigHash(), Checksums.GetSHA256(outputFilePath)); break; case Checksums.ChecksumType.SHA512: doesHashMatch = Checksums.CompareHash(faesMetaData.GetOrigHash(), Checksums.GetSHA512(outputFilePath)); break; case Checksums.ChecksumType.SHA384: doesHashMatch = Checksums.CompareHash(faesMetaData.GetOrigHash(), Checksums.GetSHA384(outputFilePath)); break; } if (!doesHashMatch) { Logging.Log("Invalid Checksum detected! Assuming password is incorrect.", Severity.DEBUG); return(false); } Logging.Log("Valid Checksum detected!", Severity.DEBUG); return(true); } catch { crypto.Close(); inputDataStream.Close(); outputDataStream.Close(); return(false); } } catch (CryptographicException) { inputDataStream.Close(); return(false); } }