« Entity Framework Performance Tip - Be a Minimalist | Main | Hiatus »
September 12, 2009
"File not found" CryptographicException
The Data Protection API (in Windows 2000 or later) provides methods to securely store secret information (e.g., a cached password) on a local computer. Only the logged-in user can decrypt the protected data (if they also have the key that was used to protect it). In .NET, these APIs are exposed through the ProtectedData class.
On one of our XP test systems, a call to ProtectedData.Protect unexpectedly failed with a CryptographicException that had a very puzzling exception message:
System.Security.Cryptography.CryptographicException: The system cannot
find the file specified.
at System.Security.Cryptography.ProtectedData.Protect(Byte[] userData,
Byte[] optionalEntropy, DataProtectionScope scope)
There is no information provided on which file is required or why it's missing, or even why protecting data (in memory) requires file system access in the first place. Searching the internet for the error message turned up just a few other programmers who were also experiencing, but no solutions.
Since the ProtectedData class is just a thin wrapper around the Win32 CryptProtectData function, I searched for the underlying Win32 error code, and found the answer: the crypto methods read the HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Explorer\User Shell Folders registry key; if there are missing values, the methods will fail. (This makes me think that the methods are incorrectly reading the "User Shell Folders" key, instead of calling SHGetFolderPath, as Raymond recommends, but I haven't been able to test that yet.)
Posted by Bradley Grainger at September 12, 2009 1:56 PM
Trackback Pings
TrackBack URL for this entry:
http://blog.logos.com/mt-cgi/mt-tb.cgi/302
Comments
I've also found that if the registry key is not writable you'll get a similiar error. Finally, I know you'll find a directory buried under Application Settings that needs to exist for Cryptography - give me a note back if you end up getting stuck.
A tool in your kit that I'm assuming you're using to find this - SysInternals' FileMon & RegMon would have pointed you in the direction...
Posted by: Michael Hollinger at September 12, 2009 8:20 PM
In my searching I did see a blog post that mentioned the directory you refer to, but in this case it turned out to be just the missing "AppData" registry value. (And if I had physical access to this particular machine, I would have used ProcMon to get a low-level look at what was going on.)
Posted by: Bradley Grainger
at September 12, 2009 10:22 PM
I am getting this error on a ProtectedData.Unprotect call. I had been working under the assumption that the user account I am impersonating does not have the correct access to the encrypted key file or that the impersonation wasn't working correctly. I am using Enterprise Library's securityCryptographyConfiguration application block. I had to set up a debug version of Enterprise Library which I have now traced into and found the error to be thrown by the ProtectedData.Unprotect call. If I log in to my machine as the user I am impersonting then it all works well. If I am myself then it fails even though the Windows identity is the correct impersonated user. Why would this key be accessable in one instance and not the other?
Posted by: Jonathan at September 28, 2009 2:00 PM
I see a lot of problems with DPAPI being reported on the internet when impersonation is involved; I haven't ever used it in that situation so I couldn't comment first-hand.
Posted by: Bradley Grainger
at September 28, 2009 2:03 PM
I was fighting with the SQL Server Express 2008 install for several days and this one had me also. Simply setting HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Explorer\User Shell Folders\AppData to %USERPROFILE%\Application as the linked article said solved it!!!
Posted by: Paul Suchko at November 5, 2009 10:38 PM