2

我们从第三方接收 GPG 加密文件。我正在修改一个 C# 程序来查找加密文件、解密它们并删除加密文件。除了在解密部分提示输入短语外,它都可以正常工作;我知道密码短语,输入时有效。我需要在命令中传递密码,所以提示永远不会出现。

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);

我也试过:

    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}",

以及其他几个变体。

这是为 Windows 2.1.0.57899 运行 GnuPG

如果问题出在其他地方,这里有一堆主要由我的前任编写的代码:

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);
}
4

2 回答 2

6

问题

您正在使用 GnuPG 2,它只允许--passphrase*选项与--batch.

使用--batch

这些--passphrase*选项旨在用于脚本。GnuPG 2 将它们(可能是为了慢慢弃用它们)限制为--batchGnuPG 不执行任何交互(例如,询问您的密码或其他“对话”)的模式。

虽然这仍然是可能的,但最好使用密码预设gpg-agent代替,它允许您从应用程序代码中完全删除密码。--passphrase请注意(系统上的所有用户都可以读取它,只要 GnuPG 正在运行!)和--passphrase-file(密码存储在硬盘上,注意权限)的含义。

预设密码

GnuPG 2 的首选方法是在 中预设密码gpg-agent,这是 GnuPG 严重依赖的;在 GnuPG 2.1 的情况下,甚至完全自己处理私钥和密码操作。

但是,为了您的救援,GnuPG 2 带来了一个新工具,gpg-preset-passphrase. 在 Debian Linux 上,它隐藏在 中/usr/lib/gnupg2/,我不知道它存储在 Windows 的什么位置。

来自man gpg-preset-passphrase

gpg-preset-passphrase是一个gpg-agent使用密码短语为运行的内部缓存播种的实用程序。它主要适用于无人看管的机器,其中pinentry可能不使用常用工具,并且在机器启动时给出要使用的密钥的密码。

[...]

gpg-preset-passphrase以这种方式调用:

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

cacheid是一个 40 个字符的十六进制字符的密钥夹,用于标识应设置或清除密码的密钥。[...]

必须给出以下命令选项之一:

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

总结一下,在为您的应用程序初始化 GnuPG 时(以及在与配置的缓存时间相对应的时间间隔内)运行gpg-preset-passphrase --preset [fingerprint]时,它将从标准输入读取密码,或者另外使用一个--passphrase passphrase选项直接在您的查询中设置它。请注意,当同时使用 echo 或--passphrase方法时,其他系统用户可能会通过列出进程来获取密码;最好直接从 C# 写入进程的标准输入。

于 2015-02-12T17:48:22.263 回答
1

我尝试了接受的答案,但没有成功。

我在Ubuntu 20.04.1 LTS

检查我的答案,这对我有用

于 2021-01-27T12:32:21.540 回答