Есть ли способ создать FIPS-совместимый MA C для файла PKCS12? - PullRequest
0 голосов
/ 19 марта 2020

Я использую библиотеку Bouncy Castle FIPS для. NET, чтобы сгенерировать файл PKCS12, соответствующий FIPS. В файле нет проблем с сертификатами и закрытыми ключами, однако реализация генератора MA C по умолчанию выдает следующее исключение в утвержденном режиме:

'PKCS12 PBE unavailable in approved mode: OpenSSL'

Считается, что алгоритм PBE PKCS # 12 по умолчанию: быть несовместимым с FIPS, и вместо этого следует использовать PBKDF2. ( руководство пользователя, раздел 9 ). Однако, когда я заменяю реализацию по умолчанию на PBKDF2, файл становится нечитаемым, и OpenSSL и Windows не могут проверить пароль с таким MA C. Я проверил спецификацию для PKCS # 12 и нашел следующую информацию относительно MA C:

Обратите внимание, что этот метод [PKCS # 12 KDF] для режима конфиденциальности пароля не является рекомендуется и не рекомендуется для нового использования. Вместо этого следует использовать процедуры и алгоритмы, определенные в PKCS # 5 v2.1 [13] [22]. В частности, PBES2 следует использовать в качестве схемы шифрования, а PBKDF2 - в качестве функции получения ключа.

Представленный здесь метод все еще используется для генерации ключа в режиме
целостности пароля.

Значит ли это, что я не могу использовать PBKDF2 для MA C? И делает ли он формат файла PKCS12 по существу не совместимым с FIPS в отношении MA C?

Вот пример кода, который я использую для создания файла PKCS12 (нужен b c -fips- 1.0.1.dll и bcpkix-fips-1.0.1.dll для его компиляции):

using Org.BouncyCastle.Asn1;
using Org.BouncyCastle.Asn1.Nist;
using Org.BouncyCastle.Asn1.Oiw;
using Org.BouncyCastle.Asn1.X509;
using Org.BouncyCastle.Cert;
using Org.BouncyCastle.Crypto;
using Org.BouncyCastle.Crypto.Asymmetric;
using Org.BouncyCastle.Crypto.Fips;
using Org.BouncyCastle.Math;
using Org.BouncyCastle.OpenSsl;
using Org.BouncyCastle.Operators;
using Org.BouncyCastle.Operators.Parameters;
using Org.BouncyCastle.Pkcs;
using Org.BouncyCastle.Security;
using System.IO;
using System.Text;

namespace TestBcFipsPfx
{
    class Program
    {
        static void Main(string[] args)
        {
            CryptoServicesRegistrar.SetApprovedOnlyMode(true);
            var cert = GetCert();
            ExportToPkcs12(cert, "12345678901234");
        }

        private static void ExportToPkcs12(KeyPair keyPair, string password)
        {
            using (var stream = File.Create(@"d:\share\output.pfx"))
            {
                var pbeEncryptor = GetPbeEncryptor(password);
                var pfxPduBuilder = new Pkcs12PfxPduBuilder();

                var certBagBuilder = new Pkcs12SafeBagBuilder(keyPair.Certificate);
                var certBag = certBagBuilder.Build();
                pfxPduBuilder.AddEncryptedData(pbeEncryptor, certBag);

                var keyBagBuilder = new Pkcs12SafeBagBuilder(keyPair.Key, pbeEncryptor);
                var keyBag = keyBagBuilder.Build();
                pfxPduBuilder.AddData(keyBag);

                var macFactory = GetMacFactory(password);
                var pfxPdu = pfxPduBuilder.Build(macFactory);
                var pfxBytes = pfxPdu.GetEncoded();
                stream.Write(pfxBytes, 0, pfxBytes.Length);
                stream.Flush();
            }
        }

        private static IMacFactory<Pkcs12MacAlgDescriptor> GetMacFactory(string password)
        {
            // Throws 'PKCS12 PBE unavailable in approved mode: OpenSSL'
            /*var macFactoryBuilder = new Pkcs12MacFactoryBuilder();
            var macFactory = macFactoryBuilder.Build(password.ToCharArray());
            return macFactory;*/

            var macFactory = new MacFactory(password);
            return macFactory;
        }

        private static ICipherBuilder<AlgorithmIdentifier> GetPbeEncryptor(string password)
        {
            var encryptorOid = NistObjectIdentifiers.IdAes256Cbc;
            var encryptorBuilder = new PkixPbeEncryptorBuilder(PasswordConverter.UTF8, FipsShs.Sha1HMac, encryptorOid).WithSalt(GetSalt()).WithSecureRandom(new SecureRandom()).WithIterationCount(1024);
            var encryptor = encryptorBuilder.Build(password.ToCharArray());
            return encryptor;
        }

        private static byte[] GetSalt()
        {
            var random = new SecureRandom();
            return BigInteger.ProbablePrime(256, random).ToByteArrayUnsigned();
        }

        private static KeyPair GetCert()
        {
            var pem = GetCertPem();
            var bytes = Encoding.UTF8.GetBytes(pem);
            using (var memoryStream = new MemoryStream(bytes))
            using (var streamReader = new StreamReader(memoryStream))
            {
                var reader = new OpenSslPemReader(streamReader);
                var cert = (X509Certificate)reader.ReadObject();
                var pkcs8Key = (Pkcs8EncryptedPrivateKeyInfo)reader.ReadObject();
                var decryptor = new PkixPbeDecryptorProviderBuilder();
                var decryptorBuilderProvider = decryptor.Build("12345678901234".ToCharArray());
                var privateKeyInfo = pkcs8Key.DecryptPrivateKeyInfo(decryptorBuilderProvider);
                var privateKey = new AsymmetricECPrivateKey(FipsEC.Alg, privateKeyInfo);
                return new KeyPair { Certificate = cert, Key = privateKey };
            }
        }

        private static string GetCertPem()
        {
            return "-----BEGIN CERTIFICATE-----\r\n" +
            "MIIBozCCAUigAwIBAgIIOjJUbuwe8V8wCgYIKoZIzj0EAwIwFDESMBAGA1UEAxMJ\r\n" +
            "bG9jYWxob3N0MB4XDTIwMDMxNjIyMDAwMFoXDTI1MDMxNTIyMDAwMFowFDESMBAG\r\n" +
            "A1UEAxMJbG9jYWxob3N0MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE/3Td+X+z\r\n" +
            "zApKJ/azi9iKVgJAzGrh/9uRUmFrb2/YE/hUbpkLHI8JTPxIH1eLk9ehcCxJDMns\r\n" +
            "RroUdjDJWEqbR6OBgzCBgDAMBgNVHRMBAf8EAjAAMB0GA1UdDgQWBBSsB9zKqbOV\r\n" +
            "ugSus1XboNzwdi5v1jALBgNVHQ8EBAMCBPAwLAYDVR0RBCUwI4IJbG9jYWxob3N0\r\n" +
            "gglsb2NhbGhvc3SCCyoubG9jYWxob3N0MBYGA1UdJQEB/wQMMAoGCCsGAQUFBwMB\r\n" +
            "MAoGCCqGSM49BAMCA0kAMEYCIQC2+KJ3u28aWG47HtKXgsNxCF70d3oYmjgkKnte\r\n" +
            "1EP2HwIhALG3fl8CuKMduXRMsCD85pSMzyUQ7FzjmNeDuiRB4PgG\r\n" +
            "-----END CERTIFICATE-----\r\n" +
            "-----BEGIN ENCRYPTED PRIVATE KEY-----\r\n" +
            "MIH1MFgGCSqGSIb3DQEFDTBLMDMGCSqGSIb3DQEFDDAmBCDHmBMqSCzTktWUrO83\r\n" +
            "wbDXbX0+YMgNhMguI3c39htGZQICBAAwFAYIKoZIhvcNAwcECGoAUh9quwsdBIGY\r\n" +
            "UfDlUaU82L/Xer41tCSchK3WewKFjSFEpm+Es4QRy9iZjhlncoQdslmWEUUhgWxe\r\n" +
            "PqUD/4QxZa5afQhCd95rRSrjvdUtSSRr+5NDpRAjEPFcgrQiGD2m6CX3hsrejBf8\r\n" +
            "1TuVY2cj/1vFtqktblF21l44g84jgNDxB/hOPq8l0+vkUCJmd4Ij1oxbpyiuUtR5\r\n" +
            "JZ3rgyuYdq0=\r\n" +
            "-----END ENCRYPTED PRIVATE KEY-----\r\n";
        }
    }

    public class KeyPair
    {
        public X509Certificate Certificate { get; set; }
        public IAsymmetricPrivateKey Key { get; set; }
    }

    public class MacFactory : IMacFactory<Pkcs12MacAlgDescriptor>
    {
        private IMacFactory<FipsShs.AuthenticationParameters> baseFactory;
        private Pkcs12MacAlgDescriptor algorithmDetails;

        public MacFactory(string password)
        {
            algorithmDetails = new Pkcs12MacAlgDescriptor(new AlgorithmIdentifier(OiwObjectIdentifiers.IdSha1, DerNull.Instance), GetSalt(), 1024);
            var pbeDeriverBuilder = CryptoServicesRegistrar.CreateService(FipsPbkd.PbkdF2).From(PasswordConverter.UTF8, password.ToCharArray());
            var pbeDeriver = pbeDeriverBuilder.WithPrf(FipsShs.Sha1).WithSalt(algorithmDetails.GetIV()).WithIterationCount(algorithmDetails.IterationCount).Build();
            baseFactory = CryptoServicesRegistrar.CreateService(new FipsShs.Key(FipsShs.Sha1HMac, pbeDeriver.DeriveKey(TargetKeyType.MAC, 20))).CreateMacFactory(FipsShs.Sha1HMac);
        }

        public Pkcs12MacAlgDescriptor AlgorithmDetails
        {
            get { return algorithmDetails; }
        }

        public int MacLength
        {
            get { return baseFactory.MacLength; }
        }

        public IStreamCalculator<IBlockResult> CreateCalculator()
        {
            return baseFactory.CreateCalculator();
        }

        private byte[] GetSalt()
        {
            var random = new SecureRandom();
            return BigInteger.ProbablePrime(256, random).ToByteArrayUnsigned();
        }
    }
}

Итак, можно ли использовать PBKDF2 для получения ключа при генерации MA C для файла PKCS12 ? Если да, нужно ли мне изменить способ кодирования этой информации в MacData? Если нет, это ограничение накладывается спецификацией?

...