Я использую библиотеку 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? Если нет, это ограничение накладывается спецификацией?