+ EVP_CIPHER_CTX_ctrl(&cipher->ctx, EVP_CTRL_GCM_SET_TAG, 16, (unsigned char *)indata + inlen - 16);
+
+ if(!EVP_DecryptUpdate(&cipher->ctx, (unsigned char *)outdata, &len, (unsigned char *)indata, inlen - 16) ||
+ !EVP_DecryptFinal(&cipher->ctx, (unsigned char *)outdata + len, &pad)) {
+ logger(DEBUG_ALWAYS, LOG_ERR, "Error while decrypting: %s", ERR_error_string(ERR_get_error(), NULL));
+ return false;
+ }
+ if(outlen)
+ *outlen = len;
+ return true;
+}
+
+bool cipher_gcm_decrypt_start(cipher_t *cipher, const void *indata, size_t inlen, void *outdata, size_t *outlen) {
+ int len = 0;
+ if(!EVP_DecryptInit_ex(&cipher->ctx, NULL, NULL, NULL, cipher->counter->counter)
+ || (inlen && !EVP_DecryptUpdate(&cipher->ctx, (unsigned char *)outdata, &len, (unsigned char *)indata, inlen))) {
+ logger(DEBUG_ALWAYS, LOG_ERR, "Error while decrypting: %s", ERR_error_string(ERR_get_error(), NULL));
+ return false;
+ }
+ if(outlen)
+ *outlen = len;
+ return true;
+}
+
+bool cipher_gcm_decrypt_finish(cipher_t *cipher, const void *indata, size_t inlen, void *outdata, size_t *outlen) {
+ if(inlen < 16)
+ return false;
+
+ EVP_CIPHER_CTX_ctrl(&cipher->ctx, EVP_CTRL_GCM_SET_TAG, 16, (unsigned char *)indata + inlen - 16);
+
+ int len = 0, pad = 0;
+ if((inlen > 16 && !EVP_DecryptUpdate(&cipher->ctx, (unsigned char *)outdata, &len, (unsigned char *)indata, inlen - 16))
+ || !EVP_DecryptFinal(&cipher->ctx, (unsigned char *)outdata + len, &pad)) {
+ logger(DEBUG_ALWAYS, LOG_ERR, "Error while decrypting: %s", ERR_error_string(ERR_get_error(), NULL));
+ return false;
+ }