C# CryptoAPI';使用PInvoke的s SignerItemsTampEx2

C# CryptoAPI';使用PInvoke的s SignerItemsTampEx2,c#,timestamp,pinvoke,sha256,cryptoapi,C#,Timestamp,Pinvoke,Sha256,Cryptoapi,我试图使用C代码中的CryptoAPI向签名程序集添加SHA256时间戳。以下是我正在使用的代码: Signer.TimestampSignedAssembly("MyAssembly.exe", "http://tsa.starfieldtech.com"); 签名者类别: public static class Signer { [StructLayoutAttribute(LayoutKind.Sequential)] struct SIGNER_SUBJECT_INFO

我试图使用C代码中的CryptoAPI向签名程序集添加SHA256时间戳。以下是我正在使用的代码:

Signer.TimestampSignedAssembly("MyAssembly.exe", "http://tsa.starfieldtech.com");
签名者类别:

public static class Signer
{
    [StructLayoutAttribute(LayoutKind.Sequential)]
    struct SIGNER_SUBJECT_INFO
    {
        public uint cbSize;
        public IntPtr pdwIndex;
        public uint dwSubjectChoice;
        public SubjectChoiceUnion Union1;
        [StructLayoutAttribute(LayoutKind.Explicit)]
        internal struct SubjectChoiceUnion
        {
            [FieldOffsetAttribute(0)]
            public IntPtr pSignerFileInfo;
            [FieldOffsetAttribute(0)]
            public IntPtr pSignerBlobInfo;
        }
    }

    [StructLayoutAttribute(LayoutKind.Sequential)]
    struct SIGNER_FILE_INFO
    {
        public uint cbSize;
        public IntPtr pwszFileName;
        public IntPtr hFile;
    }

    [DllImport("Mssign32.dll", CharSet = CharSet.Unicode, SetLastError = true)]
    private static extern int SignerTimeStampEx2(
        uint dwFlags,               // DWORD
        IntPtr pSubjectInfo,        // SIGNER_SUBJECT_INFO
        string pwszHttpTimeStamp,   // LPCWSTR
        uint dwAlgId,               // ALG_ID
        IntPtr psRequest,           // PCRYPT_ATTRIBUTES
        IntPtr pSipData,            // LPVOID 
        out IntPtr ppSignerContext  // SIGNER_CONTEXT
        );

    public static void TimestampSignedAssembly(string appPath, string tsaServer)
    {
        if (tsaServer == null) throw new ArgumentNullException("tsaServer");

        var pSubjectInfo = IntPtr.Zero;            
        try
        {                
            pSubjectInfo = CreateSignerSubjectInfo(appPath);
            TimestampSignedAssembly(pSubjectInfo, tsaServer);
        }
        finally
        {                
            if (pSubjectInfo != IntPtr.Zero)
            {
                Marshal.DestroyStructure(pSubjectInfo, typeof(SIGNER_SUBJECT_INFO));
            }                
        }
    }

    private static IntPtr CreateSignerSubjectInfo(string pathToAssembly)
    {
        var info = new SIGNER_SUBJECT_INFO
        {
            cbSize = (uint)Marshal.SizeOf(typeof(SIGNER_SUBJECT_INFO)),
            pdwIndex = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(uint)))
        };
        var index = 0;
        Marshal.StructureToPtr(index, info.pdwIndex, false);

        info.dwSubjectChoice = 0x1; //SIGNER_SUBJECT_FILE
        var assemblyFilePtr = Marshal.StringToHGlobalUni(pathToAssembly);

        var fileInfo = new SIGNER_FILE_INFO
        {
            cbSize = (uint)Marshal.SizeOf(typeof(SIGNER_FILE_INFO)),
            pwszFileName = assemblyFilePtr,
            hFile = IntPtr.Zero
        };

        info.Union1 = new SIGNER_SUBJECT_INFO.SubjectChoiceUnion
        {
            pSignerFileInfo = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(SIGNER_FILE_INFO)))
        };

        Marshal.StructureToPtr(fileInfo, info.Union1.pSignerFileInfo, false);

        IntPtr pSubjectInfo = Marshal.AllocHGlobal(Marshal.SizeOf(info));
        Marshal.StructureToPtr(info, pSubjectInfo, false);

        return pSubjectInfo;
    }

    /* 
        Here CryptoAPI function SignerTimeStampEx2 called.
    */
    private static void TimestampSignedAssembly(IntPtr pSubjectInfo, string tsaServer)
    {            
        IntPtr context;
        var hResult = SignerTimeStampEx2(
            0x1,            // I have not found anywhere what value should have this parameter!
            pSubjectInfo,   
            tsaServer,      
            0x0000800c,     // 256 bit SHA hashing algorithm. This value taken form here: http://msdn.microsoft.com/en-us/library/windows/desktop/aa375549(v=vs.85).aspx
            IntPtr.Zero,    
            IntPtr.Zero,
            out context
            );

        if (hResult != 0)
        {
            throw new Exception(string.Format("Error occured when adding timestamp - Error code: 0x{0:X}", hResult));
        }
    }
}   
尽管我向SignerTimeStampEx2函数传递了一个参数(dwAlgId),表明有必要添加SHA256时间戳(0x0000800c),但始终会生成SHA1时间戳

有人遇到过这个问题吗?我做错了什么?我应该为dwFlags和dwAlgId参数设置哪些值


提前谢谢

dwFlags需要是签名者\u时间戳\u RFC3161(2)。获取访问冲突的原因是SignerTimeStampEx2()错误。它期望算法是一个PCSTR而不是一个DWORD。如果您传递0x800C,它将尝试将其作为指针取消引用,从而导致AV。因此,将函数声明中的ALG_ID dwAlgId替换为PCSTR pszTimeStampAlgorithmOid。将szOID_NIST_sha256传递给it,应定义为“2.16.840.1.101.3.4.2.1”

SignerTimeStampEx3()也不正确。pszTimeStampAlgorithmOid应声明为PCSTR,而不是PCWSTR

根据我的经验,如果在SIGNER\u file\u INFO结构中同时指定文件名和打开的Win32文件句柄,则代码签名和时间戳更加可靠


您是否真正获得SHA-256时间戳还取决于您使用的时间戳服务,并发布SHA-256时间戳。即使在请求SHA-256时间戳时,其他服务也可能发行SHA-1时间戳

我终于成功了。以下是时间戳类的完整代码:

公共静态类时间戳
{
[StructLayout(LayoutKind.Sequential)]
结构签名者\u主题\u信息
{
公共单位cbSize;
公共IntPtr pdwIndex;
公共信息主体选择;
公共主体选择工会1;
[StructLayoutAttribute(LayoutKind.Explicit)]
内部结构SubjectChoiceUnion
{
[FieldOffsetAttribute(0)]
公共IntPtr pSignerFileInfo;
[FieldOffsetAttribute(0)]
公共IntPtr pSignerBlobInfo;
}
}
[StructLayoutAttribute(LayoutKind.Sequential)]
结构签名者\u文件\u信息
{
公共单位cbSize;
公共IntPtr pwszFileName;
公共文件;
}
[DllImport(“Mssign32.dll”,CharSet=CharSet.Unicode,SetLastError=true)]
私有静态外部int SignerItemsTampEx2(
uint dwFlags,//DWORD
IntPtr pSubjectInfo,//签名者\主题\信息
字符串pwszHttpTimeStamp,//LPCWSTR
IntPtr pszTimeStampAlgorithmOid,//PCSTR
IntPtr psRequest,//PCRYPT\u属性
IntPtr pSipData,//LPVOID
out IntPtr ppSignerContext//SIGNER\u上下文
);
公共静态void TimestampSignedAssembly(字符串appPath、字符串tsaServer)
{
如果(tsaServer==null)抛出新的ArgumentNullException(“tsaServer”);
IntPtr psubectinfo=IntPtr.Zero;
尝试
{
psObjectInfo=CreateSignerSubjectInfo(appPath);
TimestampSignedAssembly(PSObjectInfo,tsaServer);
}
最后
{
if(PSObjectInfo!=IntPtr.Zero)
{
Marshal.DestroyStructure(psObjectInfo,typeof(SIGNER_SUBJECT_INFO));
}
}
}
私有静态IntPtr CreateSignerSubjectInfo(字符串路径到汇编)
{
签名者\主题\信息=新签名者\主题\信息
{
cbSize=(uint)Marshal.SizeOf(typeof(SIGNER\u SUBJECT\u INFO)),
pdwIndex=Marshal.AllocHGlobal(Marshal.SizeOf(typeof(uint)))
};
int指数=0;
Marshal.StructureToPtr(index,info.pdwIndex,false);
info.dwSubjectChoice=0x1;//签名者\主题\文件
IntPtr assemblyFilePtr=Marshal.StringToHGlobalUni(路径到assembly);
签名者文件信息文件信息=新签名者文件信息
{
cbSize=(uint)Marshal.SizeOf(typeof(SIGNER\u FILE\u INFO)),
pwszFileName=assemblyFilePtr,
hFile=IntPtr.Zero
};
info.Union1=新签名者\u主题\u info.SubjectChoiceUnion
{
pSignerFileInfo=Marshal.AllocHGlobal(Marshal.SizeOf(typeof(SIGNER\u FILE\u INFO)))
};
Marshal.StructureToPtr(fileInfo,info.Union1.pSignerFileInfo,false);
IntPtr pSubjectInfo=Marshal.AllocHGlobal(Marshal.SizeOf(info));
Marshal.StructureToPtr(info,psubectinfo,false);
返回psubectinfo;
}
/* 
这里调用了CryptoAPI函数SignerTimeStampEx2。
*/
私有静态void TimestampSignedAssembly(IntPtr psubectinfo,string tsaServer)
{
IntPtr上下文;
int hResult=SignerTimeStampEx2(
0x2,//签名者\u时间戳\u RFC3161
PSubectInfo,
TSA服务器,
Marshal.StringToHGlobalAnsi(“2.16.840.1.101.3.4.2.1”),//szOID\u NIST\u sha256常量,sha256哈希算法。
IntPtr.Zero,
IntPtr.Zero,
断章取义
);
如果(hResult!=0)
{
抛出新异常(string.Format(“添加时间戳时出错-错误代码:0x{0:X}”,hResult));
}
}
}
用法示例:

Timestamper.TimestampSignedAssembly("Assembly.exe", "http://timestamp.comodoca.com/?td=sha256");

+1.我认为您应该使用SIGNER\u TIMESTAMP\u RFC3161作为第一个标志。现在。。。我也不知道在哪里可以找到SIGNER\u TIMESTAMP\u rfc3116和SIGNER\u TIMESTAMP\u AUTHENTICODE值。。。在反汇编mssign32.dll时,我认为“1”意味着签名者\u时间戳\u身份验证码(因为SignerTimeStamp调用SignerTimeStampEx3,第一个参数值为1)。因此,您应该尝试使用0、2或3作为标志值。谢谢您的回答。我尝试将0、2和3作为标志值传递,并得到以下结果:0和3-发生0x80070057错误(一个或多个参数无效),2-crypt32.dll中的APPCRASH(错误代码-c0000005,访问Violat