1c2c66affSColin Finck /*
2c2c66affSColin Finck  * Unit test suite for crypt32.dll's CryptProtectData/CryptUnprotectData
3c2c66affSColin Finck  *
4c2c66affSColin Finck  * Copyright 2005 Kees Cook <kees@outflux.net>
5c2c66affSColin Finck  *
6c2c66affSColin Finck  * This library is free software; you can redistribute it and/or
7c2c66affSColin Finck  * modify it under the terms of the GNU Lesser General Public
8c2c66affSColin Finck  * License as published by the Free Software Foundation; either
9c2c66affSColin Finck  * version 2.1 of the License, or (at your option) any later version.
10c2c66affSColin Finck  *
11c2c66affSColin Finck  * This library is distributed in the hope that it will be useful,
12c2c66affSColin Finck  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13c2c66affSColin Finck  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14c2c66affSColin Finck  * Lesser General Public License for more details.
15c2c66affSColin Finck  *
16c2c66affSColin Finck  * You should have received a copy of the GNU Lesser General Public
17c2c66affSColin Finck  * License along with this library; if not, write to the Free Software
18c2c66affSColin Finck  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19c2c66affSColin Finck  */
20c2c66affSColin Finck 
21*d03ac84fSAmine Khaldi #include <stdio.h>
22*d03ac84fSAmine Khaldi #include <stdarg.h>
23*d03ac84fSAmine Khaldi #include <windef.h>
24*d03ac84fSAmine Khaldi #include <winbase.h>
25*d03ac84fSAmine Khaldi #include <winerror.h>
26*d03ac84fSAmine Khaldi #include <wincrypt.h>
27*d03ac84fSAmine Khaldi 
28*d03ac84fSAmine Khaldi #include "wine/test.h"
29c2c66affSColin Finck 
30c2c66affSColin Finck static BOOL (WINAPI *pCryptProtectData)(DATA_BLOB*,LPCWSTR,DATA_BLOB*,PVOID,CRYPTPROTECT_PROMPTSTRUCT*,DWORD,DATA_BLOB*);
31c2c66affSColin Finck static BOOL (WINAPI *pCryptUnprotectData)(DATA_BLOB*,LPWSTR*,DATA_BLOB*,PVOID,CRYPTPROTECT_PROMPTSTRUCT*,DWORD,DATA_BLOB*);
32c2c66affSColin Finck 
33c2c66affSColin Finck static char  secret[]     = "I am a super secret string that no one can see!";
34c2c66affSColin Finck static char  secret2[]    = "I am a super secret string indescribable string";
35c2c66affSColin Finck static char  key[]        = "Wibble wibble wibble";
36c2c66affSColin Finck static const WCHAR desc[] = {'U','l','t','r','a',' ','s','e','c','r','e','t',' ','t','e','s','t',' ','m','e','s','s','a','g','e',0};
37c2c66affSColin Finck static BOOL protected = FALSE; /* if true, the unprotect tests can run */
38c2c66affSColin Finck static DATA_BLOB cipher;
39c2c66affSColin Finck static DATA_BLOB cipher_entropy;
40c2c66affSColin Finck static DATA_BLOB cipher_no_desc;
41c2c66affSColin Finck 
test_cryptprotectdata(void)42c2c66affSColin Finck static void test_cryptprotectdata(void)
43c2c66affSColin Finck {
44c2c66affSColin Finck     LONG r;
45c2c66affSColin Finck     DATA_BLOB plain;
46c2c66affSColin Finck     DATA_BLOB entropy;
47c2c66affSColin Finck 
48c2c66affSColin Finck     plain.pbData=(void*)secret;
49c2c66affSColin Finck     plain.cbData=strlen(secret)+1;
50c2c66affSColin Finck 
51c2c66affSColin Finck     entropy.pbData=(void*)key;
52c2c66affSColin Finck     entropy.cbData=strlen(key)+1;
53c2c66affSColin Finck 
54c2c66affSColin Finck     SetLastError(0xDEADBEEF);
55c2c66affSColin Finck     protected = pCryptProtectData(NULL,desc,NULL,NULL,NULL,0,&cipher);
56c2c66affSColin Finck     ok(!protected, "Encrypting without plain data source.\n");
57c2c66affSColin Finck     r = GetLastError();
58c2c66affSColin Finck     ok(r == ERROR_INVALID_PARAMETER, "Wrong (%u) GetLastError seen\n",r);
59c2c66affSColin Finck 
60c2c66affSColin Finck     SetLastError(0xDEADBEEF);
61c2c66affSColin Finck     protected = pCryptProtectData(&plain,desc,NULL,NULL,NULL,0,NULL);
62c2c66affSColin Finck     ok(!protected, "Encrypting without cipher destination.\n");
63c2c66affSColin Finck     r = GetLastError();
64c2c66affSColin Finck     ok(r == ERROR_INVALID_PARAMETER, "Wrong (%u) GetLastError seen\n",r);
65c2c66affSColin Finck 
66c2c66affSColin Finck     cipher.pbData=NULL;
67c2c66affSColin Finck     cipher.cbData=0;
68c2c66affSColin Finck 
69c2c66affSColin Finck     /* without entropy */
70c2c66affSColin Finck     SetLastError(0xDEADBEEF);
71c2c66affSColin Finck     protected = pCryptProtectData(&plain,desc,NULL,NULL,NULL,0,&cipher);
72c2c66affSColin Finck     ok(protected ||
73c2c66affSColin Finck      broken(!protected), /* Win9x/NT4 */
74c2c66affSColin Finck      "Encrypting without entropy.\n");
75c2c66affSColin Finck     if (protected)
76c2c66affSColin Finck     {
77c2c66affSColin Finck         r = GetLastError();
78c2c66affSColin Finck         ok(r == ERROR_SUCCESS ||
79c2c66affSColin Finck            r == ERROR_IO_PENDING, /* win2k */
80c2c66affSColin Finck            "Expected ERROR_SUCCESS or ERROR_IO_PENDING, got %d\n",r);
81c2c66affSColin Finck     }
82c2c66affSColin Finck 
83c2c66affSColin Finck     cipher_entropy.pbData=NULL;
84c2c66affSColin Finck     cipher_entropy.cbData=0;
85c2c66affSColin Finck 
86c2c66affSColin Finck     /* with entropy */
87c2c66affSColin Finck     SetLastError(0xDEADBEEF);
88c2c66affSColin Finck     protected = pCryptProtectData(&plain,desc,&entropy,NULL,NULL,0,&cipher_entropy);
89c2c66affSColin Finck     ok(protected ||
90c2c66affSColin Finck      broken(!protected), /* Win9x/NT4 */
91c2c66affSColin Finck      "Encrypting with entropy.\n");
92c2c66affSColin Finck 
93c2c66affSColin Finck     cipher_no_desc.pbData=NULL;
94c2c66affSColin Finck     cipher_no_desc.cbData=0;
95c2c66affSColin Finck 
96c2c66affSColin Finck     /* with entropy but no description */
97c2c66affSColin Finck     plain.pbData=(void*)secret2;
98c2c66affSColin Finck     plain.cbData=strlen(secret2)+1;
99c2c66affSColin Finck     SetLastError(0xDEADBEEF);
100c2c66affSColin Finck     protected = pCryptProtectData(&plain,NULL,&entropy,NULL,NULL,0,&cipher_no_desc);
101c2c66affSColin Finck     if (!protected)
102c2c66affSColin Finck     {
103c2c66affSColin Finck         /* fails in win2k */
104c2c66affSColin Finck         ok(GetLastError() == ERROR_INVALID_PARAMETER,
105c2c66affSColin Finck            "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
106c2c66affSColin Finck     }
107c2c66affSColin Finck }
108c2c66affSColin Finck 
test_cryptunprotectdata(void)109c2c66affSColin Finck static void test_cryptunprotectdata(void)
110c2c66affSColin Finck {
111c2c66affSColin Finck     LONG r;
112c2c66affSColin Finck     DATA_BLOB plain;
113c2c66affSColin Finck     DATA_BLOB entropy;
114c2c66affSColin Finck     BOOL okay;
115c2c66affSColin Finck     WCHAR * data_desc;
116c2c66affSColin Finck 
117c2c66affSColin Finck     entropy.pbData=(void*)key;
118c2c66affSColin Finck     entropy.cbData=strlen(key)+1;
119c2c66affSColin Finck 
120c2c66affSColin Finck     /* fails in win2k */
121c2c66affSColin Finck     if (!protected)
122c2c66affSColin Finck     {
123c2c66affSColin Finck         skip("CryptProtectData failed to run\n");
124c2c66affSColin Finck         return;
125c2c66affSColin Finck     }
126c2c66affSColin Finck 
127c2c66affSColin Finck     plain.pbData=NULL;
128c2c66affSColin Finck     plain.cbData=0;
129c2c66affSColin Finck 
130c2c66affSColin Finck     SetLastError(0xDEADBEEF);
131c2c66affSColin Finck     okay = pCryptUnprotectData(&cipher,NULL,NULL,NULL,NULL,0,NULL);
132c2c66affSColin Finck     ok(!okay,"Decrypting without destination\n");
133c2c66affSColin Finck     r = GetLastError();
134c2c66affSColin Finck     ok(r == ERROR_INVALID_PARAMETER, "Wrong (%u) GetLastError seen\n",r);
135c2c66affSColin Finck 
136c2c66affSColin Finck     SetLastError(0xDEADBEEF);
137c2c66affSColin Finck     okay = pCryptUnprotectData(NULL,NULL,NULL,NULL,NULL,0,&plain);
138c2c66affSColin Finck     ok(!okay,"Decrypting without source\n");
139c2c66affSColin Finck     r = GetLastError();
140c2c66affSColin Finck     ok(r == ERROR_INVALID_PARAMETER, "Wrong (%u) GetLastError seen\n",r);
141c2c66affSColin Finck 
142c2c66affSColin Finck     plain.pbData=NULL;
143c2c66affSColin Finck     plain.cbData=0;
144c2c66affSColin Finck 
145c2c66affSColin Finck     SetLastError(0xDEADBEEF);
146c2c66affSColin Finck     okay = pCryptUnprotectData(&cipher_entropy,NULL,NULL,NULL,NULL,0,&plain);
147c2c66affSColin Finck     ok(!okay,"Decrypting without needed entropy\n");
148c2c66affSColin Finck     r = GetLastError();
149c2c66affSColin Finck     ok(r == ERROR_INVALID_DATA, "Wrong (%u) GetLastError seen\n", r);
150c2c66affSColin Finck 
151c2c66affSColin Finck     plain.pbData=NULL;
152c2c66affSColin Finck     plain.cbData=0;
153c2c66affSColin Finck     data_desc=NULL;
154c2c66affSColin Finck 
155c2c66affSColin Finck     /* without entropy */
156c2c66affSColin Finck     SetLastError(0xDEADBEEF);
157c2c66affSColin Finck     okay = pCryptUnprotectData(&cipher,&data_desc,NULL,NULL,NULL,0,&plain);
158c2c66affSColin Finck     ok(okay,"Decrypting without entropy\n");
159c2c66affSColin Finck 
160c2c66affSColin Finck     ok(plain.pbData!=NULL,"Plain DATA_BLOB missing data\n");
161c2c66affSColin Finck     ok(plain.cbData==strlen(secret)+1,"Plain DATA_BLOB wrong length\n");
162c2c66affSColin Finck     ok(!strcmp((const char*)plain.pbData,secret),"Plain does not match secret\n");
163c2c66affSColin Finck     ok(data_desc!=NULL,"Description not allocated\n");
164c2c66affSColin Finck     ok(!lstrcmpW(data_desc,desc),"Description does not match\n");
165c2c66affSColin Finck 
166c2c66affSColin Finck     LocalFree(plain.pbData);
167c2c66affSColin Finck     LocalFree(data_desc);
168c2c66affSColin Finck 
169c2c66affSColin Finck     plain.pbData=NULL;
170c2c66affSColin Finck     plain.cbData=0;
171c2c66affSColin Finck     data_desc=NULL;
172c2c66affSColin Finck 
173c2c66affSColin Finck     /* with wrong entropy */
174c2c66affSColin Finck     SetLastError(0xDEADBEEF);
175c2c66affSColin Finck     okay = pCryptUnprotectData(&cipher_entropy,&data_desc,&cipher_entropy,NULL,NULL,0,&plain);
176c2c66affSColin Finck     ok(!okay,"Decrypting with wrong entropy\n");
177c2c66affSColin Finck     r = GetLastError();
178c2c66affSColin Finck     ok(r == ERROR_INVALID_DATA, "Wrong (%u) GetLastError seen\n",r);
179c2c66affSColin Finck 
180c2c66affSColin Finck     /* with entropy */
181c2c66affSColin Finck     SetLastError(0xDEADBEEF);
182c2c66affSColin Finck     okay = pCryptUnprotectData(&cipher_entropy,&data_desc,&entropy,NULL,NULL,0,&plain);
183c2c66affSColin Finck     ok(okay,"Decrypting with entropy\n");
184c2c66affSColin Finck 
185c2c66affSColin Finck     ok(plain.pbData!=NULL,"Plain DATA_BLOB missing data\n");
186c2c66affSColin Finck     ok(plain.cbData==strlen(secret)+1,"Plain DATA_BLOB wrong length\n");
187c2c66affSColin Finck     ok(!strcmp((const char*)plain.pbData,secret),"Plain does not match secret\n");
188c2c66affSColin Finck     ok(data_desc!=NULL,"Description not allocated\n");
189c2c66affSColin Finck     ok(!lstrcmpW(data_desc,desc),"Description does not match\n");
190c2c66affSColin Finck 
191c2c66affSColin Finck     LocalFree(plain.pbData);
192c2c66affSColin Finck     LocalFree(data_desc);
193c2c66affSColin Finck 
194c2c66affSColin Finck     plain.pbData=NULL;
195c2c66affSColin Finck     plain.cbData=0;
196c2c66affSColin Finck     data_desc=NULL;
197c2c66affSColin Finck 
198c2c66affSColin Finck     /* with entropy but no description */
199c2c66affSColin Finck     SetLastError(0xDEADBEEF);
200c2c66affSColin Finck     okay = pCryptUnprotectData(&cipher_no_desc,&data_desc,&entropy,NULL,NULL,0,&plain);
201c2c66affSColin Finck     ok(okay,"Decrypting with entropy and no description\n");
202c2c66affSColin Finck 
203c2c66affSColin Finck     ok(plain.pbData!=NULL,"Plain DATA_BLOB missing data\n");
204c2c66affSColin Finck     ok(plain.cbData==strlen(secret2)+1,"Plain DATA_BLOB wrong length\n");
205c2c66affSColin Finck     ok(!strcmp((const char*)plain.pbData,secret2),"Plain does not match secret\n");
206c2c66affSColin Finck     ok(data_desc!=NULL,"Description not allocated\n");
207c2c66affSColin Finck     ok(data_desc[0]=='\0',"Description not empty\n");
208c2c66affSColin Finck 
209c2c66affSColin Finck     LocalFree(data_desc);
210c2c66affSColin Finck     LocalFree(plain.pbData);
211c2c66affSColin Finck 
212c2c66affSColin Finck     plain.pbData=NULL;
213c2c66affSColin Finck     plain.cbData=0;
214c2c66affSColin Finck }
215c2c66affSColin Finck 
test_simpleroundtrip(const char * plaintext)216c2c66affSColin Finck static void test_simpleroundtrip(const char *plaintext)
217c2c66affSColin Finck {
218c2c66affSColin Finck     DATA_BLOB input;
219c2c66affSColin Finck     DATA_BLOB encrypted;
220c2c66affSColin Finck     DATA_BLOB output;
221c2c66affSColin Finck     int res;
222c2c66affSColin Finck     WCHAR emptyW[1];
223c2c66affSColin Finck 
224c2c66affSColin Finck     emptyW[0] = 0;
225c2c66affSColin Finck     input.pbData = (unsigned char *)plaintext;
226c2c66affSColin Finck     input.cbData = strlen(plaintext);
227c2c66affSColin Finck     res = pCryptProtectData(&input, emptyW, NULL, NULL, NULL, 0, &encrypted);
228c2c66affSColin Finck     ok(res != 0 || broken(!res), "can't protect\n");
229c2c66affSColin Finck     if (!res)
230c2c66affSColin Finck     {
231c2c66affSColin Finck         /* Fails on Win9x, NT4 */
232c2c66affSColin Finck         win_skip("CryptProtectData failed\n");
233c2c66affSColin Finck         return;
234c2c66affSColin Finck     }
235c2c66affSColin Finck 
236c2c66affSColin Finck     res = pCryptUnprotectData(&encrypted, NULL, NULL, NULL, NULL, 0, &output);
237c2c66affSColin Finck     ok(res != 0, "can't unprotect; last error %u\n", GetLastError());
238c2c66affSColin Finck     ok(output.cbData == strlen(plaintext), "output wrong length %d for input '%s', wanted %d\n", output.cbData, plaintext, lstrlenA(plaintext));
239c2c66affSColin Finck     ok(!memcmp(plaintext, (char *)output.pbData, output.cbData), "output wrong contents for input '%s'\n", plaintext);
240c2c66affSColin Finck     LocalFree(output.pbData);
241c2c66affSColin Finck     LocalFree(encrypted.pbData);
242c2c66affSColin Finck }
243c2c66affSColin Finck 
START_TEST(protectdata)244c2c66affSColin Finck START_TEST(protectdata)
245c2c66affSColin Finck {
246c2c66affSColin Finck     HMODULE hCrypt32 = GetModuleHandleA("crypt32.dll");
247c2c66affSColin Finck     pCryptProtectData = (void*)GetProcAddress(hCrypt32, "CryptProtectData");
248c2c66affSColin Finck     pCryptUnprotectData = (void*)GetProcAddress(hCrypt32, "CryptUnprotectData");
249c2c66affSColin Finck     if (!pCryptProtectData || !pCryptUnprotectData)
250c2c66affSColin Finck     {
251c2c66affSColin Finck         win_skip("Crypt(Un)ProtectData() is not available\n");
252c2c66affSColin Finck         return;
253c2c66affSColin Finck     }
254c2c66affSColin Finck 
255c2c66affSColin Finck     protected=FALSE;
256c2c66affSColin Finck     test_cryptprotectdata();
257c2c66affSColin Finck     test_cryptunprotectdata();
258c2c66affSColin Finck     test_simpleroundtrip("");
259c2c66affSColin Finck     test_simpleroundtrip("hello");
260c2c66affSColin Finck 
261c2c66affSColin Finck     /* deinit globals here */
262c2c66affSColin Finck     if (cipher.pbData) LocalFree(cipher.pbData);
263c2c66affSColin Finck     if (cipher_entropy.pbData) LocalFree(cipher_entropy.pbData);
264c2c66affSColin Finck     if (cipher_no_desc.pbData) LocalFree(cipher_no_desc.pbData);
265c2c66affSColin Finck }
266