summary refs log tree commit diff
path: root/Crypto/src/openssl/PEMUtilities.cs
diff options
context:
space:
mode:
Diffstat (limited to 'Crypto/src/openssl/PEMUtilities.cs')
-rw-r--r--Crypto/src/openssl/PEMUtilities.cs158
1 files changed, 158 insertions, 0 deletions
diff --git a/Crypto/src/openssl/PEMUtilities.cs b/Crypto/src/openssl/PEMUtilities.cs
new file mode 100644
index 000000000..b58e5e765
--- /dev/null
+++ b/Crypto/src/openssl/PEMUtilities.cs
@@ -0,0 +1,158 @@
+using System;
+
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Crypto.Generators;
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Security;
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.OpenSsl
+{
+	internal sealed class PemUtilities
+	{
+		private enum PemBaseAlg { AES_128, AES_192, AES_256, BF, DES, DES_EDE, DES_EDE3, RC2, RC2_40, RC2_64 };
+		private enum PemMode { CBC, CFB, ECB, OFB };
+
+		static PemUtilities()
+		{
+			// Signal to obfuscation tools not to change enum constants
+			((PemBaseAlg)Enums.GetArbitraryValue(typeof(PemBaseAlg))).ToString();
+			((PemMode)Enums.GetArbitraryValue(typeof(PemMode))).ToString();
+		}
+
+		private static void ParseDekAlgName(
+			string			dekAlgName,
+			out PemBaseAlg	baseAlg,
+			out PemMode		mode)
+		{
+			try
+			{
+				mode = PemMode.ECB;
+
+				if (dekAlgName == "DES-EDE" || dekAlgName == "DES-EDE3")
+				{
+					baseAlg = (PemBaseAlg)Enums.GetEnumValue(typeof(PemBaseAlg), dekAlgName);
+					return;
+				}
+
+				int pos = dekAlgName.LastIndexOf('-');
+				if (pos >= 0)
+				{
+					baseAlg = (PemBaseAlg)Enums.GetEnumValue(typeof(PemBaseAlg), dekAlgName.Substring(0, pos));
+					mode = (PemMode)Enums.GetEnumValue(typeof(PemMode), dekAlgName.Substring(pos + 1));
+					return;
+				}
+			}
+			catch (ArgumentException)
+			{
+			}
+
+			throw new EncryptionException("Unknown DEK algorithm: " + dekAlgName);
+		}
+
+		internal static byte[] Crypt(
+			bool	encrypt,
+			byte[]	bytes,
+			char[]	password,
+			string	dekAlgName,
+			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;
+
+			byte[] salt = iv;
+			switch (baseAlg)
+			{
+				case PemBaseAlg.AES_128:
+				case PemBaseAlg.AES_192:
+				case PemBaseAlg.AES_256:
+					algorithm = "AES";
+					if (salt.Length > 8)
+					{
+						salt = new byte[8];
+						Array.Copy(iv, 0, salt, 0, salt.Length);
+					}
+					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);
+
+			return cipher.DoFinal(bytes);
+		}
+
+		private static ICipherParameters GetCipherParameters(
+			char[]		password,
+			PemBaseAlg	baseAlg,
+			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);
+		}
+	}
+}