Click here to Skip to main content
15,886,919 members
Please Sign up or sign in to vote.
0.00/5 (No votes)
See more:
I am using C# in Visual Studio 2012 class library assembly, .Net Framework version 4.5.1.

I am trying to decrypt a file encrypted using [^]GnuPG. Files are encrypted using a password and without using key files. If possible, I would prefer not to have to install GPG4Win or equivalent on the server. I would rather use a library like BouncyCastle within my C# class assembly.

I can find all sorts of examples and help encrypting and decrypting using key files, but not a workable scenario where a simple password is used.

What I have tried:

1. Using cmd.exe process and a command line string. For example:
echo D4pBiQpTJInd3N| gpg.exe --passphrase-fd 0 -o "D:\TESTEncrypt.txt" --decrypt "D:\TESTEncrypt.txt.gpg"

Code (found on [^]CodeProject):
System.Diagnostics.ProcessStartInfo psi = new System.Diagnostics.ProcessStartInfo("cmd.exe");
psi.CreateNoWindow = true;
psi.UseShellExecute = false;
psi.RedirectStandardError = true;
psi.RedirectStandardInput = true;
psi.RedirectStandardOutput = true;
psi.WorkingDirectory = Path.GetDirectoryName(gpgExePath);

// Must construct the command line arguments as a local string variable and pass it to the process or it will fail.
//string sCommandLine = "echo " + passphrase + "| gpg.exe --passphrase-fd 0 -o \"" + outputFileNameFullPath + "\" --decrypt \"" + encryptedFile.FullName + "\"";
string sCommandLine = string.Format("echo {0}|gpg.exe --passphrase-fd 0 -o \"{1}\" --decrypt \"{2}\"", passphrase, decryptedOutputFile, encryptedSourceFile);

var process = System.Diagnostics.Process.Start(psi);
process.StandardInput.WriteLine(sCommandLine);
process.StandardInput.Flush();
process.StandardInput.Close();
process.WaitForExit();
//string result = process.StandardOutput.ReadToEnd();
//string error = process.StandardError.ReadToEnd();
int rc = process.ExitCode;
process.Close();

Debug.WriteLine(string.Format("{0} exited with return code {1},", Path.GetFileName(gpgExePath), rc));

This code causes a "pinentry" prompt to appear. If I type in the password the file will decrypt. However, I need this to run on a server that is not manned. I thought piping the password in would solve that, but apparently not.

2. I have looked into BouncyCastle, but have not found any examples using just a password (verses using key files).

Thank you.
Posted
Updated 25-May-23 15:12pm
Comments
j snooze 27-Apr-17 17:31pm    
have you tried
gpg --passphrase "your phrase" --batch --yes --decrypt "your path"
tbim 2-May-17 7:55am    
Thank you! I was missing --batch. I was able to get it to work.
Member 16014218 25-May-23 8:30am    
where did you add --batch? can you please add cmd.exe of it?
Member 16014218 25-May-23 10:03am    
I added batch but still message pop up to enter passphrase

1 solution

This has been working correctly for me for years. You have to have GPG installed, of course. Recommend placing in try/catch block with logging.

Decrypt file:

C#
/// <summary>
/// Decrypts the file using GnuPG, saves it to the file system and returns the new (decrypted) 
/// path and file name. If decryptedOutputFile is null or invalid, encryptedSourceFile is used 
/// to set the decryptedOutputFile value. In this case, if the encryptedSourceFile ends in a 
/// '.gpg' extension, the resulting decryptedOutputFile will be the encryptedSourceFile minus 
/// the extension. If this resulting file name has no file extension, then it will be assumed 
/// to be a txt file and a '.txt' extension will be added. For example, MyFile.txt.gpg and 
/// MyFile.gpg will both be decrypted to MyFile.txt. If an error occurs, an empty string is 
/// returned and the LastException property is set.
/// </summary>
/// <param name="encryptedSourceFile">The encrypted file that is to be decrypted.</param>
/// <param name="decryptedOutputFile">The path and filename of where the decrypted file should be written.</param>
/// <param name="passphrase">The passphrase or password to use to decrypt the file.</param>
/// <returns>Returns the path and filename of the decrypted file or null if errors.</returns>
public static string GPGDecryptFile(string encryptedSourceFile, string decryptedOutputFile = "", string passphrase = "")
{
    // Code Project: https://www.codeproject.com/Articles/22055/Automated-File-Decryption-Using-GnuPG-and-C
    // Stack Overflow 2 of 2: https://stackoverflow.com/questions/15624819/decrypting-a-gpg-string-from-command-line

    ClearExceptionProperties(); // Clears class-level exception properties.

    if (!encryptedSourceFile.HasValueP4() || !File.Exists(encryptedSourceFile)) return null;
    if (!decryptedOutputFile.HasValueP4()) decryptedOutputFile = Path.GetDirectoryName(encryptedSourceFile) + "\\" + Path.GetFileNameWithoutExtension(encryptedSourceFile);
    if (!decryptedOutputFile.Contains(".")) decryptedOutputFile += ".txt"; // Assume it is a text file.

    GetConfigSettings(); // Sets class-level fields gpgExePath and gpgPassphrase (password).

    if (!passphrase.HasValueP4()) passphrase = gpgPassphrase;

    try
    {
        System.Diagnostics.ProcessStartInfo psi = new System.Diagnostics.ProcessStartInfo("cmd.exe");
        psi.CreateNoWindow = true;
        psi.UseShellExecute = false;
        psi.RedirectStandardError = true;
        psi.RedirectStandardInput = true;
        psi.RedirectStandardOutput = true;
        psi.WorkingDirectory = Path.GetDirectoryName(gpgExePath);

        // Must construct the command line arguments as a local string variable and pass it to the process or it will fail.
        string sCommandLine = string.Format("echo {1}|\"{0}\" --batch --passphrase-fd 0 -o \"{2}\" --decrypt \"{3}\"", gpgExePath, passphrase, decryptedOutputFile, encryptedSourceFile);

        var process = System.Diagnostics.Process.Start(psi);
        process.StandardInput.WriteLine(sCommandLine);
        process.StandardInput.Flush();
        process.StandardInput.Close();
        process.WaitForExit();
        int rc = process.ExitCode;
        process.Close();

        Debug.WriteLine(string.Format("{0} exited with return code {1}.", Path.GetFileName(gpgExePath), rc));
    }
    catch (Exception ex)
    {
        Debug.WriteLine(ex.ToString());
        decryptedOutputFile = "";
        // Set class-level exception properties.
        LastExceptionInfo = string.Format("Error in ADO operation {0}. Error: {1}", new StackFrame().SFP4(), ex.Message);
        LastException = ex;
    }
    return decryptedOutputFile;
}
 
Share this answer
 

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)



CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900