/* * Copyright 2005 Kees Cook * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ /* * The Win32 CryptProtectData and CryptUnprotectData functions are meant * to provide a mechanism for encrypting data on a machine where other users * of the system can't be trusted. It is used in many examples as a way * to store username and password information to the registry, but store * it not in the clear. * * The encryption is symmetric, but the method is unknown. However, since * it is keyed to the machine and the user, it is unlikely that the values * would be portable. Since programs must first call CryptProtectData to * get a cipher text, the underlying system doesn't have to exactly * match the real Windows version. However, attempts have been made to * at least try to look like the Windows version, including guesses at the * purpose of various portions of the "opaque data blob" that is used. * */ #include #include #include #include #include "windef.h" #include "winbase.h" #include "wincrypt.h" #include "winreg.h" #include "wine/debug.h" WINE_DEFAULT_DEBUG_CHANNEL(crypt); #define CRYPT32_PROTECTDATA_PROV PROV_RSA_FULL #define CRYPT32_PROTECTDATA_HASH_CALG CALG_MD5 #define CRYPT32_PROTECTDATA_KEY_CALG CALG_RC2 #define CRYPT32_PROTECTDATA_SALT_LEN 16 #define CRYPT32_PROTECTDATA_SECRET "I'm hunting wabbits" /* * The data format returned by the real Windows CryptProtectData seems * to be something like this: DWORD count0; - how many "info0_*[16]" blocks follow (was always 1) BYTE info0_0[16]; - unknown information ... DWORD count1; - how many "info1_*[16]" blocks follow (was always 1) BYTE info1_0[16]; - unknown information ... DWORD null0; - NULL "end of records"? DWORD str_len; - length of WCHAR string including term WCHAR str[str_len]; - The "dataDescription" value DWORD unknown0; - unknown value (seems large, but only WORD large) DWORD unknown1; - unknown value (seems small, less than a BYTE) DWORD data_len; - length of data (was 16 in samples) BYTE data[data_len]; - unknown data (fingerprint?) DWORD null1; - NULL ? DWORD unknown2; - unknown value (seems large, but only WORD large) DWORD unknown3; - unknown value (seems small, less than a BYTE) DWORD salt_len; - length of salt(?) data BYTE salt[salt_len]; - salt(?) for symmetric encryption DWORD cipher_len; - length of cipher(?) data - was close to plain len BYTE cipher[cipher_len]; - cipher text? DWORD crc_len; - length of fingerprint(?) data - was 20 byte==160b SHA1 BYTE crc[crc_len]; - fingerprint of record? * The data structures used in Wine are modelled after this guess. */ struct protect_data_t { DWORD count0; DATA_BLOB info0; /* using this to hold crypt_magic_str */ DWORD count1; DATA_BLOB info1; DWORD null0; WCHAR * szDataDescr; /* serialized differently than the DATA_BLOBs */ DWORD unknown0; /* perhaps the HASH alg const should go here? */ DWORD unknown1; DATA_BLOB data0; DWORD null1; DWORD unknown2; /* perhaps the KEY alg const should go here? */ DWORD unknown3; DATA_BLOB salt; DATA_BLOB cipher; DATA_BLOB fingerprint; };