Example #1
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);
        }
    }
Example #2
0
    public void StreamingCipherKeyRetainsStateAcrossOperations_Encrypt()
    {
        // NetFX doesn't support RC4. If another streaming cipher is ever added to the suite,
        // this test should be modified to use that cipher to test the NetFx PCL wrapper for
        // streaming cipher behavior.
        SymmetricAlgorithmName         symmetricAlgorithm = SymmetricAlgorithmName.Rc4;
        SymmetricAlgorithmMode         mode              = SymmetricAlgorithmMode.Streaming;
        SymmetricAlgorithmPadding      padding           = SymmetricAlgorithmPadding.None;
        ISymmetricKeyAlgorithmProvider?algorithmProvider = WinRTCrypto.SymmetricKeyAlgorithmProvider.OpenAlgorithm(symmetricAlgorithm, mode, padding);
        int keyLength = GetKeyLength(symmetricAlgorithm, algorithmProvider);

        byte[]            keyMaterial = WinRTCrypto.CryptographicBuffer.GenerateRandom(keyLength);
        ICryptographicKey?key1        = algorithmProvider.CreateSymmetricKey(keyMaterial);
        ICryptographicKey?key2        = algorithmProvider.CreateSymmetricKey(keyMaterial);

        byte[] allData       = new byte[] { 1, 2, 3 };
        byte[] allCiphertext = WinRTCrypto.CryptographicEngine.Encrypt(key1, allData);

        var cipherStream = new MemoryStream();

        for (int i = 0; i < allData.Length; i++)
        {
            byte[] cipherText = WinRTCrypto.CryptographicEngine.Encrypt(key2, new byte[] { allData[i] });
            cipherStream.Write(cipherText, 0, cipherText.Length);
        }

        byte[] incrementalResult = cipherStream.ToArray();
        Assert.Equal(
            Convert.ToBase64String(allCiphertext),
            Convert.ToBase64String(incrementalResult));
    }
Example #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;
        }

        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="CryptoTransformAdaptor"/> 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>
 /// <param name="transform">The transform.</param>
 internal CryptoTransformAdaptor(SymmetricAlgorithmName name, SymmetricAlgorithmMode mode, SymmetricAlgorithmPadding padding, Cipher transform)
 {
     Requires.NotNull(transform, "transform");
     this.name      = name;
     this.mode      = mode;
     this.padding   = padding;
     this.transform = transform;
 }
 /// <summary>
 /// Initializes a new instance of the <see cref="SymmetricCryptographicKey"/> class.
 /// </summary>
 /// <param name="algorithm">The algorithm, initialized with the key.</param>
 /// <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>
 internal SymmetricCryptographicKey(Platform.SymmetricAlgorithm algorithm, SymmetricAlgorithmName name, SymmetricAlgorithmMode mode, SymmetricAlgorithmPadding padding)
 {
     Requires.NotNull(algorithm, "algorithm");
     this.algorithm = algorithm;
     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;
        }
Example #7
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;
        }
Example #8
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)
        {
            this.Name    = name;
            this.Mode    = mode;
            this.Padding = padding;

            // Try opening the algorithm now to throw any exceptions that it may.
            using (this.OpenAlgorithm())
            {
            }
        }
Example #9
0
        /// <summary>
        /// Gets the block size (in bytes) for the specified algorithm.
        /// </summary>
        /// <param name="mode">The algorithm mode.</param>
        /// <param name="algorithm">The platform-specific algorithm.</param>
        /// <returns>The block size (in bytes).</returns>
        internal static int GetBlockSize(SymmetricAlgorithmMode mode, Cipher algorithm)
        {
            Requires.NotNull(algorithm, nameof(algorithm));

            if (algorithm.BlockSize == 0 && mode == SymmetricAlgorithmMode.Streaming)
            {
                // This is a streaming cipher without a block size. Return 1 to emulate behavior of other platforms.
                return(1);
            }

            return(algorithm.BlockSize);
        }
Example #10
0
        /// <summary>
        /// Finds a composite <see cref="SymmetricAlgorithm"/> for the specified unit parts, if one exists.
        /// </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>
        /// <param name="algorithm">Receives the composite algorithm enum value, if one exists.</param>
        /// <returns><c>true</c> if a match was found; otherwise <c>false</c>.</returns>
        public static bool TryAssemblyAlgorithm(SymmetricAlgorithmName name, SymmetricAlgorithmMode mode, SymmetricAlgorithmPadding padding, out SymmetricAlgorithm algorithm)
        {
            foreach (SymmetricAlgorithm assembled in Enum.GetValues(typeof(SymmetricAlgorithm)))
            {
                if (assembled.GetName() == name && assembled.GetMode() == mode && assembled.GetPadding() == padding)
                {
                    algorithm = assembled;
                    return(true);
                }
            }

            algorithm = (SymmetricAlgorithm)0;
            return(false);
        }
Example #11
0
        /// <summary>
        /// Gets the platform enum value for the block mode used by the specified algorithm.
        /// </summary>
        /// <param name="mode">The algorithm mode.</param>
        /// <returns>The platform-specific enum value describing the block mode.</returns>
        private static Platform.CipherMode GetMode(SymmetricAlgorithmMode mode)
        {
            switch (mode)
            {
            case SymmetricAlgorithmMode.Cbc:
                return(Platform.CipherMode.CBC);

            case SymmetricAlgorithmMode.Ecb:
                return(Platform.CipherMode.ECB);

            default:
                throw new NotSupportedException();
            }
        }
Example #12
0
    public void LegalKeySizes(SymmetricAlgorithmName name, int minSize, int maxSize, int stepSize)
    {
        SymmetricAlgorithmMode         blockMode = name.IsBlockCipher() ? SymmetricAlgorithmMode.Cbc : SymmetricAlgorithmMode.Streaming;
        SymmetricAlgorithmPadding      padding   = name.IsBlockCipher() ? SymmetricAlgorithmPadding.PKCS7 : SymmetricAlgorithmPadding.None;
        ISymmetricKeyAlgorithmProvider provider  = WinRTCrypto.SymmetricKeyAlgorithmProvider.OpenAlgorithm(name, blockMode, padding);
        IReadOnlyList <KeySizes>?      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 (KeySizes 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
        }

        KeySizes range = result.Single();
        Assert.Equal(minSize, range.MinSize);
        Assert.Equal(maxSize, range.MaxSize);
        Assert.Equal(stepSize, range.StepSize);
    }
        /// <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)
        {
            this.Name = name;
            this.Mode = mode;
            this.Padding = padding;

            this.Algorithm = BCryptOpenAlgorithmProvider(GetAlgorithmName(name));
            try
            {
                BCryptSetProperty(this.Algorithm, PropertyNames.BCRYPT_CHAINING_MODE, GetChainingMode(mode));
            }
            catch (PInvoke.Win32Exception ex)
            {
                throw new ArgumentException(ex.Message, ex);
            }
        }
        /// <summary>
        /// Gets a value indicating whether the specified block mode requires an initialization vector.
        /// </summary>
        /// <param name="mode">The block mode to check.</param>
        /// <returns><c>true</c> if the block mode uses an initialization vector; <c>false</c> otherwise.</returns>
        public static bool UsesIV(this SymmetricAlgorithmMode mode)
        {
            switch (mode)
            {
            case SymmetricAlgorithmMode.Cbc:
            case SymmetricAlgorithmMode.Ccm:
            case SymmetricAlgorithmMode.Gcm:
                return(true);

            case SymmetricAlgorithmMode.Ecb:
                return(false);

            default:
                throw new ArgumentException();
            }
        }
Example #15
0
        /// <summary>
        /// Gets the BCrypt chaining mode to pass to set as the <see cref="PropertyNames.BCRYPT_CHAINING_MODE"/> property.
        /// </summary>
        /// <param name="mode">The block chaining mode.</param>
        /// <returns>The string name for the block chaining mode.</returns>
        private static string GetChainingMode(SymmetricAlgorithmMode mode)
        {
            switch (mode)
            {
            case SymmetricAlgorithmMode.Streaming: return(ChainingModes.NotApplicable);

            case SymmetricAlgorithmMode.Cbc: return(ChainingModes.Cbc);

            case SymmetricAlgorithmMode.Ecb: return(ChainingModes.Ecb);

            case SymmetricAlgorithmMode.Ccm: return(ChainingModes.Ccm);

            case SymmetricAlgorithmMode.Gcm: return(ChainingModes.Gcm);

            default: throw new NotSupportedException();
            }
        }
        /// <summary>
        /// Initializes a new instance of the <see cref="SymmetricCryptographicKey" /> class.
        /// </summary>
        /// <param name="provider">The provider that created this instance.</param>
        /// <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>
        /// <param name="keyMaterial">The key.</param>
        internal SymmetricCryptographicKey(SymmetricKeyAlgorithmProvider provider, SymmetricAlgorithmName name, SymmetricAlgorithmMode mode, SymmetricAlgorithmPadding padding, byte[] keyMaterial)
        {
            Requires.NotNull(provider, nameof(provider));
            Requires.NotNull(keyMaterial, nameof(keyMaterial));

            if (name == SymmetricAlgorithmName.Aes && mode == SymmetricAlgorithmMode.Ccm && padding == SymmetricAlgorithmPadding.None)
            {
                // On Android encryption misbehaves causing our unit tests to fail.
                throw new NotSupportedException();
            }

            this.provider = provider;
            this.Name = name;
            this.Mode = mode;
            this.Padding = padding;
            this.key = new SecretKeySpec(keyMaterial, this.Name.GetString());
            this.KeySize = keyMaterial.Length * 8;
        }
Example #17
0
        /// <summary>
        /// Gets a value indicating whether the specified block mode requires an initialization vector.
        /// </summary>
        /// <param name="mode">The block mode to check.</param>
        /// <returns><c>true</c> if the block mode uses an initialization vector; <c>false</c> otherwise.</returns>
        public static bool UsesIV(this SymmetricAlgorithmMode mode)
        {
            switch (mode)
            {
            case SymmetricAlgorithmMode.Cbc:
            case SymmetricAlgorithmMode.Ccm:
            case SymmetricAlgorithmMode.Gcm:
                return(true);

            case SymmetricAlgorithmMode.Ecb:
                return(false);

            case SymmetricAlgorithmMode.Streaming:
                return(false);

            default:
                throw new ArgumentOutOfRangeException(nameof(mode));
            }
        }
 /// <inheritdoc />
 public ISymmetricKeyAlgorithmProvider OpenAlgorithm(SymmetricAlgorithmName name, SymmetricAlgorithmMode mode, SymmetricAlgorithmPadding padding)
 {
     return new SymmetricKeyAlgorithmProvider(name, mode, padding);
 }
        /// <summary>
        /// Finds a composite <see cref="SymmetricAlgorithm"/> for the specified unit parts, if one exists.
        /// </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>
        /// <param name="algorithm">Receives the composite algorithm enum value, if one exists.</param>
        /// <returns><c>true</c> if a match was found; otherwise <c>false</c>.</returns>
        public static bool TryAssemblyAlgorithm(SymmetricAlgorithmName name, SymmetricAlgorithmMode mode, SymmetricAlgorithmPadding padding, out SymmetricAlgorithm algorithm)
        {
            foreach (SymmetricAlgorithm assembled in Enum.GetValues(typeof(SymmetricAlgorithm)))
            {
                if (assembled.GetName() == name && assembled.GetMode() == mode && assembled.GetPadding() == padding)
                {
                    algorithm = assembled;
                    return true;
                }
            }

            algorithm = (SymmetricAlgorithm)0;
            return false;
        }
Example #20
0
 /// <summary>
 /// Initializes a new instance of the <see cref="SymmetricCryptographicKey"/> class.
 /// </summary>
 /// <param name="algorithm">The algorithm, initialized with the key.</param>
 /// <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>
 internal SymmetricCryptographicKey(Platform.SymmetricAlgorithm algorithm, SymmetricAlgorithmName name, SymmetricAlgorithmMode mode, SymmetricAlgorithmPadding padding)
 {
     Requires.NotNull(algorithm, "algorithm");
     this.algorithm = algorithm;
     this.Name      = name;
     this.Mode      = mode;
     this.Padding   = padding;
 }
 /// <summary>
 /// Initializes a new instance of the <see cref="CryptoTransformAdaptor"/> 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>
 /// <param name="transform">The transform.</param>
 internal CryptoTransformAdaptor(SymmetricAlgorithmName name, SymmetricAlgorithmMode mode, SymmetricAlgorithmPadding padding, Cipher transform)
 {
     Requires.NotNull(transform, "transform");
     this.name = name;
     this.mode = mode;
     this.padding = padding;
     this.transform = transform;
 }
Example #22
0
 /// <summary>
 /// Gets a value indicating whether the specified mode offers authentication.
 /// </summary>
 /// <param name="mode">The mode to check.</param>
 /// <returns><c>true</c> if the cipher is an authenticating block mode cipher; <c>false</c> otherwise.</returns>
 public static bool IsAuthenticated(this SymmetricAlgorithmMode mode)
 => mode == SymmetricAlgorithmMode.Gcm || mode == SymmetricAlgorithmMode.Ccm;
Example #23
0
 /// <summary>
 /// Gets a value indicating whether the specified mode is implemented by a block cipher.
 /// </summary>
 /// <param name="mode">The mode to check.</param>
 /// <returns><c>true</c> if the cipher is a block cipher; <c>false</c> otherwise.</returns>
 public static bool IsBlockCipher(this SymmetricAlgorithmMode mode) => mode != SymmetricAlgorithmMode.Streaming;
    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));
            }
        }
    }
Example #25
0
 /// <inheritdoc />
 public ISymmetricKeyAlgorithmProvider OpenAlgorithm(SymmetricAlgorithmName name, SymmetricAlgorithmMode mode, SymmetricAlgorithmPadding padding)
 {
     return(new SymmetricKeyAlgorithmProvider(name, mode, padding));
 }
        /// <summary>
        /// Initializes a new instance of the <see cref="SymmetricCryptographicKey" /> class.
        /// </summary>
        /// <param name="provider">The provider that created this instance.</param>
        /// <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>
        /// <param name="keyMaterial">The key.</param>
        internal SymmetricCryptographicKey(SymmetricKeyAlgorithmProvider provider, SymmetricAlgorithmName name, SymmetricAlgorithmMode mode, SymmetricAlgorithmPadding padding, byte[] keyMaterial)
        {
            Requires.NotNull(provider, nameof(provider));
            Requires.NotNull(keyMaterial, nameof(keyMaterial));

            if (name == SymmetricAlgorithmName.Aes && mode == SymmetricAlgorithmMode.Ccm && padding == SymmetricAlgorithmPadding.None)
            {
                // On Android encryption misbehaves causing our unit tests to fail.
                throw new NotSupportedException();
            }

            this.provider = provider;
            this.Name     = name;
            this.Mode     = mode;
            this.Padding  = padding;
            this.key      = new SecretKeySpec(keyMaterial, this.Name.GetString());
            this.KeySize  = keyMaterial.Length * 8;
        }
        /// <summary>
        /// Gets the block size (in bytes) for the specified algorithm.
        /// </summary>
        /// <param name="mode">The algorithm mode.</param>
        /// <param name="algorithm">The platform-specific algorithm.</param>
        /// <returns>The block size (in bytes).</returns>
        internal static int GetBlockSize(SymmetricAlgorithmMode mode, Cipher algorithm)
        {
            Requires.NotNull(algorithm, "algorithm");

            if (algorithm.BlockSize == 0 && mode == SymmetricAlgorithmMode.Streaming)
            {
                // This is a streaming cipher without a block size. Return 1 to emulate behavior of other platforms.
                return 1;
            }

            return algorithm.BlockSize;
        }
 /// <summary>
 /// Gets the platform enum value for the block mode used by the specified algorithm.
 /// </summary>
 /// <param name="mode">The algorithm mode.</param>
 /// <returns>The platform-specific enum value describing the block mode.</returns>
 private static Platform.CipherMode GetMode(SymmetricAlgorithmMode mode)
 {
     switch (mode)
     {
         case SymmetricAlgorithmMode.Cbc:
             return Platform.CipherMode.CBC;
         case SymmetricAlgorithmMode.Ecb:
             return Platform.CipherMode.ECB;
         default:
             throw new NotSupportedException();
     }
 }
 /// <summary>
 /// Gets the BCrypt chaining mode to pass to set as the <see cref="PropertyNames.BCRYPT_CHAINING_MODE"/> property.
 /// </summary>
 /// <param name="mode">The block chaining mode.</param>
 /// <returns>The block chaining mode.</returns>
 private static string GetChainingMode(SymmetricAlgorithmMode mode)
 {
     switch (mode)
     {
         case SymmetricAlgorithmMode.Streaming: return ChainingModes.NotApplicable;
         case SymmetricAlgorithmMode.Cbc: return ChainingModes.Cbc;
         case SymmetricAlgorithmMode.Ecb: return ChainingModes.Ecb;
         case SymmetricAlgorithmMode.Ccm: return ChainingModes.Ccm;
         case SymmetricAlgorithmMode.Gcm: return ChainingModes.Gcm;
         default: throw new NotSupportedException();
     }
 }
Example #30
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));
            }
        }
    }