ErrorType decrypt(unsigned char* packet,
                    uint32_t packet_len,
                    unsigned char* mac,
                    uint32_t seqno) {
    ErrorType r = kErrNone;
    size_t sig_len = 16;
    int outlen = 0;

    // `packet` layout:
    //   <padding length> <payload> <padding>

    unsigned char polykey[POLY1305_KEYLEN] = {0};
    unsigned char calc_mac[POLY1305_TAGLEN] = {0};

    uint8_t seqbuf[16] = {0};
    ((uint8_t*)(seqbuf))[12] = (seqno >> 24) & 0xff;
    ((uint8_t*)(seqbuf))[13] = (seqno >> 16) & 0xff;
    ((uint8_t*)(seqbuf))[14] = (seqno >> 8) & 0xff;
    ((uint8_t*)(seqbuf))[15] = seqno & 0xff;

    // Generate Poly1305 key
    if (EVP_EncryptInit_ex(ctx_main_, nullptr, nullptr, nullptr, seqbuf) != 1) {
      r = kErrOpenSSL;
      goto out;
    }
    if (EVP_EncryptUpdate(ctx_main_,
                          polykey,
                          &outlen,
                          polykey,
                          sizeof(polykey)) != 1) {
      r = kErrOpenSSL;
      goto out;
    }
    if (static_cast<size_t>(outlen) != sizeof(polykey)) {
      r = kErrPartialEncrypt;
      goto out;
    }

    // Poly1305 over ciphertext
    if (polykey_) {
      if (EVP_PKEY_CTX_ctrl(polykey_ctx_,
                            -1,
                            EVP_PKEY_OP_SIGNCTX,
                            EVP_PKEY_CTRL_SET_MAC_KEY,
                            sizeof(polykey),
                            (void*)polykey) <= 0) {
        r = kErrOpenSSL;
        goto out;
      }
    } else {
      polykey_ = EVP_PKEY_new_raw_private_key(EVP_PKEY_POLY1305,
                                              nullptr,
                                              polykey,
                                              sizeof(polykey));
      if (polykey_ == nullptr) {
        r = kErrOpenSSL;
        goto out;
      }

      if (!EVP_DigestSignInit(md_ctx_,
                              &polykey_ctx_,
                              nullptr,
                              nullptr,
                              polykey_)) {
        r = kErrOpenSSL;
        goto out;
      }
    }
    if (EVP_DigestSignUpdate(md_ctx_,
                             length_bytes,
                             sizeof(length_bytes)) != 1) {
      r = kErrOpenSSL;
      goto out;
    }
    if (EVP_DigestSignUpdate(md_ctx_, packet, packet_len) != 1) {
      r = kErrOpenSSL;
      goto out;
    }

    // Generate Poly1305 MAC
    if (EVP_DigestSignFinal(md_ctx_, calc_mac, &sig_len) != 1) {
      r = kErrOpenSSL;
      goto out;
    }

    // Compare MACs
    if (CRYPTO_memcmp(mac, calc_mac, sizeof(calc_mac))) {
      r = kErrInvalidMAC;
      goto out;
    }

    // Decrypt packet
    seqbuf[0] = 1;
    if (EVP_DecryptInit_ex(ctx_main_, nullptr, nullptr, nullptr, seqbuf) != 1) {
      r = kErrOpenSSL;
      goto out;
    }
    if (EVP_DecryptUpdate(ctx_main_,
                          packet,
                          &outlen,
                          packet,
                          packet_len) != 1) {
      r = kErrOpenSSL;
      goto out;
    }
    if (static_cast<size_t>(outlen) != packet_len) {
      r = kErrPartialDecrypt;
      goto out;
    }

  out:
    return r;
  }