如何使用 aes-256-gcm 加密并将其放入 pkcs7 文件中?

问题描述 投票:0回答:1

为了遵循挪威银行业的新 Peppol 要求,我必须使用非对称加密。我需要发送的文件是pkcs#7文件并且密钥的加密需要是aes-256-gcm。

请注意,我正在 Windows 计算机上工作,并且希望能够在 C# 中执行此操作。

加密本身效果很好

仅使用 System.Security.Cryptography 我可以做到这一点:

X509Certificate2 cert = new X509Certificate2(certificateAsByteArray);

byte[] encryptedData = new byte[data.Length];
byte[] tag = new byte[16]; // GCM tag length is 16 bytes
byte[] nonce = new byte[12]; // GCM standard nonce length is 12 bytes
RandomNumberGenerator.Fill(nonce); // Generate a random nonce

byte[] symmetricKey = new byte[32]; // 256 bits for AES-256-GCM
RandomNumberGenerator.Fill(symmetricKey);
using (AesGcm aesGcm = new AesGcm(symmetricKey))
{
    aesGcm.Encrypt(nonce, indreAsice, encryptedData, tag);
}

但我不知道如何将其放入 pkcs#7 文件中。

MimeKit 制作 pkcs#7 文件

MimeKit 是一个可以帮助解决此问题的工具。

var pkcs7AsStream = new MemoryStream();
using (var memoryStream = new MemoryStream(indreAsice))
using (var ctx = new AesGcmContextContext())
{
    ctx.Import(cert);
    var recipients = new MimeKit.Cryptography.CmsRecipientCollection
    {
        new MimeKit.Cryptography.CmsRecipient(cert)
    };
    var mimePart = new MimePart(MimeKit.ContentType.Parse("application/pkcs7-mime"))
    {
        Content = new MimeContent(memoryStream)
    };

    var mime = ApplicationPkcs7Mime.Encrypt(ctx, recipients, mimePart);
    mime.WriteTo(pkcs7AsStream);
}
pkcs7AsStream.Seek(0, SeekOrigin.Begin);

上下文被我覆盖了:

public class AesGcmContextContext : TemporarySecureMimeContext
{
    protected override EncryptionAlgorithm GetPreferredEncryptionAlgorithm(MimeKit.Cryptography.CmsRecipientCollection recipients)
    {
        return EncryptionAlgorithm.Aes256;
        //return base.GetPreferredEncryptionAlgorithm(recipients);
    }
}

这给出了一个 pkcs#7 文件,其中使用的加密是 aes-256-cbc,而不是 aes-256-gcm。事实证明,你无法在 MimeKit 中选择 aes-256-gcm,并且

.Aes256
给出了 aes-256-cbc。

OpenSSL

生成 pkcs#7 的另一种方法是使用

cms
的 OpenSSL,如下所示:

codeopenssl cms -encrypt -in plaintext.txt -outform DER -out cms-enveloped-data.p7m -aes-256-gcm recipient-cert.pem

但这不起作用。不过,aes-256-cbc 的类似方法效果很好。

充气城堡

这也许是最好的机会,但我似乎无法让它发挥作用:

Org.BouncyCastle.Cms.CmsEnvelopedDataGenerator envData = new CmsEnvelopedDataGenerator();
envData.AddKeyTransRecipient(sertifikater.GetPublicCertificate());
var enveloped = envData.Generate(new CmsProcessableByteArray(data), "2.16.840.1.101.3.4.1.46");
var kryptencoded = enveloped.GetEncoded();

它接受

2.16.840.1.101.3.4.1.42
(aes-256-cbc),但不接受
2.16.840.1.101.3.4.1.46
(aes-256-gcm)。

我最近的尝试是使用

CryptoConfig.AddAlgorithm
添加算法,但没有成功。

最后一个问题:

似乎 aes-256-gcm 和 pkcs#7 互不喜欢。我听说这在 Java 世界中运行良好,但我们希望继续使用 .Net,因为我们所做的其他一切都是 .Net。我怎样才能让它发挥作用?

c# bouncycastle encryption-asymmetric pkcs#7 aes-gcm
1个回答
0
投票

同事的朋友终于找到了解决这个问题的方法。为他喝点啤酒吧!事实证明,在.Net世界里有两种不同的BouncyCastle,Portable.BouncyCastle和另一种(抱歉,不知道它有没有名字)。对于解密,常规 BouncyCastle 包可以工作,但对于加密,我们必须使用 Portable.BouncyCastle 并进行一些调整。

请注意,由于我们必须使用这两个包,因此我们必须使用别名来区分,因此当您阅读

Port.BouncyCastle
时,它意味着 Portable.BouncyCastle,但否则它是另一个。

首先

CmsEnvelopedDataGenerator
必须扩展并覆盖
GetAlgorithmIdentifier

public class SmarterCmsEnveloped : Port.Org.BouncyCastle.Cms.CmsEnvelopedDataGenerator
{

    protected override Port.Org.BouncyCastle.Asn1.X509.AlgorithmIdentifier GetAlgorithmIdentifier(string encryptionOid, Port.Org.BouncyCastle.Crypto.Parameters.KeyParameter encKey, Port.Org.BouncyCastle.Asn1.Asn1Encodable asn1Params,
        out Port.Org.BouncyCastle.Crypto.ICipherParameters cipherParameters)
    {
        if (encryptionOid == NistObjectIdentifiers.IdAes256Gcm.Id)
        {
            var random = new Port.Org.BouncyCastle.Security.SecureRandom();
            var nonce = Port.Org.BouncyCastle.Security.SecureRandom.GetNextBytes(random, 12);
            cipherParameters = new Port.Org.BouncyCastle.Crypto.Parameters.AeadParameters(encKey, 12 * 8, nonce);
            return new Port.Org.BouncyCastle.Asn1.X509.AlgorithmIdentifier(Port.Org.BouncyCastle.Asn1.Nist.NistObjectIdentifiers.IdAes256Gcm, new Port.Org.BouncyCastle.Asn1.DerSequence(new Port.Org.BouncyCastle.Asn1.DerOctetString(nonce)));
        }

        return base.GetAlgorithmIdentifier(encryptionOid, encKey, asn1Params, out cipherParameters);
    }
}

然后这将为我们提供带有使用 aes-256-gcm 加密的对称密钥的 plcs#7:

var cmsGenerator = new SmarterCmsEnveloped();
var parser = new Port.Org.BouncyCastle.X509.X509CertificateParser();
var certificate = parser.ReadCertificate(certificateAsByteArray);
var sha256 = new Port.Org.BouncyCastle.Asn1.X509.AlgorithmIdentifier(Port.Org.BouncyCastle.Asn1.Nist.NistObjectIdentifiers.IdSha256);
cmsGenerator.AddRecipientInfoGenerator(new Port.Org.BouncyCastle.Operators.CmsKeyTransRecipientInfoGenerator(
    certificate, 
    new Port.Org.BouncyCastle.Crypto.Operators.Asn1KeyWrapper(Port.Org.BouncyCastle.Asn1.Pkcs.PkcsObjectIdentifiers.IdRsaesOaep,
    new Port.Org.BouncyCastle.Asn1.Pkcs.RsaesOaepParameters(sha256,
    new Port.Org.BouncyCastle.Asn1.X509.AlgorithmIdentifier(Port.Org.BouncyCastle.Asn1.Pkcs.PkcsObjectIdentifiers.IdMgf1, sha256)) , certificate.GetPublicKey())));

var content = new Port.Org.BouncyCastle.Cms.CmsProcessableByteArray(dataToBeEncryptedWithAes256Gcm);
var generator = cmsGenerator.Generate(content, Port.Org.BouncyCastle.Asn1.Nist.NistObjectIdentifiers.IdAes256Gcm.Id);

我希望这对其他人有帮助,因为合作起来很令人沮丧!

© www.soinside.com 2019 - 2024. All rights reserved.