none
I Am Having Difficulty Importing a Private RSA Key from the Microsoft Software Key Storage Provider Using CNG RRS feed

  • Question

  • I use the following code to store a RSA key pair in the KSP and to retrieve the private key from the KSP.  When I try and decrypt my cipher text, I receive an invalid parameter error.  It appears that the private key that I'm using is of the correct length but contains the wrong bytes.  Please help!

    
    

            internal static byte[] GenerateStoredKey(int keyByteLength, string keyName, CngExportPolicies exportPolicies, CngKeyCreationOptions cngKeyCreationOptions, CngKeyUsages cngKeyUsages, CngUIProtectionLevels cngUIProtectionLevels)
            {
                if (keyByteLength < MIN_KEY_BYTE_LENGTH)
                    throw new ArgumentException(String.Format("Key length must be at least {0} bytes!", MIN_KEY_BYTE_LENGTH), "length");

                CngKeyCreationParameters creationParameters = new CngKeyCreationParameters()
                {
                    ExportPolicy =  exportPolicies,
                    KeyCreationOptions = cngKeyCreationOptions,
                    KeyUsage = cngKeyUsages,
                    Provider = CngProvider.MicrosoftSoftwareKeyStorageProvider,
                    UIPolicy = new CngUIPolicy(cngUIProtectionLevels)
                };

                using (CngKey key = CngKey.Create(CngAlgorithm.Rsa, keyName, creationParameters))
                {
                    using (RSACng rsa = new RSACng(key)
                    {
                        KeySize = keyByteLength * 8
                    })
                    {
                        return rsa.Key.Export(CngKeyBlobFormat.GenericPublicBlob);  // Return public key.
                    }
                }
            }

    internal static byte[] RetrieveStoredKey(int keyByteLength, string keyName)
            {
                if (CngKey.Exists(keyName, CngProvider.MicrosoftSoftwareKeyStorageProvider))
                {
                    using (CngKey key = CngKey.Open(keyName))
                    {
                        using (RSACng rsa = new RSACng(key)
                        {
                            KeySize = keyByteLength * 8
                        })
                        {
                            return rsa.Key.Export(CngKeyBlobFormat.GenericPrivateBlob);  // Return private key.
                        }
                    }
                }
                else
                    return null;
            }

            internal static byte[] Decrypt( byte[] cipherText, int keyByteLength, byte[] privateKey)
            {
                using (CngKey key = CngKey.Import( privateKey, CngKeyBlobFormat.GenericPrivateBlob))
                {
                    using (RSACng rsa = new RSACng(key)
                    {
                        KeySize = keyByteLength * 8
                    })
                    {
                        return rsa.Decrypt(cipherText, RSAEncryptionPadding.OaepSHA512);
                    }
                }
            }

    • Edited by dis081278 Saturday, April 13, 2019 8:13 AM
    Saturday, April 13, 2019 7:27 AM

All replies

  • I was able to solve my own problem.  The issue was I was not manually setting the length of the key within the procedure 'GenerateStoredKey'.  This can be done by adding a CngProperty to the CngKeyCreationParameters collection.  See below:

            internal static byte[] GenerateStoredKey(int keyByteLength, string keyName, CngExportPolicies exportPolicies, CngKeyCreationOptions cngKeyCreationOptions, CngKeyUsages cngKeyUsages, CngUIProtectionLevels cngUIProtectionLevels)
            {
                if (keyByteLength < MIN_KEY_BYTE_LENGTH)
                    throw new ArgumentException(String.Format("Key length must be at least {0} bytes!", MIN_KEY_BYTE_LENGTH), "length");
                if (keyName == null)
                    throw new ArgumentNullException("Key name required!", "message");
    
                // Generate CngKeyCreationParameters
                CngKeyCreationParameters creationParameters = new CngKeyCreationParameters()
                {
                    ExportPolicy = exportPolicies,
                    KeyCreationOptions = cngKeyCreationOptions,
                    KeyUsage = cngKeyUsages,
                    Provider = CngProvider.MicrosoftSoftwareKeyStorageProvider,
                    UIPolicy = new CngUIPolicy(cngUIProtectionLevels),
                };
    
                // Must add length to creationParameters separately
                CngProperty keySizeProperty = new CngProperty("Length", BitConverter.GetBytes(keyByteLength * 8), CngPropertyOptions.None);
                creationParameters.Parameters.Add(keySizeProperty);
    
                using (CngKey key = CngKey.Create(CngAlgorithm.Rsa, keyName, creationParameters))
                {
                    using (RSACng rsa = new RSACng(key)
                    {
                        KeySize = keyByteLength * 8
                    })
                    {
                        return rsa.Key.Export(CngKeyBlobFormat.GenericPublicBlob);  // Return public key.
                    }
                }
            }

    Saturday, April 13, 2019 9:52 AM
  • Hi dis081278,

    Thanks for your sharing.

    Please mark the solution as answer. This will make answer searching easier in the forum and be beneficial to community members.

    Best Regards,

    Wendy


    MSDN Community Support
    Please remember to click "Mark as Answer" the responses that resolved your issue, and to click "Unmark as Answer" if not. This can be beneficial to other community members reading this thread. If you have any compliments or complaints to MSDN Support, feel free to contact MSDNFSF@microsoft.com.

    Monday, April 15, 2019 6:05 AM
    Moderator