⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 protectdata.c

📁 这是一个开放源代码的与WINNT/WIN2K/WIN2003兼容的操作系统
💻 C
📖 第 1 页 / 共 3 页
字号:
/*
 * Copyright 2005 Kees Cook <kees@outflux.net>
 *
 * 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, 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 <stdarg.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>

#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

static const BYTE crypt32_protectdata_secret[] = {
    'I','\'','m',' ','h','u','n','t','i','n','g',' ',
    'w','a','b','b','i','t','s',0
};

/*
 * 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;
};

/* this is used to check if an incoming structure was built by Wine */
static const char crypt_magic_str[] = "Wine Crypt32 ok";

/* debugging tool to print strings of hex chars */
static const char *
hex_str(const unsigned char *p, int n)
{
    const char * ptr;
    char report[80];
    int r=-1;
    report[0]='\0';
    ptr = wine_dbg_sprintf("%s","");
    while (--n >= 0)
    {
        if (r++ % 20 == 19)
        {
            ptr = wine_dbg_sprintf("%s%s",ptr,report);
            report[0]='\0';
        }
        sprintf(report+strlen(report),"%s%02x", r ? "," : "", *p++);
    }
    return wine_dbg_sprintf("%s%s",ptr,report);
}

#define TRACE_DATA_BLOB(blob) do { \
    TRACE("%s cbData: %u\n", #blob ,(unsigned int)((blob)->cbData)); \
    TRACE("%s pbData @ %p:%s\n", #blob ,(blob)->pbData, \
          hex_str((blob)->pbData, (blob)->cbData)); \
} while (0)

static
void serialize_dword(DWORD value,BYTE ** ptr)
{
    /*TRACE("called\n");*/

    memcpy(*ptr,&value,sizeof(DWORD));
    *ptr+=sizeof(DWORD);
}

static
void serialize_string(const BYTE *str, BYTE **ptr, DWORD len, DWORD width,
                      BOOL prepend_len)
{
    /*TRACE("called %ux%u\n",(unsigned int)len,(unsigned int)width);*/

    if (prepend_len)
    {
        serialize_dword(len,ptr);
    }
    memcpy(*ptr,str,len*width);
    *ptr+=len*width;
}

static
BOOL unserialize_dword(const BYTE *ptr, DWORD *index, DWORD size, DWORD *value)
{
    /*TRACE("called\n");*/

    if (!ptr || !index || !value) return FALSE;

    if (*index+sizeof(DWORD)>size)
    {
        return FALSE;
    }

    memcpy(value,&(ptr[*index]),sizeof(DWORD));
    *index+=sizeof(DWORD);

    return TRUE;
}

static
BOOL unserialize_string(const BYTE *ptr, DWORD *index, DWORD size,
                        DWORD len, DWORD width, BOOL inline_len,
                        BYTE ** data, DWORD * stored)
{
    /*TRACE("called\n");*/

    if (!ptr || !data) return FALSE;

    if (inline_len) {
        if (!unserialize_dword(ptr,index,size,&len))
            return FALSE;
    }

    if (*index+len*width>size)
    {
        return FALSE;
    }

    if (!(*data = CryptMemAlloc( len*width)))
    {
        return FALSE;
    }

    memcpy(*data,&(ptr[*index]),len*width);
    if (stored)
    {
        *stored = len;
    }
    *index+=len*width;

    return TRUE;
}

static
BOOL serialize(const struct protect_data_t *pInfo, DATA_BLOB *pSerial)
{
    BYTE * ptr;
    DWORD dwStrLen;
    DWORD dwStruct;

    TRACE("called\n");

    if (!pInfo || !pInfo->szDataDescr || !pSerial ||
        !pInfo->info0.pbData || !pInfo->info1.pbData ||
        !pInfo->data0.pbData || !pInfo->salt.pbData ||
        !pInfo->cipher.pbData || !pInfo->fingerprint.pbData)
    {
        return FALSE;
    }

    if (pInfo->info0.cbData!=16)
    {
        ERR("protect_data_t info0 not 16 bytes long\n");
    }

    if (pInfo->info1.cbData!=16)
    {
        ERR("protect_data_t info1 not 16 bytes long\n");
    }

    dwStrLen=lstrlenW(pInfo->szDataDescr);

    pSerial->cbData=0;
    pSerial->cbData+=sizeof(DWORD)*8; /* 8 raw DWORDs */
    pSerial->cbData+=sizeof(DWORD)*4; /* 4 BLOBs with size */
    pSerial->cbData+=pInfo->info0.cbData;
    pSerial->cbData+=pInfo->info1.cbData;
    pSerial->cbData+=(dwStrLen+1)*sizeof(WCHAR) + 4; /* str, null, size */
    pSerial->cbData+=pInfo->data0.cbData;
    pSerial->cbData+=pInfo->salt.cbData;
    pSerial->cbData+=pInfo->cipher.cbData;
    pSerial->cbData+=pInfo->fingerprint.cbData;

    /* save the actual structure size */
    dwStruct = pSerial->cbData;
    /* There may be a 256 byte minimum, but I can't prove it. */
    /*if (pSerial->cbData<256) pSerial->cbData=256;*/

    pSerial->pbData=LocalAlloc(LPTR,pSerial->cbData);
    if (!pSerial->pbData) return FALSE;

    ptr=pSerial->pbData;

    /* count0 */
    serialize_dword(pInfo->count0,&ptr);
    /*TRACE("used %u\n",ptr-pSerial->pbData);*/
    
    /* info0 */
    serialize_string(pInfo->info0.pbData,&ptr,
                     pInfo->info0.cbData,sizeof(BYTE),FALSE);
    /*TRACE("used %u\n",ptr-pSerial->pbData);*/

    /* count1 */
    serialize_dword(pInfo->count1,&ptr);
    /*TRACE("used %u\n",ptr-pSerial->pbData);*/

    /* info1 */
    serialize_string(pInfo->info1.pbData,&ptr,
                     pInfo->info1.cbData,sizeof(BYTE),FALSE);
    /*TRACE("used %u\n",ptr-pSerial->pbData);*/

    /* null0 */
    serialize_dword(pInfo->null0,&ptr);
    /*TRACE("used %u\n",ptr-pSerial->pbData);*/
    
    /* szDataDescr */
    serialize_string((BYTE*)pInfo->szDataDescr,&ptr,
                     (dwStrLen+1)*sizeof(WCHAR),sizeof(BYTE),TRUE);
    /*TRACE("used %u\n",ptr-pSerial->pbData);*/

    /* unknown0 */
    serialize_dword(pInfo->unknown0,&ptr);
    /*TRACE("used %u\n",ptr-pSerial->pbData);*/
    /* unknown1 */
    serialize_dword(pInfo->unknown1,&ptr);
    /*TRACE("used %u\n",ptr-pSerial->pbData);*/
    
    /* data0 */
    serialize_string(pInfo->data0.pbData,&ptr,
                     pInfo->data0.cbData,sizeof(BYTE),TRUE);
    /*TRACE("used %u\n",ptr-pSerial->pbData);*/

    /* null1 */
    serialize_dword(pInfo->null1,&ptr);
    /*TRACE("used %u\n",ptr-pSerial->pbData);*/
    
    /* unknown2 */
    serialize_dword(pInfo->unknown2,&ptr);
    /*TRACE("used %u\n",ptr-pSerial->pbData);*/
    /* unknown3 */
    serialize_dword(pInfo->unknown3,&ptr);
    /*TRACE("used %u\n",ptr-pSerial->pbData);*/
    
    /* salt */
    serialize_string(pInfo->salt.pbData,&ptr,
                     pInfo->salt.cbData,sizeof(BYTE),TRUE);
    /*TRACE("used %u\n",ptr-pSerial->pbData);*/

    /* cipher */
    serialize_string(pInfo->cipher.pbData,&ptr,
                     pInfo->cipher.cbData,sizeof(BYTE),TRUE);
    /*TRACE("used %u\n",ptr-pSerial->pbData);*/

    /* fingerprint */
    serialize_string(pInfo->fingerprint.pbData,&ptr,
                     pInfo->fingerprint.cbData,sizeof(BYTE),TRUE);
    /*TRACE("used %u\n",ptr-pSerial->pbData);*/

    if (ptr - pSerial->pbData != dwStruct)
    {
        ERR("struct size changed!? %u != expected %u\n",
            ptr - pSerial->pbData, (unsigned int)dwStruct);
        LocalFree(pSerial->pbData);
        pSerial->pbData=NULL;
        pSerial->cbData=0;
        return FALSE;
    }

    return TRUE;
}

static
BOOL unserialize(const DATA_BLOB *pSerial, struct protect_data_t *pInfo)
{
    BYTE * ptr;
    DWORD index;
    DWORD size;
    BOOL status=TRUE;

    TRACE("called\n");

    if (!pInfo || !pSerial || !pSerial->pbData)
        return FALSE;

    index=0;
    ptr=pSerial->pbData;
    size=pSerial->cbData;

    /* count0 */
    if (!unserialize_dword(ptr,&index,size,&pInfo->count0))
    {
        ERR("reading count0 failed!\n");
        return FALSE;
    }
    
    /* info0 */
    if (!unserialize_string(ptr,&index,size,16,sizeof(BYTE),FALSE,
                            &pInfo->info0.pbData, &pInfo->info0.cbData))
    {
        ERR("reading info0 failed!\n");
        return FALSE;
    }

    /* count1 */
    if (!unserialize_dword(ptr,&index,size,&pInfo->count1))
    {
        ERR("reading count1 failed!\n");

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -