public void StreamingCipherKeyRetainsStateAcrossOperations_Decrypt() { // 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; ISymmetricKeyAlgorithmProvider?algorithmProvider = WinRTCrypto.SymmetricKeyAlgorithmProvider.OpenAlgorithm(symmetricAlgorithm, SymmetricAlgorithmMode.Streaming, SymmetricAlgorithmPadding.None); 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.Decrypt(key1, allData); var cipherStream = new MemoryStream(); for (int i = 0; i < allData.Length; i++) { byte[] cipherText = WinRTCrypto.CryptographicEngine.Decrypt(key2, new byte[] { allData[i] }); cipherStream.Write(cipherText, 0, cipherText.Length); } byte[] incrementalResult = cipherStream.ToArray(); Assert.Equal( Convert.ToBase64String(allCiphertext), Convert.ToBase64String(incrementalResult)); }
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); } } }
public CertificateOutputViewModel(byte[] signature, byte[] data, byte[] key, HashAlgorithmName hash, SymmetricAlgorithmName sym, SymmetricAlgorithmKey symKey, AsymmetricAlgorithmName alg, AsymmetricAlgorithmKey algKey, string file) { this.Description = "Certificate"; this.EnvelopeData = Convert.ToBase64String(data); this.EnvelopeCryptKey = key.ConvertToHex(); this.Signature = signature.ConvertToHex(); this.Methods = new List <string>() { hash.ToString(), sym.ToString(), alg.ToString() }; this.Method = string.Join("\n", Methods); this.KeyLengths = new List <string>() { "", ((int)symKey).ToString("X"), // hex ((int)algKey).ToString("X") // hex }; this.KeyLength = string.Join("\n", KeyLengths); this.FileName = file; }
/// <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; }
/// <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()) { } }
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); }
/// <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); }
/// <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 algorithm is implemented by a block cipher. /// </summary> /// <param name="algorithm">The algorithm to check.</param> /// <returns><c>true</c> if the cipher is a block cipher; <c>false</c> otherwise.</returns> public static bool IsBlockCipher(this SymmetricAlgorithmName algorithm) { switch (algorithm) { case SymmetricAlgorithmName.Aes: case SymmetricAlgorithmName.Des: case SymmetricAlgorithmName.TripleDes: case SymmetricAlgorithmName.Rc2: return(true); case SymmetricAlgorithmName.Rc4: return(false); default: throw new NotSupportedException(); } }
private static int GetKeyLength(SymmetricAlgorithmName symmetricAlgorithm, ISymmetricKeyAlgorithmProvider algorithmProvider) { int keyLength; switch (symmetricAlgorithm) { case SymmetricAlgorithmName.TripleDes: keyLength = algorithmProvider.BlockLength * 3; break; default: keyLength = algorithmProvider.BlockLength; break; } return(keyLength); }
private static ISymmetricCryptoAlgorithm GetSymmetricAlgorithm(this SymmetricAlgorithmName name, SymmetricAlgorithmKey keySize, System.Security.Cryptography.CipherMode mode) { switch (name) { case SymmetricAlgorithmName.TripleDES: return(new TripleDES(keySize: (int)keySize, mode: mode)); break; case SymmetricAlgorithmName.AES: default: return(new AES(keySize: (int)keySize, mode: mode)); break; } }
/// <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; }
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)); } } }
/// <summary> /// Gets the string representation of an algorithm name. /// </summary> /// <param name="algorithm">The algorithm.</param> /// <returns>A non-empty string, such as "AES".</returns> public static string GetString(this SymmetricAlgorithmName algorithm) { switch (algorithm) { case SymmetricAlgorithmName.Aes: return("AES"); case SymmetricAlgorithmName.Des: return("DES"); case SymmetricAlgorithmName.Rc2: return("RC2"); case SymmetricAlgorithmName.Rc4: return("RC4"); case SymmetricAlgorithmName.TripleDes: return("TRIPLEDES"); default: throw new ArgumentException(); } }
/// <summary> /// Returns the string to pass to the platform APIs for a given algorithm. /// </summary> /// <param name="algorithm">The algorithm desired.</param> /// <returns>The platform-specific string to pass to OpenAlgorithm.</returns> private static string GetAlgorithmName(SymmetricAlgorithmName algorithm) { switch (algorithm) { case SymmetricAlgorithmName.Aes: return(AlgorithmIdentifiers.BCRYPT_AES_ALGORITHM); case SymmetricAlgorithmName.Des: return(AlgorithmIdentifiers.BCRYPT_DES_ALGORITHM); case SymmetricAlgorithmName.TripleDes: return(AlgorithmIdentifiers.BCRYPT_3DES_ALGORITHM); case SymmetricAlgorithmName.Rc2: return(AlgorithmIdentifiers.BCRYPT_RC2_ALGORITHM); case SymmetricAlgorithmName.Rc4: return(AlgorithmIdentifiers.BCRYPT_RC4_ALGORITHM); default: throw new NotSupportedException(); } }
/// <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; }
private static int GetKeyLength(SymmetricAlgorithmName symmetricAlgorithm, ISymmetricKeyAlgorithmProvider algorithmProvider) { int keyLength; switch (symmetricAlgorithm) { case SymmetricAlgorithmName.TripleDes: keyLength = algorithmProvider.BlockLength * 3; break; default: keyLength = algorithmProvider.BlockLength; break; } return keyLength; }
/// <inheritdoc /> public ISymmetricKeyAlgorithmProvider OpenAlgorithm(SymmetricAlgorithmName name, SymmetricAlgorithmMode mode, SymmetricAlgorithmPadding padding) { return(new SymmetricKeyAlgorithmProvider(name, mode, padding)); }
/// <summary> /// Gets the BCrypt algorithm identifier to pass to <see cref="BCryptOpenAlgorithmProvider(string, string, BCryptOpenAlgorithmProviderFlags)"/>. /// </summary> /// <param name="algorithm">The algorithm.</param> /// <returns>The algorithm identifier.</returns> private static string GetAlgorithmIdentifier(SymmetricAlgorithmName algorithm) { switch (algorithm) { case SymmetricAlgorithmName.Aes: return AlgorithmIdentifiers.BCRYPT_AES_ALGORITHM; case SymmetricAlgorithmName.Des: return AlgorithmIdentifiers.BCRYPT_DES_ALGORITHM; case SymmetricAlgorithmName.TripleDes: return AlgorithmIdentifiers.BCRYPT_3DES_ALGORITHM; case SymmetricAlgorithmName.Rc2: return AlgorithmIdentifiers.BCRYPT_RC2_ALGORITHM; case SymmetricAlgorithmName.Rc4: return AlgorithmIdentifiers.BCRYPT_RC4_ALGORITHM; default: throw new NotSupportedException(); } }