diff --git a/src/NServiceBus.Core.Tests/Encryption/EncryptionServiceTests.cs b/src/NServiceBus.Core.Tests/Encryption/EncryptionServiceTests.cs index d51435ac4c0..f9648b250d2 100644 --- a/src/NServiceBus.Core.Tests/Encryption/EncryptionServiceTests.cs +++ b/src/NServiceBus.Core.Tests/Encryption/EncryptionServiceTests.cs @@ -77,5 +77,18 @@ public void Should_throw_when_decrypt_with_wrong_key() } } + [Test] + public void Should_throw_when_encrypt_and_decrypt_keys_are_too_similar() + { + var key = Encoding.ASCII.GetBytes("gdDbqRpqdRbTs3mhdZh9qCaDaxJXl+e6"); + var service = new EncryptionService + { + Key = key, + ExpiredKeys = new List { key } //note that we use the same key to get the code to throw + }; + var exception = Assert.Throws(service.VerifyKeysAreNotTooSimilar); + + Assert.AreEqual("The new Encryption Key is too similar to the Expired Key at index 0. This can cause issues when decrypting data. To fix this issue please ensure the new encryption key is not too similar to the existing Expired Keys.", exception.Message); + } } } \ No newline at end of file diff --git a/src/NServiceBus.Core/ConfigureRijndaelEncryptionService.cs b/src/NServiceBus.Core/ConfigureRijndaelEncryptionService.cs index 0a76762726a..bcfb0bd6884 100644 --- a/src/NServiceBus.Core/ConfigureRijndaelEncryptionService.cs +++ b/src/NServiceBus.Core/ConfigureRijndaelEncryptionService.cs @@ -5,6 +5,7 @@ namespace NServiceBus using System.Linq; using System.Text; using Config; + using Encryption; using Encryption.Rijndael; using Logging; @@ -25,7 +26,7 @@ public static Configure RijndaelEncryptionService(this Configure config) if (section == null) Logger.Warn("Could not find configuration section for Rijndael Encryption Service."); - var encryptConfig = config.Configurer.ConfigureComponent(DependencyLifecycle.SingleInstance); + var encryptionService = new EncryptionService(); if (section != null) { @@ -34,10 +35,15 @@ public static Configure RijndaelEncryptionService(this Configure config) throw new Exception("The RijndaelEncryptionServiceConfig has an empty 'Key' attribute."); } var expiredKeys = ExtractExpiredKeysFromConfigSection(section); - encryptConfig.ConfigureProperty(s => s.Key, Encoding.ASCII.GetBytes(section.Key)); - encryptConfig.ConfigureProperty(s => s.ExpiredKeys, expiredKeys.Select(x=>Encoding.ASCII.GetBytes(x)).ToList()); + + encryptionService.Key = Encoding.ASCII.GetBytes(section.Key); + encryptionService.ExpiredKeys = expiredKeys.Select(x => Encoding.ASCII.GetBytes(x)).ToList(); } + encryptionService.VerifyKeysAreNotTooSimilar(); + + config.Configurer.RegisterSingleton(encryptionService); + return config; } @@ -68,4 +74,4 @@ internal static List ExtractExpiredKeysFromConfigSection(RijndaelEncrypt } private static readonly ILog Logger = LogManager.GetLogger(typeof(RijndaelEncryptionServiceConfig)); } -} +} \ No newline at end of file diff --git a/src/NServiceBus.Core/Encryption/Rijndael/EncryptionService.cs b/src/NServiceBus.Core/Encryption/Rijndael/EncryptionService.cs index 78e6b89d0ed..9d12dbcf32e 100644 --- a/src/NServiceBus.Core/Encryption/Rijndael/EncryptionService.cs +++ b/src/NServiceBus.Core/Encryption/Rijndael/EncryptionService.cs @@ -31,42 +31,43 @@ string IEncryptionService.Decrypt(EncryptedValue encryptedValue) return encryptedValue.EncryptedBase64Value; } - var decryptionKeys = new List{Key}; + var decryptionKeys = new List { Key }; if (ExpiredKeys != null) { decryptionKeys.AddRange(ExpiredKeys); } - var encrypted = Convert.FromBase64String(encryptedValue.EncryptedBase64Value); var cryptographicExceptions = new List(); - using (var rijndael = new RijndaelManaged()) - { - rijndael.IV = Convert.FromBase64String(encryptedValue.Base64Iv); - rijndael.Mode = CipherMode.CBC; - foreach (var key in decryptionKeys) + foreach (var key in decryptionKeys) + { + try { - rijndael.Key = key; - try - { - return Decrypt(rijndael, encrypted); - } - catch (CryptographicException exception) - { - cryptographicExceptions.Add(exception); - } + return Decrypt(encryptedValue, key); + } + catch (CryptographicException exception) + { + cryptographicExceptions.Add(exception); } } var message = string.Format("Could not decrypt message. Tried {0} keys.", decryptionKeys.Count); throw new AggregateException(message, cryptographicExceptions); } - static string Decrypt(RijndaelManaged rijndael, byte[] encrypted) + + static string Decrypt(EncryptedValue encryptedValue, byte[] key) { - using (var decryptor = rijndael.CreateDecryptor()) - using (var memoryStream = new MemoryStream(encrypted)) - using (var cryptoStream = new CryptoStream(memoryStream, decryptor, CryptoStreamMode.Read)) - using (var reader = new StreamReader(cryptoStream)) + using (var rijndael = new RijndaelManaged()) { - return reader.ReadToEnd(); + var encrypted = Convert.FromBase64String(encryptedValue.EncryptedBase64Value); + rijndael.IV = Convert.FromBase64String(encryptedValue.Base64Iv); + rijndael.Mode = CipherMode.CBC; + rijndael.Key = key; + using (var decryptor = rijndael.CreateDecryptor()) + using (var memoryStream = new MemoryStream(encrypted)) + using (var cryptoStream = new CryptoStream(memoryStream, decryptor, CryptoStreamMode.Read)) + using (var reader = new StreamReader(cryptoStream)) + { + return reader.ReadToEnd(); + } } } @@ -99,6 +100,29 @@ EncryptedValue IEncryptionService.Encrypt(string value) } } - private static readonly ILog Logger = LogManager.GetLogger(typeof (EncryptionService)); + internal void VerifyKeysAreNotTooSimilar() + { + for (var index = 0; index < ExpiredKeys.Count; index++) + { + var decryption = ExpiredKeys[index]; + CryptographicException exception = null; + var encryptedValue = ((IEncryptionService)this).Encrypt("a"); + try + { + Decrypt(encryptedValue, decryption); + } + catch (CryptographicException cryptographicException) + { + exception = cryptographicException; + } + if (exception == null) + { + var message = string.Format("The new Encryption Key is too similar to the Expired Key at index {0}. This can cause issues when decrypting data. To fix this issue please ensure the new encryption key is not too similar to the existing Expired Keys.", index); + throw new Exception(message); + } + } + } + + static readonly ILog Logger = LogManager.GetLogger(typeof(EncryptionService)); } -} +} \ No newline at end of file