summary refs log tree commit diff
path: root/crypto/src/openssl
diff options
context:
space:
mode:
Diffstat (limited to 'crypto/src/openssl')
-rw-r--r--crypto/src/openssl/MiscPemGenerator.cs69
-rw-r--r--crypto/src/openssl/PEMUtilities.cs111
2 files changed, 166 insertions, 14 deletions
diff --git a/crypto/src/openssl/MiscPemGenerator.cs b/crypto/src/openssl/MiscPemGenerator.cs
index ada0b84ed..0e918f793 100644
--- a/crypto/src/openssl/MiscPemGenerator.cs
+++ b/crypto/src/openssl/MiscPemGenerator.cs
@@ -128,20 +128,62 @@ namespace Org.BouncyCastle.OpenSsl
             return new PemObject(type, encoding);
         }
 
-//		private string GetHexEncoded(byte[] bytes)
-//		{
-//			bytes = Hex.Encode(bytes);
-//
-//			char[] chars = new char[bytes.Length];
-//
-//			for (int i = 0; i != bytes.Length; i++)
-//			{
-//				chars[i] = (char)bytes[i];
-//			}
-//
-//			return new string(chars);
-//		}
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+        private static PemObject CreatePemObject(object obj, string algorithm, ReadOnlySpan<char> password,
+            SecureRandom random)
+        {
+            if (obj == null)
+                throw new ArgumentNullException("obj");
+            if (algorithm == null)
+                throw new ArgumentNullException("algorithm");
+            if (random == null)
+                throw new ArgumentNullException("random");
+
+            if (obj is AsymmetricCipherKeyPair keyPair)
+            {
+                return CreatePemObject(keyPair.Private, algorithm, password, random);
+            }
+
+            string type = null;
+            byte[] keyData = null;
 
+            if (obj is AsymmetricKeyParameter akp)
+            {
+                if (akp.IsPrivate)
+                {
+                    keyData = EncodePrivateKey(akp, out type);
+                }
+            }
+
+            if (type == null || keyData == null)
+            {
+                // TODO Support other types?
+                throw new PemGenerationException("Object type not supported: " + Platform.GetTypeName(obj));
+            }
+
+
+            string dekAlgName = algorithm.ToUpperInvariant();
+
+            // Note: For backward compatibility
+            if (dekAlgName == "DESEDE")
+            {
+                dekAlgName = "DES-EDE3-CBC";
+            }
+
+            int ivLength = Platform.StartsWith(dekAlgName, "AES-") ? 16 : 8;
+
+            byte[] iv = new byte[ivLength];
+            random.NextBytes(iv);
+
+            byte[] encData = PemUtilities.Crypt(true, keyData, password, dekAlgName, iv);
+
+            var headers = new List<PemHeader>(2);
+            headers.Add(new PemHeader("Proc-Type", "4,ENCRYPTED"));
+            headers.Add(new PemHeader("DEK-Info", dekAlgName + "," + Hex.ToHexString(iv).ToUpperInvariant()));
+
+            return new PemObject(type, headers, encData);
+        }
+#else
         private static PemObject CreatePemObject(
             object			obj,
             string			algorithm,
@@ -201,6 +243,7 @@ namespace Org.BouncyCastle.OpenSsl
 
             return new PemObject(type, headers, encData);
         }
+#endif
 
         private static byte[] EncodePrivateKey(
             AsymmetricKeyParameter	akp,
diff --git a/crypto/src/openssl/PEMUtilities.cs b/crypto/src/openssl/PEMUtilities.cs
index 332768083..4ff340b12 100644
--- a/crypto/src/openssl/PEMUtilities.cs
+++ b/crypto/src/openssl/PEMUtilities.cs
@@ -50,6 +50,84 @@ namespace Org.BouncyCastle.OpenSsl
 			throw new EncryptionException("Unknown DEK algorithm: " + dekAlgName);
 		}
 
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+        internal static byte[] Crypt(bool encrypt, ReadOnlySpan<byte> bytes, ReadOnlySpan<char> password,
+			string dekAlgName, ReadOnlySpan<byte> iv)
+        {
+            PemBaseAlg baseAlg;
+            PemMode mode;
+            ParseDekAlgName(dekAlgName, out baseAlg, out mode);
+
+            string padding;
+            switch (mode)
+            {
+            case PemMode.CBC:
+            case PemMode.ECB:
+                padding = "PKCS5Padding";
+                break;
+            case PemMode.CFB:
+            case PemMode.OFB:
+                padding = "NoPadding";
+                break;
+            default:
+                throw new EncryptionException("Unknown DEK algorithm: " + dekAlgName);
+            }
+
+            string algorithm;
+
+            ReadOnlySpan<byte> salt = iv;
+            switch (baseAlg)
+            {
+            case PemBaseAlg.AES_128:
+            case PemBaseAlg.AES_192:
+            case PemBaseAlg.AES_256:
+                algorithm = "AES";
+                if (salt.Length > 8)
+                {
+					salt = iv[..8].ToArray();
+                }
+                break;
+            case PemBaseAlg.BF:
+                algorithm = "BLOWFISH";
+                break;
+            case PemBaseAlg.DES:
+                algorithm = "DES";
+                break;
+            case PemBaseAlg.DES_EDE:
+            case PemBaseAlg.DES_EDE3:
+                algorithm = "DESede";
+                break;
+            case PemBaseAlg.RC2:
+            case PemBaseAlg.RC2_40:
+            case PemBaseAlg.RC2_64:
+                algorithm = "RC2";
+                break;
+            default:
+                throw new EncryptionException("Unknown DEK algorithm: " + dekAlgName);
+            }
+
+            string cipherName = algorithm + "/" + mode + "/" + padding;
+            IBufferedCipher cipher = CipherUtilities.GetCipher(cipherName);
+
+            ICipherParameters cParams = GetCipherParameters(password, baseAlg, salt);
+
+            if (mode != PemMode.ECB)
+            {
+                cParams = new ParametersWithIV(cParams, iv);
+            }
+
+            cipher.Init(encrypt, cParams);
+
+			int outputSize = cipher.GetOutputSize(bytes.Length);
+			byte[] output = new byte[outputSize];
+			int length = cipher.DoFinal(bytes, output);
+			if (length < outputSize)
+			{
+				output = Arrays.CopyOfRange(output, 0, length);
+			}
+			return output;
+        }
+#else
 		internal static byte[] Crypt(
 			bool	encrypt,
 			byte[]	bytes,
@@ -124,7 +202,37 @@ namespace Org.BouncyCastle.OpenSsl
 
 			return cipher.DoFinal(bytes);
 		}
+#endif
+
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+        private static ICipherParameters GetCipherParameters(ReadOnlySpan<char> password, PemBaseAlg baseAlg,
+            ReadOnlySpan<byte> salt)
+        {
+            string algorithm;
+            int keyBits;
+            switch (baseAlg)
+            {
+            case PemBaseAlg.AES_128: keyBits = 128; algorithm = "AES128"; break;
+            case PemBaseAlg.AES_192: keyBits = 192; algorithm = "AES192"; break;
+            case PemBaseAlg.AES_256: keyBits = 256; algorithm = "AES256"; break;
+            case PemBaseAlg.BF: keyBits = 128; algorithm = "BLOWFISH"; break;
+            case PemBaseAlg.DES: keyBits = 64; algorithm = "DES"; break;
+            case PemBaseAlg.DES_EDE: keyBits = 128; algorithm = "DESEDE"; break;
+            case PemBaseAlg.DES_EDE3: keyBits = 192; algorithm = "DESEDE3"; break;
+            case PemBaseAlg.RC2: keyBits = 128; algorithm = "RC2"; break;
+            case PemBaseAlg.RC2_40: keyBits = 40; algorithm = "RC2"; break;
+            case PemBaseAlg.RC2_64: keyBits = 64; algorithm = "RC2"; break;
+            default:
+                return null;
+            }
+
+            OpenSslPbeParametersGenerator pGen = new OpenSslPbeParametersGenerator();
+
+            pGen.Init(PbeParametersGenerator.Pkcs5PasswordToBytes(password), salt);
 
+            return pGen.GenerateDerivedParameters(algorithm, keyBits);
+        }
+#else
 		private static ICipherParameters GetCipherParameters(
 			char[]		password,
 			PemBaseAlg	baseAlg,
@@ -154,5 +262,6 @@ namespace Org.BouncyCastle.OpenSsl
 
 			return pGen.GenerateDerivedParameters(algorithm, keyBits);
 		}
-	}
+#endif
+    }
 }