/* ** Copyright (c) 2009 D. Richard Hipp ** ** This program is free software; you can redistribute it and/or ** modify it under the terms of the Simplified BSD License (also ** known as the "2-Clause License" or "FreeBSD License".) ** This program 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. ** ** Author contact information: ** drh@hwaci.com ** http://www.hwaci.com/drh/ ** ******************************************************************************* ** ** This file contains code to a simple text-based CAPTCHA. Though easily ** defeated by a sophisticated attacker, this CAPTCHA does at least make ** scripting attacks more difficult. */ #include "config.h" #include #include "captcha.h" #if INTERFACE #define CAPTCHA 3 /* Which captcha rendering to use */ #endif /* ** Convert a hex digit into a value between 0 and 15 */ int hex_digit_value(char c){ if( c>='0' && c<='9' ){ return c - '0'; }else if( c>='a' && c<='f' ){ return c - 'a' + 10; }else if( c>='A' && c<='F' ){ return c - 'A' + 10; }else{ return 0; } } #if CAPTCHA==1 /* ** A 4x6 pixel bitmap font for hexadecimal digits */ static const unsigned int aFont1[] = { 0x699996, 0x262227, 0x69124f, 0xf16196, 0x26af22, 0xf8e196, 0x68e996, 0xf12244, 0x696996, 0x699716, 0x699f99, 0xe9e99e, 0x698896, 0xe9999e, 0xf8e88f, 0xf8e888, }; /* ** Render an 8-character hexadecimal string as ascii art. ** Space to hold the result is obtained from malloc() and should be freed ** by the caller. */ char *captcha_render(const char *zPw){ char *z = fossil_malloc( 9*6*strlen(zPw) + 7 ); int i, j, k, m; k = 0; for(i=0; i<6; i++){ for(j=0; zPw[j]; j++){ unsigned char v = hex_digit_value(zPw[j]); v = (aFont1[v] >> ((5-i)*4)) & 0xf; for(m=8; m>=1; m = m>>1){ if( v & m ){ z[k++] = 'X'; z[k++] = 'X'; }else{ z[k++] = ' '; z[k++] = ' '; } } z[k++] = ' '; z[k++] = ' '; } z[k++] = '\n'; } z[k] = 0; return z; } #endif /* CAPTCHA==1 */ #if CAPTCHA==2 static const char *const azFont2[] = { /* 0 */ " __ ", " / \\ ", "| () |", " \\__/ ", /* 1 */ " _ ", "/ |", "| |", "|_|", /* 2 */ " ___ ", "|_ )", " / / ", "/___|", /* 3 */ " ____", "|__ /", " |_ \\", "|___/", /* 4 */ " _ _ ", "| | | ", "|_ _|", " |_| ", /* 5 */ " ___ ", "| __|", "|__ \\", "|___/", /* 6 */ " __ ", " / / ", "/ _ \\", "\\___/", /* 7 */ " ____ ", "|__ |", " / / ", " /_/ ", /* 8 */ " ___ ", "( _ )", "/ _ \\", "\\___/", /* 9 */ " ___ ", "/ _ \\", "\\_, /", " /_/ ", /* A */ " ", " /\\ ", " / \\ ", "/_/\\_\\", /* B */ " ___ ", "| _ )", "| _ \\", "|___/", /* C */ " ___ ", " / __|", "| (__ ", " \\___|", /* D */ " ___ ", "| \\ ", "| |) |", "|___/ ", /* E */ " ___ ", "| __|", "| _| ", "|___|", /* F */ " ___ ", "| __|", "| _| ", "|_| ", }; /* ** Render an 8-digit hexadecimal string as ascii arg. ** Space to hold the result is obtained from malloc() and should be freed ** by the caller. */ char *captcha_render(const char *zPw){ char *z = fossil_malloc( 7*4*strlen(zPw) + 5 ); int i, j, k, m; const char *zChar; k = 0; for(i=0; i<4; i++){ for(j=0; zPw[j]; j++){ unsigned char v = hex_digit_value(zPw[j]); zChar = azFont2[4*v + i]; for(m=0; zChar[m]; m++){ z[k++] = zChar[m]; } } z[k++] = '\n'; } z[k] = 0; return z; } #endif /* CAPTCHA==2 */ #if CAPTCHA==3 static const char *const azFont3[] = { /* 0 */ " ___ ", " / _ \\ ", "| | | |", "| | | |", "| |_| |", " \\___/ ", /* 1 */ " __ ", "/_ |", " | |", " | |", " | |", " |_|", /* 2 */ " ___ ", "|__ \\ ", " ) |", " / / ", " / /_ ", "|____|", /* 3 */ " ____ ", "|___ \\ ", " __) |", " |__ < ", " ___) |", "|____/ ", /* 4 */ " _ _ ", "| || | ", "| || |_ ", "|__ _|", " | | ", " |_| ", /* 5 */ " _____ ", "| ____|", "| |__ ", "|___ \\ ", " ___) |", "|____/ ", /* 6 */ " __ ", " / / ", " / /_ ", "| '_ \\ ", "| (_) |", " \\___/ ", /* 7 */ " ______ ", "|____ |", " / / ", " / / ", " / / ", " /_/ ", /* 8 */ " ___ ", " / _ \\ ", "| (_) |", " > _ < ", "| (_) |", " \\___/ ", /* 9 */ " ___ ", " / _ \\ ", "| (_) |", " \\__, |", " / / ", " /_/ ", /* A */ " ", " /\\ ", " / \\ ", " / /\\ \\ ", " / ____ \\ ", "/_/ \\_\\", /* B */ " ____ ", "| _ \\ ", "| |_) |", "| _ < ", "| |_) |", "|____/ ", /* C */ " _____ ", " / ____|", "| | ", "| | ", "| |____ ", " \\_____|", /* D */ " _____ ", "| __ \\ ", "| | | |", "| | | |", "| |__| |", "|_____/ ", /* E */ " ______ ", "| ____|", "| |__ ", "| __| ", "| |____ ", "|______|", /* F */ " ______ ", "| ____|", "| |__ ", "| __| ", "| | ", "|_| ", }; /* ** Render an 8-digit hexadecimal string as ascii arg. ** Space to hold the result is obtained from malloc() and should be freed ** by the caller. */ char *captcha_render(const char *zPw){ char *z = fossil_malloc( 10*6*strlen(zPw) + 7 ); int i, j, k, m; const char *zChar; unsigned char x; int y; k = 0; for(i=0; i<6; i++){ x = 0; for(j=0; zPw[j]; j++){ unsigned char v = hex_digit_value(zPw[j]); x = (x<<4) + v; switch( x ){ case 0x7a: case 0xfa: y = 3; break; case 0x47: y = 2; break; case 0xf6: case 0xa9: case 0xa4: case 0xa1: case 0x9a: case 0x76: case 0x61: case 0x67: case 0x69: case 0x41: case 0x42: case 0x43: case 0x4a: y = 1; break; default: y = 0; break; } zChar = azFont3[6*v + i]; while( y && zChar[0]==' ' ){ y--; zChar++; } while( y && z[k-1]==' ' ){ y--; k--; } for(m=0; zChar[m]; m++){ z[k++] = zChar[m]; } } z[k++] = '\n'; } z[k] = 0; return z; } #endif /* CAPTCHA==3 */ /* ** COMMAND: test-captcha ** ** Render an ASCII-art captcha for numbers given on the command line. */ void test_captcha(void){ int i; unsigned int v; char *z; for(i=2; i