首页 -> 安全研究

安全研究

绿盟月刊
绿盟安全月刊->第53期->安全文摘
期刊号: 类型: 关键词:
secure string comparison

作者:coolq
出处:http://www.linuxforum.net/forum/showflat.php?Cat=&Board=security&Number=
日期:2004-11-05

coolq

最近看了Secure Programming
Cookbook的12.2,感觉里边的构思很好,照葫芦画瓢,做了点修改。
平常的时候用strcmp比较字符串很容易被破解,而下例的主要方法是:
  1. 先计算出需要比较字符串的散列值,CRC32、MD5、SHA1都可以,例子中用的是MD5
  2.
对得到的散列值,一次取四位,构造一个指针数组,大小为16,其中只有一个指针是正确的,以该
四位值作为索引,得到一个指针,调用该指针的函数。正确的指针指向下一个函数,依此类推。
  3. 最后四位对应的指针为出口函数,在这里为digest_ok
这样做的好处:
  密码可以在代码中不出现名文而只是散列值;没有比较指令,破解的难度较大
注意:
  该程序的使用需要openssl库的支持,当然你也可以把有用代码提取出来
-------------------------------------------------------------------------------------


/* Name: secure_str_compare.c
* Author: CoolQ
* Compile:
*     1) edit secure_str_compare.c
*         set TEST_STRING to proper value
*     2) gcc -o generate secure_str_compare.c -lssl
*     3) ./generate > compare.c
*     4) edit compare.c
*         in func main, point p to whatever you want to compare
*         in func digest_ok, you can add some greetings or
*                 just leave it empty
*     5) gcc -o compare compare.c -lssl
*     6) ./compare
*         if the string matches, you'll see "verify ok"
*         .or.
*         you get a segmentation fault
* Note:
*     You must have openssl and openssl-devel installed
*     If you want to use CRC32 or SHA1, only change DIGEST_LENGTH to 4 / 20,
*         chage get_md5 to proper func
*/
#include <stdio.h>
#include <openssl/md5.h>
#include <string.h>
#include <stdlib.h>
#include <time.h>

#define TEST_STRING "1234567890"
#define DIGEST_LENGTH 16
/* print separator */
#define PRINT_SEP(i) if(((i+1) % 4) == 0) fprintf(stdout, "\n\t")

/* get md5 digest and put in result[DIGEST_LENGTH] */
void get_md5(unsigned char result[DIGEST_LENGTH])
{
    MD5_CTX ctx;
    
    MD5_Init(&ctx);
    MD5_Update(&ctx, TEST_STRING, strlen(TEST_STRING));
    MD5_Final(result, &ctx);

    return;
}

/* generate include file and function declaration */
void generate_fun_declare(void)
{
    int    count;
    
    fprintf(stdout, "#include <openssl/md5.h>\n");
    fprintf(stdout, "#include <stdio.h>\n");
    fprintf(stdout, "#include <string.h>\n\n");
    fprintf(stdout, "#define DIGEST_LENGTH %d\n\n", DIGEST_LENGTH);

    fprintf(stdout, "static void calc_md5(const char *, unsigned charresult[DIGEST_LENGTH]);\n");
    fprintf(stdout, "typedef void (*digest_check_fn)(unsigned char *);\n\n");
    for(count = 0; count < DIGEST_LENGTH; count++){
        fprintf(stdout, "static void digest_nib%d(unsigned char *digest);\n",
                count * 2 + 1);
        fprintf(stdout, "static void digest_nib%d(unsigned char *digest);\n",
                count * 2 + 2);
    }
    fprintf(stdout, "\nstatic void digest_ok(void);\n");
    return;
}

/* generate jmp function arrays */
void generate_jmp_array(unsigned char result[DIGEST_LENGTH])
{
    int         count, pos;
    unsigned int    low, high;
    char         r;
    srandom((int) time(NULL));
    fprintf(stdout, "digest_check_fn ");
    for(count = 0; count < DIGEST_LENGTH; count++){
        low = result[count] & 0x0F;
        high = result[count] >> 4;
        
        fprintf(stdout, "b%d[DIGEST_LENGTH] = { \n\t", count * 2 + 1);
        for(pos = 0; pos < low; pos++){
            r = random() & 0xFF;
            fprintf(stdout, "digest_nib%d+%d,\t",
                    count * 2 + 2, r);
            PRINT_SEP(pos);
            
        }
        fprintf(stdout, "digest_nib%d,\t", count * 2 + 2);
        PRINT_SEP(low);
        for(pos = low + 1; pos < DIGEST_LENGTH; pos++){
            r = random() & 0xFF;
            fprintf(stdout, "digest_nib%d+%d,\t",
                    count * 2 + 2, r);
            PRINT_SEP(pos);
        }
        fprintf(stdout, "},\n");

        fprintf(stdout, "b%d[DIGEST_LENGTH] = { \n\t", count * 2 + 2);
        for(pos = 0; pos < high; pos++){
            r = random() & 0xFF;
            if(count != DIGEST_LENGTH - 1)
                fprintf(stdout, "digest_nib%d+%d,\t",
                        count * 2 + 3, r);
            else
                fprintf(stdout, "digest_ok+%d,\t", r);
            PRINT_SEP(pos);
        }
        if(count != DIGEST_LENGTH - 1)
            fprintf(stdout, "digest_nib%d,\t", count * 2 + 3);
        else
            fprintf(stdout, "digest_ok,\t");
        PRINT_SEP(high);
        for(pos = high + 1; pos < DIGEST_LENGTH; pos++){
            r = random() & 0xFF;
            if(count != DIGEST_LENGTH - 1)
                fprintf(stdout, "digest_nib%d+%d,\t",
                    count * 2 + 3, r);
            else
                fprintf(stdout, "digest_ok+%d,\t", r);
            PRINT_SEP(pos);
        }
        fprintf(stdout, "}%s", count == DIGEST_LENGTH - 1
                    ? ";\n" : ",\n");
    }
    return;
}

/* generate DIG_TABLE_LOOKUP macro */
void generate_macro(void)
{
    fprintf(stdout, "#define DIG_TABLE_LOOKUP(table, pdigest, low)        \\\n");
    fprintf(stdout, "    do{                        \\\n");
    fprintf(stdout, "        int index = *pdigest & 0x0F;        \\\n");
    fprintf(stdout, "        digest_check_fn next = table[index];    \\\n");
    fprintf(stdout, "        *pdigest >>= 4;                \\\n");
    fprintf(stdout, "        if(low == 1) pdigest++;            \\\n");
    fprintf(stdout, "        (*next)(pdigest);            \\\n");
    fprintf(stdout, "    }while(0)                    \n");
    
    return;
}

/* generate function logic */
void generate_func_exec(void)
{
    int    count;
    for(count = 0; count < DIGEST_LENGTH; count++){
        fprintf(stdout, "static void digest_nib%d(unsigned char *digest)"
                " \n{ DIG_TABLE_LOOKUP(b%d, (digest), 0); }\n",
                count * 2 + 1, count * 2 + 1);
        fprintf(stdout, "static void digest_nib%d(unsigned char *digest)"
                " \n{ DIG_TABLE_LOOKUP(b%d, (digest), 1); }\n",
                count * 2 + 2, count * 2 + 2);
    }
    fprintf(stdout, "\nstatic void calc_md5(const char *p, unsigned charresult[DIGEST_LENGTH])\n");
    fprintf(stdout, "{\n");
    fprintf(stdout, "\tMD5_CTX ctx;\n");
    fprintf(stdout, "\tMD5_Init(&ctx);\n");
    fprintf(stdout, "\tMD5_Update(&ctx, p, strlen(p));\n");
    fprintf(stdout, "\tMD5_Final(result, &ctx);\n");
    fprintf(stdout, "\n\treturn;\n}\n");

    fprintf(stdout, "static void digest_ok(void)"
            " { printf(\"Verify OK.\\n\");} \n");
    return;
}

/* show you how to use */
void generate_func_use(void)
{
    fprintf(stdout, "int main(int argc, char *argv[])\n");
    fprintf(stdout, "{\n");
    fprintf(stdout, "\tunsigned char md5sum[DIGEST_LENGTH];\n");
    fprintf(stdout, "\tunsigned char *p = \"1234567890\";\n\n");
    fprintf(stdout, "\tcalc_md5(p, md5sum);\n");
    fprintf(stdout, "\tdigest_nib1(md5sum);\n");
    fprintf(stdout, "\treturn 0;\n}\n");

    return;
}

/* main func */
int main(int argc, char *argv[])
{
    unsigned char     md5sum[DIGEST_LENGTH];
    int        count;
    
    get_md5(md5sum);
    generate_fun_declare();
    generate_jmp_array(md5sum);
    generate_macro();
    generate_func_exec();
    generate_func_use();
    return 0;
}
版权所有,未经许可,不得转载