GPG automatic decryption password passing
Asked Answered
O

2

2

We receive GPG encrypted files from a third party. I'm modifying a C# program that finds the encrypted files, decrypts them, and deletes the encrypted ones. It all works except during the decryption part it prompts for a phassphrase; I know the passphrase and it works when entered. I need to pass the passphrase in the command so the prompt never appears.

string CommandText = string.Format("echo {0}|gpg.exe --keyring {1} --secret-keyring {2} --batch --yes --passphrase-fd 0 -o {3} -d {4}",
                passPhrase, publicKeyRingPath, secretKeyRingPath, outputFullPath, encryptedFilePath);

I have also tried:

    string CommandText = string.Format("gpg.exe --keyring {1} --secret-keyring {2} --batch --yes --passphrase {0} -o {3} -d {4}",
    string CommandText = string.Format("gpg.exe --keyring {1} --secret-keyring {2} --batch --yes --passphrase-fd {0} -o {3} -d {4}",

As well as several other variations.

This is running GnuPG for Windows 2.1.0.57899

In case the issues is elsewhere here is a bunch of code primarily written by my predecessor:

public bool decryptInputFile(string encryptedFilePath, string outputFullPath, out string message)
{
    message = "decryptInputFile: Started";
    try
    {
        ProcessStartInfo psi = new ProcessStartInfo("cmd.exe")
        {
            CreateNoWindow = true,
            UseShellExecute = true,
            RedirectStandardInput = true,
            RedirectStandardOutput = true,
            RedirectStandardError = true,
            WorkingDirectory = decryptPath,
        };

        message = "decryptInputFile: PSI Initialized";
        using (Process process = Process.Start(psi))
        {
            string CommandText = string.Format("echo {0}|gpg.exe --keyring {1} --secret-keyring {2} --batch --yes --passphrase-fd 0 -o {3} -d {4}",
                                passPhrase, publicKeyRingPath, secretKeyRingPath, outputFullPath, encryptedFilePath);
            process.StandardInput.WriteLine(CommandText);
            process.StandardInput.Flush();
            process.StandardInput.Close();
            process.WaitForExit();
            process.Close();
            process.Dispose();
            message = "decryptInputFile: Success";


            //These processes don't close and it keeps the file from being deleted.
            foreach (Process P in Process.GetProcessesByName("gpg")) { P.Kill(); }
            foreach (Process P in Process.GetProcessesByName("gpg2")) { P.Kill(); }

        }
    }
    catch (Exception x)
    {
        // If there was an error, we're going to eat it and just let the user know we failed.
        message = "decryptInputFile: Error: " + x.Message;
        string errMessage = "ERROR: could not decrypt. " + x.Message + "\r\n";
        File.AppendAllText(System.Configuration.ConfigurationSettings.AppSettings["LogPath"], errMessage);

        return false;
    }

    if (File.Exists(outputFullPath) && File.Exists(encryptedFilePath))
    {
        File.Delete(encryptedFilePath);
    }
    return File.Exists(outputFullPath);
}
Odetteodeum answered 12/2, 2015 at 15:59 Comment(0)
E
6

The Problem

You're using GnuPG 2, which only allows the --passphrase* options together with --batch.

Using --batch

The --passphrase* options are meant to be used for scripting. GnuPG 2 limits them (probably for slowly deprecating them out) to the --batch mode, where GnuPG does not perform any interaction (eg., asking for your passphrase or other "dialogues").

While this is still possible, it might be preferable to use the password presetting in gpg-agent instead, which allows you to remove the passphrase completely from your application code. Note the implications of --passphrase (all users on your system can read it, as long as GnuPG is running!) and --passphrase-file (the passphrase is stored on the hard disk, watch out for permissions).

Presetting the Passphrase

Preferred method with GnuPG 2 is to preset the passphrase in gpg-agent, which GnuPG heavily relies on; in case of GnuPG 2.1 the even handles private key and passphrase operations completely on its own.

But, to your rescue, GnuPG 2 brings a new tool, gpg-preset-passphrase. On Debian Linux, it hides in /usr/lib/gnupg2/, I don't know where it is stored in Windows.

From man gpg-preset-passphrase:

The gpg-preset-passphrase is a utility to seed the internal cache of a running gpg-agent with passphrases. It is mainly useful for unattended machines, where the usual pinentry tool may not be used and the passphrases for the to be used keys are given at machine startup.

[...]

gpg-preset-passphrase is invoked this way:

gpg-preset-passphrase [options] [command] cacheid

cacheid is either a 40 character keygrip of hexadecimal characters identifying the key for which the passphrase should be set or cleared. [...]

One of the following command options must be given:

--preset
    Preset a passphrase. This is what you usually will use.
    gpg-preset-passphrase will then read the passphrase from stdin.

To wrap up, when initialising GnuPG for your application (and in intervalls corresponding to the configured cache time) run gpg-preset-passphrase --preset [fingerprint], which will read the passphrase from stdin, or additionally use a --passphrase passphrase option to directly set it in your query. Be aware that when using both the echo or --passphrase approach, other system users might get hold of the passphrase by listing processes; better directly write to the process' stdin from C#.

Embay answered 12/2, 2015 at 17:48 Comment(6)
gpg2 absolutely allows the --passphrase* options. However, you must specify the --batch parameter.Numerary
You're right. I seem to have misremembered the restrictions, and reworked the answer to be accurate.Embay
--batch --passpharse abcxyz works great on windows command line, when I call it from a C# process pointing to gpg it doesnt work....Mckeon
I have the same issue @RollRoll. Were you able to get this fixed? Please share your fix. Thank youFaqir
hey man, I solved it with a work around: you have to decrypt using "batch" syntax and still you won't be able to pass the pass phrase in the same command if it contains space s(I tried different things in the same command between { } etc nothing worked). I made it work by using this "batch" decrypt command syntax with getting passphrase from .txt file. Not the cleanest, not the dirtiest. I will try to get the code once I have it back to show youMckeon
@Mckeon can you please show what you did? I am having the same issue. So where did you put this txt file? Thank you so muchFaqir
G
1

I tried the accepted answer but didn't work out.

I was on Ubuntu 20.04.1 LTS

Check my answer which worked out for me

Graiae answered 27/1, 2021 at 12:32 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.