How would you implement a feature that would show the user a warning whenever he opens a file with my application that comes from a source other than his computer?
This is a feature Visual Studio already has:

I was thinking about adding some of the user’s system information as a hash code to the file, but this is not very safe as someone else could get this information if he can access any of the files the “victim” has created on his system and see the system ID hash, and then create a file and modify it to contain this system hash.
My other option would be to store a hash of the file together with the system information as a single hash and add this hash instead of the system info hash alone. This way the “hacker” could not figure out the “victim”‘s system hash by opening one of his files.
I know nothing is 100% safe. I read it as a first comment to every single question related to security issues. But do you have any suggestion as what’s a good way to implement such a functionality?
I think your question is: How do I verify file origin for a given computer even if that computer is compromised?
Let’s look at the general outline.
Now for the questions:
What type of compromise are we designing against?
In the face of a complete compromise there is no solution. In a complete compromise an adversary can modify any application or operating system function.
So, what compromises can we design against?
There must be some functions we can still trust. An attacker could compromise your application, in which case any check done by your application could not be trusted. An attacker could compromise the operating system. It is a small step from an operating system compromise to an application compromise. So let’s assume that the attacker has not compromised the operating system or your application. Let’s assume that the attacker has the ability to modify any file on the system except for the file containing your executable, and the files containing essential operating system components.
How do we authenticate origin?
Hash values, such as SHA1 and MD5, are used to verify integrity. A hash value on a file can only tell you if the file has been unmodified since the hash was created. It does not tell you where the file came from. A digital signature provides a check on origin. A digital signature tells you that the signed data originated with a person who has control over the key used to sign the message.
Now if you want to verify that a file on a computer originated from that computer, then every computer must have a different key to sign digital messages.
This is not a problem if you have only one copy of your application on one computer. But, when you have more than one you need to think about key generation and distribution. Key generation and distribution is a very hard problem. Digital signatures require a public private key pair. The private key has to be protected, and it has to be unique for each computer. We assumed before that an attacker could not modify your application, but I think it is fair to assume that the attacker could read your executable. This assumption makes your executable a poor place to store your private key. You could encrypt you key, but then you need another key to decrypt your key. There are a few possible answers here:
Using the operating system only works if the operating system provides these functions. A basic problem here is how do you know each computer has a unique key?
The network server is very similar to the operating system, but you could provide greater protection for the server than for an individual’s computer. Given sufficient protection, you can assume that a compromise will be detected and in that event, it will stop the signing and verification service. It also gives you a guarantee of unique keys, because the server will generate a new unique key for each instance of the application.
I think we’re all familiar with the issues involved with memorized passwords and pins. A slight variant here is that you could use a shorter or simpler password to encrypt a larger more complex key. The downside to the shorter/simpler password is that it becomes easier to brute force decrypt the longer/complex key.