Where should I put the public key in a standalone application - c#

I wrote an C# WPF application that signs a license xml file using the standard .Net SignedXml class. I am able to extract the public and private key as xml strings. I can safely tuck away my private key locally for the signing application, but what about the public key needed in the remote sign check application (library)? Options considered:
KeyContainer: no good, because signing and checking happens in 2 separate environments
Hardcoded: hardcode the public key as xml string in my checking library. I know the public key is not secret, but how can I prevent hackers from replacing the key with their own? I can sign the library, but then they could tamper with the application using the library....

Put the public key in a standard digital certificate that you distribute with your app. The integrity of the certificate will then be guaranteed by Windows, and you can tell if it's been changed.
Of course both the hardware and Windows itself is under the control of any potential attacker, so you can't really prevent a compromise of a specific machine.
Here's an example from a program that I used to distribute. When the program was activated from a licence perspective, it sent a hardware hash to a web service. This returned a self-signed certificate containing the hardware hash, which my program then checked whenever it was started. If the certificate had been changed in any way, the program would stop.

I put the public key in a directory outside of the inetpub directory, and if you move the private key off of the computer, then the worst someone could do is to replace the public key and it no longer can decrypt, but you could be informed when it can't decrypt to know something happened.
But, if someone was able to change your file you will have bigger problems that just having this one file changed.
UPDATE:
Oops, I missed that this is a WPF program. Unfortunately the best you can do is to have the private key separate from the public key, so, you can decrypt, but if the hacker changes the public key the application won't function properly.
That is one of the advantages of using the public/private key, to verify that only you can do the encryption.
The other option is to fetch the public key from a webserver, but then you have the same problem in that it is possible for someone to trick the application to go to the wrong server, so it isn't full-proof, and it will require that the user had an Internet connection, and for you to uniquely identify them.

Related

Cannot find the symmetric key 'keyFieldProtection', because it does not exist or you do not have permission.'

I am trying to use a stored procedure that has encrypted data, I have written the same program in Python with success. However when I use c# connecting to same db, it throws this error. Cannot find the symmetric key 'keyFieldProtection', because it does not exist or you do not have permission.'
You need to grant permissions to the keys. If you are unable to grant permissions, need to switch mode to windows authentication.
Else if you are opening master key, then refer to the following:
https://learn.microsoft.com/en-us/sql/t-sql/statements/open-master-key-transact-sql?redirectedfrom=MSDN&view=sql-server-2017
As per above;
“If the database master key was encrypted with the service master key, it will be automatically opened when it is needed for decryption or encryption. In this case, it is not necessary to use the OPEN MASTER KEY statement.”
Its hard to tell without looking at your code

Password required to access private key in code?

I have a certificate with private key installed in my certificate store. It required the password in order to install it, which I provided. My question is whether or not I need to provide it again when referencing it in code. I need to "sign" a SAML2 request using the private key. Do I need to use an overload of X509Certificate2() that takes in the password in order for the code to allow me to access the private key for signing? It was questionable to me since I already had to provide it upon installation of the certificate.
My sources tell me no. =)
Once you have installed it in the windows keystore, the private key is usable to all the applications running as the user.
There is an option which you can use called "Enable strong private key protection". Password would then be prompted at every use.
The overloaded version X509Certificate2() constructor is used to read a raw p12 file, in the case you don't use the keystore. http://msdn.microsoft.com/en-us/library/ms148417.aspx

Must GnuPG to have installed keys for every username profile?

I'm running (on my local machine) the GPG (wingpg ) - command line version.
My login name at win7 - is RoyiN. ( so I have a profile for it)
When I logged in - I've installed the keys (using PKA.exe) both private and public.
All fine.
Then I wrote this code ( which is working )
Process proc = new Process();
proc.StartInfo.FileName = cfg.PGP_Program_FullPath;
proc.StartInfo.UserName = "Royin";
proc.StartInfo.Domain = ...;
proc.StartInfo.Password = ...
proc.StartInfo.Verb = "runas";
proc.Start();
...
However if I write in the UserName field - another user which is also Administrator on my local machine - it says :
gpg: decryption failed: No secret key
Then I swapped again to RoyiN and it did work
Are keys installed per user? is there a way to change that so it will be global ? ( so every user on the machine will be able to use these keys - without having to install the keys under each every profile) ?
It also implies that if i want to allow other's to connect to my computer - I must be logged on with RoiyN 24/7....
Is there any workaround for this ?
There are two different things happening here that are related to the "person" running gpg.
GPG searches for keys in the default keyring files, which are installed in your user profile directory (under a folder named .gnupg). This will be a set of files like pubring.gpg and secring.gpg. This part is easy to work around: pass --secret-keyring "path\to\file" as one of the parameters and it will add that keyring file to its search path. You may want to move it to a publically readable location, like %ALLUSERSPROFILE%, first.
Apart from that, GnuPG keys are generated for and tied to an identity, which is usually your email address. When receiving files, the data will specify the identify of the person who's key is needed to decrypt and/or verify the integrity. When encrypting or signing files, you have to tell GPG who's key to use. Your secret key is used when you sign things for others, or when you decrypt data sent to you. You need to make sure the appropriate keys are in whatever keyring file you use, regardless of where it is.
There's no need for you to actually stay logged in when you run gpg, if you give it an explicit location for the data. It's simply that gpg, by default, reads the current environment variables, set at login, to determine where those things are.
You'll probably need to specify a keyring file path, a secret keyring file path, and a configuration file path if you want to run GPG unattended. The entire list of options you can specify is on the GPG Configuration Options page.
(You may want to try starting with just the --homedir option, which I think will override the default paths for everything else in one go, but you'd need to test that to make sure.)
Yes, they are installed on per-user basis
Simple answer - just export the private/public key pair, and install it for the Administrator account as well.
Although, it'd be better to create a separate key for your automated system with own public key - whoever has your key with a high level of trust, will accept this one as well.

Auto Update Downloading Latest .exe file - how to verify it's not been tampered with?

We have a small console application (under 200kb) that will be distributed to clients and we want to ensure they run the latest version (verified by a WCF service). Currently it downloads the new .exe file over HTTPS and replaces the current .exe file with it.
Assuming our server isn't compromised, this would be ok. However we also sign our .exe file with a Code Signing certificate. Is there a way to verify this and delete the file if it doesn't match? We would need to be able to verify and delete the file without it ever being executed in case it is a virus.
How can we verify our signed .exe file? For example, Windows will show if it is invalid:
Edit: would this code do the job?
X509Certificate basicSigner = X509Certificate.CreateFromSignedFile(file);
X509Certificate2 cert = new X509Certificate2(basicSigner);
if (cert.Subject.Contains("CN=MY COMPANY NAME IN CERTIFICATE"))
valid = true;
Edit: if we also check StrongNameSignatureVerificationEx, it comes back failed if one bit is changed in the file. Perhaps this is enough?
[DllImport("mscoree.dll", CharSet = CharSet.Unicode)]
static extern bool StrongNameSignatureVerificationEx(string wszFilePath, bool fForceVerification, ref bool pfWasVerified);
Edit: I've implemented this code too which calls WinVerifyTrust in WinTrust.dll to actually verify the Authenticode signature: http://www.pinvoke.net/default.aspx/wintrust.winverifytrust
Now, it checks if the digital signature contains the correct subject, is from a valid trusted root, the signature is valid and if the code is strong named with it's digital signature. This must be safe enough now?
This is a nice walkthrough including source code on the options available to achieve what you want...
Basically you need to pinvoke StrongNameSignatureVerificationEx since there is no managed API to do what you need.
Another option might be to call SignTool.
This is a pretty fundamentally wrong way to go about it. The only thing that a code signing certificate proves is the identity of the person or company that signed the EXE. The certificate authority merely proves that identity is valid. What you haven't proved at all is that it is your certificate, you only proved that it is somebody's certificate. An attacker could trivially replace your EXE with another one that was signed by him.
You'll probably object with "but can't I just verify it is mine!". And the answer is no, if the attacker can replace the EXE then he'll have no trouble replacing your checking code either. There is zero security in having the verification performed on the same machine.
Code certificates serve only one purpose, they prove the identity of the signer to the user. Making them do anything else is a security hole. The really bad kind, the kind that make you feel that your system is secure. And make you stop thinking about implementing real security.

Import certificate with private key programmatically

I'm trying to use the HttpListener class in a C# application to have a mini webserver serve content over SSL. In order to do this I need to use the httpcfg tool. I have a .pfx file with my public and private key pair. If I import this key pair manually using mmc into the local machine store, everything works fine. However, if I import this key pair programmatically using the X509Store class, I am not able to connect to my mini webserver. Note that in both methods the cert is getting imported to the MY store in LocalMachine. Oddly, I am able to view the certificate in mmc once I programmatically import it and when I view it, the UI indicates that a private key is also available for this certificate.
Digging a little deeper, I notice that when I manually import the key pair, I can see a new file appear in C:\Documents and Settings\All Users\Application Data\Microsoft\Crypto\RSA\MachineKeys, but one does not appear when I import programmatically. On a related note, when I delete a manually imported certificate, it does not remove the corresponding private key file from the previously mentioned directory.
Ultimately, my question is this: When I programmatically add the certificate to the store, where is the private key being stored and why isn't it accessible to the HttpListener class (HttpApi)?
Note that this question is slightly related but I don't think permissioning is the problem since this is all being done as the same Windows user:
How to set read permission on the private key file of X.509 certificate from .NET
Ok, I figured it out. It had to do with the key storage parameters for the certificate object. For anyone else that runs into this problem, make sure you construct your X509Certificate2 objects that you are adding to the store using the X509KeyStorageFlags.PersistKeySet and X509KeyStorageFlags.MachineKeySet flags. This will force the private key to persist in the machine key set location which is required by HttpApi (HttpListener wraps this).
Is this a 2 way SSL? If it is then did you send over a SSL Certificate Request file generated on your machine? This Certificate Request file will be used to create the SSL and they together form a public private key pair.
Also did you try assigning the cert permission for the user account that is being used to run the web app? You can do this by using the Microsoft WSE 3.0 tool.
Not exactly the answer to your question, but here for reference of others going down this path:
Here is a link to a MS chat that gives sample C# code to do what httpcfg does, thus eliminating the need for the tool on deployment.

Categories