11

Windows SDK 附带一个名为 signtool.exe 的工具,可让您使用证书对文件进行签名。我需要在后台服务中做同样的事情,所以我正在寻找一个库(最好是托管代码,但 COM 会做)来做同样的事情。有任何想法吗?

找到了答案。以下是如何使用 X.509 证书在 .NET 中对文件进行签名:

CmsSigner signer = new CmsSigner();
signer.Certificate = new X509Certificate2(certificate);

SignedCms content = new SignedCms(new ContentInfo(File.ReadAllBytes(fileToSign)));
content.ComputeSignature(signer, true);
byte[] signedFile = content.Encode();

string signedFileName = fileToSign + ".signed";
File.WriteAllBytes(signedFileName, signedFile);

Console.WriteLine("Signed file: " + signedFileName);

这里,certificate是包含证书的 .pfx 文件的路径,而fileToSign是要签名的文件。

4

4 回答 4

3

SignTool 正在使用 CAPICOM,它是 Crypto API 的 COM 包装器。您可以使用任何一种。如果您使用 CAPICOM,您可以在此处查看信息。

于 2009-02-04T10:29:34.020 回答
2

对于到达这里的谷歌旅行者:

这个 MSDN 论坛帖子说 Windows 中有一个CryptUIWizDigitalSign API。它还指向Alejandro Campos Magencio 的一篇博客文章,该文章展示了 VB.NET 中的示例实现。

由于似乎缺少 C# 版本,我将 Alejandro 的代码转换为 C#。请注意,以下代码仅适用于文件(尚未)。

using System;
using System.Security.Cryptography.X509Certificates;
using System.ComponentModel;
using System.Runtime.InteropServices;

namespace ConsoleApp1
{
    /// <summary>
    /// Provides code signing functionality via Windows COM Cryptui.dll.
    /// </summary>
    class Signer
    {

        public const Int32 CRYPTUI_WIZ_NO_UI = 1;
        public const Int32 CRYPTUI_WIZ_DIGITAL_SIGN_SUBJECT_FILE = 1;
        public const Int32 CRYPTUI_WIZ_DIGITAL_SIGN_CERT = 1;

        public struct CRYPTUI_WIZ_DIGITAL_SIGN_INFO
        {
            public Int32 dwSize;
            public Int32 dwSubjectChoice;
            [MarshalAs(UnmanagedType.LPWStr)]
            public string pwszFileName;
            public Int32 dwSigningCertChoice;
            public IntPtr pSigningCertContext;
            public string pwszTimestampURL;
            public Int32 dwAdditionalCertChoice;
            public IntPtr pSignExtInfo;
        }

        [StructLayout(LayoutKind.Sequential)]
        public struct CRYPTUI_WIZ_DIGITAL_SIGN_CONTEXT
        {
            public Int32 dwSize;
            public Int32 cbBlob;
            public IntPtr pbBlob;
        }

        [DllImport("Cryptui.dll", CharSet = CharSet.Unicode, SetLastError = true)]
        public static extern bool CryptUIWizDigitalSign(Int32 dwFlags, IntPtr hwndParent, string pwszWizardTitle, ref CRYPTUI_WIZ_DIGITAL_SIGN_INFO pDigitalSignInfo, ref IntPtr ppSignContext);

        [DllImport("Cryptui.dll", CharSet = CharSet.Auto, SetLastError = true)]
        public static extern bool CryptUIWizFreeDigitalSignContext(IntPtr pSignContext);

        /// <summary>
        /// Signs the executable at the given path with the given code signing certificate.
        /// </summary>
        /// <example>
        ///    string certPath = @"C:\certs\CodeSigningTestCert.pfx";
        ///    string exePath = @"C:\temp\ConsoleApp2ToBeSigned.exe";
        ///    string certPwd = "myGreatSecurePassword";
        ///    
        ///    try
        ///    {
        ///        string resultingSignature = Signer.SignExecutable(certPath, exePath, certPwd);
        ///    }
        ///    catch (Win32Exception ex)
        ///    {
        ///        Console.WriteLine(ex.Message + ", Native error code: " + ex.NativeErrorCode.ToString());
        ///    }
        ///    catch (Exception ex)
        ///    {
        ///        // Any unexpected errors?
        ///        Console.WriteLine(ex.Message);
        ///    }
        /// 
        /// </example>
        /// <param name="certPath">The absolute path to the PFX file to be used for signing the exe file.</param>
        /// <param name="exePath">The absolute path to the executable to be signed.</param>
        /// <param name="certPwd">The password for the PFX file.</param>
        public static string SignExecutable(string certPath, string exePath, string certPwd)
        {
            X509Certificate2 cert = default(X509Certificate2);

            CRYPTUI_WIZ_DIGITAL_SIGN_INFO digitalSignInfo = default(CRYPTUI_WIZ_DIGITAL_SIGN_INFO);
            CRYPTUI_WIZ_DIGITAL_SIGN_CONTEXT signContext = default(CRYPTUI_WIZ_DIGITAL_SIGN_CONTEXT);

            IntPtr pSignContext = default(IntPtr);
            IntPtr pSigningCertContext = default(IntPtr);

            // Get certificate context
            cert = new X509Certificate2(certPath, certPwd);
            pSigningCertContext = cert.Handle;

            // Prepare signing info: exe and cert
            digitalSignInfo = new CRYPTUI_WIZ_DIGITAL_SIGN_INFO();
            digitalSignInfo.dwSize = Marshal.SizeOf(digitalSignInfo);
            digitalSignInfo.dwSubjectChoice = CRYPTUI_WIZ_DIGITAL_SIGN_SUBJECT_FILE;
            digitalSignInfo.pwszFileName = exePath;
            digitalSignInfo.dwSigningCertChoice = CRYPTUI_WIZ_DIGITAL_SIGN_CERT;
            digitalSignInfo.pSigningCertContext = pSigningCertContext;
            digitalSignInfo.pwszTimestampURL = null;
            digitalSignInfo.dwAdditionalCertChoice = 0;
            digitalSignInfo.pSignExtInfo = IntPtr.Zero;

            // Sign exe
            if ((!CryptUIWizDigitalSign(CRYPTUI_WIZ_NO_UI, IntPtr.Zero, null, ref digitalSignInfo, ref pSignContext)))
                throw new Win32Exception(Marshal.GetLastWin32Error(), "CryptUIWizDigitalSign");

            // Get the blob with the signature
            signContext = (CRYPTUI_WIZ_DIGITAL_SIGN_CONTEXT)Marshal.PtrToStructure(pSignContext, typeof(CRYPTUI_WIZ_DIGITAL_SIGN_CONTEXT));
            byte[] blob = new byte[signContext.cbBlob + 1];
            Marshal.Copy(signContext.pbBlob, blob, 0, signContext.cbBlob);

            // Free blob memory
            if ((!CryptUIWizFreeDigitalSignContext(pSignContext)))
                throw new Win32Exception(Marshal.GetLastWin32Error(), "CryptUIWizFreeDigitalSignContext");

            return System.Text.Encoding.Default.GetString(blob);
        }
    }
}

希望能帮助到你!

于 2017-11-17T09:58:38.790 回答
0

我遇到了和塞巴斯蒂安一样的问题。查看 API,这似乎是用于对封装消息进行签名。Authenticode - signtool 所做的代码签名 - 是不同的,这就是 EXE 在签名后不运行的原因。

我仍在寻找替代品。

于 2010-10-12T15:26:10.730 回答
-1

您不能只是编写脚本来解决它吗?编写一个简单的批处理文件,为其提供正确的参数和输入?至少当我们在 UNIX 服务器上看到这个问题时,我们会这样做。

于 2009-02-04T10:30:51.243 回答