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);
        }
    }
Esempio n. 2
0
    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);
    }
Esempio n. 3
0
    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);
        }
    }
Esempio n. 4
0
    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);
            }
        }
    }
Esempio n. 5
0
        /// <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;
        }
Esempio n. 7
0
    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));
            }
        }
    }