/// <summary> /// Returns <c>true</c> if the key string passed is a valid XML key /// and is NOT a key container name. /// </summary> /// <param name="algorithm">The asymmetric algorithm.</param> /// <param name="key">The key string to be tested.</param> /// <returns><c>true</c> if the key is a valid XML key.</returns> /// <remarks> /// The current implementation supports only the "RSA" provider. /// </remarks> public static bool IsXmlKey(string algorithm, string key) { AsymmetricAlgorithm asymmetric = null; try { if (ParseKeyContainer(key) != null) { return(false); } asymmetric = EncryptionConfig.CreateAsymmetric(algorithm, 0); asymmetric.FromXmlString(key); return(true); } catch { return(false); } finally { if (asymmetric != null) { asymmetric.Clear(); } } }
/// <summary> /// Generates a symmetric encryption key of the given size and algorithm /// from a shared secret and optional cryptographic salt. /// </summary> /// <param name="algorithm">The algorithm name.</param> /// <param name="keySize">The desired key size in bits.</param> /// <param name="secret">The shared secret as a byta array.</param> /// <param name="salt">An optional array of at least 8 salt bytes or <c>null</c>.</param> /// <returns>The <see cref="SymmetricKey" />.</returns> /// <exception cref="ArgumentException">Thrown if <paramref name="salt" /> is not <c>null</c> and contains less than 8 bytes of salt.</exception> /// <remarks> /// <para> /// This method is useful for situations where two endpoints wish to communicate /// securely when they each know a shared secret such as a password or the hash /// of a password. /// </para> /// <note> /// Endpoints that wish to generate a key from a password string should use /// a text <see cref="Encoding"/> to convert the string into bytes. Note also /// that the endpoints will need to agree on the same salt bytes to make sure /// that the same key is generated on both ends. /// </note> /// <note> /// If <paramref name="salt" /> is passed as <c>null</c> then the class will use /// 8 bytes of built-in salt instead. /// </note> /// </remarks> public static SymmetricKey GenerateSymmetricKeyFromSecret(string algorithm, int keySize, byte[] secret, byte[] salt) { if (salt != null && salt.Length < 8) { throw new ArgumentException("At least eight bytes of cryptographic salt is required.", "salt"); } if (String.Compare(algorithm, CryptoAlgorithm.PlainText, StringComparison.OrdinalIgnoreCase) == 0) { return(new SymmetricKey(CryptoAlgorithm.PlainText, new byte[keySize], new byte[0])); } SymmetricAlgorithm symmetric = EncryptionConfig.CreateSymmetric(algorithm); Rfc2898DeriveBytes key; if (salt == null) { salt = new byte[] { 0x89, 0x55, 0x71, 0xEA, 0xD3, 0x16, 0x87, 0xFF } } ; key = new Rfc2898DeriveBytes(secret, salt, 3); try { symmetric.KeySize = keySize; return(new SymmetricKey(algorithm, key.GetBytes(symmetric.KeySize / 8), key.GetBytes(symmetric.BlockSize / 8))); } finally { symmetric.Clear(); } }
/// <summary> /// Generates a symmetric encryption key and initialization vector /// of a given size for the specified encryption algorithm. /// </summary> /// <param name="algorithm">The algorithm name.</param> /// <param name="keySize">The desired key size in bits.</param> /// <param name="key">Returns as the generated key.</param> /// <param name="IV">Returns as the generated initialization vector.</param> /// <remarks> /// The current supported cross platform encryption algorithms /// are: "DES", "RC2", "TripleDES", and "AES" (Rijndael). /// </remarks> public static void GenerateSymmetricKey(string algorithm, int keySize, out byte[] key, out byte[] IV) { if (String.Compare(algorithm, CryptoAlgorithm.PlainText, StringComparison.OrdinalIgnoreCase) == 0) { key = new byte[keySize]; IV = new byte[0]; return; } var symmetric = EncryptionConfig.CreateSymmetric(algorithm); try { symmetric.KeySize = keySize; symmetric.GenerateKey(); symmetric.GenerateIV(); key = symmetric.Key; IV = symmetric.IV; } finally { symmetric.Clear(); } }
/// <summary> /// Returns the valid key sizes in bits for the specified encryption algorithm. /// </summary> /// <param name="algorithm">The algorithm name.</param> /// <returns>The array of possible key sizes in bits sorted in decending order.</returns> public static int[] GetValidKeySizes(string algorithm) { EncryptionConfig config = null; for (int i = 0; i < platformSymmetric.Length; i++) { if (String.Compare(algorithm, platformSymmetric[i].Algorithm, StringComparison.OrdinalIgnoreCase) == 0) { config = platformSymmetric[i]; break; } } for (int i = 0; i < platformAsymmetric.Length; i++) { if (String.Compare(algorithm, platformAsymmetric[i].Algorithm, StringComparison.OrdinalIgnoreCase) == 0) { config = platformAsymmetric[i]; break; } } if (config == null) { throw new ArgumentException(Crypto.UnknownAlgorithm); } return(config.KeySizes); }
/// <summary> /// Initializes the decryptor to use the specified encryption algorithm, /// key, and initialization vector. /// </summary> /// <param name="algorithm">The symmetric algorithm name.</param> /// <param name="key">The encryption key.</param> /// <param name="IV">The initialization vector.</param> public BlockDecryptor(string algorithm, byte[] key, byte[] IV) { this.algorithm = algorithm; this.key = key; this.IV = IV; this.provider = EncryptionConfig.CreateSymmetric(algorithm); this.provider.Key = key; this.provider.IV = IV; this.decryptor = null; }
/// <summary> /// Generates an asymmetric private key and returns the result as XML. /// </summary> /// <param name="algorithm">The asymmetric algorithm name.</param> /// <param name="keySize">The key size in bits.</param> /// <returns>The private key encoded as XML.</returns> /// <remarks> /// The current implementation supports only the "RSA" provider. /// </remarks> public static string CreatePrivateKey(string algorithm, int keySize) { var asymmetric = EncryptionConfig.CreateAsymmetric(algorithm, keySize); try { return(asymmetric.ToXmlString(true)); } finally { asymmetric.Clear(); } }
/// <summary> /// Returns the public key for a private key. /// </summary> /// <param name="algorithm">The asymmetric algorithm.</param> /// <param name="privateKeyXml">The private key encoded as XML.</param> /// <returns>The public key encoded as XML.</returns> /// <remarks> /// The current implementation supports only the "RSA" provider. /// </remarks> public static string GetPublicKey(string algorithm, string privateKeyXml) { var asymmetric = EncryptionConfig.CreateAsymmetric(algorithm, 0); try { asymmetric.FromXmlString(privateKeyXml); return(asymmetric.ToXmlString(false)); } finally { asymmetric.Clear(); } }
static EncryptionConfig() { platformSymmetric = new EncryptionConfig[] { EncryptionConfig.Parse("PlainText:0"), EncryptionConfig.Parse("RC2:128,120,112,104,96,88,80,72,64,56,48,40"), EncryptionConfig.Parse("TripleDES:192,128"), EncryptionConfig.Parse("DES:64"), EncryptionConfig.Parse("AES:256,192,128"), }; platformAsymmetric = new EncryptionConfig[] { EncryptionConfig.Parse("RSA:4096,2048,1024,512") }; }
/// <summary> /// Returns the largest valid key size (expressed in bits) for the /// algorithm specified. /// </summary> /// <param name="algorithm">The algorithm name.</param> /// <returns>The maximum key size in bits.</returns> public static int MaxAlgorithmKeySize(string algorithm) { EncryptionConfig config = null; int maxKey = 0; for (int i = 0; i < platformSymmetric.Length; i++) { if (String.Compare(algorithm, platformSymmetric[i].Algorithm, StringComparison.OrdinalIgnoreCase) == 0) { config = platformSymmetric[i]; break; } } for (int i = 0; i < platformAsymmetric.Length; i++) { if (String.Compare(algorithm, platformAsymmetric[i].Algorithm, StringComparison.OrdinalIgnoreCase) == 0) { config = platformAsymmetric[i]; break; } } if (config == null) { throw new ArgumentException(Crypto.UnknownAlgorithm); } for (int i = 0; i < config.KeySizes.Length; i++) { if (config.KeySizes[i] > maxKey) { maxKey = config.KeySizes[i]; } } Assertion.Test(maxKey > 0); return(maxKey); }