Bouncycastle以ascii /二进制格式写入cms MIME头

问题描述

我使用Bouncycastle C#生成cms签名的数据文件,而我的openSsl命令在下面

openssl cms -sign -in data.txt -binary -signer selfsigned.crt -inkey keypair.pem -out data.signed -keyopt rsa_padding_mode:pss 

输出文件格式openssl

MIME-Version: 1.0
Content-Type: multipart/signed; protocol="application/pkcs7-signature"; micalg="sha-256"; boundary="----DE5BACF44AD3EE95D349BA916BEEB444"

This is an S/MIME signed message

------DE5BACF44AD3EE95D349BA916BEEB444
Data HERE
------DE5BACF44AD3EE95D349BA916BEEB444
Content-Type: application/pkcs7-signature; name="smime.p7s"
Content-transfer-encoding: base64
Content-disposition: attachment; filename="smime.p7s"

SOME BASE 64 DATA
------DE5BACF44AD3EE95D349BA916BEEB444--

===============================================

BouncyCastle的输出不一样,即以ascii格式编写的标头

0€  *†H†÷
 €0€10
    `†He 0€ *†H†÷
 €$€‚

Data HERE

 €0€10
    `†He 0€ *†H†÷
 €$€‚ €0€10
    `†He 0€ *†H†÷
 €$€‚ €0€10
    `†He 0€ *†H†÷
 €$€‚ €0€10
    `†He 0€ *†H†÷
 €$€‚

如何获得与openssl相同的标题

cms符号的BouncyCastle代码

void Sign(byte[] data,byte[] signCert,byte[] privateKey){
            X509CertificateParser parser = new X509CertificateParser();
            X509Certificate certificate = parser.ReadCertificate(signCert);
            var reader = new StreamReader(new MemoryStream(privateKey),Encoding.Default);
            asymmetricCipherKeyPair keyPair = (asymmetricCipherKeyPair)new PemReader(reader).Readobject();
            CmsSignedDataGenerator generator = new CmsSignedDataGenerator();
            generator.AddSigner(keyPair.Private,certificate,CmsSignedGenerator.EncryptionRsaPss,CmsSignedGenerator.DigestSha256);
            List<X509Certificate> certList = new List<X509Certificate>();
            certList.Add(certificate);
            CmsSignedData signedData = generator.Generate(CmsSignedGenerator.Data,new 
            CmsProcessableByteArray(data),true);
            File.WriteallBytes(@"c:\data.txt.signed",signedData.GetEncoded());
    }

有什么想法吗?

解决方法

BouncyCastle不会产生这些标头。您需要自己动手做,或者使用MimeKit之类的库来帮您。

,

尝试了不同的库但没有运气之后,我想出了一种使用BouncyCastle实现此目的的方法,我只需要手动添加标头并修复代码即可实现

public byte[] Sign(byte[] data,byte[] signCert,byte[] privateKey)
        {
            
            X509CertificateParser parser = new X509CertificateParser();
            X509Certificate certificate = parser.ReadCertificate(signCert);
            var reader = new StreamReader(new MemoryStream(privateKey),Encoding.Default);
            AsymmetricCipherKeyPair keyPair = (AsymmetricCipherKeyPair)new PemReader(reader).ReadObject();

            CmsSignedDataGenerator generator = new CmsSignedDataGenerator();

            generator.AddSigner(keyPair.Private,certificate,CmsSignedGenerator.EncryptionRsaPss,CmsSignedGenerator.DigestSha256);

            List<X509Certificate> certList = new List<X509Certificate>
            {
                certificate
            };
            IX509Store iX509Store = X509StoreFactory.Create("Certificate/Collection",new X509CollectionStoreParameters(certList));
            generator.AddCertificates(iX509Store);

            CmsSignedData signedData = generator.Generate(CmsSignedGenerator.Data,new CmsProcessableByteArray(data),true);

            var signedBase64Encoded = Base64.Encode(signedData.GetEncoded());
            var signedString = Encoding.UTF8.GetString(signedBase64Encoded);
            signedString = "MIME-Version: 1.0\n"
                            + "Content-Disposition: attachment; filename=\"smime.p7m\"\n"
                            + "Content-Type: application/pkcs7-mime; smime-type=signed-data; name=\"smime.p7m\"\n"
                            + "Content-Transfer-Encoding: base64\n\n"
                            + Regex.Replace(signedString,"(.{" + 64 + "})","$1" + Environment.NewLine);

            return Encoding.UTF8.GetBytes(signedString);
        }