| File: Internal\Cryptography\Pal\AnyOS\ManagedPal.Encrypt.cs | Web Access |
| Project: src\runtime\src\libraries\System.Security.Cryptography.Pkcs\src\System.Security.Cryptography.Pkcs.csproj (System.Security.Cryptography.Pkcs) |
// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. using System; using System.Collections.Generic; using System.Formats.Asn1; using System.IO; using System.Security.Cryptography; using System.Security.Cryptography.Asn1; using System.Security.Cryptography.Asn1.Pkcs7; using System.Security.Cryptography.Pkcs; using System.Security.Cryptography.Pkcs.Asn1; using System.Security.Cryptography.X509Certificates; namespace Internal.Cryptography.Pal.AnyOS { internal sealed partial class ManagedPkcsPal : PkcsPal { public override unsafe byte[] Encrypt( CmsRecipientCollection recipients, ContentInfo contentInfo, AlgorithmIdentifier contentEncryptionAlgorithm, X509Certificate2Collection originatorCerts, CryptographicAttributeObjectCollection unprotectedAttributes) { byte[] encryptedContent = EncryptContent( contentInfo, contentEncryptionAlgorithm, out byte[] cek, out byte[] parameterBytes); // Pin the CEK to prevent it from getting copied during heap compaction. fixed (byte* pinnedCek = cek) { try { return Encrypt( recipients, contentInfo, contentEncryptionAlgorithm, originatorCerts, unprotectedAttributes, encryptedContent, cek, parameterBytes); } finally { Array.Clear(cek, 0, cek.Length); } } } private byte[] Encrypt( CmsRecipientCollection recipients, ContentInfo contentInfo, AlgorithmIdentifier contentEncryptionAlgorithm, X509Certificate2Collection originatorCerts, CryptographicAttributeObjectCollection unprotectedAttributes, byte[] encryptedContent, byte[] cek, byte[] parameterBytes) { EnvelopedDataAsn envelopedData = new EnvelopedDataAsn { EncryptedContentInfo = { ContentType = contentInfo.ContentType.Value!, ContentEncryptionAlgorithm = { Algorithm = contentEncryptionAlgorithm.Oid.Value!, Parameters = parameterBytes, }, EncryptedContent = encryptedContent, }, }; if (unprotectedAttributes != null && unprotectedAttributes.Count > 0) { List<AttributeAsn> attrList = PkcsHelpers.BuildAttributes(unprotectedAttributes); envelopedData.UnprotectedAttributes = PkcsHelpers.NormalizeAttributeSet(attrList.ToArray()); } if (originatorCerts != null && originatorCerts.Count > 0) { CertificateChoiceAsn[] certs = new CertificateChoiceAsn[originatorCerts.Count]; for (int i = 0; i < originatorCerts.Count; i++) { certs[i].Certificate = originatorCerts[i].RawData; } envelopedData.OriginatorInfo = new OriginatorInfoAsn { CertificateSet = certs, }; } envelopedData.RecipientInfos = new RecipientInfoAsn[recipients.Count]; bool allRecipientsVersion0 = true; for (var i = 0; i < recipients.Count; i++) { CmsRecipient recipient = recipients[i]; bool v0Recipient; envelopedData.RecipientInfos[i].Ktri = recipient.Certificate.GetKeyAlgorithm() switch { Oids.Rsa => MakeKtri(cek, recipient, out v0Recipient), _ => throw new CryptographicException( SR.Cryptography_Cms_UnknownAlgorithm, recipient.Certificate.GetKeyAlgorithm()), }; allRecipientsVersion0 = allRecipientsVersion0 && v0Recipient; } // https://tools.ietf.org/html/rfc5652#section-6.1 // // v4 (RFC 3852): // * OriginatorInfo contains certificates with type other (not supported) // * OriginatorInfo contains crls with type other (not supported) // v3 (RFC 3369): // * OriginatorInfo contains v2 attribute certificates (not supported) // * Any PWRI (password) recipients are present (not supported) // * Any ORI (other) recipients are present (not supported) // v2 (RFC 2630): // * OriginatorInfo is present // * Any RecipientInfo has a non-zero version number // * UnprotectedAttrs is present // v1 (not defined for EnvelopedData) // v0 (RFC 2315): // * Anything not already matched if (envelopedData.OriginatorInfo != null || !allRecipientsVersion0 || envelopedData.UnprotectedAttributes != null) { envelopedData.Version = 2; } AsnWriter writer = new AsnWriter(AsnEncodingRules.DER); envelopedData.Encode(writer); return PkcsHelpers.EncodeContentInfo(writer.Encode(), Oids.Pkcs7Enveloped); } private static byte[] EncryptContent( ContentInfo contentInfo, AlgorithmIdentifier contentEncryptionAlgorithm, out byte[] cek, out byte[] parameterBytes) { using (SymmetricAlgorithm alg = OpenAlgorithm(contentEncryptionAlgorithm)) { cek = alg.Key; if (alg is RC2) { Rc2CbcParameters rc2Params = new Rc2CbcParameters(alg.IV, alg.KeySize); AsnWriter writer = new AsnWriter(AsnEncodingRules.DER); rc2Params.Encode(writer); parameterBytes = writer.Encode(); } else { parameterBytes = PkcsHelpers.EncodeOctetString(alg.IV); } byte[] toEncrypt = contentInfo.Content; if (contentInfo.ContentType.Value == Oids.Pkcs7Data || contentInfo.Content.Length == 0) { return EncryptOneShot(alg, contentInfo.Content); } else { try { AsnDecoder.ReadEncodedValue( contentInfo.Content, AsnEncodingRules.BER, out int contentOffset, out int contentLength, out _); ReadOnlySpan<byte> content = contentInfo.Content.AsSpan(contentOffset, contentLength); return EncryptOneShot(alg, content); } catch (AsnContentException e) { throw new CryptographicException(SR.Cryptography_Der_Invalid_Encoding, e); } } } static byte[] EncryptOneShot(SymmetricAlgorithm alg, ReadOnlySpan<byte> plaintext) { #if NET return alg.EncryptCbc(plaintext, alg.IV); #else using (ICryptoTransform encryptor = alg.CreateEncryptor()) { return encryptor.OneShot(plaintext.ToArray()); } #endif } } } }