+static u_char *
+do_decrypt(netdissect_options *ndo, const char *caller, struct sa_list *sa,
+ const u_char *iv, const u_char *ct, unsigned int ctlen)
+{
+ EVP_CIPHER_CTX *ctx;
+ unsigned int block_size;
+ unsigned int ptlen;
+ u_char *pt;
+ int len;
+
+ ctx = EVP_CIPHER_CTX_new();
+ if (ctx == NULL) {
+ /*
+ * Failed to initialize the cipher context.
+ * From a look at the OpenSSL code, this appears to
+ * mean "couldn't allocate memory for the cipher context";
+ * note that we're not passing any parameters, so there's
+ * not much else it can mean.
+ */
+ (*ndo->ndo_error)(ndo, S_ERR_ND_MEM_ALLOC,
+ "%s: can't allocate memory for cipher context", caller);
+ return NULL;
+ }
+
+ if (set_cipher_parameters(ctx, sa->evp, sa->secret, NULL) < 0) {
+ EVP_CIPHER_CTX_free(ctx);
+ (*ndo->ndo_warning)(ndo, "%s: espkey init failed", caller);
+ return NULL;
+ }
+ if (set_cipher_parameters(ctx, NULL, NULL, iv) < 0) {
+ EVP_CIPHER_CTX_free(ctx);
+ (*ndo->ndo_warning)(ndo, "%s: IV init failed", caller);
+ return NULL;
+ }
+
+ /*
+ * At least as I read RFC 5996 section 3.14 and RFC 4303 section 2.4,
+ * if the cipher has a block size of which the ciphertext's size must
+ * be a multiple, the payload must be padded to make that happen, so
+ * the ciphertext length must be a multiple of the block size. Fail
+ * if that's not the case.
+ */
+ block_size = (unsigned int)EVP_CIPHER_CTX_block_size(ctx);
+ if ((ctlen % block_size) != 0) {
+ EVP_CIPHER_CTX_free(ctx);
+ (*ndo->ndo_warning)(ndo,
+ "%s: ciphertext size %u is not a multiple of the cipher block size %u",
+ caller, ctlen, block_size);
+ return NULL;
+ }
+
+ /*
+ * Attempt to allocate a buffer for the decrypted data, because
+ * we can't decrypt on top of the input buffer.
+ */
+ ptlen = ctlen;
+ pt = (u_char *)calloc(1, ptlen);
+ if (pt == NULL) {
+ EVP_CIPHER_CTX_free(ctx);
+ (*ndo->ndo_error)(ndo, S_ERR_ND_MEM_ALLOC,
+ "%s: can't allocate memory for decryption buffer", caller);
+ return NULL;
+ }
+
+ /*
+ * The size of the ciphertext handed to us is a multiple of the
+ * cipher block size, so we don't need to worry about padding.
+ */
+ if (!EVP_CIPHER_CTX_set_padding(ctx, 0)) {
+ free(pt);
+ EVP_CIPHER_CTX_free(ctx);
+ (*ndo->ndo_warning)(ndo,
+ "%s: EVP_CIPHER_CTX_set_padding failed", caller);
+ return NULL;
+ }
+ if (!EVP_DecryptUpdate(ctx, pt, &len, ct, ctlen)) {
+ free(pt);
+ EVP_CIPHER_CTX_free(ctx);
+ (*ndo->ndo_warning)(ndo, "%s: EVP_DecryptUpdate failed",
+ caller);
+ return NULL;
+ }
+ EVP_CIPHER_CTX_free(ctx);
+ return pt;
+}
+