/// <summary>Negotiate a cipher option which server supports.</summary>
        /// <param name="conf">the configuration</param>
        /// <param name="options">the cipher options which client supports</param>
        /// <returns>CipherOption negotiated cipher option</returns>
        /// <exception cref="System.IO.IOException"/>
        public static CipherOption NegotiateCipherOption(Configuration conf, IList <CipherOption
                                                                                    > options)
        {
            // Negotiate cipher suites if configured.  Currently, the only supported
            // cipher suite is AES/CTR/NoPadding, but the protocol allows multiple
            // values for future expansion.
            string cipherSuites = conf.Get(DFSConfigKeys.DfsEncryptDataTransferCipherSuitesKey
                                           );

            if (cipherSuites == null || cipherSuites.IsEmpty())
            {
                return(null);
            }
            if (!cipherSuites.Equals(CipherSuite.AesCtrNopadding.GetName()))
            {
                throw new IOException(string.Format("Invalid cipher suite, %s=%s", DFSConfigKeys.
                                                    DfsEncryptDataTransferCipherSuitesKey, cipherSuites));
            }
            if (options != null)
            {
                foreach (CipherOption option in options)
                {
                    CipherSuite suite = option.GetCipherSuite();
                    if (suite == CipherSuite.AesCtrNopadding)
                    {
                        int keyLen = conf.GetInt(DFSConfigKeys.DfsEncryptDataTransferCipherKeyBitlengthKey
                                                 , DFSConfigKeys.DfsEncryptDataTransferCipherKeyBitlengthDefault) / 8;
                        CryptoCodec codec  = CryptoCodec.GetInstance(conf, suite);
                        byte[]      inKey  = new byte[keyLen];
                        byte[]      inIv   = new byte[suite.GetAlgorithmBlockSize()];
                        byte[]      outKey = new byte[keyLen];
                        byte[]      outIv  = new byte[suite.GetAlgorithmBlockSize()];
                        codec.GenerateSecureRandom(inKey);
                        codec.GenerateSecureRandom(inIv);
                        codec.GenerateSecureRandom(outKey);
                        codec.GenerateSecureRandom(outIv);
                        return(new CipherOption(suite, inKey, inIv, outKey, outIv));
                    }
                }
            }
            return(null);
        }
 /// <summary>Create a FileEncryptionInfo.</summary>
 /// <param name="suite">CipherSuite used to encrypt the file</param>
 /// <param name="edek">encrypted data encryption key (EDEK) of the file</param>
 /// <param name="iv">initialization vector (IV) used to encrypt the file</param>
 /// <param name="keyName">name of the key used for the encryption zone</param>
 /// <param name="ezKeyVersionName">
 /// name of the KeyVersion used to encrypt the
 /// encrypted data encryption key.
 /// </param>
 public FileEncryptionInfo(CipherSuite suite, CryptoProtocolVersion version, byte[]
                           edek, byte[] iv, string keyName, string ezKeyVersionName)
 {
     Preconditions.CheckNotNull(suite);
     Preconditions.CheckNotNull(version);
     Preconditions.CheckNotNull(edek);
     Preconditions.CheckNotNull(iv);
     Preconditions.CheckNotNull(keyName);
     Preconditions.CheckNotNull(ezKeyVersionName);
     Preconditions.CheckArgument(iv.Length == suite.GetAlgorithmBlockSize(), "Unexpected IV length"
                                 );
     this.cipherSuite      = suite;
     this.version          = version;
     this.edek             = edek;
     this.iv               = iv;
     this.keyName          = keyName;
     this.ezKeyVersionName = ezKeyVersionName;
 }