  ErrorType init(unsigned char* keys, size_t keys_len) {
    ErrorType r = kErrNone;

    if (keys_len != 64) {
      r = kErrBadKeyLen;
      goto out;
    }

    if ((ctx_pktlen_ = EVP_CIPHER_CTX_new()) == nullptr
        || (ctx_main_ = EVP_CIPHER_CTX_new()) == nullptr
        || (md_ctx_ = EVP_MD_CTX_new()) == nullptr
        || EVP_EncryptInit_ex(ctx_pktlen_,
                              EVP_chacha20(),
                              nullptr,
                              keys + 32,
                              nullptr) != 1
        || EVP_EncryptInit_ex(ctx_main_,
                              EVP_chacha20(),
                              nullptr,
                              keys,
                              nullptr) != 1) {
      r = kErrOpenSSL;
      goto out;
    }
    if (EVP_CIPHER_CTX_iv_length(ctx_pktlen_) != 16) {
      r = kErrBadIVLen;
      goto out;
    }

out:
    if (r != kErrNone)
      clear();
    return r;
  }
  ErrorType init(unsigned char* keys, size_t keys_len) {
    ErrorType r = kErrNone;

    if (keys_len != 64) {
      r = kErrBadKeyLen;
      goto out;
    }

    if ((ctx_pktlen_ = EVP_CIPHER_CTX_new()) == nullptr
        || (ctx_main_ = EVP_CIPHER_CTX_new()) == nullptr
        || (md_ctx_ = EVP_MD_CTX_new()) == nullptr
        || EVP_EncryptInit_ex(ctx_pktlen_,
                              EVP_chacha20(),
                              nullptr,
                              keys + 32,
                              nullptr) != 1
        || EVP_EncryptInit_ex(ctx_main_,
                              EVP_chacha20(),
                              nullptr,
                              keys,
                              nullptr) != 1) {
      r = kErrOpenSSL;
      goto out;
    }
    if (EVP_CIPHER_CTX_iv_length(ctx_pktlen_) != 16) {
      r = kErrBadIVLen;
      goto out;
    }

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