How can I implement both an async method and its synchronous counterpart?

If your library needs to implement both synchronous and asynchronous members, then you implement both members. There are no shortcuts (assuming this is intended to be a reusable library).

public async Task<string> GetContentAsync(string url)
{
  ... // Logic here, e.g., using HttpClient
}

public string GetContent(string url)
{
  ... // Duplicate logic here, e.g., using WebClient
}

The duplication of logic is certainly unfortunate, but if you try to take shortcuts you'll actually end up in a worse situation. The details of "why" are a bit long for an SO answer, but Stephen Toub covers the problems that arise when wrapping in his classic pair of blog posts "Should I expose synchronous wrappers for asynchronous methods?" and "Should I expose asynchronous wrappers for synchronous methods?"

BTW, the answer to both questions is "no". Also, see my SO answer here.