I'm not sure you're going to find a silver bullet for this. The primary problem with building a generic solution for an ETag/Last-Modified feature in Sitecore is that cache invalidation is hard.
So, unless you already have a strategy in place for handling cache eviction for all of the items you mentioned (page-level item, datasources & dynamic search results) you won't be able to avoid recalculating the value for your ETag/Last-Modified header on dynamic pages.
That said, if you're OK with performing that recalculation on each page request, and simply want to save some bytes in transmission when the client performs a HEAD/GET 'If-Not-Modified*' request, you can certainly do that.
My recommendation would be to do this with an HTTP Module - you should be able to hook into the EndRequest event, perform your ETag calculation, and then add your custom ETag or Last-Modified header there. Further information exists in MSDN as well: https://msdn.microsoft.com/en-us/library/ms227673.aspx
NB: This will only work if you don't flush your headers prior to the EndRequest event being fired. Once the headers are sent, you can't modify them, so be sure you're not manually flushing them anywhere else in the application earlier in the ASP lifecycle.