summary refs log tree commit diff
diff options
context:
space:
mode:
authorDavid Hook <dgh@bouncycastle.org>2021-05-24 13:06:31 +1000
committerDavid Hook <dgh@bouncycastle.org>2021-05-24 13:06:31 +1000
commit01238566c1d4b2a606e4859a75ad05ca79db4ffb (patch)
treeee7d1057d41cd25c3f0383b5d1ca2e213a976feb
parentgithub#54 test for mixed mode definition (diff)
downloadBouncyCastle.NET-ed25519-01238566c1d4b2a606e4859a75ad05ca79db4ffb.tar.xz
github #222 addressed OAEP parameter setting, refactored KeyTransRecipientInfoGenerator to allow deprecation of sub class
-rw-r--r--crypto/src/asn1/pkcs/RSAESOAEPparams.cs11
-rw-r--r--crypto/src/cms/CMSEnvelopedGenerator.cs15
-rw-r--r--crypto/src/cms/KeyTransRecipientInfoGenerator.cs65
-rw-r--r--crypto/src/cms/KeyTransRecipientInformation.cs27
-rw-r--r--crypto/src/crypto/encodings/OaepEncoding.cs30
-rw-r--r--crypto/src/crypto/operators/Asn1KeyWrapper.cs203
-rw-r--r--crypto/src/crypto/operators/CmsKeyTransRecipientInfoGenerator.cs21
-rw-r--r--crypto/src/crypto/signers/PssSigner.cs24
-rw-r--r--crypto/src/security/WrapperUtilities.cs1
-rw-r--r--crypto/test/src/cms/test/EnvelopedDataTest.cs135
-rw-r--r--crypto/test/src/crmf/test/CrmfTest.cs2
11 files changed, 434 insertions, 100 deletions
diff --git a/crypto/src/asn1/pkcs/RSAESOAEPparams.cs b/crypto/src/asn1/pkcs/RSAESOAEPparams.cs
index 0cf22f860..6434f0935 100644
--- a/crypto/src/asn1/pkcs/RSAESOAEPparams.cs
+++ b/crypto/src/asn1/pkcs/RSAESOAEPparams.cs
@@ -36,10 +36,15 @@ namespace Org.BouncyCastle.Asn1.Pkcs
 		 * The default version
 		 */
 		public RsaesOaepParameters()
+		: this(DefaultHashAlgorithm, DefaultMaskGenFunction, DefaultPSourceAlgorithm)
+		{ 
+		}
+
+		public RsaesOaepParameters(
+			AlgorithmIdentifier hashAlgorithm,
+			AlgorithmIdentifier maskGenAlgorithm)
+		: this(DefaultHashAlgorithm, DefaultMaskGenFunction, DefaultPSourceAlgorithm)
 		{
-			hashAlgorithm = DefaultHashAlgorithm;
-			maskGenAlgorithm = DefaultMaskGenFunction;
-			pSourceAlgorithm = DefaultPSourceAlgorithm;
 		}
 
 		public RsaesOaepParameters(
diff --git a/crypto/src/cms/CMSEnvelopedGenerator.cs b/crypto/src/cms/CMSEnvelopedGenerator.cs
index ed7e1edee..d7d3e4bbf 100644
--- a/crypto/src/cms/CMSEnvelopedGenerator.cs
+++ b/crypto/src/cms/CMSEnvelopedGenerator.cs
@@ -10,6 +10,7 @@ using Org.BouncyCastle.Asn1.Pkcs;
 using Org.BouncyCastle.Asn1.X509;
 using Org.BouncyCastle.Asn1.X9;
 using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Crypto.Operators;
 using Org.BouncyCastle.Crypto.Parameters;
 using Org.BouncyCastle.Security;
 using Org.BouncyCastle.Utilities;
@@ -132,10 +133,9 @@ namespace Org.BouncyCastle.Cms
 		public void AddKeyTransRecipient(
 			X509Certificate cert)
 		{
-			KeyTransRecipientInfoGenerator ktrig = new KeyTransRecipientInfoGenerator();
-			ktrig.RecipientCert = cert;
-
-			recipientInfoGenerators.Add(ktrig);
+			TbsCertificateStructure recipientTbsCert = CmsUtilities.GetTbsCertificateStructure(cert);
+			SubjectPublicKeyInfo info = recipientTbsCert.SubjectPublicKeyInfo;
+			this.AddRecipientInfoGenerator(new KeyTransRecipientInfoGenerator(cert, new Asn1KeyWrapper(info.AlgorithmID.Algorithm, info.AlgorithmID.Parameters, cert)));
 		}
 
 		/**
@@ -149,11 +149,8 @@ namespace Org.BouncyCastle.Cms
 			AsymmetricKeyParameter	pubKey,
 			byte[]					subKeyId)
 		{
-			KeyTransRecipientInfoGenerator ktrig = new KeyTransRecipientInfoGenerator();
-			ktrig.RecipientPublicKey = pubKey;
-			ktrig.SubjectKeyIdentifier = new DerOctetString(subKeyId);
-
-			recipientInfoGenerators.Add(ktrig);
+			SubjectPublicKeyInfo info = SubjectPublicKeyInfoFactory.CreateSubjectPublicKeyInfo(pubKey);
+			this.AddRecipientInfoGenerator(new KeyTransRecipientInfoGenerator(subKeyId, new Asn1KeyWrapper(info.AlgorithmID.Algorithm, info.AlgorithmID.Parameters, pubKey)));
 		}
 
 		/**
diff --git a/crypto/src/cms/KeyTransRecipientInfoGenerator.cs b/crypto/src/cms/KeyTransRecipientInfoGenerator.cs
index 23b06d3b3..60020be1f 100644
--- a/crypto/src/cms/KeyTransRecipientInfoGenerator.cs
+++ b/crypto/src/cms/KeyTransRecipientInfoGenerator.cs
@@ -15,60 +15,30 @@ namespace Org.BouncyCastle.Cms
     {
         private static readonly CmsEnvelopedHelper Helper = CmsEnvelopedHelper.Instance;
 
-        private TbsCertificateStructure recipientTbsCert;
-        private AsymmetricKeyParameter recipientPublicKey;
         private Asn1OctetString subjectKeyIdentifier;
+        private IKeyWrapper keyWrapper;
 
         // Derived fields
         private SubjectPublicKeyInfo info;
         private IssuerAndSerialNumber issuerAndSerialNumber;
         private SecureRandom random;
+       
 
-        internal KeyTransRecipientInfoGenerator()
+        public KeyTransRecipientInfoGenerator(X509Certificate recipCert, IKeyWrapper keyWrapper)
+            : this(new Asn1.Cms.IssuerAndSerialNumber(recipCert.IssuerDN, new DerInteger(recipCert.SerialNumber)), keyWrapper)
         {
         }
 
-        protected KeyTransRecipientInfoGenerator(IssuerAndSerialNumber issuerAndSerialNumber)
+        public KeyTransRecipientInfoGenerator(IssuerAndSerialNumber issuerAndSerial, IKeyWrapper keyWrapper)
         {
-            this.issuerAndSerialNumber = issuerAndSerialNumber;
+            this.issuerAndSerialNumber = issuerAndSerial;
+            this.keyWrapper = keyWrapper;
         }
 
-        protected KeyTransRecipientInfoGenerator(byte[] subjectKeyIdentifier)
+        public KeyTransRecipientInfoGenerator(byte[] subjectKeyID, IKeyWrapper keyWrapper)
         {
             this.subjectKeyIdentifier = new DerOctetString(subjectKeyIdentifier);
-        }
-
-        internal X509Certificate RecipientCert
-        {
-            set
-            {
-                this.recipientTbsCert = CmsUtilities.GetTbsCertificateStructure(value);
-                this.recipientPublicKey = value.GetPublicKey();
-                this.info = recipientTbsCert.SubjectPublicKeyInfo;
-            }
-        }
-
-        internal AsymmetricKeyParameter RecipientPublicKey
-        {
-            set
-            {
-                this.recipientPublicKey = value;
-
-                try
-                {
-                    info = SubjectPublicKeyInfoFactory.CreateSubjectPublicKeyInfo(
-                        recipientPublicKey);
-                }
-                catch (IOException)
-                {
-                    throw new ArgumentException("can't extract key algorithm from this key");
-                }
-            }
-        }
-
-        internal Asn1OctetString SubjectKeyIdentifier
-        {
-            set { this.subjectKeyIdentifier = value; }
+            this.keyWrapper = keyWrapper;
         }
 
         public RecipientInfo Generate(KeyParameter contentEncryptionKey, SecureRandom random)
@@ -80,11 +50,9 @@ namespace Org.BouncyCastle.Cms
             byte[] encryptedKeyBytes = GenerateWrappedKey(contentEncryptionKey);
 
             RecipientIdentifier recipId;
-            if (recipientTbsCert != null)
+            if (issuerAndSerialNumber != null)
             {
-                IssuerAndSerialNumber issuerAndSerial = new IssuerAndSerialNumber(
-                    recipientTbsCert.Issuer, recipientTbsCert.SerialNumber.Value);
-                recipId = new RecipientIdentifier(issuerAndSerial);
+                recipId = new RecipientIdentifier(issuerAndSerialNumber);
             }
             else
             {
@@ -99,18 +67,17 @@ namespace Org.BouncyCastle.Cms
         {
             get
             {
+                if (this.keyWrapper != null)
+                {
+                    return (AlgorithmIdentifier)keyWrapper.AlgorithmDetails;
+                }
                 return info.AlgorithmID;
             }
         }
 
         protected virtual byte[] GenerateWrappedKey(KeyParameter contentEncryptionKey)
         {
-            byte[] keyBytes = contentEncryptionKey.GetKey();
-            AlgorithmIdentifier keyEncryptionAlgorithm = info.AlgorithmID;
-
-            IWrapper keyWrapper = Helper.CreateWrapper(keyEncryptionAlgorithm.Algorithm.Id);
-            keyWrapper.Init(true, new ParametersWithRandom(recipientPublicKey, random));
-            return keyWrapper.Wrap(keyBytes, 0, keyBytes.Length);
+            return keyWrapper.Wrap(contentEncryptionKey.GetKey()).Collect();
         }
     }
 }
diff --git a/crypto/src/cms/KeyTransRecipientInformation.cs b/crypto/src/cms/KeyTransRecipientInformation.cs
index 7d2f072b5..2a40fed06 100644
--- a/crypto/src/cms/KeyTransRecipientInformation.cs
+++ b/crypto/src/cms/KeyTransRecipientInformation.cs
@@ -9,6 +9,8 @@ using Org.BouncyCastle.Crypto;
 using Org.BouncyCastle.Crypto.Parameters;
 using Org.BouncyCastle.Security;
 using Org.BouncyCastle.X509;
+using Org.BouncyCastle.Asn1.Pkcs;
+using Org.BouncyCastle.Crypto.Operators;
 
 namespace Org.BouncyCastle.Cms
 {
@@ -42,7 +44,7 @@ namespace Org.BouncyCastle.Cms
                 }
                 else
                 {
-                    IssuerAndSerialNumber iAnds = IssuerAndSerialNumber.GetInstance(r.ID);
+                    Asn1.Cms.IssuerAndSerialNumber iAnds = Asn1.Cms.IssuerAndSerialNumber.GetInstance(r.ID);
 
 					rid.Issuer = iAnds.Name;
                     rid.SerialNumber = iAnds.SerialNumber.Value;
@@ -74,16 +76,27 @@ namespace Org.BouncyCastle.Cms
 		internal KeyParameter UnwrapKey(ICipherParameters key)
 		{
 			byte[] encryptedKey = info.EncryptedKey.GetOctets();
-            string keyExchangeAlgorithm = GetExchangeEncryptionAlgorithmName(keyEncAlg);
+            
 
 			try
 			{
-				IWrapper keyWrapper = WrapperUtilities.GetWrapper(keyExchangeAlgorithm);
-				keyWrapper.Init(false, key);
+				if (keyEncAlg.Algorithm.Equals(PkcsObjectIdentifiers.IdRsaesOaep))
+				{
+					IKeyUnwrapper keyWrapper = new Asn1KeyUnwrapper(keyEncAlg.Algorithm, keyEncAlg.Parameters, key);
 
-				// FIXME Support for MAC algorithm parameters similar to cipher parameters
-				return ParameterUtilities.CreateKeyParameter(
-					GetContentAlgorithmName(), keyWrapper.Unwrap(encryptedKey, 0, encryptedKey.Length));
+					return ParameterUtilities.CreateKeyParameter(
+							GetContentAlgorithmName(), keyWrapper.Unwrap(encryptedKey, 0, encryptedKey.Length).Collect());
+				}
+				else
+				{
+					string keyExchangeAlgorithm = GetExchangeEncryptionAlgorithmName(keyEncAlg);
+					IWrapper keyWrapper = WrapperUtilities.GetWrapper(keyExchangeAlgorithm);
+					keyWrapper.Init(false, key);
+
+					// FIXME Support for MAC algorithm parameters similar to cipher parameters
+					return ParameterUtilities.CreateKeyParameter(
+						GetContentAlgorithmName(), keyWrapper.Unwrap(encryptedKey, 0, encryptedKey.Length));
+				}
 			}
 			catch (SecurityUtilityException e)
 			{
diff --git a/crypto/src/crypto/encodings/OaepEncoding.cs b/crypto/src/crypto/encodings/OaepEncoding.cs
index 690be116d..b01af6eed 100644
--- a/crypto/src/crypto/encodings/OaepEncoding.cs
+++ b/crypto/src/crypto/encodings/OaepEncoding.cs
@@ -169,7 +169,7 @@ namespace Org.BouncyCastle.Crypto.Encodings
             //
             // mask the message block.
             //
-            byte[] mask = maskGeneratorFunction1(seed, 0, seed.Length, block.Length - defHash.Length);
+            byte[] mask = MaskGeneratorFunction(seed, 0, seed.Length, block.Length - defHash.Length);
 
             for (int i = defHash.Length; i != block.Length; i++)
             {
@@ -184,7 +184,7 @@ namespace Org.BouncyCastle.Crypto.Encodings
             //
             // mask the seed.
             //
-            mask = maskGeneratorFunction1(
+            mask = MaskGeneratorFunction(
                 block, defHash.Length, block.Length - defHash.Length, defHash.Length);
 
             for (int i = 0; i != defHash.Length; i++)
@@ -227,7 +227,7 @@ namespace Org.BouncyCastle.Crypto.Encodings
             //
             // unmask the seed.
             //
-            byte[] mask = maskGeneratorFunction1(
+            byte[] mask = MaskGeneratorFunction(
                 block, defHash.Length, block.Length - defHash.Length, defHash.Length);
 
             for (int i = 0; i != defHash.Length; i++)
@@ -238,7 +238,7 @@ namespace Org.BouncyCastle.Crypto.Encodings
             //
             // unmask the message block.
             //
-            mask = maskGeneratorFunction1(block, 0, defHash.Length, block.Length - defHash.Length);
+            mask = MaskGeneratorFunction(block, 0, defHash.Length, block.Length - defHash.Length);
 
             for (int i = defHash.Length; i != block.Length; i++)
             {
@@ -306,10 +306,30 @@ namespace Org.BouncyCastle.Crypto.Encodings
             sp[3] = (byte)((uint)i >> 0);
         }
 
+        private byte[] MaskGeneratorFunction(
+            byte[] Z,
+            int zOff,
+            int zLen,
+            int length)
+        {
+            if (mgf1Hash is IXof)
+            {
+                byte[] mask = new byte[length];
+                mgf1Hash.BlockUpdate(Z, zOff, zLen);
+                ((IXof)mgf1Hash).DoFinal(mask, 0, mask.Length);
+
+                return mask;
+            }
+            else
+            {
+                return MaskGeneratorFunction1(Z, zOff, zLen, length);
+            }
+        }
+
         /**
         * mask generator function, as described in PKCS1v2.
         */
-        private byte[] maskGeneratorFunction1(
+        private byte[] MaskGeneratorFunction1(
             byte[]	Z,
             int		zOff,
             int		zLen,
diff --git a/crypto/src/crypto/operators/Asn1KeyWrapper.cs b/crypto/src/crypto/operators/Asn1KeyWrapper.cs
index e2b2f8a37..a34d93d54 100644
--- a/crypto/src/crypto/operators/Asn1KeyWrapper.cs
+++ b/crypto/src/crypto/operators/Asn1KeyWrapper.cs
@@ -26,6 +26,50 @@ namespace Org.BouncyCastle.Crypto.Operators
             wrapper = KeyWrapperUtil.WrapperForName(algorithm, cert.GetPublicKey());
         }
 
+        public Asn1KeyWrapper(DerObjectIdentifier algorithm, X509Certificate cert)
+             : this(algorithm, cert.GetPublicKey())
+        {
+        }
+
+        public Asn1KeyWrapper(DerObjectIdentifier algorithm, ICipherParameters key)
+            : this(algorithm, null, key)
+        {
+        }
+
+        public Asn1KeyWrapper(DerObjectIdentifier algorithm, Asn1Encodable parameters, X509Certificate cert)
+            :this(algorithm, parameters, cert.GetPublicKey())
+        {
+        }
+
+        public Asn1KeyWrapper(DerObjectIdentifier algorithm, Asn1Encodable parameters, ICipherParameters key)
+        {
+            this.algorithm = algorithm.Id;
+            if (algorithm.Equals(PkcsObjectIdentifiers.IdRsaesOaep))
+            {
+                RsaesOaepParameters oaepParams = RsaesOaepParameters.GetInstance(parameters);
+                WrapperProvider provider;
+                if (oaepParams.MaskGenAlgorithm.Algorithm.Equals(PkcsObjectIdentifiers.IdMgf1))
+                {
+                    AlgorithmIdentifier digAlg = AlgorithmIdentifier.GetInstance(oaepParams.MaskGenAlgorithm.Parameters);
+
+                    provider = new RsaOaepWrapperProvider(oaepParams.HashAlgorithm.Algorithm, digAlg.Algorithm);
+                }
+                else
+                {
+                    provider = new RsaOaepWrapperProvider(oaepParams.HashAlgorithm.Algorithm, oaepParams.MaskGenAlgorithm.Algorithm);
+                }
+                wrapper = (IKeyWrapper)provider.CreateWrapper(true, key);
+            }
+            else if (algorithm.Equals(PkcsObjectIdentifiers.RsaEncryption))
+            {
+                wrapper = (IKeyWrapper)new RsaPkcs1Wrapper(true, key);
+            }
+            else
+            {
+                throw new ArgumentException("unknown algorithm: " + algorithm.Id);
+            }
+        }
+
         public object AlgorithmDetails
         {
             get { return wrapper.AlgorithmDetails; }
@@ -37,6 +81,75 @@ namespace Org.BouncyCastle.Crypto.Operators
         }
     }
 
+    public class Asn1KeyUnwrapper
+     : IKeyUnwrapper
+    {
+        private string algorithm;
+        private IKeyUnwrapper wrapper;
+
+        public Asn1KeyUnwrapper(string algorithm, ICipherParameters key)
+        {
+            this.algorithm = algorithm;
+            wrapper = KeyWrapperUtil.UnwrapperForName(algorithm, key);
+        }
+
+        public Asn1KeyUnwrapper(DerObjectIdentifier algorithm, ICipherParameters key)
+            : this(algorithm, null, key)
+        {
+        }
+
+        public Asn1KeyUnwrapper(DerObjectIdentifier algorithm, Asn1Encodable parameters, ICipherParameters key)
+        {
+            this.algorithm = algorithm.Id;
+            if (algorithm.Equals(PkcsObjectIdentifiers.IdRsaesOaep))
+            {
+                RsaesOaepParameters oaepParams = RsaesOaepParameters.GetInstance(parameters);
+                WrapperProvider provider;
+                if (oaepParams.MaskGenAlgorithm.Algorithm.Equals(PkcsObjectIdentifiers.IdMgf1))
+                {
+                    AlgorithmIdentifier digAlg = AlgorithmIdentifier.GetInstance(oaepParams.MaskGenAlgorithm.Parameters);
+
+                    provider = new RsaOaepWrapperProvider(oaepParams.HashAlgorithm.Algorithm, digAlg.Algorithm);
+                }
+                else
+                {
+                    provider = new RsaOaepWrapperProvider(oaepParams.HashAlgorithm.Algorithm, oaepParams.MaskGenAlgorithm.Algorithm);
+                }
+                wrapper = (IKeyUnwrapper)provider.CreateWrapper(false, key);
+            }
+            else if (algorithm.Equals(PkcsObjectIdentifiers.RsaEncryption))
+            {
+                RsaesOaepParameters oaepParams = RsaesOaepParameters.GetInstance(parameters);
+                WrapperProvider provider;
+                if (oaepParams.MaskGenAlgorithm.Algorithm.Equals(PkcsObjectIdentifiers.IdMgf1))
+                {
+                    AlgorithmIdentifier digAlg = AlgorithmIdentifier.GetInstance(oaepParams.MaskGenAlgorithm.Parameters);
+
+                    provider = new RsaOaepWrapperProvider(oaepParams.HashAlgorithm.Algorithm, digAlg.Algorithm);
+                }
+                else
+                {
+                    provider = new RsaOaepWrapperProvider(oaepParams.HashAlgorithm.Algorithm, oaepParams.MaskGenAlgorithm.Algorithm);
+                }
+                wrapper = (IKeyUnwrapper)new RsaPkcs1Wrapper(false, key);
+            }
+            else
+            {
+                throw new ArgumentException("unknown algorithm: " + algorithm.Id);
+            }
+        }
+
+        public object AlgorithmDetails
+        {
+            get { return wrapper.AlgorithmDetails; }
+        }
+
+        public IBlockResult Unwrap(byte[] keyData, int offSet, int length)
+        {
+            return wrapper.Unwrap(keyData, offSet, length);
+        }
+    }
+
     internal class KeyWrapperUtil
     {
         //
@@ -45,12 +158,16 @@ namespace Org.BouncyCastle.Crypto.Operators
         private static readonly IDictionary providerMap = Platform.CreateHashtable();
 
         static KeyWrapperUtil()
+            
         {
+            providerMap.Add("RSA/ECB/PKCS1PADDING", new RsaOaepWrapperProvider(OiwObjectIdentifiers.IdSha1));
+            providerMap.Add("RSA/NONE/PKCS1PADDING", new RsaOaepWrapperProvider(OiwObjectIdentifiers.IdSha1));
             providerMap.Add("RSA/NONE/OAEPWITHSHA1ANDMGF1PADDING", new RsaOaepWrapperProvider(OiwObjectIdentifiers.IdSha1));
             providerMap.Add("RSA/NONE/OAEPWITHSHA224ANDMGF1PADDING", new RsaOaepWrapperProvider(NistObjectIdentifiers.IdSha224));
             providerMap.Add("RSA/NONE/OAEPWITHSHA256ANDMGF1PADDING", new RsaOaepWrapperProvider(NistObjectIdentifiers.IdSha256));
             providerMap.Add("RSA/NONE/OAEPWITHSHA384ANDMGF1PADDING", new RsaOaepWrapperProvider(NistObjectIdentifiers.IdSha384));
             providerMap.Add("RSA/NONE/OAEPWITHSHA512ANDMGF1PADDING", new RsaOaepWrapperProvider(NistObjectIdentifiers.IdSha512));
+            providerMap.Add("RSA/NONE/OAEPWITHSHA256ANDMGF1WITHSHA1PADDING", new RsaOaepWrapperProvider(NistObjectIdentifiers.IdSha256, OiwObjectIdentifiers.IdSha1));
         }
 
         public static IKeyWrapper WrapperForName(string algorithm, ICipherParameters parameters)
@@ -78,22 +195,84 @@ namespace Org.BouncyCastle.Crypto.Operators
         object CreateWrapper(bool forWrapping, ICipherParameters parameters);
     }
 
+    internal class RsaPkcs1Wrapper : IKeyWrapper, IKeyUnwrapper
+    {
+        private readonly AlgorithmIdentifier algId;
+        private readonly IAsymmetricBlockCipher engine;
+
+        public RsaPkcs1Wrapper(bool forWrapping, ICipherParameters parameters)
+        {
+            this.algId = new AlgorithmIdentifier(
+                                PkcsObjectIdentifiers.RsaEncryption,
+                                DerNull.Instance);
+
+            this.engine = new Pkcs1Encoding(new RsaBlindedEngine());
+            this.engine.Init(forWrapping, parameters);
+        }
+
+        public object AlgorithmDetails
+        {
+            get { return algId; }
+        }
+
+        public IBlockResult Unwrap(byte[] cipherText, int offset, int length)
+        {
+            return new SimpleBlockResult(engine.ProcessBlock(cipherText, offset, length));
+        }
+
+        public IBlockResult Wrap(byte[] keyData)
+        {
+            return new SimpleBlockResult(engine.ProcessBlock(keyData, 0, keyData.Length));
+        }
+    }
+
+    internal class RsaPkcs1WrapperProvider
+    : WrapperProvider
+    {
+        internal RsaPkcs1WrapperProvider()
+        {
+        }
+
+        object WrapperProvider.CreateWrapper(bool forWrapping, ICipherParameters parameters)
+        {
+            return new RsaPkcs1Wrapper(forWrapping, parameters);
+        }
+    }
+
     internal class RsaOaepWrapper : IKeyWrapper, IKeyUnwrapper
     {
         private readonly AlgorithmIdentifier algId;
         private readonly IAsymmetricBlockCipher engine;
 
         public RsaOaepWrapper(bool forWrapping, ICipherParameters parameters, DerObjectIdentifier digestOid)
+            : this(forWrapping, parameters, digestOid, digestOid)
+        {
+        }
+
+        public RsaOaepWrapper(bool forWrapping, ICipherParameters parameters, DerObjectIdentifier digestOid, DerObjectIdentifier mgfOid)
         {
             AlgorithmIdentifier digestAlgId = new AlgorithmIdentifier(digestOid, DerNull.Instance);
 
-            this.algId = new AlgorithmIdentifier(
-                PkcsObjectIdentifiers.IdRsaesOaep,
-                new RsaesOaepParameters(
-                    digestAlgId,
-                    new AlgorithmIdentifier(PkcsObjectIdentifiers.IdMgf1, digestAlgId),
-                    RsaesOaepParameters.DefaultPSourceAlgorithm));
-            this.engine = new OaepEncoding(new RsaBlindedEngine(), DigestUtilities.GetDigest(digestOid) );
+            if (mgfOid.Equals(NistObjectIdentifiers.IdShake128) || mgfOid.Equals(NistObjectIdentifiers.IdShake256))
+            {
+                this.algId = new AlgorithmIdentifier(
+                    PkcsObjectIdentifiers.IdRsaesOaep,
+                    new RsaesOaepParameters(
+                        digestAlgId,
+                        new AlgorithmIdentifier(mgfOid),
+                        RsaesOaepParameters.DefaultPSourceAlgorithm));
+            }
+            else
+            {
+                this.algId = new AlgorithmIdentifier(
+                     PkcsObjectIdentifiers.IdRsaesOaep,
+                     new RsaesOaepParameters(
+                         digestAlgId,
+                         new AlgorithmIdentifier(PkcsObjectIdentifiers.IdMgf1, new AlgorithmIdentifier(mgfOid, DerNull.Instance)),
+                         RsaesOaepParameters.DefaultPSourceAlgorithm));
+            }
+
+            this.engine = new OaepEncoding(new RsaBlindedEngine(), DigestUtilities.GetDigest(digestOid), DigestUtilities.GetDigest(mgfOid), null);
             this.engine.Init(forWrapping, parameters);
         }
 
@@ -117,15 +296,23 @@ namespace Org.BouncyCastle.Crypto.Operators
         : WrapperProvider
     {
         private readonly DerObjectIdentifier digestOid;
+        private readonly DerObjectIdentifier mgfOid;
 
         internal RsaOaepWrapperProvider(DerObjectIdentifier digestOid)
         {
             this.digestOid = digestOid;
+            this.mgfOid = digestOid;
+        }
+
+        internal RsaOaepWrapperProvider(DerObjectIdentifier digestOid, DerObjectIdentifier mgfOid)
+        {
+            this.digestOid = digestOid;
+            this.mgfOid = mgfOid;
         }
 
         object WrapperProvider.CreateWrapper(bool forWrapping, ICipherParameters parameters)
         {
-            return new RsaOaepWrapper(forWrapping, parameters, digestOid);
+            return new RsaOaepWrapper(forWrapping, parameters, digestOid, mgfOid);
         }
     }
 }
diff --git a/crypto/src/crypto/operators/CmsKeyTransRecipientInfoGenerator.cs b/crypto/src/crypto/operators/CmsKeyTransRecipientInfoGenerator.cs
index b73c41dbd..0165f6af0 100644
--- a/crypto/src/crypto/operators/CmsKeyTransRecipientInfoGenerator.cs
+++ b/crypto/src/crypto/operators/CmsKeyTransRecipientInfoGenerator.cs
@@ -1,6 +1,7 @@
 using System;
 
 using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.Cms;
 using Org.BouncyCastle.Asn1.X509;
 using Org.BouncyCastle.Cms;
 using Org.BouncyCastle.Crypto;
@@ -8,32 +9,22 @@ using Org.BouncyCastle.X509;
 
 namespace Org.BouncyCastle.Operators
 {
+    /// <deprecated>Use KeyTransRecipientInfoGenerator</deprecated>
     public class CmsKeyTransRecipientInfoGenerator
         : KeyTransRecipientInfoGenerator
     {
-        private readonly IKeyWrapper keyWrapper;
-
         public CmsKeyTransRecipientInfoGenerator(X509Certificate recipCert, IKeyWrapper keyWrapper)
-            : base(new Asn1.Cms.IssuerAndSerialNumber(recipCert.IssuerDN, new DerInteger(recipCert.SerialNumber)))
-        {
-            this.keyWrapper = keyWrapper;
-            this.RecipientCert = recipCert;
-            this.RecipientPublicKey = recipCert.GetPublicKey();
-        }
-
-        public CmsKeyTransRecipientInfoGenerator(byte[] subjectKeyID, IKeyWrapper keyWrapper) : base(subjectKeyID)
+            : base(new Asn1.Cms.IssuerAndSerialNumber(recipCert.IssuerDN, new DerInteger(recipCert.SerialNumber)), keyWrapper)
         {
-            this.keyWrapper = keyWrapper;
         }
 
-        protected override AlgorithmIdentifier AlgorithmDetails
+        public CmsKeyTransRecipientInfoGenerator(IssuerAndSerialNumber issuerAndSerial, IKeyWrapper keyWrapper)
+            : base(issuerAndSerial, keyWrapper)
         {
-            get { return (AlgorithmIdentifier)keyWrapper.AlgorithmDetails; }
         }
 
-        protected override byte[] GenerateWrappedKey(Crypto.Parameters.KeyParameter contentKey)
+        public CmsKeyTransRecipientInfoGenerator(byte[] subjectKeyID, IKeyWrapper keyWrapper) : base(subjectKeyID, keyWrapper)
         {
-            return keyWrapper.Wrap(contentKey.GetKey()).Collect();
         }
     }
 }
diff --git a/crypto/src/crypto/signers/PssSigner.cs b/crypto/src/crypto/signers/PssSigner.cs
index b31384783..66efa51b8 100644
--- a/crypto/src/crypto/signers/PssSigner.cs
+++ b/crypto/src/crypto/signers/PssSigner.cs
@@ -245,7 +245,7 @@ namespace Org.BouncyCastle.Crypto.Signers
 			block[block.Length - sLen - 1 - hLen - 1] = (byte) (0x01);
 			salt.CopyTo(block, block.Length - sLen - hLen - 1);
 
-			byte[] dbMask = MaskGeneratorFunction1(h, 0, h.Length, block.Length - hLen - 1);
+			byte[] dbMask = MaskGeneratorFunction(h, 0, h.Length, block.Length - hLen - 1);
 			for (int i = 0; i != dbMask.Length; i++)
 			{
 				block[i] ^= dbMask[i];
@@ -286,7 +286,7 @@ namespace Org.BouncyCastle.Crypto.Signers
 				return false;
 			}
 
-			byte[] dbMask = MaskGeneratorFunction1(block, block.Length - hLen - 1, hLen, block.Length - hLen - 1);
+			byte[] dbMask = MaskGeneratorFunction(block, block.Length - hLen - 1, hLen, block.Length - hLen - 1);
 
 			for (int i = 0; i != dbMask.Length; i++)
 			{
@@ -349,6 +349,26 @@ namespace Org.BouncyCastle.Crypto.Signers
 			sp[3] = (byte)((uint) i >> 0);
 		}
 
+		private byte[] MaskGeneratorFunction(
+			byte[] Z,
+			int zOff,
+			int zLen,
+			int length)
+		{
+			if (mgfDigest is IXof)
+			{
+				byte[] mask = new byte[length];
+				mgfDigest.BlockUpdate(Z, zOff, zLen);
+				((IXof)mgfDigest).DoFinal(mask, 0, mask.Length);
+
+				return mask;
+			}
+			else
+			{
+				return MaskGeneratorFunction1(Z, zOff, zLen, length);
+			}
+		}
+
 		/// <summary> mask generator function, as described in Pkcs1v2.</summary>
 		private byte[] MaskGeneratorFunction1(
 			byte[]	Z,
diff --git a/crypto/src/security/WrapperUtilities.cs b/crypto/src/security/WrapperUtilities.cs
index c57632081..e0c677e42 100644
--- a/crypto/src/security/WrapperUtilities.cs
+++ b/crypto/src/security/WrapperUtilities.cs
@@ -6,6 +6,7 @@ using Org.BouncyCastle.Asn1.Kisa;
 using Org.BouncyCastle.Asn1.Nist;
 using Org.BouncyCastle.Asn1.Ntt;
 using Org.BouncyCastle.Asn1.Pkcs;
+using Org.BouncyCastle.Asn1.X509;
 using Org.BouncyCastle.Crypto;
 using Org.BouncyCastle.Crypto.Engines;
 using Org.BouncyCastle.Utilities;
diff --git a/crypto/test/src/cms/test/EnvelopedDataTest.cs b/crypto/test/src/cms/test/EnvelopedDataTest.cs
index be588ef42..04e75f623 100644
--- a/crypto/test/src/cms/test/EnvelopedDataTest.cs
+++ b/crypto/test/src/cms/test/EnvelopedDataTest.cs
@@ -9,9 +9,12 @@ using Org.BouncyCastle.Asn1.Nist;
 using Org.BouncyCastle.Asn1.Ntt;
 using Org.BouncyCastle.Asn1.Oiw;
 using Org.BouncyCastle.Asn1.Pkcs;
+using Org.BouncyCastle.Asn1.X509;
 using Org.BouncyCastle.Cms;
 using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Crypto.Operators;
 using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Operators;
 using Org.BouncyCastle.Security;
 using Org.BouncyCastle.Utilities;
 using Org.BouncyCastle.Utilities.Encoders;
@@ -241,7 +244,8 @@ namespace Org.BouncyCastle.Cms.Tests
 
 			CmsEnvelopedDataGenerator edGen = new CmsEnvelopedDataGenerator();
 
-			edGen.AddKeyTransRecipient(ReciCert);
+			edGen.AddRecipientInfoGenerator(new KeyTransRecipientInfoGenerator(ReciCert,
+				new Asn1KeyWrapper("RSA/ECB/PKCS1Padding", ReciCert)));
 
 			CmsEnvelopedData ed = edGen.Generate(
 				new CmsProcessableByteArray(data),
@@ -322,6 +326,135 @@ namespace Org.BouncyCastle.Cms.Tests
 		}
 
 		[Test]
+		public void TestKeyTransSmallAesUsingAoep()
+		{
+			byte[] data = new byte[] { 0, 1, 2, 3 };
+
+			CmsEnvelopedDataGenerator edGen = new CmsEnvelopedDataGenerator();
+
+			edGen.AddRecipientInfoGenerator(new KeyTransRecipientInfoGenerator(ReciCert, 
+				new Asn1KeyWrapper("RSA/None/OAEPwithSHA256andMGF1withSHA1Padding", ReciCert)));
+
+			CmsEnvelopedData ed = edGen.Generate(
+				new CmsProcessableByteArray(data),
+				CmsEnvelopedDataGenerator.Aes128Cbc);
+
+			RecipientInformationStore recipients = ed.GetRecipientInfos();
+
+			Assert.AreEqual(ed.EncryptionAlgOid,
+				CmsEnvelopedDataGenerator.Aes128Cbc);
+
+			ICollection c = recipients.GetRecipients();
+
+			Assert.AreEqual(1, c.Count);
+
+			foreach (RecipientInformation recipient in c)
+			{
+				byte[] recData = recipient.GetContent(ReciKP.Private);
+				Assert.IsTrue(Arrays.AreEqual(data, recData));
+			}
+		}
+
+		[Test]
+		public void TestKeyTransSmallAesUsingAoepMixed()
+		{
+			byte[] data = new byte[] { 0, 1, 2, 3 };
+
+			CmsEnvelopedDataGenerator edGen = new CmsEnvelopedDataGenerator();
+
+			edGen.AddRecipientInfoGenerator(new KeyTransRecipientInfoGenerator(ReciCert, new Asn1KeyWrapper("RSA/None/OAEPwithSHA256andMGF1withSHA1Padding", ReciCert)));
+
+			CmsEnvelopedData ed = edGen.Generate(
+				new CmsProcessableByteArray(data),
+				CmsEnvelopedDataGenerator.Aes128Cbc);
+
+			RecipientInformationStore recipients = ed.GetRecipientInfos();
+
+			Assert.AreEqual(ed.EncryptionAlgOid,
+				CmsEnvelopedDataGenerator.Aes128Cbc);
+
+			ICollection c = recipients.GetRecipients();
+
+			Assert.AreEqual(1, c.Count);
+
+			foreach (RecipientInformation recipient in c)
+			{
+				byte[] recData = recipient.GetContent(ReciKP.Private);
+				Assert.IsTrue(Arrays.AreEqual(data, recData));
+			}
+		}
+
+		[Test]
+		public void TestKeyTransSmallAesUsingAoepMixedParams()
+		{
+			byte[] data = new byte[] { 0, 1, 2, 3 };
+
+			CmsEnvelopedDataGenerator edGen = new CmsEnvelopedDataGenerator();
+
+			edGen.AddRecipientInfoGenerator(
+				new KeyTransRecipientInfoGenerator(
+					ReciCert, 
+					new Asn1KeyWrapper(
+						PkcsObjectIdentifiers.IdRsaesOaep, 
+						new RsaesOaepParameters(
+							new AlgorithmIdentifier(NistObjectIdentifiers.IdSha256, DerNull.Instance),
+							new AlgorithmIdentifier(PkcsObjectIdentifiers.IdMgf1, new AlgorithmIdentifier(NistObjectIdentifiers.IdSha224, DerNull.Instance))),
+								ReciCert)));
+
+			CmsEnvelopedData ed = edGen.Generate(
+				new CmsProcessableByteArray(data),
+				CmsEnvelopedDataGenerator.Aes128Cbc);
+
+			RecipientInformationStore recipients = ed.GetRecipientInfos();
+
+			Assert.AreEqual(ed.EncryptionAlgOid,
+				CmsEnvelopedDataGenerator.Aes128Cbc);
+
+			ICollection c = recipients.GetRecipients();
+
+			Assert.AreEqual(1, c.Count);
+
+			foreach (RecipientInformation recipient in c)
+			{
+				byte[] recData = recipient.GetContent(ReciKP.Private);
+				Assert.IsTrue(Arrays.AreEqual(data, recData));
+			}
+		}
+
+		[Test]
+		public void TestKeyTransSmallAesUsingPkcs1()
+		{
+			byte[] data = new byte[] { 0, 1, 2, 3 };
+
+			CmsEnvelopedDataGenerator edGen = new CmsEnvelopedDataGenerator();
+
+			edGen.AddRecipientInfoGenerator(
+				new KeyTransRecipientInfoGenerator(
+					ReciCert,
+					new Asn1KeyWrapper(
+						PkcsObjectIdentifiers.RsaEncryption, ReciCert)));
+
+			CmsEnvelopedData ed = edGen.Generate(
+				new CmsProcessableByteArray(data),
+				CmsEnvelopedDataGenerator.Aes128Cbc);
+
+			RecipientInformationStore recipients = ed.GetRecipientInfos();
+
+			Assert.AreEqual(ed.EncryptionAlgOid,
+				CmsEnvelopedDataGenerator.Aes128Cbc);
+
+			ICollection c = recipients.GetRecipients();
+
+			Assert.AreEqual(1, c.Count);
+
+			foreach (RecipientInformation recipient in c)
+			{
+				byte[] recData = recipient.GetContent(ReciKP.Private);
+				Assert.IsTrue(Arrays.AreEqual(data, recData));
+			}
+		}
+
+		[Test]
 		public void TestKeyTransCast5()
 		{
 			TryKeyTrans(CmsEnvelopedDataGenerator.Cast5Cbc,
diff --git a/crypto/test/src/crmf/test/CrmfTest.cs b/crypto/test/src/crmf/test/CrmfTest.cs
index 8211fe1c4..3e5251d18 100644
--- a/crypto/test/src/crmf/test/CrmfTest.cs
+++ b/crypto/test/src/crmf/test/CrmfTest.cs
@@ -110,7 +110,7 @@ namespace Org.BouncyCastle.Crmf.Tests
            
             certificateRequestMessageBuilder.AddControl(
                 new PkiArchiveControlBuilder(privateInfo, new GeneralName(new X509Name("CN=Test")))
-                    .AddRecipientGenerator(new CmsKeyTransRecipientInfoGenerator(cert, new Asn1KeyWrapper("RSA/None/OAEPwithSHA256andMGF1Padding", cert)))
+                    .AddRecipientGenerator(new KeyTransRecipientInfoGenerator(cert, new Asn1KeyWrapper("RSA/None/OAEPwithSHA256andMGF1Padding", cert)))
                     .Build(new CmsContentEncryptorBuilder(NistObjectIdentifiers.IdAes128Cbc).Build())
             );