I have a console application named Keycreator that is used to create key using DataProtection.I am using ProtectKeysWithDpapiNG() extension for key configuration. Here's a snippet for the same:
var securityIdentifiers = identities.Select(identity => $"SID={new NTAccount(identity).Translate(typeof(SecurityIdentifier))}");
dataProtectionBuilder.ProtectKeysWithDpapiNG(string.Join(" OR ", securityIdentifiers), flags: DpapiNGProtectionDescriptorFlags.None);
The key generation works as expected.
There is another console app named DataProtector that takes in the key as one of the parameter that is generated using the keycreator console to encrypt/decrypt the file.
Working scenario: When I pass in identities to generate key that includes the current user ,the data protection exe works as expected ie .the encrypt/decrypt of the file being passed works with no issue.
Problem Area: When passing in identities excluding the current user, the data protection creates a new key that is unencrypted even though the encrypted key is already available.
There is an extension to disable Automatic Key Generation
[https://learn.microsoft.com/en-us/dotnet/api/microsoft.aspnetcore.dataprotection.dataprotectionbuilderextensions.disableautomatickeygeneration?view=aspnetcore-6.0][1]
but even with the extension dataprotection application creates an unencrypted key file.
The Point that i am trying to convey is ,this unencrypted key creation issue exists only when the key that is generated in the keycreator console does not include the current user as one of the identity.
Here is the error that is thrown:
The key ring does not contain a valid default protection key. The data protection system cannot create a new key because auto-generation of keys is disabled. For more information go to http://aka.ms/dataprotectionwarning
at Microsoft.AspNetCore.DataProtection.KeyManagement.KeyRingProvider.CreateCacheableKeyRingCore(DateTimeOffset now, IKey keyJustAdded)
at Microsoft.AspNetCore.DataProtection.KeyManagement.KeyRingProvider.GetCurrentKeyRingCore(DateTime utcNow, Boolean forceRefresh)
at Microsoft.AspNetCore.DataProtection.KeyManagement.KeyRingBasedDataProtector.Protect(Byte[] plaintext)
Any input is appreciated.
Related
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
I have 2 DLLs signed in Visual Studio (VS) 2015. A former employee created an asymmetric key and login and I ran one of the assemblies in UNSAFE mode correctly.
I get the following error with the second one:
Msg 10327, Level 14, State 1, Line 27
CREATE ASSEMBLY for assembly 'TableFile' failed because assembly 'TableFile' is not authorized for PERMISSION_SET = UNSAFE. The assembly is authorized when either of the following is true: the database owner (DBO) has UNSAFE ASSEMBLY permission and the database has the TRUSTWORTHY database property on; or the assembly is signed with a certificate or an asymmetric key that has a corresponding login with UNSAFE ASSEMBLY permission.
I can't ask the former employee so how do I find out how to get this to run? I tried this too:
USE master;
GO
CREATE ASYMMETRIC KEY AProjectKey FROM EXECUTABLE FILE = 'E:\sqldlls\TableFile.dll'
CREATE LOGIN AProjectLogin FROM ASYMMETRIC KEY AProjectKey ;
GRANT UNSAFE ASSEMBLY TO AProjectLogin ;
GO
This gives the following errors:
Msg 15396, Level 16, State 1, Line 9
An asymmetric key with name 'AProjectKey' already exists or this asymmetric key already has been added to the database.
Msg 15151, Level 16, State 1, Line 10
Cannot find the asymmetric key 'AProjectKey', because it does not exist or you do not have permission.
Msg 15151, Level 16, State 1, Line 11
Cannot find the login 'AProjectLogin', because it does not exist or you do not have permission.
How do I get both these assemblies running in unsafe mode? Thanks in advance.
Regarding those 3 error messages:
The first could be due to the Asymmetric Key already existing, but under a different name. Keys and Certificates need to be unique in terms of their public key, not just the name (though that obviously needs to be unique as well). Each Key and Certificate has a hash of the public key which is referred to as the "thumbprint". The thumbprints of existing Keys / Certificates are checked when creating a new one and will prevent the creation, even of a differently named Key / Certificate, if the thumbprint already exists. That is what the error message means by "or this asymmetric key already has been added to the database".
OR:
It could mean that a different Asymmetric Key (i.e. different "thumbprint") exists in master, but with the name AProjectKey
Because you couldn't create the same key under a different name, no Asymmetric Key exists with that new name, hence you can't create a Login from it (since, again, the CREATE ASYMMETRIC KEY statement failed).
Because you couldn't create the Login, it doesn't exist to be granted any permissions.
Error # 2 helps narrow down the issue. If Error # 1 was caused by an existing Asymmetric Key having the same name but different "thumbprint", then you either would have been able to create the Login (if it did not already exist), or you would have gotten an error stating that the Login (i.e. "server principal") already exists. But the error is that an Asymmetric Key by that name cannot be found. This should mean that the Asymmetric Key itself does already exist, but under a different name. You can see what Asymmetric Keys have been created by executing the following:
SELECT * FROM sys.asymmetric_keys;
But that doesn't tell you which one came from that Assembly (or an Assembly signed with the same Strong Name Key used to sign this one). For that you need to know the "thumbprint", and for that you need to open a Command Prompt (preferably a "Developer Command Prompt" which Visual Studio sets up when installed, as it has the correct path set up upon opening it). Then, run the following:
CD /D E:\sqldlls\
sn -T TableFile.dll
You should see:
Public key token is XXXXXXXXXXXXXXXX
Copy and paste that XXXXX "token" (i.e. thumbprint) into the following query:
SELECT ak.[name], ak.[sid]
FROM sys.asymmetric_keys ak
WHERE ak.[thumbprint] = 0x{XXXXXXXXXXXXXXXX}; -- remove the { and }
Assuming that you get a row returned, we need to see if the Login exists. Simply trying to create a Login from the Asymmetric Key won't get us the Login's name if it does exist since you can only have 1 Login created per Key / Certificate, and the error message only reports back the name you are trying to create as the one that already exists, even though it can be a different name for the same Key. So, take the SID from the returned row and paste it in the following query:
SELECT sp.*
FROM sys.server_principals sp
WHERE sp.[sid] = 0x{SID_from_sys_asymmetric_keys}; -- remove the { and }
If no row is returned then you should create a Login from that Asymmetric Key.
At this point a Login should exist, so grant it the UNSAFE ASSEMBLY permission.
Now try creating the Assembly again.
I am using HMACSHA256 for message authentication in a web-farm environment.
Within the web-farm each machine has the same machine key, so the ViewState will work across machines, however, I need to do HMAC message authentication which will work across machines, so I figured that since all machines use the same machine key, there should be a way to derive a key from that to use as the HMAC key.
I notice that as of .NET 4.0 there is the MachineKey class, however, I am stuck with using .NET 3.5, and this is unavailable to me.
Is there a way to get some sort key that is the same on all machines without generating my own, for use in an ASP.NET 3.5 environment?
Edit
I don't actually need the machine key itself, just the validation key that is derived from the machine key (or equivalent).
You can read the machine key from the web.config. This link shows how to do so: http://aspnetresources.com/blog/how_to_read_auto_generated_machinekey
Keep in mind, that the author of the article reads the generated machine key - so you have to do some changes in the code.
I just read the article a little bit more and saw, that it uses reflection, which isn't neccessary, if you store the machine key inside the web.config.
Essentially it breaks down to this line:
MachineKeySection section = (MachineKeySection)
ConfigurationManager.GetSection ("system.web/machineKey");
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.
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.