  ErrorType init(const char* name,
                 unsigned char* key,
                 size_t key_len,
                 unsigned char* iv,
                 size_t iv_len,
                 const char* hmac_name,
                 unsigned char* hmac_key,
                 size_t hmac_key_len,
                 int is_etm) {
    ErrorType r = kErrNone;

    const EVP_MD* md;
    const EVP_CIPHER* const cipher = EVP_get_cipherbyname(name);
    if (cipher == nullptr) {
      r = kErrOpenSSL;
      goto out;
    }

    if ((ctx_ = EVP_CIPHER_CTX_new()) == nullptr
        || EVP_EncryptInit_ex(ctx_, cipher, nullptr, nullptr, nullptr) != 1) {
      r = kErrOpenSSL;
      goto out;
    }

    if (iv_len != static_cast<size_t>(EVP_CIPHER_CTX_iv_length(ctx_))) {
      r = kErrBadIVLen;
      goto out;
    }

    if (key_len != static_cast<size_t>(EVP_CIPHER_CTX_key_length(ctx_))) {
      if (!EVP_CIPHER_CTX_set_key_length(ctx_, key_len)) {
        r = kErrBadKeyLen;
        goto out;
      }
    }

    // Set key and IV
    if (EVP_EncryptInit_ex(ctx_, nullptr, nullptr, key, iv) != 1) {
      r = kErrOpenSSL;
      goto out;
    }

    // Disable padding
    EVP_CIPHER_CTX_set_padding(ctx_, 0);

    if (cipher == EVP_rc4()) {
      /* The "arcfour128" algorithm is the RC4 cipher, as described in
         [SCHNEIER], using a 128-bit key.  The first 1536 bytes of keystream
         generated by the cipher MUST be discarded, and the first byte of the
         first encrypted packet MUST be encrypted using the 1537th byte of
         keystream.

         -- http://tools.ietf.org/html/rfc4345#section-4 */
      unsigned char zeros[1536] = {0};
      int outlen = sizeof(zeros);
      if (EVP_EncryptUpdate(ctx_,
                            zeros,
                            &outlen,
                            zeros,
                            sizeof(zeros)) != 1) {
        r = kErrOpenSSL;
        goto out;
      }
      if (static_cast<size_t>(outlen) != sizeof(zeros)) {
        r = kErrBadInit;
        goto out;
      }
    }

    md = EVP_get_digestbyname(hmac_name);
    if (md == nullptr) {
      r = kErrBadHMACName;
      goto out;
    }

    if ((ctx_hmac_ = HMAC_CTX_new()) == nullptr
        || HMAC_Init_ex(ctx_hmac_, hmac_key, hmac_key_len, md, nullptr) != 1) {
      r = kErrOpenSSL;
      goto out;
    }

    hmac_len_ = HMAC_size(ctx_hmac_);
    is_etm_ = is_etm;

out:
    if (r != kErrNone)
      clear();
    return r;
  }
  ErrorType init(const char* name,
                 unsigned char* key,
                 size_t key_len,
                 unsigned char* iv,
                 size_t iv_len,
                 const char* hmac_name,
                 unsigned char* hmac_key,
                 size_t hmac_key_len,
                 int is_etm) {
    ErrorType r = kErrNone;

    const EVP_MD* md;
    const EVP_CIPHER* const cipher = EVP_get_cipherbyname(name);
    if (cipher == nullptr) {
      r = kErrOpenSSL;
      goto out;
    }

    if ((ctx_ = EVP_CIPHER_CTX_new()) == nullptr
        || EVP_EncryptInit_ex(ctx_, cipher, nullptr, nullptr, nullptr) != 1) {
      r = kErrOpenSSL;
      goto out;
    }

    if (iv_len != static_cast<size_t>(EVP_CIPHER_CTX_iv_length(ctx_))) {
      r = kErrBadIVLen;
      goto out;
    }

    if (key_len != static_cast<size_t>(EVP_CIPHER_CTX_key_length(ctx_))) {
      if (!EVP_CIPHER_CTX_set_key_length(ctx_, key_len)) {
        r = kErrBadKeyLen;
        goto out;
      }
    }

     
    if (EVP_EncryptInit_ex(ctx_, nullptr, nullptr, key, iv) != 1) {
      r = kErrOpenSSL;
      goto out;
    }

     
    EVP_CIPHER_CTX_set_padding(ctx_, 0);

    if (cipher == EVP_rc4()) {
       
      unsigned char zeros[1536] = {0};
      int outlen = sizeof(zeros);
      if (EVP_EncryptUpdate(ctx_,
                            zeros,
                            &outlen,
                            zeros,
                            sizeof(zeros)) != 1) {
        r = kErrOpenSSL;
        goto out;
      }
      if (static_cast<size_t>(outlen) != sizeof(zeros)) {
        r = kErrBadInit;
        goto out;
      }
    }

    md = EVP_get_digestbyname(hmac_name);
    if (md == nullptr) {
      r = kErrBadHMACName;
      goto out;
    }

    if ((ctx_hmac_ = HMAC_CTX_new()) == nullptr
        || HMAC_Init_ex(ctx_hmac_, hmac_key, hmac_key_len, md, nullptr) != 1) {
      r = kErrOpenSSL;
      goto out;
    }

    hmac_len_ = HMAC_size(ctx_hmac_);
    is_etm_ = is_etm;

out:
    if (r != kErrNone)
      clear();
    return r;
  }