Пока придумал брать id какого-нибудь железа, шифровать RSA, например, а при запуске сравнивать данные
Одной железки, по-моему, будет мало. В идеале, брать несколько железок и каким-нибудь алгоритмом ( например, который здесь:
geektimes.ru/post/69623 ) генерировать открытым ключом последовательность, уникальную для данного компьютера, а уже на сервере производить подпись, выдавая серийный номер к каждому экземпляру программы.
Учитывая, что пишите на C#, а в нем очень легко восстановить исходный код программы, нужно будет использовать обфускаторы. Возможно даже скрывать реализацию защиты в отдельных модулях, написанных на компилируемых ЯП.
Ну, и в заключение, чтобы избавиться от разных патчеров и генераторов ключей, нужно будет дописать еще один модуль защиты, который бы при запуске сверял хеш программы/отдельных модулей и, если они были изменены, запрещал запуск программы.