How to create a key container which is accessible for many users?



By ganton ~ September 23rd, 2008. Filed under: .Net, C#.

.Net Framework supports a key containers which can be used to store asymmetric keys. Key containers are available for user-level and machine-level store.

User-level RSA key containers are stored with the Windows user profile for a particular user and can be used to encrypt and decrypt information for applications that run under that specific user identity. User-level RSA key containers can be useful if you want to ensure that the RSA key information is removed when the Windows user profile is removed. However, because you must be logged in with the specific user account that will make use of the user-level RSA key container in order to encrypt or decrypt protected configuration sections, they are inconvenient to use.

Machine-level RSA key containers are available to all users that can log in to a computer, by default, and are the most useful as you can use them to encrypt or decrypt protected configuration sections while logged in with an administrator account. A machine-level RSA key container can be used to protect information for a single application, all the applications on a server, or a group of applications on a server that run under the same user identity. Although machine-level RSA key containers are available to all users, they can be secured with NTFS Access Control Lists (ACLs) so that only required users can access them.

quote from http://msdn.microsoft.com/en-us/library/f5cs0acs.aspx

Moreover, machine level key containers are created with access permissions for current user (the user which creates a key container) and for the system account. But what if we have an application which uses windows authentication for user authentication? In this case the thread will be ran under authenticated user account and it will not be allowed to access that key container created earlier. To solve this problem we can use CryptoKeySecurity, CryptoKeyAccessRule and CspParameters. What we should do is to create permissions for every user or for a group of users which should access created key container. Below is an example how to do this.


RSACryptoServiceProvider rsaProvider = null;

CspParameters cspParameters = new CspParameters()
{
KeyContainerName = "my key name",
Flags = CspProviderFlags.UseMachineKeyStore
};
try
{
CryptoKeySecurity security = new CryptoKeySecurity();
CryptoKeyAccessRule rule = new CryptoKeyAccessRule("SecuredUserGroup", CryptoKeyRights.ReadData, AccessControlType.Allow);
CryptoKeyAccessRule rule1 = new CryptoKeyAccessRule(WindowsIdentity.GetCurrent().Name, CryptoKeyRights.ReadData | CryptoKeyRights.WriteData, AccessControlType.Allow);
security.AddAccessRule(rule);
security.AddAccessRule(rule1);

cspParameters.CryptoKeySecurity = security;
rsaProvider = new RSACryptoServiceProvider(cspParameters);
}
catch (UnauthorizedAccessException)
{
rsaProvider = null;
}
if (rsaProvider == null)
{
cspParameters.CryptoKeySecurity = null;
rsaProvider = new RSACryptoServiceProvider(cspParameters);
}

As one can see the code above creates a read access rule for “SecuredUserGroup” which means that it will not be allowed to do any operations which will modify key container parameters. I also handle UnauthorizedAccessException exception in order to check if the container is created and a user without write access rights attempts to open the container. If so I clear CryptoKeySecurity from cspParameters and I initialize rsaProvider again. unfortunately, I still didn’t found to check if a key container already exists :(.

Machine-level key containers are stored into “C:\Documents and Settings\All Users\Application Data\Microsoft\Crypto\RSA\MachineKeys” and user-level key containers are stored into “C:\Documents and Settings\<current user>\Application Data\Microsoft\Crypto\RSA”. These paths are valid for Windows XP.

Leave a Reply