diff options
Diffstat (limited to 'crypto/src/openssl')
-rw-r--r-- | crypto/src/openssl/MiscPemGenerator.cs | 69 | ||||
-rw-r--r-- | crypto/src/openssl/PEMUtilities.cs | 111 |
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 + } } |