public void LegalKeySizes(SymmetricAlgorithmName name, int minSize, int maxSize, int stepSize) { var blockMode = name.IsBlockCipher() ? SymmetricAlgorithmMode.Cbc : SymmetricAlgorithmMode.Streaming; var padding = name.IsBlockCipher() ? SymmetricAlgorithmPadding.PKCS7 : SymmetricAlgorithmPadding.None; using (ISymmetricKeyAlgorithmProvider provider = WinRTCrypto.SymmetricKeyAlgorithmProvider.OpenAlgorithm(name, blockMode, padding)) { var result = provider.LegalKeySizes; Assert.NotNull(result); Assert.NotEmpty(result); var random = new Random(); Action<int> attemptKeySize = size => { var keyMaterial = new byte[size / 8]; random.NextBytes(keyMaterial); // some algorithms check against weak keys (e.g. all zeros) provider.CreateSymmetricKey(keyMaterial).Dispose(); }; // Verify that each allegedly legal key size actually works. foreach (var item in result) { this.logger.WriteLine($"{item.MinSize}-{item.MaxSize} ({item.StepSize})"); foreach (var keySize in item) { attemptKeySize(keySize); } // Also check the cases just off the edges of the range to see that they actually fail. // This ensures the returned values aren't too conservative. #if false // WinRT actually doesn't throw when given keys of inappropriate size. Go figure. if (item.StepSize > 0) { if (item.MinSize - item.StepSize > 0) { Assert.Throws<ArgumentException>(() => attemptKeySize(item.MinSize - item.StepSize)); } if (item.MaxSize + item.StepSize > 0) { Assert.Throws<ArgumentException>(() => attemptKeySize(item.MaxSize + item.StepSize)); } } #endif } var range = result.Single(); Assert.Equal(minSize, range.MinSize); Assert.Equal(maxSize, range.MaxSize); Assert.Equal(stepSize, range.StepSize); } }
public void LegalKeySizes(SymmetricAlgorithmName name, int minSize, int maxSize, int stepSize) { var blockMode = name.IsBlockCipher() ? SymmetricAlgorithmMode.Cbc : SymmetricAlgorithmMode.Streaming; var padding = name.IsBlockCipher() ? SymmetricAlgorithmPadding.PKCS7 : SymmetricAlgorithmPadding.None; ISymmetricKeyAlgorithmProvider provider = WinRTCrypto.SymmetricKeyAlgorithmProvider.OpenAlgorithm(name, blockMode, padding); var result = provider.LegalKeySizes; Assert.NotNull(result); Assert.NotEmpty(result); var random = new Random(); Action <int> attemptKeySize = size => { var keyMaterial = new byte[size / 8]; random.NextBytes(keyMaterial); // some algorithms check against weak keys (e.g. all zeros) provider.CreateSymmetricKey(keyMaterial).Dispose(); }; // Verify that each allegedly legal key size actually works. foreach (var item in result) { this.logger.WriteLine($"{item.MinSize}-{item.MaxSize} ({item.StepSize})"); foreach (var keySize in item) { attemptKeySize(keySize); } // Also check the cases just off the edges of the range to see that they actually fail. // This ensures the returned values aren't too conservative. #if false // WinRT actually doesn't throw when given keys of inappropriate size. Go figure. if (item.StepSize > 0) { if (item.MinSize - item.StepSize > 0) { Assert.Throws <ArgumentException>(() => attemptKeySize(item.MinSize - item.StepSize)); } if (item.MaxSize + item.StepSize > 0) { Assert.Throws <ArgumentException>(() => attemptKeySize(item.MaxSize + item.StepSize)); } } #endif } var range = result.Single(); Assert.Equal(minSize, range.MinSize); Assert.Equal(maxSize, range.MaxSize); Assert.Equal(stepSize, range.StepSize); }
public void SymmetricEncryption(SymmetricAlgorithmName name, SymmetricAlgorithmMode mode, SymmetricAlgorithmPadding padding) { Skip.If(mode.IsAuthenticated(), "This test is only for non-authenticated block modes."); bool badCombination = false; badCombination |= !mode.IsBlockCipher() && padding != SymmetricAlgorithmPadding.None; // Padding does not apply to streaming ciphers. badCombination |= name.IsBlockCipher() != mode.IsBlockCipher(); // Incompatible cipher and block mode. Func <ISymmetricKeyAlgorithmProvider> creator = () => WinRTCrypto.SymmetricKeyAlgorithmProvider.OpenAlgorithm(name, mode, padding); if (badCombination) { Assert.Throws <ArgumentException>(creator); this.logger.WriteLine("Expected exception thrown for invalid combination."); return; } var algorithm = creator(); int keyLength = algorithm.LegalKeySizes.First().MinSize; var keyMaterial = WinRTCrypto.CryptographicBuffer.GenerateRandom(keyLength / 8); using (var key = algorithm.CreateSymmetricKey(keyMaterial)) { var ciphertext = WinRTCrypto.CryptographicEngine.Encrypt(key, new byte[algorithm.BlockLength], null); Assert.NotEmpty(ciphertext); } }
public void SymmetricEncryption(SymmetricAlgorithmName name, SymmetricAlgorithmMode mode, SymmetricAlgorithmPadding padding) { Skip.If(mode.IsAuthenticated(), "This test is only for non-authenticated block modes."); bool badCombination = false; badCombination |= !mode.IsBlockCipher() && padding != SymmetricAlgorithmPadding.None; // Padding does not apply to streaming ciphers. badCombination |= name.IsBlockCipher() != mode.IsBlockCipher(); // Incompatible cipher and block mode. Func<ISymmetricKeyAlgorithmProvider> creator = () => WinRTCrypto.SymmetricKeyAlgorithmProvider.OpenAlgorithm(name, mode, padding); if (badCombination) { Assert.Throws<ArgumentException>(creator); this.logger.WriteLine("Expected exception thrown for invalid combination."); return; } using (var algorithm = creator()) { int keyLength = algorithm.LegalKeySizes.First().MinSize; var keyMaterial = WinRTCrypto.CryptographicBuffer.GenerateRandom(keyLength / 8); using (var key = algorithm.CreateSymmetricKey(keyMaterial)) { var ciphertext = WinRTCrypto.CryptographicEngine.Encrypt(key, new byte[algorithm.BlockLength], null); Assert.NotEqual(0, ciphertext.Length); } } }
/// <summary> /// Initializes a new instance of the <see cref="SymmetricKeyAlgorithmProvider"/> class. /// </summary> /// <param name="name">The name of the base algorithm to use.</param> /// <param name="mode">The algorithm's mode (i.e. streaming or some block mode).</param> /// <param name="padding">The padding to use.</param> public SymmetricKeyAlgorithmProvider(SymmetricAlgorithmName name, SymmetricAlgorithmMode mode, SymmetricAlgorithmPadding padding) { Requires.Argument(mode.IsBlockCipher() == name.IsBlockCipher(), nameof(mode), "Block chaining mode incompatible with cipher. Don't mix streaming and non-streaming ciphers and modes."); Requires.Argument(padding == SymmetricAlgorithmPadding.None || mode.IsBlockCipher(), nameof(padding), "Padding does not apply to streaming ciphers."); this.Name = name; this.Mode = mode; this.Padding = padding; }
/// <summary> /// Initializes a new instance of the <see cref="SymmetricKeyAlgorithmProvider"/> class. /// </summary> /// <param name="name">The name of the base algorithm to use.</param> /// <param name="mode">The algorithm's mode (i.e. streaming or some block mode).</param> /// <param name="padding">The padding to use.</param> public SymmetricKeyAlgorithmProvider(SymmetricAlgorithmName name, SymmetricAlgorithmMode mode, SymmetricAlgorithmPadding padding) { Requires.Argument(mode.IsBlockCipher() == name.IsBlockCipher(), nameof(mode), "Block chaining mode incompatible with cipher. Don't mix streaming and non-streaming ciphers and modes."); Requires.Argument(padding == SymmetricAlgorithmPadding.None || mode.IsBlockCipher(), nameof(padding), "Padding does not apply to streaming ciphers."); this.Name = name; this.Mode = mode; this.Padding = padding; }
public void CreateEncryptor_SymmetricEncryptionEquivalence(SymmetricAlgorithmName name, SymmetricAlgorithmMode mode, SymmetricAlgorithmPadding padding) { Skip.If(!name.IsBlockCipher() && padding != SymmetricAlgorithmPadding.None, "By design - streaming ciphers need no padding."); var algorithmProvider = WinRTCrypto.SymmetricKeyAlgorithmProvider.OpenAlgorithm(name, mode, padding); int keyLength = GetKeyLength(name, algorithmProvider); byte[] keyMaterial = WinRTCrypto.CryptographicBuffer.GenerateRandom(keyLength); var key1 = algorithmProvider.CreateSymmetricKey(keyMaterial); var key2 = algorithmProvider.CreateSymmetricKey(keyMaterial); // create a second key so that streaming ciphers will be produce the same result when executed the second time var iv = mode.UsesIV() ? WinRTCrypto.CryptographicBuffer.GenerateRandom(algorithmProvider.BlockLength) : null; float incrementBy = padding == SymmetricAlgorithmPadding.None ? 1 : 0.5f; for (float dataLengthFactor = 1; dataLengthFactor <= 3; dataLengthFactor += incrementBy) { var data = WinRTCrypto.CryptographicBuffer.GenerateRandom((int)(dataLengthFactor * algorithmProvider.BlockLength)); var expected = WinRTCrypto.CryptographicEngine.Encrypt(key1, data, iv); var encryptor = WinRTCrypto.CryptographicEngine.CreateEncryptor(key2, iv); var actualStream = new MemoryStream(); using (var cryptoStream = CryptoStream.WriteTo(actualStream, encryptor)) { // Write it in smaller than block length chunks so we're exercising more product code. int chunkSize = Math.Max(1, (int)(data.Length / Math.Max(1, dataLengthFactor + 1))); for (int dataOffset = 0; dataOffset < data.Length; dataOffset += chunkSize) { cryptoStream.Write(data, dataOffset, Math.Min(chunkSize, data.Length - dataOffset)); } cryptoStream.FlushFinalBlock(); byte[] actual = actualStream.ToArray(); Assert.Equal( Convert.ToBase64String(expected), Convert.ToBase64String(actual)); } } }
public void CreateEncryptor_SymmetricEncryptionEquivalence(SymmetricAlgorithmName name, SymmetricAlgorithmMode mode, SymmetricAlgorithmPadding padding) { Skip.If(!name.IsBlockCipher() && padding != SymmetricAlgorithmPadding.None, "By design - streaming ciphers need no padding."); var algorithmProvider = WinRTCrypto.SymmetricKeyAlgorithmProvider.OpenAlgorithm(name, mode, padding); int keyLength = GetKeyLength(name, algorithmProvider); byte[] keyMaterial = WinRTCrypto.CryptographicBuffer.GenerateRandom(keyLength); var key1 = algorithmProvider.CreateSymmetricKey(keyMaterial); var key2 = algorithmProvider.CreateSymmetricKey(keyMaterial); // create a second key so that streaming ciphers will be produce the same result when executed the second time var iv = mode.UsesIV() ? WinRTCrypto.CryptographicBuffer.GenerateRandom(algorithmProvider.BlockLength) : null; float incrementBy = padding == SymmetricAlgorithmPadding.None ? 1 : 0.5f; for (float dataLengthFactor = 1; dataLengthFactor <= 3; dataLengthFactor += incrementBy) { var data = WinRTCrypto.CryptographicBuffer.GenerateRandom((int)(dataLengthFactor * algorithmProvider.BlockLength)); var expected = WinRTCrypto.CryptographicEngine.Encrypt(key1, data, iv); var encryptor = WinRTCrypto.CryptographicEngine.CreateEncryptor(key2, iv); var actualStream = new MemoryStream(); using (var cryptoStream = CryptoStream.WriteTo(actualStream, encryptor)) { // Write it in smaller than block length chunks so we're exercising more product code. int chunkSize = Math.Max(1, (int)(data.Length / Math.Max(1, dataLengthFactor + 1))); for (int dataOffset = 0; dataOffset < data.Length; dataOffset += chunkSize) { cryptoStream.Write(data, dataOffset, Math.Min(chunkSize, data.Length - dataOffset)); } cryptoStream.FlushFinalBlock(); byte[] actual = actualStream.ToArray(); Assert.Equal( Convert.ToBase64String(expected), Convert.ToBase64String(actual)); } } }