Obfuscation is one way, but it can\'t protect from breaking the piracy protection security of the application. How do I make sure that the application is not tampered with,
Bear in mind that 99%+ of your users aren't going to be interested in examining your executable to see how it works.
Given that so few people are even going to bother trying and that most obfuscators can be worked around, is it worth your time and effort?
You'd be better off investing the time into improving your product so that more people want to use it.
How to make sure that the application is not tampered with, and how to make sure that the registration mechanism can't be reverse engineered.
Both have the same very simple answer: don't hand out object code to untrusted parties, such as (apparently) your customers. Whether it's feasible to host the application on your machines only depends on what it does.
If it isn't a web application, maybe you can allow for SSH login with X forwarding to an application server (or Remote Desktop Connection, I guess, for Windows).
If you give object code to nerdy type persons, and they think your program might be fun to crack, it will get cracked. No way around it.
If you don't believe me, point out a high-profile application that hasn't been cracked and pirated.
If you go with the hardware keys, it'll make production more expensive and your users are going to hate you for it. It's a real bitch to crawl around on the floor plugging and unplugging your 27 different USB thingies because software makers don't trust you (I imagine).
There are packages out there that will encrypt your EXE and decrypt it when the user is allowed to use it
Of course, the way around it is to crack the "can-I-use-it" test so that it always returns true.
A nasty trick might be to use the byte values of the opcodes that perform the test somewhere else in the program in a dirty way that'll make the program crash with high probability unless the value is just right. It makes you linked to a particular architecture, though :-(
Broadly speaking, there are three groups of people out there.
Those who will not buy your software and resort to cracks, or if they don't find any, not use your software at all. Don't expect to make any money from this group. They rely either on their own skills or on crackers (who tend to prioritize their time depending on your useful and how big your audience is. The more useful, the sooner a crack will be available).
The group of legitimate users who will buy (pay for) your software, irrespective of what protection mechanism you use. Don't make life hard for your legitimate users by using an elaborate protection mechanism since they are going to pay for it in any case. A complex protection mechanism can easily spoil the user experience and you don't want this happening to this group. Personally, I'd vote against any hardware solution, which adds to the cost of your software.
A minority who will resort to "unethical" cracking and will only pay for your software because its features are protected by a licensing mechanism. You probably don't want to make it exceedingly easy for this group to circumvent your protection. However, all that effort you spend on protecting your software will pay back, depending on how big this group of people is. This entirely depends on the type of software you're building.
Given what you've said, if you think there is a large enough minority who can be pushed into buying your software, go ahead and implement some form of protection. Think about how much money you can make from this minority versus the time you spend working on the protection, or the amount you spend on a third party protection API/tool.
If you like to implement a solution of your own, using public-key cryptography is a good way (as opposed to symmetric algorithms) to prevent easy hacks. You could for instance digitally sign your license (serial no, or license file). The only way to get around this would then be to decompile, alter and recompile the code (which you could make harder using techniques such as those suggested in Simucal's answer).
There is a detailed comparison sheet for several .Net obfuscation tools.
Screenshoot taken from obfuscators.io
.NET Reactor
Update
Jared pointed out that de4dot claims to be able to decompile it.
.NET Reactor provides complete protection for your sensitive intellectual property by converting your .NET assemblies into unmanaged processes which cannot be understood as CIL, and which no existing tool can decompile. Hackers have no access to any intelligible form of your source.
Powerful and flexible, the .NET Reactor licensing features allow you to enforce your license conditions and protect your revenue stream by using hardware and software locks. The license manager can build trial or permanent licenses, in a matter of seconds. A fully documented software development kit (SDK), complete with examples, allows you to call the licensing system directly from your code, allowing you to create custom extensions to the licensing system.
You can't prevent people from cracking your software.
However, you can make them create cracks that will hurt your sales less. Keygenerators that can issue a valid registration code for your software are much worse than simple patches that remove registration incentives from your software. That's because a crack will work for one software version only, and will cease to work with the next software update you release. The keygenerator will continue to work until you change your registration key algorithm and that's something you don't want to do often because it will put off your honest clients.
So, if you are looking for a method to fight illegal keygenerators for your software and you do not want to use assymetric encryption because of the long registration codes this generates, you might have a look at Partial Key Verification.
Partial Key Verification makes sure that each illegal keygenerator works only for one particular release of your software. Basically what you do is to make sure that each release of your software only links with the code for checking SOME digits of the registration code. Which digits exactly is random, so crackers would have to reverse engineer many different versions of your software and combine all this into one keygenerator in order to release a keygenerator that works for all versions of your software.
If you release new software versions on a regular basis, this leads to numerous keygenerators spread on all kinds of software piracy archives which are not working anymore. Potential software pirates usually look for a crack or keygen for the latest version, so they will likely try a few of those and give up eventually.
I've used the Partial Key Verification in my (C++) newer shareware games and it has been very effective. Before we had plenty of problems with keygenerators which we could not fight. Afterewards there were lots of cracks and some few keygenerators that worked only for that particular version of the game, but no key generator that would work with all versions. We regularly released very minor updates of the game and to render all previously existing cracks useless.
There seems to be an open source .NET framework for Partial Key Verification, although I have not tried it.