【问题标题】:Is there an alternative of SignedCMS in WinRT?WinRT 中是否有 SignedCMS 的替代方案?
【发布时间】:2014-03-26 10:43:29
【问题描述】:

在将 .NET 桌面应用程序移植到 Windows 应用商店应用程序时,我又遇到了麻烦...... 长话短说,我有一个 ZIP 文件,其中包含一个加密和签名的 XML 文件和一个证书。解密工作(或多或少)但现在我必须“取消签名”XML,我被卡住了。

在 .NET 应用程序中,取消签名是使用 System.Security.Cryptography.Pkcs.SignedCms 完成的,但 WinRt 中不存在该类(一如既往...)

WinRT 中是否有替代方案?

这是 .NET 应用程序中使用的一些代码:

public static byte[] CheckAndRemoveSignature(byte[] data,  X509Certificate2Collection certStore, out SignedCms out_signature)
    {
        SignedCms signedMessage = new SignedCms();
        signedMessage.Decode(data);

        if ((certStore != null) && (certStore.Count > 0))
            signedMessage.CheckSignature(certStore, true);
        else
            signedMessage.CheckSignature(true);

        out_signature = signedMessage;

        // return data without signature
        return signedMessage.ContentInfo.Content;
    }

我已经搜索了很多,但我发现的唯一对我有帮助的就是这篇文章。不幸的是,标记的答案没有提供任何有用的信息:(

Windows 8 Metro cryptography - using SignedCms Pkcs7

我真的很感激这里的一些帮助:)


编辑

本质问题是从有符号字节数组中取出原始xml数据。 或者,更具体地说,我需要 WinRT 中这几行代码的功能

SignedCms signedMessage = new SignedCms();
signedMessage.Decode(data);
byte[] result = signedMessage.ContentInfo.Content;

我尝试了 pepo 中的示例,但出现 MalformedContent 异常

private byte[] CheckAndRemoveSignature(byte[] data)
    {
        try
        {
            // load using bouncyCastle
            CmsSignedData sig = new CmsSignedData(data);
            // var allSigsValid = VerifySignatures(sig);
            byte[] content = sig.SignedContent.GetContent() as byte[];
            return content;
        }
        catch (Exception ex)
        {
            cryptOutput.Text += "Error removing Signature: " + ex;
            return data;
        }

我得到了这个例外:

Org.BouncyCastle.Cms.CmsException: Malformed content. ---> System.ArgumentException: unknown object in factory: DerApplicationSpecific
at Org.BouncyCastle.Asn1.Cms.ContentInfo.GetInstance(Object obj)
at Org.BouncyCastle.Cms.CmsUtilities.ReadContentInfo(Asn1InputStream aIn)
   --- End of inner exception stack trace ---
at Org.BouncyCastle.Cms.CmsUtilities.ReadContentInfo(Asn1InputStream aIn)
at Org.BouncyCastle.Cms.CmsUtilities.ReadContentInfo(Stream input)
at Org.BouncyCastle.Cms.CmsSignedData..ctor(Byte[] sigBlock)
at TestApp.MainPage.CheckAndRemoveSignature(Byte[] data)

来自已签署 XML 文件的桌面应用程序的代码:

  private byte[] signInternal(byte[] data, X509Certificate2 signatureCert, bool signatureOnly)
    {
        CAPICOM.SignedData signedData = new CAPICOM.SignedDataClass();
        CAPICOM.Utilities u = new CAPICOM.UtilitiesClass();
        signedData.set_Content(u.ByteArrayToBinaryString(data));
        GC.Collect();

        CAPICOM.Signer signer = new CAPICOM.Signer();
        signer.Options = CAPICOM.CAPICOM_CERTIFICATE_INCLUDE_OPTION.CAPICOM_CERTIFICATE_INCLUDE_END_ENTITY_ONLY;

        CAPICOM.CertificateClass certClass = new CAPICOM.CertificateClass();
        certClass.Import(Convert.ToBase64String(signatureCert.Export(X509ContentType.SerializedCert)));
        signer.Certificate = certClass;

        GC.Collect();

        if (this.validateCert(signatureCert))
            return (byte[])Convert.FromBase64String(signedData.Sign(signer, signatureOnly, CAPICOM.CAPICOM_ENCODING_TYPE.CAPICOM_ENCODE_BASE64));
        else
            return new byte[] { };
    }

解决方案

最后发现编码有一个大问题,我认为这不是值得注意的。 pepo 的答案是有效的,但是我将发布我的版本,以展示如果您从 zip 文件夹中获取文件,它是如何工作的:

// get bytes from zip
byte[] data = getFileContentAsByteArray(zipBytes, ze.FileName);
var dataString = Encoding.UTF8.GetString(data, 0, data.Length);

// check and remove signature
bool isValid;
byte[] withoutSig = CheckAndRemoveSignature(dataString, out isValid);


    private byte[] CheckAndRemoveSignature(string data, out bool isValid)
    {
        isValid = false;

        // using bouncyCastle
        try
        {
            var bytes = Convert.FromBase64String(data);

            // assign data to CmsSignedData                  
            CmsSignedData sig = new CmsSignedData(bytes);

            // check if signature is valid
            var allSigsValid = VerifySignaturesBC(sig);
            if (allSigsValid.Equals(true)) { isValid = true; }

            // get signature from cms
            byte[] content = sig.SignedContent.GetContent() as byte[];

            return content;
        }
        catch (Exception ex) { cryptOutput.Text += "Error in 'BouncyCastle unsign' " + ex; return null; }
    }

【问题讨论】:

  • 为什么需要 SignedCMS?你有 xmldsig 或 CMS (PKCS#7) 吗?
  • 正如我所说,我正在移植一个现有的应用程序,在那里,SignedCMS.ContentInfo.Content 用于从 ZIP 文件中获取 .xml - 我认为我在 WinRT 中也需要它,因为当我只解密,不行。
  • 那么你有两个选择。使用 c# 版本的 bouncycastle 或使用一些 ASN.1 库手动解析 xml。
  • 有没有办法用标准的 WinRT API 做到这一点?干得好微软...不过还是谢谢你的回复:)
  • 好吧,您可以使用 LINQ to XML 让解析 XML 变得异常简单。

标签: c# .net windows-runtime windows-store-apps asn.1


【解决方案1】:

根据 cmets,我了解到您有一个 PKCS#7 结构 (SignedCms),该结构的内容是 XmlDocument。

因为 WinRT API 中没有 SignedCms,所以您有两种选择。要么使用一些 ASN.1 库并手动解析 PKCS#7 以查找内容,要么使用已实现 SignedCms 并可以解析该结构的 BouncyCastle。 您询问了一个使用 bouncyCastle 的示例。在这里。

using Org.BouncyCastle.Cms;
using Org.BouncyCastle.X509.Store;
using System.Collections;
using System.Security.Cryptography.Pkcs;

namespace ConsoleApplication2
{
    class Program
    {
        static void Main(string[] args)
        {
            // make some pkcs7 signedCms to work on
            SignedCms p7 = new SignedCms(new System.Security.Cryptography.Pkcs.ContentInfo(new byte[] { 0x01, 0x02 }));
            p7.ComputeSignature(new CmsSigner(), false);

            // encode to get signedCms byte[] representation
            var signedCms = p7.Encode();

            // load using bouncyCastle
            CmsSignedData sig = new CmsSignedData(signedCms);

            var allSigsValid = VerifySignatures(sig);

            byte[] content = sig.SignedContent.GetContent() as byte[];
        }

        // taken from bouncy castle SignedDataTest.cs
        private static bool VerifySignatures(
            CmsSignedData sp)
        {
            var signaturesValid = true;
            IX509Store x509Certs = sp.GetCertificates("Collection");
            SignerInformationStore signers = sp.GetSignerInfos();

            foreach (SignerInformation signer in signers.GetSigners())
            {
                ICollection certCollection = x509Certs.GetMatches(signer.SignerID);

                IEnumerator certEnum = certCollection.GetEnumerator();
                certEnum.MoveNext();
                Org.BouncyCastle.X509.X509Certificate cert = (Org.BouncyCastle.X509.X509Certificate)certEnum.Current;

                signaturesValid &= signer.Verify(cert);
            }
            return signaturesValid;
        }
    }
}

至于 ASN.1 库,我只使用过具有 ASN.1 解析器的 bouncyCastle 或 ASN.1 editor,这是一个非常有用的 GUI 应用程序,用于显示 PKCS#7、证书等的结构。所以我只能推荐那两个。

【讨论】:

  • 感谢您的回答。不幸的是,当我想将我的字节数组加载到 CmsSignedData 中时,我总是遇到异常...Org.BouncyCastle.Cms.CmsException: Malformed content. ---> System.ArgumentException: unknown object in factory:
  • 你能发送这个签名的Cms吗?或者它有一些敏感数据吗?
  • 不幸的是它确实有敏感数据 :( 但我可以尝试在桌面应用程序中找到签署 xml 的代码部分
  • 好的,将此 SignedCms 转储到文件(二进制格式)并尝试使用 ASN.1 编辑器打开它。可以贴截图吗?如果这个 oid 1.2.840.113549.1.7.1 之前的所有内容都应该是安全的。这个oid表示数据,这个数据应该在下一行(我不需要数据,只需要上面的行)。
  • 当我在 ASN.1 编辑器中打开它时,它只显示一行:(0,73) Application (13) : '4D424133....' 当我将其转换为 Base64String 时,SignedCms 的内容如下所示:“MIMBA3AGC...”我猜 CAPICOM 对数据的签名有些特殊,所以其他 ASN.1 解码方法不起作用?会是这样吗?
【解决方案2】:

您可能正在寻找类似 Windows.Security.Cryptography.Certificates.CmsAttachedSignature.VerifySignature() 的东西,它是“内容”属性 见here

【讨论】:

  • 感谢您的回答,但我已经尝试过了,但我得到了一个例外:“ASN1 bad tag value met。” ... :(
猜你喜欢
  • 2012-09-02
  • 2017-04-16
  • 2017-03-21
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-01-29
  • 1970-01-01
相关资源
最近更新 更多