From 2891bad0cdb08e7b9198738eeef5247ddf48a7cb Mon Sep 17 00:00:00 2001 From: Jiri Cincura Date: Thu, 13 Jul 2017 09:09:04 +0200 Subject: [PATCH] Support for passing encryption key. --- .../Client/Managed/GdsConnection.cs | 4 + .../Client/Managed/Version10/GdsDatabase.cs | 4 +- .../Client/Managed/Version11/GdsDatabase.cs | 2 +- .../Version13/CryptKeyCallbackReponse.cs | 34 +++ .../Client/Managed/Version13/GdsDatabase.cs | 34 ++- .../Client/Native/FesDatabase.cs | 10 +- .../Common/IDatabase.cs | 4 +- .../FirebirdClient/FbConnectionInternal.cs | 6 +- .../FirebirdClient/FbConnectionString.cs | 239 ++++++------------ .../FbConnectionStringBuilder.cs | 52 ++-- .../FbConnectionStringTests.cs | 24 ++ .../FbConnectionTests.cs | 12 + 12 files changed, 238 insertions(+), 187 deletions(-) create mode 100644 Provider/src/FirebirdSql.Data.FirebirdClient/Client/Managed/Version13/CryptKeyCallbackReponse.cs diff --git a/Provider/src/FirebirdSql.Data.FirebirdClient/Client/Managed/GdsConnection.cs b/Provider/src/FirebirdSql.Data.FirebirdClient/Client/Managed/GdsConnection.cs index fd073892..71313de0 100644 --- a/Provider/src/FirebirdSql.Data.FirebirdClient/Client/Managed/GdsConnection.cs +++ b/Provider/src/FirebirdSql.Data.FirebirdClient/Client/Managed/GdsConnection.cs @@ -24,6 +24,7 @@ using System.Net.Sockets; using System.Text; using FirebirdSql.Data.Client.Managed.Version11; +using FirebirdSql.Data.Client.Managed.Version13; using FirebirdSql.Data.Common; namespace FirebirdSql.Data.Client.Managed @@ -369,6 +370,9 @@ public static IResponse ProcessOperation(int operation, XdrStream xdr) case IscCodes.op_trusted_auth: return new AuthResponse(xdr.ReadBuffer()); + case IscCodes.op_crypt_key_callback: + return new CryptKeyCallbackReponse(xdr.ReadBuffer()); + default: return null; } diff --git a/Provider/src/FirebirdSql.Data.FirebirdClient/Client/Managed/Version10/GdsDatabase.cs b/Provider/src/FirebirdSql.Data.FirebirdClient/Client/Managed/Version10/GdsDatabase.cs index f4b6a747..b63a270f 100644 --- a/Provider/src/FirebirdSql.Data.FirebirdClient/Client/Managed/Version10/GdsDatabase.cs +++ b/Provider/src/FirebirdSql.Data.FirebirdClient/Client/Managed/Version10/GdsDatabase.cs @@ -164,7 +164,7 @@ public void Dispose() #region Attach/Detach Methods - public virtual void Attach(DatabaseParameterBuffer dpb, string dataSource, int port, string database) + public virtual void Attach(DatabaseParameterBuffer dpb, string dataSource, int port, string database, byte[] cryptKey) { try { @@ -208,7 +208,7 @@ protected void AfterAttachActions() _serverVersion = GetServerVersion(); } - public virtual void AttachWithTrustedAuth(DatabaseParameterBuffer dpb, string dataSource, int port, string database) + public virtual void AttachWithTrustedAuth(DatabaseParameterBuffer dpb, string dataSource, int port, string database, byte[] cryptKey) { throw new NotSupportedException("Trusted Auth isn't supported on < FB2.1."); } diff --git a/Provider/src/FirebirdSql.Data.FirebirdClient/Client/Managed/Version11/GdsDatabase.cs b/Provider/src/FirebirdSql.Data.FirebirdClient/Client/Managed/Version11/GdsDatabase.cs index d98fcb81..1b6345ea 100644 --- a/Provider/src/FirebirdSql.Data.FirebirdClient/Client/Managed/Version11/GdsDatabase.cs +++ b/Provider/src/FirebirdSql.Data.FirebirdClient/Client/Managed/Version11/GdsDatabase.cs @@ -65,7 +65,7 @@ public override StatementBase CreateStatement(TransactionBase transaction) #endregion #region Trusted Auth - public override void AttachWithTrustedAuth(DatabaseParameterBuffer dpb, string dataSource, int port, string database) + public override void AttachWithTrustedAuth(DatabaseParameterBuffer dpb, string dataSource, int port, string database, byte[] cryptKey) { try { diff --git a/Provider/src/FirebirdSql.Data.FirebirdClient/Client/Managed/Version13/CryptKeyCallbackReponse.cs b/Provider/src/FirebirdSql.Data.FirebirdClient/Client/Managed/Version13/CryptKeyCallbackReponse.cs new file mode 100644 index 00000000..79b6835b --- /dev/null +++ b/Provider/src/FirebirdSql.Data.FirebirdClient/Client/Managed/Version13/CryptKeyCallbackReponse.cs @@ -0,0 +1,34 @@ +/* + * Firebird ADO.NET Data provider for .NET and Mono + * + * The contents of this file are subject to the Initial + * Developer's Public License Version 1.0 (the "License"); + * you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * http://www.firebirdsql.org/index.php?op=doc&id=idpl + * + * Software distributed under the License is distributed on + * an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, either + * express or implied. See the License for the specific + * language governing rights and limitations under the License. + * + * Copyright (c) 2017 Jiri Cincura (jiri@cincura.net) + * All Rights Reserved. + * + */ + +using System; +using FirebirdSql.Data.Client.Managed; + +namespace FirebirdSql.Data.Client.Managed.Version13 +{ + internal class CryptKeyCallbackReponse : IResponse + { + public byte[] Data { get; } + + public CryptKeyCallbackReponse(byte[] data) + { + Data = data; + } + } +} diff --git a/Provider/src/FirebirdSql.Data.FirebirdClient/Client/Managed/Version13/GdsDatabase.cs b/Provider/src/FirebirdSql.Data.FirebirdClient/Client/Managed/Version13/GdsDatabase.cs index 1c9dd574..ca81af24 100644 --- a/Provider/src/FirebirdSql.Data.FirebirdClient/Client/Managed/Version13/GdsDatabase.cs +++ b/Provider/src/FirebirdSql.Data.FirebirdClient/Client/Managed/Version13/GdsDatabase.cs @@ -37,6 +37,36 @@ public GdsDatabase(GdsConnection connection) : base(connection) { } + public override void Attach(DatabaseParameterBuffer dpb, string dataSource, int port, string database, byte[] cryptKey) + { + try + { + SendAttachToBuffer(dpb, database); + XdrStream.Flush(); + var response = ReadResponse(); + while (response is CryptKeyCallbackReponse cryptResponse) + { + XdrStream.Write(IscCodes.op_crypt_key_callback); + XdrStream.WriteBuffer(cryptKey); + XdrStream.Flush(); + response = ReadResponse(); + } + ProcessAttachResponse(response as GenericResponse); + } + catch (IscException) + { + SafelyDetach(); + throw; + } + catch (IOException ex) + { + SafelyDetach(); + throw IscException.ForErrorCode(IscCodes.isc_net_write_err, ex); + } + + AfterAttachActions(); + } + protected override void SendAttachToBuffer(DatabaseParameterBuffer dpb, string database) { XdrStream.Write(IscCodes.op_attach); @@ -63,9 +93,9 @@ protected override void SendCreateToBuffer(DatabaseParameterBuffer dpb, string d XdrStream.WriteBuffer(dpb.ToArray()); } - public override void AttachWithTrustedAuth(DatabaseParameterBuffer dpb, string dataSource, int port, string database) + public override void AttachWithTrustedAuth(DatabaseParameterBuffer dpb, string dataSource, int port, string database, byte[] cryptKey) { - Attach(dpb, dataSource, port, database); + Attach(dpb, dataSource, port, database, cryptKey); } #region Override Statement Creation Methods diff --git a/Provider/src/FirebirdSql.Data.FirebirdClient/Client/Native/FesDatabase.cs b/Provider/src/FirebirdSql.Data.FirebirdClient/Client/Native/FesDatabase.cs index 839dfa99..562136e5 100644 --- a/Provider/src/FirebirdSql.Data.FirebirdClient/Client/Native/FesDatabase.cs +++ b/Provider/src/FirebirdSql.Data.FirebirdClient/Client/Native/FesDatabase.cs @@ -202,8 +202,12 @@ public void CancelEvents(RemoteEvent events) #region Methods - public void Attach(DatabaseParameterBuffer dpb, string dataSource, int port, string database) + public void Attach(DatabaseParameterBuffer dpb, string dataSource, int port, string database, byte[] cryptKey) { + // ICryptKeyCallbackImpl would have to be passed from C# for 'cryptKey' passing + if (cryptKey?.Length > 0) + throw new NotSupportedException("Passing Encryption Key isn't, yet, supported on Firebird Embedded."); + byte[] databaseBuffer = Encoding2.Default.GetBytes(database); ClearStatusVector(); @@ -221,9 +225,9 @@ public void Attach(DatabaseParameterBuffer dpb, string dataSource, int port, str _serverVersion = GetServerVersion(); } - public void AttachWithTrustedAuth(DatabaseParameterBuffer dpb, string dataSource, int port, string database) + public void AttachWithTrustedAuth(DatabaseParameterBuffer dpb, string dataSource, int port, string database, byte[] cryptKey) { - throw new NotSupportedException("Trusted Auth isn't supported on Embedded Firebird."); + throw new NotSupportedException("Trusted Auth isn't supported on Firebird Embedded."); } public void Detach() diff --git a/Provider/src/FirebirdSql.Data.FirebirdClient/Common/IDatabase.cs b/Provider/src/FirebirdSql.Data.FirebirdClient/Common/IDatabase.cs index 593778e7..70469268 100644 --- a/Provider/src/FirebirdSql.Data.FirebirdClient/Common/IDatabase.cs +++ b/Provider/src/FirebirdSql.Data.FirebirdClient/Common/IDatabase.cs @@ -37,8 +37,8 @@ internal interface IDatabase : IDisposable short Dialect { get; set; } bool HasRemoteEventSupport { get; } - void Attach(DatabaseParameterBuffer dpb, string dataSource, int port, string database); - void AttachWithTrustedAuth(DatabaseParameterBuffer dpb, string dataSource, int port, string database); + void Attach(DatabaseParameterBuffer dpb, string dataSource, int port, string database, byte[] cryptKey); + void AttachWithTrustedAuth(DatabaseParameterBuffer dpb, string dataSource, int port, string database, byte[] cryptKey); void Detach(); void CreateDatabase(DatabaseParameterBuffer dpb, string dataSource, int port, string database); diff --git a/Provider/src/FirebirdSql.Data.FirebirdClient/FirebirdClient/FbConnectionInternal.cs b/Provider/src/FirebirdSql.Data.FirebirdClient/FirebirdClient/FbConnectionInternal.cs index f105a7b0..1334e8e7 100644 --- a/Provider/src/FirebirdSql.Data.FirebirdClient/FirebirdClient/FbConnectionInternal.cs +++ b/Provider/src/FirebirdSql.Data.FirebirdClient/FirebirdClient/FbConnectionInternal.cs @@ -133,7 +133,7 @@ public void CreateDatabase(DatabaseParameterBuffer dpb) public void DropDatabase() { IDatabase db = ClientFactory.CreateDatabase(_options); - db.Attach(BuildDpb(db, _options), _options.DataSource, _options.Port, _options.Database); + db.Attach(BuildDpb(db, _options), _options.DataSource, _options.Port, _options.Database, _options.CryptKey); db.DropDatabase(); } @@ -159,11 +159,11 @@ public void Connect() if (string.IsNullOrEmpty(_options.UserID) && string.IsNullOrEmpty(_options.Password)) { - _db.AttachWithTrustedAuth(dpb, _options.DataSource, _options.Port, _options.Database); + _db.AttachWithTrustedAuth(dpb, _options.DataSource, _options.Port, _options.Database, _options.CryptKey); } else { - _db.Attach(dpb, _options.DataSource, _options.Port, _options.Database); + _db.Attach(dpb, _options.DataSource, _options.Port, _options.Database, _options.CryptKey); } } catch (IscException ex) diff --git a/Provider/src/FirebirdSql.Data.FirebirdClient/FirebirdClient/FbConnectionString.cs b/Provider/src/FirebirdSql.Data.FirebirdClient/FirebirdClient/FbConnectionString.cs index 35466d1a..4998e755 100644 --- a/Provider/src/FirebirdSql.Data.FirebirdClient/FirebirdClient/FbConnectionString.cs +++ b/Provider/src/FirebirdSql.Data.FirebirdClient/FirebirdClient/FbConnectionString.cs @@ -56,6 +56,7 @@ internal sealed class FbConnectionString internal const bool DefaultValueNoDbTriggers = false; internal const bool DefaultValueNoGarbageCollect = false; internal const bool DefaultValueCompression = false; + internal const byte[] DefaultValueCryptKey = null; internal const string DefaultKeyUserId = "user id"; internal const string DefaultKeyPortNumber = "port number"; @@ -81,6 +82,7 @@ internal sealed class FbConnectionString internal const string DefaultKeyNoDbTriggers = "no db triggers"; internal const string DefaultKeyNoGarbageCollect = "no garbage collect"; internal const string DefaultKeyCompression = "compression"; + internal const string DefaultKeyCryptKey = "crypt key"; #endregion #region Static Fields @@ -144,6 +146,8 @@ internal sealed class FbConnectionString { "nogarbagecollect", DefaultKeyNoGarbageCollect }, { DefaultKeyCompression, DefaultKeyCompression }, { "wire compression", DefaultKeyCompression }, + { DefaultKeyCryptKey, DefaultKeyCryptKey }, + { "cryptkey", DefaultKeyCryptKey }, }; internal static readonly IDictionary DefaultValues = new Dictionary(StringComparer.Ordinal) @@ -172,6 +176,7 @@ internal sealed class FbConnectionString { DefaultKeyNoDbTriggers, DefaultValueNoDbTriggers }, { DefaultKeyNoGarbageCollect, DefaultValueNoGarbageCollect }, { DefaultKeyCompression, DefaultValueCompression }, + { DefaultKeyCryptKey, DefaultValueCryptKey }, }; #endregion @@ -185,132 +190,38 @@ internal sealed class FbConnectionString #region Properties - public string UserID - { - get { return GetString(DefaultKeyUserId); } - } - - public string Password - { - get { return GetString(DefaultKeyPassword); } - } - - public string DataSource - { - get { return GetString(DefaultKeyDataSource); } - } - - public int Port - { - get { return GetInt32(DefaultKeyPortNumber); } - } - - public string Database - { - get { return ExpandDataDirectory(GetString(DefaultKeyCatalog)); } - } - - public short PacketSize - { - get { return GetInt16(DefaultKeyPacketSize); } - } - - public string Role - { - get { return GetString(DefaultKeyRoleName); } - } - - public byte Dialect - { - get { return GetByte(DefaultKeyDialect); } - } - - public string Charset - { - get { return GetString(DefaultKeyCharacterSet); } - } - - public int ConnectionTimeout - { - get { return GetInt32(DefaultKeyConnectionTimeout); } - } - - public bool Pooling - { - get { return GetBoolean(DefaultKeyPooling); } - } - - public long ConnectionLifeTime - { - get { return GetInt64(DefaultKeyConnectionLifetime); } - } - - public int MinPoolSize - { - get { return GetInt32(DefaultKeyMinPoolSize); } - } - - public int MaxPoolSize - { - get { return GetInt32(DefaultKeyMaxPoolSize); } - } - - public int FetchSize - { - get { return GetInt32(DefaultKeyFetchSize); } - } - - public FbServerType ServerType - { - get { return (FbServerType)GetInt32(DefaultKeyServerType); } - } - - public IsolationLevel IsolationLevel - { - get { return GetIsolationLevel(DefaultKeyIsolationLevel); } - } - - public bool ReturnRecordsAffected - { - get { return GetBoolean(DefaultKeyRecordsAffected); } - } - - public bool Enlist - { - get { return GetBoolean(DefaultKeyEnlist); } - } - - public string ClientLibrary - { - get { return GetString(DefaultKeyClientLibrary); } - } - - public int DbCachePages - { - get { return GetInt32(DefaultKeyDbCachePages); } - } - - public bool NoDatabaseTriggers - { - get { return GetBoolean(DefaultKeyNoDbTriggers); } - } - - public bool NoGarbageCollect - { - get { return GetBoolean(DefaultKeyNoGarbageCollect); } - } - - public bool Compression - { - get { return GetBoolean(DefaultKeyCompression); } - } + public string UserID => GetString(DefaultKeyUserId); + public string Password => GetString(DefaultKeyPassword); + public string DataSource => GetString(DefaultKeyDataSource); + public int Port => GetInt32(DefaultKeyPortNumber); + public string Database => ExpandDataDirectory(GetString(DefaultKeyCatalog)); + public short PacketSize => GetInt16(DefaultKeyPacketSize); + public string Role => GetString(DefaultKeyRoleName); + public byte Dialect => GetByte(DefaultKeyDialect); + public string Charset => GetString(DefaultKeyCharacterSet); + public int ConnectionTimeout => GetInt32(DefaultKeyConnectionTimeout); + public bool Pooling => GetBoolean(DefaultKeyPooling); + public long ConnectionLifeTime => GetInt64(DefaultKeyConnectionLifetime); + public int MinPoolSize => GetInt32(DefaultKeyMinPoolSize); + public int MaxPoolSize => GetInt32(DefaultKeyMaxPoolSize); + public int FetchSize => GetInt32(DefaultKeyFetchSize); + public FbServerType ServerType => (FbServerType)GetInt32(DefaultKeyServerType); + public IsolationLevel IsolationLevel => GetIsolationLevel(DefaultKeyIsolationLevel); + public bool ReturnRecordsAffected => GetBoolean(DefaultKeyRecordsAffected); + public bool Enlist => GetBoolean(DefaultKeyEnlist); + public string ClientLibrary => GetString(DefaultKeyClientLibrary); + public int DbCachePages => GetInt32(DefaultKeyDbCachePages); + public bool NoDatabaseTriggers => GetBoolean(DefaultKeyNoDbTriggers); + public bool NoGarbageCollect => GetBoolean(DefaultKeyNoGarbageCollect); + public bool Compression => GetBoolean(DefaultKeyCompression); + public byte[] CryptKey => GetBytes(DefaultKeyCryptKey); #endregion #region Internal Properties internal string NormalizedConnectionString { - get { return string.Join(";", _options.Keys.OrderBy(x => x, StringComparer.Ordinal).Select(key => string.Format("{0}={1}", key, WrapValueIfNeeded(_options[key].ToString())))); } + get { return string.Join(";", _options.OrderBy(x => x.Key, StringComparer.Ordinal).Where(x => x.Value != null).Select(x => string.Format("{0}={1}", x.Key, WrapValueIfNeeded(x.Value.ToString())))); } } #endregion @@ -366,25 +277,37 @@ public void Load(string connectionString) if (values.Length == 2 && !string.IsNullOrEmpty(values[0]) && !string.IsNullOrEmpty(values[1])) { - string key; - if (Synonyms.TryGetValue(values[0], out key)) + if (Synonyms.TryGetValue(values[0], out var key)) { - if (key == DefaultKeyServerType) - { - FbServerType serverType = default(FbServerType); - try - { - serverType = (FbServerType)Enum.Parse(typeof(FbServerType), values[1], true); - } - catch - { - throw new NotSupportedException("Not supported 'server type'."); - } - _options[key] = serverType; - } - else + switch (key) { - _options[key] = values[1]; + case DefaultKeyServerType: + var serverType = default(FbServerType); + try + { + serverType = (FbServerType)Enum.Parse(typeof(FbServerType), values[1], true); + } + catch + { + throw new NotSupportedException($"Not supported '{DefaultKeyServerType}'."); + } + _options[key] = serverType; + break; + case DefaultKeyCryptKey: + var cryptKey = default(byte[]); + try + { + cryptKey = Convert.FromBase64String(values[1]); + } + catch + { + throw new NotSupportedException($"Not supported '{DefaultKeyCryptKey}'."); + } + _options[key] = cryptKey; + break; + default: + _options[key] = values[1]; + break; } } } @@ -442,9 +365,9 @@ private void SetDefaultOptions() private void ParseConnectionInfo(string connectInfo) { - string database = null; - string dataSource = null; - int portNumber = -1; + var database = (string)null; + var dataSource = (string)null; + var portNumber = -1; // allows standard syntax //host:port/.... // and old fb syntax host/port:.... @@ -526,66 +449,66 @@ private string ExpandDataDirectory(string s) if (s == null) return s; - string dataDirectoryLocation = (string)AppDomain.CurrentDomain.GetData("DataDirectory") ?? string.Empty; - string pattern = string.Format("{0}{1}?", Regex.Escape(DataDirectoryKeyword), Regex.Escape(Path.DirectorySeparatorChar.ToString())); + var dataDirectoryLocation = (string)AppDomain.CurrentDomain.GetData("DataDirectory") ?? string.Empty; + var pattern = string.Format("{0}{1}?", Regex.Escape(DataDirectoryKeyword), Regex.Escape(Path.DirectorySeparatorChar.ToString())); return Regex.Replace(s, pattern, dataDirectoryLocation + Path.DirectorySeparatorChar, RegexOptions.IgnoreCase | RegexOptions.CultureInvariant); #endif } private string GetString(string key) { - object value; - return _options.TryGetValue(key, out value) + return _options.TryGetValue(key, out var value) ? (string)value : null; } private bool GetBoolean(string key) { - object value; - return _options.TryGetValue(key, out value) + return _options.TryGetValue(key, out var value) ? bool.Parse(value.ToString()) : false; } private byte GetByte(string key) { - object value; - return _options.TryGetValue(key, out value) + return _options.TryGetValue(key, out var value) ? Convert.ToByte(value, CultureInfo.CurrentCulture) : (byte)0; } private short GetInt16(string key) { - object value; - return _options.TryGetValue(key, out value) + return _options.TryGetValue(key, out var value) ? Convert.ToInt16(value, CultureInfo.InvariantCulture) : (short)0; } private int GetInt32(string key) { - object value; - return _options.TryGetValue(key, out value) + return _options.TryGetValue(key, out var value) ? Convert.ToInt32(value, CultureInfo.InvariantCulture) : 0; } private long GetInt64(string key) { - object value; - return _options.TryGetValue(key, out value) + return _options.TryGetValue(key, out var value) ? Convert.ToInt64(value, CultureInfo.InvariantCulture) : 0; } + private byte[] GetBytes(string key) + { + return _options.TryGetValue(key, out var value) + ? (byte[])value + : null; + } + private IsolationLevel GetIsolationLevel(string key) { - object value; - if (_options.TryGetValue(key, out value)) + if (_options.TryGetValue(key, out var value)) { - string il = value.ToString().ToLowerInvariant(); + var il = value.ToString().ToLowerInvariant(); switch (il) { @@ -617,7 +540,7 @@ private IsolationLevel GetIsolationLevel(string key) private void CheckIsolationLevel() { - string il = _options[DefaultKeyIsolationLevel].ToString().ToLowerInvariant(); + var il = _options[DefaultKeyIsolationLevel].ToString().ToLowerInvariant(); switch (il) { diff --git a/Provider/src/FirebirdSql.Data.FirebirdClient/FirebirdClient/FbConnectionStringBuilder.cs b/Provider/src/FirebirdSql.Data.FirebirdClient/FirebirdClient/FbConnectionStringBuilder.cs index be2e9cf0..861ef2af 100644 --- a/Provider/src/FirebirdSql.Data.FirebirdClient/FirebirdClient/FbConnectionStringBuilder.cs +++ b/Provider/src/FirebirdSql.Data.FirebirdClient/FirebirdClient/FbConnectionStringBuilder.cs @@ -228,7 +228,7 @@ public bool Enlist [Category("Advanced")] [DisplayName("Client Library")] - [Description("Client library for Firebird Embedded Server.")] + [Description("Client library for Firebird Embedded.")] [DefaultValue(FbConnectionString.DefaultValueClientLibrary)] public string ClientLibrary { @@ -276,6 +276,16 @@ public bool Compression set { SetValue(FbConnectionString.DefaultKeyCompression, value); } } + [Category("Advanced")] + [DisplayName("CryptKey")] + [Description("Key used for database decryption.")] + [DefaultValue(FbConnectionString.DefaultValueCryptKey)] + public byte[] CryptKey + { + get { return GetBytes(FbConnectionString.DefaultKeyCryptKey, FbConnectionString.DefaultValueCryptKey); } + set { SetValue(FbConnectionString.DefaultKeyCryptKey, value); } + } + #endregion #region Constructors @@ -306,23 +316,17 @@ private FbServerType GetServerType(string keyword, FbServerType defaultValue) if (!TryGetValue(GetKey(keyword), out var value)) return defaultValue; - if (value is FbServerType) + switch (value) { - return (FbServerType)value; - } - else if (value is string) - { - switch ((string)value) - { - case "Default": - return FbServerType.Default; - - case "Embedded": - return FbServerType.Embedded; - } + case FbServerType fbServerType: + return fbServerType; + case string s when s == "Default": + return FbServerType.Default; + case string s when s == "Embedded": + return FbServerType.Embedded; + default: + return (FbServerType)GetInt32(keyword, (int)defaultValue); } - - return (FbServerType)GetInt32(keyword, (int)defaultValue); } private IsolationLevel GetIsolationLevel(string keyword, IsolationLevel defaultValue) @@ -347,6 +351,22 @@ private bool GetBoolean(string keyword, bool defaultValue) : defaultValue; } + private byte[] GetBytes(string keyword, byte[] defaultValue) + { + if (!TryGetValue(GetKey(keyword), out var value)) + return defaultValue; + + switch (value) + { + case byte[] bytes: + return bytes; + case string s: + return Convert.FromBase64String(s); + default: + return defaultValue; + } + } + private void SetValue(string keyword, T value) { this[GetKey(keyword)] = value; diff --git a/Provider/src/FirebirdSql.Data.UnitTests/FbConnectionStringTests.cs b/Provider/src/FirebirdSql.Data.UnitTests/FbConnectionStringTests.cs index 3898f685..9018425b 100644 --- a/Provider/src/FirebirdSql.Data.UnitTests/FbConnectionStringTests.cs +++ b/Provider/src/FirebirdSql.Data.UnitTests/FbConnectionStringTests.cs @@ -153,5 +153,29 @@ public void ParsingWithWhiteSpacesKeyConnectionStringTest() Assert.AreEqual("", cs.UserID); Assert.AreEqual("testpwd", cs.Password); } + + [Test] + public void CryptKeyWithBase64FullPadding() + { + const string ConnectionString = "user=u;cryptkey=dGVzdA==;password=p"; + var cs = new FbConnectionString(ConnectionString); + Assert.AreEqual("test", cs.CryptKey); + } + + [Test] + public void CryptKeyWithBase64SinglePadding() + { + const string ConnectionString = "user=u;cryptkey=YWE=;password=p"; + var cs = new FbConnectionString(ConnectionString); + Assert.AreEqual("aa", cs.CryptKey); + } + + [Test] + public void CryptKeyWithBase64NoPadding() + { + const string ConnectionString = "user=u;cryptkey=YWFh;password=p"; + var cs = new FbConnectionString(ConnectionString); + Assert.AreEqual("aaa", cs.CryptKey); + } } } diff --git a/Provider/src/FirebirdSql.Data.UnitTests/FbConnectionTests.cs b/Provider/src/FirebirdSql.Data.UnitTests/FbConnectionTests.cs index 6461f494..1454bf72 100644 --- a/Provider/src/FirebirdSql.Data.UnitTests/FbConnectionTests.cs +++ b/Provider/src/FirebirdSql.Data.UnitTests/FbConnectionTests.cs @@ -24,6 +24,7 @@ using System.IO; using System.Linq; using System.Reflection; +using System.Text; using System.Threading; using FirebirdSql.Data.FirebirdClient; using NUnit.Framework; @@ -361,6 +362,17 @@ public void UseCompression(bool compression) } } + [Test, Ignore("Needs plugin")] + public void PassCryptKey() + { + var csb = BuildConnectionStringBuilder(FbServerType, Compression); + csb.CryptKey = Encoding.ASCII.GetBytes("1234567890123456"); + using (var conn = new FbConnection(csb.ToString())) + { + conn.Open(); + } + } + #endregion #region Methods