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