Skip to content

Commit

Permalink
VerifyKeysAreNotTooSimilar
Browse files Browse the repository at this point in the history
  • Loading branch information
SimonCropp committed Aug 18, 2014
1 parent 885741c commit bef9609
Show file tree
Hide file tree
Showing 3 changed files with 71 additions and 28 deletions.
13 changes: 13 additions & 0 deletions src/NServiceBus.Core.Tests/Encryption/EncryptionServiceTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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<byte[]> { key } //note that we use the same key to get the code to throw
};
var exception = Assert.Throws<Exception>(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);
}
}
}
14 changes: 10 additions & 4 deletions src/NServiceBus.Core/ConfigureRijndaelEncryptionService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ namespace NServiceBus
using System.Linq;
using System.Text;
using Config;
using Encryption;
using Encryption.Rijndael;
using Logging;

Expand All @@ -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<EncryptionService>(DependencyLifecycle.SingleInstance);
var encryptionService = new EncryptionService();

if (section != null)
{
Expand All @@ -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<IEncryptionService>(encryptionService);

return config;
}

Expand Down Expand Up @@ -68,4 +74,4 @@ internal static List<string> ExtractExpiredKeysFromConfigSection(RijndaelEncrypt
}
private static readonly ILog Logger = LogManager.GetLogger(typeof(RijndaelEncryptionServiceConfig));
}
}
}
72 changes: 48 additions & 24 deletions src/NServiceBus.Core/Encryption/Rijndael/EncryptionService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -31,42 +31,43 @@ string IEncryptionService.Decrypt(EncryptedValue encryptedValue)
return encryptedValue.EncryptedBase64Value;
}

var decryptionKeys = new List<byte[]>{Key};
var decryptionKeys = new List<byte[]> { Key };
if (ExpiredKeys != null)
{
decryptionKeys.AddRange(ExpiredKeys);
}
var encrypted = Convert.FromBase64String(encryptedValue.EncryptedBase64Value);
var cryptographicExceptions = new List<CryptographicException>();
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();
}
}
}

Expand Down Expand Up @@ -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));
}
}
}

0 comments on commit bef9609

Please sign in to comment.