crypt32 [3/4]: unprotectdata function
Kees Cook
kees at outflux.net
Thu May 19 05:19:32 CDT 2005
ChangeLog:
Implement CryptUnprotectData counterpart to CryptProtectData.
--
Kees Cook @outflux.net
-------------- next part --------------
Index: dlls/crypt32/crypt32.spec
===================================================================
RCS file: /home/wine/wine/dlls/crypt32/crypt32.spec,v
retrieving revision 1.19
diff -u -p -r1.19 crypt32.spec
--- dlls/crypt32/crypt32.spec 10 Nov 2004 01:31:50 -0000 1.19
+++ dlls/crypt32/crypt32.spec 19 May 2005 10:13:12 -0000
@@ -149,7 +149,7 @@
@ stub CryptSignHashU
@ stub CryptSignMessage
@ stub CryptSignMessageWithKey
-@ stub CryptUnprotectData
+@ stdcall CryptUnprotectData(ptr ptr ptr ptr ptr long ptr)
@ stub CryptUnregisterDefaultOIDFunction
@ stub CryptUnregisterOIDFunction
@ stub CryptUnregisterOIDInfo
--- dlls/crypt32/protectdata.c.orig 2005-05-19 03:11:38.042638718 -0700
+++ dlls/crypt32/protectdata.c 2005-05-19 03:12:12.525713917 -0700
@@ -963,3 +963,172 @@ finished:
return rc;
}
+/***************************************************************************
+ * CryptUnprotectData [CRYPT32.@]
+ *
+ * Generate Plain data and Description from given Cipher and Entropy data.
+ *
+ * PARAMS
+ * pDataIn [I] Cipher data to be decoded
+ * ppszDataDescr [O] Optional Unicode string describing the Plain data
+ * pOptionalEntropy [I] Optional entropy data to adjust cipher, can be NULL
+ * pvReserved [I] Reserved, must be NULL
+ * pPromptStruct [I] Structure describing if/how to prompt during decoding
+ * dwFlags [I] Flags describing options to the decoding
+ * pDataOut [O] Resulting Plain data, from calls to CryptProtectData
+ *
+ * RETURNS
+ * TRUE If a Plain was generated.
+ * FALSE If something failed and no Plain is available.
+ *
+ * FIXME
+ * The true Windows encryption and keying mechanisms are unknown.
+ *
+ * dwFlags and pPromptStruct are currently ignored.
+ *
+ * NOTES
+ * Memory allocated in pDataOut and non-NULL ppszDataDescr must be freed
+ * with LocalFree.
+ *
+ */
+BOOL WINAPI CryptUnprotectData(DATA_BLOB* pDataIn,
+ LPWSTR * ppszDataDescr,
+ DATA_BLOB* pOptionalEntropy,
+ PVOID pvReserved,
+ CRYPTPROTECT_PROMPTSTRUCT* pPromptStruct,
+ DWORD dwFlags,
+ DATA_BLOB* pDataOut)
+{
+ BOOL rc = FALSE;
+
+ HCRYPTPROV hProv;
+ struct protect_data_t protect_data;
+ HCRYPTHASH hHash;
+ HCRYPTKEY hKey;
+ DWORD dwLength;
+
+ const char * announce_bad_opaque_data = "CryptUnprotectData received a DATA_BLOB that seems to have NOT been generated by Wine. Please enable tracing ('export WINEDEBUG=crypt') to see details.";
+
+ TRACE("called\n");
+
+ SetLastError(ERROR_SUCCESS);
+
+ if (!pDataIn || !pDataOut)
+ {
+ SetLastError(ERROR_INVALID_PARAMETER);
+ goto finished;
+ }
+
+ /* debug: show our arguments */
+ report(pDataIn,pOptionalEntropy,pPromptStruct,dwFlags);
+ TRACE("\tppszDataDescr: 0x%x\n",(unsigned int)ppszDataDescr);
+
+ /* take apart the opaque blob */
+ if (!unserialize(pDataIn, &protect_data))
+ {
+ SetLastError(ERROR_INVALID_DATA);
+ FIXME("%s\n",announce_bad_opaque_data);
+ goto finished;
+ }
+
+ /* perform basic validation on the resulting structure */
+ if (!valid_protect_data(&protect_data))
+ {
+ SetLastError(ERROR_INVALID_DATA);
+ FIXME("%s\n",announce_bad_opaque_data);
+ goto free_protect_data;
+ }
+
+ /* get a crypt context */
+ if (!CryptAcquireContextW(&hProv,NULL,NULL,CRYPT32_PROTECTDATA_PROV,0))
+ {
+ ERR("CryptAcquireContextW failed\n");
+ goto free_protect_data;
+ }
+
+ /* load key */
+ if (!load_encryption_key(hProv,&protect_data.salt,pOptionalEntropy,&hKey))
+ {
+ goto free_context;
+ }
+
+ /* create a hash for the decryption validation */
+ if (!CryptCreateHash(hProv,CRYPT32_PROTECTDATA_HASH_CALG,0,0,&hHash))
+ {
+ ERR("CryptCreateHash\n");
+ goto free_key;
+ }
+
+ /* prepare for plaintext */
+ pDataOut->cbData=protect_data.cipher.cbData;
+ if (!(pDataOut->pbData=LocalAlloc( LPTR, pDataOut->cbData)))
+ {
+ ERR("HeapAlloc\n");
+ goto free_hash;
+ }
+ memcpy(pDataOut->pbData,protect_data.cipher.pbData,protect_data.cipher.cbData);
+
+ /* decrypt! */
+ if (!CryptDecrypt(hKey, hHash, TRUE, 0, pDataOut->pbData,
+ &pDataOut->cbData) ||
+ /* check the hash fingerprint */
+ pDataOut->cbData > protect_data.cipher.cbData ||
+ !hash_matches_blob(hHash, &protect_data.fingerprint))
+ {
+ SetLastError(ERROR_INVALID_DATA);
+
+ LocalFree( pDataOut->pbData );
+ pDataOut->pbData = NULL;
+ pDataOut->cbData = 0;
+
+ goto free_hash;
+ }
+
+ /* Copy out the description */
+ dwLength = (lstrlenW(protect_data.szDataDescr)+1) * sizeof(WCHAR);
+ if (ppszDataDescr)
+ {
+ if (!(*ppszDataDescr = LocalAlloc(LPTR,dwLength)))
+ {
+ ERR("LocalAlloc (ppszDataDescr)\n");
+ goto free_hash;
+ }
+ else {
+ memcpy(*ppszDataDescr,protect_data.szDataDescr,dwLength);
+ }
+ }
+
+ /* success! */
+ rc = TRUE;
+
+free_hash:
+ CryptDestroyHash(hHash);
+free_key:
+ CryptDestroyKey(hKey);
+free_context:
+ CryptReleaseContext(hProv,0);
+free_protect_data:
+ free_protect_data(&protect_data);
+finished:
+ /* If some error occured, and no error code was set, force one. */
+ if (!rc && GetLastError()==ERROR_SUCCESS)
+ {
+ SetLastError(ERROR_INVALID_DATA);
+ }
+
+ if (rc) {
+ SetLastError(ERROR_SUCCESS);
+
+ if (ppszDataDescr)
+ {
+ TRACE("szDataDescr: %s\n",debugstr_w(*ppszDataDescr));
+ }
+ TRACE_DATA_BLOB(pDataOut);
+ }
+
+ TRACE("returning %s\n", rc ? "ok" : "FAIL");
+
+ return rc;
+}
+
+/* vi:set ai ts=4 sw=4 expandtab: */
More information about the wine-patches
mailing list