diff --git a/crypto/src/pkcs/EncryptedPrivateKeyInfoFactory.cs b/crypto/src/pkcs/EncryptedPrivateKeyInfoFactory.cs
index b6b7bac65..000eb7ae5 100644
--- a/crypto/src/pkcs/EncryptedPrivateKeyInfoFactory.cs
+++ b/crypto/src/pkcs/EncryptedPrivateKeyInfoFactory.cs
@@ -60,5 +60,43 @@ namespace Org.BouncyCastle.Pkcs
AlgorithmIdentifier algID = new AlgorithmIdentifier(oid, pbeParameters);
return new EncryptedPrivateKeyInfo(algID, encoding);
}
+
+ public static EncryptedPrivateKeyInfo CreateEncryptedPrivateKeyInfo(
+ DerObjectIdentifier cipherAlgorithm,
+ DerObjectIdentifier prfAlgorithm,
+ char[] passPhrase,
+ byte[] salt,
+ int iterationCount,
+ SecureRandom random,
+ AsymmetricKeyParameter key)
+ {
+ return CreateEncryptedPrivateKeyInfo(
+ cipherAlgorithm, prfAlgorithm, passPhrase, salt, iterationCount, random,
+ PrivateKeyInfoFactory.CreatePrivateKeyInfo(key));
+ }
+
+ public static EncryptedPrivateKeyInfo CreateEncryptedPrivateKeyInfo(
+ DerObjectIdentifier cipherAlgorithm,
+ DerObjectIdentifier prfAlgorithm,
+ char[] passPhrase,
+ byte[] salt,
+ int iterationCount,
+ SecureRandom random,
+ PrivateKeyInfo keyInfo)
+ {
+ IBufferedCipher cipher = CipherUtilities.GetCipher(cipherAlgorithm) as IBufferedCipher;
+ if (cipher == null)
+ throw new Exception("Unknown encryption algorithm: " + cipherAlgorithm);
+
+ Asn1Encodable pbeParameters = PbeUtilities.GenerateAlgorithmParameters(
+ cipherAlgorithm, prfAlgorithm, salt, iterationCount, random);
+ ICipherParameters cipherParameters = PbeUtilities.GenerateCipherParameters(
+ PkcsObjectIdentifiers.IdPbeS2, passPhrase, pbeParameters);
+ cipher.Init(true, cipherParameters);
+ byte[] encoding = cipher.DoFinal(keyInfo.GetEncoded());
+
+ AlgorithmIdentifier algID = new AlgorithmIdentifier(PkcsObjectIdentifiers.IdPbeS2, pbeParameters);
+ return new EncryptedPrivateKeyInfo(algID, encoding);
+ }
}
}
diff --git a/crypto/src/pkcs/PKCS12StoreBuilder.cs b/crypto/src/pkcs/PKCS12StoreBuilder.cs
index c8fa0f603..b61a9ea63 100644
--- a/crypto/src/pkcs/PKCS12StoreBuilder.cs
+++ b/crypto/src/pkcs/PKCS12StoreBuilder.cs
@@ -9,6 +9,8 @@ namespace Org.BouncyCastle.Pkcs
{
private DerObjectIdentifier keyAlgorithm = PkcsObjectIdentifiers.PbeWithShaAnd3KeyTripleDesCbc;
private DerObjectIdentifier certAlgorithm = PkcsObjectIdentifiers.PbewithShaAnd40BitRC2Cbc;
+ private DerObjectIdentifier keyPrfAlgorithm = null;
+ private DerObjectIdentifier certPrfAlgorithm = null;
private bool useDerEncoding = false;
public Pkcs12StoreBuilder()
@@ -17,7 +19,7 @@ namespace Org.BouncyCastle.Pkcs
public Pkcs12Store Build()
{
- return new Pkcs12Store(keyAlgorithm, certAlgorithm, useDerEncoding);
+ return new Pkcs12Store(keyAlgorithm, keyPrfAlgorithm, certAlgorithm, certPrfAlgorithm, useDerEncoding);
}
public Pkcs12StoreBuilder SetCertAlgorithm(DerObjectIdentifier certAlgorithm)
@@ -32,6 +34,13 @@ namespace Org.BouncyCastle.Pkcs
return this;
}
+ // Specify a PKCS#5 Scheme 2 encryption for keys
+ public Pkcs12StoreBuilder SetKeyAlgorithm(DerObjectIdentifier keyAlgorithm, DerObjectIdentifier keyPrfAlgorithm)
+ {
+ this.keyAlgorithm = keyAlgorithm;
+ this.keyPrfAlgorithm = keyPrfAlgorithm;
+ return this;
+ }
public Pkcs12StoreBuilder SetUseDerEncoding(bool useDerEncoding)
{
this.useDerEncoding = useDerEncoding;
diff --git a/crypto/src/pkcs/Pkcs12Store.cs b/crypto/src/pkcs/Pkcs12Store.cs
index 50db14d61..0eff8eb92 100644
--- a/crypto/src/pkcs/Pkcs12Store.cs
+++ b/crypto/src/pkcs/Pkcs12Store.cs
@@ -27,7 +27,9 @@ namespace Org.BouncyCastle.Pkcs
private readonly IDictionary chainCerts = Platform.CreateHashtable();
private readonly IDictionary keyCerts = Platform.CreateHashtable();
private readonly DerObjectIdentifier keyAlgorithm;
+ private readonly DerObjectIdentifier keyPrfAlgorithm;
private readonly DerObjectIdentifier certAlgorithm;
+ private readonly DerObjectIdentifier certPrfAlgorithm;
private readonly bool useDerEncoding;
private AsymmetricKeyEntry unmarkedKeyEntry = null;
@@ -89,12 +91,28 @@ namespace Org.BouncyCastle.Pkcs
bool useDerEncoding)
{
this.keyAlgorithm = keyAlgorithm;
+ this.keyPrfAlgorithm = null;
this.certAlgorithm = certAlgorithm;
+ this.certPrfAlgorithm = null;
+ this.useDerEncoding = useDerEncoding;
+ }
+
+ internal Pkcs12Store(
+ DerObjectIdentifier keyAlgorithm,
+ DerObjectIdentifier keyPrfAlgorithm,
+ DerObjectIdentifier certAlgorithm,
+ DerObjectIdentifier certPrfAlgorithm,
+ bool useDerEncoding)
+ {
+ this.keyAlgorithm = keyAlgorithm;
+ this.keyPrfAlgorithm = keyPrfAlgorithm;
+ this.certAlgorithm = certAlgorithm;
+ this.certPrfAlgorithm = certPrfAlgorithm;
this.useDerEncoding = useDerEncoding;
}
// TODO Consider making obsolete
-// [Obsolete("Use 'Pkcs12StoreBuilder' instead")]
+ // [Obsolete("Use 'Pkcs12StoreBuilder' instead")]
public Pkcs12Store()
: this(PkcsObjectIdentifiers.PbeWithShaAnd3KeyTripleDesCbc,
PkcsObjectIdentifiers.PbewithShaAnd40BitRC2Cbc, false)
@@ -748,8 +766,16 @@ namespace Org.BouncyCastle.Pkcs
else
{
bagOid = PkcsObjectIdentifiers.Pkcs8ShroudedKeyBag;
- bagData = EncryptedPrivateKeyInfoFactory.CreateEncryptedPrivateKeyInfo(
- keyAlgorithm, password, kSalt, MinIterations, privKey.Key);
+ if (keyPrfAlgorithm != null)
+ {
+ bagData = EncryptedPrivateKeyInfoFactory.CreateEncryptedPrivateKeyInfo(
+ keyAlgorithm, keyPrfAlgorithm, password, kSalt, MinIterations, random, privKey.Key);
+ }
+ else
+ {
+ bagData = EncryptedPrivateKeyInfoFactory.CreateEncryptedPrivateKeyInfo(
+ keyAlgorithm, password, kSalt, MinIterations, privKey.Key);
+ }
}
Asn1EncodableVector kName = new Asn1EncodableVector();
@@ -952,7 +978,7 @@ namespace Org.BouncyCastle.Pkcs
byte[] certBagsEncoding = new DerSequence(certBags).GetDerEncoded();
ContentInfo certsInfo;
- if (password == null)
+ if (password == null || certAlgorithm == null)
{
certsInfo = new ContentInfo(PkcsObjectIdentifiers.Data, new BerOctetString(certBagsEncoding));
}
diff --git a/crypto/src/security/PbeUtilities.cs b/crypto/src/security/PbeUtilities.cs
index ce47e38e5..622c6dd43 100644
--- a/crypto/src/security/PbeUtilities.cs
+++ b/crypto/src/security/PbeUtilities.cs
@@ -42,6 +42,7 @@ namespace Org.BouncyCastle.Security
{
algorithms["PKCS5SCHEME1"] = "Pkcs5scheme1";
algorithms["PKCS5SCHEME2"] = "Pkcs5scheme2";
+ algorithms["PBKDF2"] = "Pkcs5scheme2";
algorithms[PkcsObjectIdentifiers.IdPbeS2.Id] = "Pkcs5scheme2";
// algorithms[PkcsObjectIdentifiers.IdPbkdf2.Id] = "Pkcs5scheme2";
@@ -324,6 +325,35 @@ namespace Org.BouncyCastle.Security
}
}
+ public static Asn1Encodable GenerateAlgorithmParameters(
+ DerObjectIdentifier cipherAlgorithm,
+ DerObjectIdentifier hashAlgorithm,
+ byte[] salt,
+ int iterationCount,
+ SecureRandom secureRandom)
+ {
+ EncryptionScheme encScheme;
+ if (NistObjectIdentifiers.IdAes128Cbc.Equals(cipherAlgorithm)
+ || NistObjectIdentifiers.IdAes192Cbc.Equals(cipherAlgorithm)
+ || NistObjectIdentifiers.IdAes256Cbc.Equals(cipherAlgorithm)
+ || NistObjectIdentifiers.IdAes128Cfb.Equals(cipherAlgorithm)
+ || NistObjectIdentifiers.IdAes192Cfb.Equals(cipherAlgorithm)
+ || NistObjectIdentifiers.IdAes256Cfb.Equals(cipherAlgorithm))
+ {
+ byte[] iv = new byte[16];
+ secureRandom.NextBytes(iv);
+ encScheme = new EncryptionScheme(cipherAlgorithm, new DerOctetString(iv));
+ }
+ else
+ {
+ throw new ArgumentException("unknown cipher: " + cipherAlgorithm);
+ }
+
+ KeyDerivationFunc func = new KeyDerivationFunc(PkcsObjectIdentifiers.IdPbkdf2, new Pbkdf2Params(salt, iterationCount, new AlgorithmIdentifier(hashAlgorithm, DerNull.Instance)));
+
+ return new PbeS2Parameters(func, encScheme);
+ }
+
public static ICipherParameters GenerateCipherParameters(
DerObjectIdentifier algorithmOid,
char[] password,
|