File Annotation
Not logged in
b4a29fac93 2009-08-10       drh: /*
b4a29fac93 2009-08-10       drh: ** Copyright (c) 2009 D. Richard Hipp
b4a29fac93 2009-08-10       drh: **
b4a29fac93 2009-08-10       drh: ** This program is free software; you can redistribute it and/or
b4a29fac93 2009-08-10       drh: ** modify it under the terms of the GNU General Public
b4a29fac93 2009-08-10       drh: ** License version 2 as published by the Free Software Foundation.
b4a29fac93 2009-08-10       drh: **
b4a29fac93 2009-08-10       drh: ** This program is distributed in the hope that it will be useful,
b4a29fac93 2009-08-10       drh: ** but WITHOUT ANY WARRANTY; without even the implied warranty of
b4a29fac93 2009-08-10       drh: ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
b4a29fac93 2009-08-10       drh: ** General Public License for more details.
b4a29fac93 2009-08-10       drh: **
b4a29fac93 2009-08-10       drh: ** You should have received a copy of the GNU General Public
b4a29fac93 2009-08-10       drh: ** License along with this library; if not, write to the
b4a29fac93 2009-08-10       drh: ** Free Software Foundation, Inc., 59 Temple Place - Suite 330,
b4a29fac93 2009-08-10       drh: ** Boston, MA  02111-1307, USA.
b4a29fac93 2009-08-10       drh: **
b4a29fac93 2009-08-10       drh: ** Author contact information:
b4a29fac93 2009-08-10       drh: **   drh@hwaci.com
b4a29fac93 2009-08-10       drh: **   http://www.hwaci.com/drh/
b4a29fac93 2009-08-10       drh: **
b4a29fac93 2009-08-10       drh: *******************************************************************************
b4a29fac93 2009-08-10       drh: **
b4a29fac93 2009-08-10       drh: ** This file contains code to a simple text-based CAPTCHA.  Though eaily
b4a29fac93 2009-08-10       drh: ** defeated by a sophisticated attacker, this CAPTCHA does at least make
b4a29fac93 2009-08-10       drh: ** scripting attacks more difficult.
b4a29fac93 2009-08-10       drh: */
b4a29fac93 2009-08-10       drh: #include <assert.h>
b4a29fac93 2009-08-10       drh: #include "config.h"
b4a29fac93 2009-08-10       drh: #include "captcha.h"
b4a29fac93 2009-08-10       drh: 
b4a29fac93 2009-08-10       drh: #if INTERFACE
b4a29fac93 2009-08-10       drh: #define CAPTCHA 2  /* Which captcha rendering to use */
b4a29fac93 2009-08-10       drh: #endif
b4a29fac93 2009-08-10       drh: 
b4a29fac93 2009-08-10       drh: /*
b4a29fac93 2009-08-10       drh: ** Convert a hex digit into a value between 0 and 15
b4a29fac93 2009-08-10       drh: */
b4a29fac93 2009-08-10       drh: static int hexValue(char c){
b4a29fac93 2009-08-10       drh:   if( c>='0' && c<='9' ){
b4a29fac93 2009-08-10       drh:     return c - '0';
b4a29fac93 2009-08-10       drh:   }else if( c>='a' && c<='f' ){
b4a29fac93 2009-08-10       drh:     return c - 'a' + 10;
b4a29fac93 2009-08-10       drh:   }else if( c>='A' && c<='F' ){
b4a29fac93 2009-08-10       drh:     return c - 'A' + 10;
b4a29fac93 2009-08-10       drh:   }else{
b4a29fac93 2009-08-10       drh:     return 0;
b4a29fac93 2009-08-10       drh:   }
b4a29fac93 2009-08-10       drh: }
b4a29fac93 2009-08-10       drh: 
b4a29fac93 2009-08-10       drh: #if CAPTCHA==1
b4a29fac93 2009-08-10       drh: /*
b4a29fac93 2009-08-10       drh: ** A 4x6 pixel bitmap font for hexadecimal digits
b4a29fac93 2009-08-10       drh: */
b4a29fac93 2009-08-10       drh: static const unsigned int aFont1[] = {
b4a29fac93 2009-08-10       drh:   0x699996,
b4a29fac93 2009-08-10       drh:   0x262227,
b4a29fac93 2009-08-10       drh:   0x69124f,
b4a29fac93 2009-08-10       drh:   0xf16196,
b4a29fac93 2009-08-10       drh:   0x26af22,
b4a29fac93 2009-08-10       drh:   0xf8e196,
b4a29fac93 2009-08-10       drh:   0x68e996,
b4a29fac93 2009-08-10       drh:   0xf12244,
b4a29fac93 2009-08-10       drh:   0x696996,
b4a29fac93 2009-08-10       drh:   0x699716,
b4a29fac93 2009-08-10       drh:   0x699f99,
b4a29fac93 2009-08-10       drh:   0xe9e99e,
b4a29fac93 2009-08-10       drh:   0x698896,
b4a29fac93 2009-08-10       drh:   0xe9999e,
b4a29fac93 2009-08-10       drh:   0xf8e88f,
b4a29fac93 2009-08-10       drh:   0xf8e888,
b4a29fac93 2009-08-10       drh: };
b4a29fac93 2009-08-10       drh: 
b4a29fac93 2009-08-10       drh: /*
b4a29fac93 2009-08-10       drh: ** Render a 32-bit unsigned integer as an 8-digit ascii-art hex number.
b4a29fac93 2009-08-10       drh: ** Space to hold the result is obtained from malloc() and should be freed
b4a29fac93 2009-08-10       drh: ** by the caller.
b4a29fac93 2009-08-10       drh: */
b4a29fac93 2009-08-10       drh: char *captcha_render(const char *zPw){
b4a29fac93 2009-08-10       drh:   char *z = malloc( 500 );
b4a29fac93 2009-08-10       drh:   int i, j, k, m;
b4a29fac93 2009-08-10       drh: 
b4a29fac93 2009-08-10       drh:   k = 0;
b4a29fac93 2009-08-10       drh:   for(i=0; i<6; i++){
b4a29fac93 2009-08-10       drh:     for(j=0; j<8; j++){
b4a29fac93 2009-08-10       drh:       unsigned char v = hexValue(zPw[j]);
b4a29fac93 2009-08-10       drh:       v = (aFont1[v] >> ((5-i)*4)) & 0xf;
b4a29fac93 2009-08-10       drh:       for(m=8; m>=1; m = m>>1){
b4a29fac93 2009-08-10       drh:         if( v & m ){
b4a29fac93 2009-08-10       drh:           z[k++] = 'X';
b4a29fac93 2009-08-10       drh:           z[k++] = 'X';
b4a29fac93 2009-08-10       drh:         }else{
b4a29fac93 2009-08-10       drh:           z[k++] = ' ';
b4a29fac93 2009-08-10       drh:           z[k++] = ' ';
b4a29fac93 2009-08-10       drh:         }
b4a29fac93 2009-08-10       drh:       }
b4a29fac93 2009-08-10       drh:       z[k++] = ' ';
b4a29fac93 2009-08-10       drh:       z[k++] = ' ';
b4a29fac93 2009-08-10       drh:     }
b4a29fac93 2009-08-10       drh:     z[k++] = '\n';
b4a29fac93 2009-08-10       drh:   }
b4a29fac93 2009-08-10       drh:   z[k] = 0;
b4a29fac93 2009-08-10       drh:   return z;
b4a29fac93 2009-08-10       drh: }
b4a29fac93 2009-08-10       drh: #endif /* CAPTCHA==1 */
b4a29fac93 2009-08-10       drh: 
b4a29fac93 2009-08-10       drh: 
b4a29fac93 2009-08-10       drh: #if CAPTCHA==2
b4a29fac93 2009-08-10       drh: static const char *azFont2[] = {
b4a29fac93 2009-08-10       drh:  /* 0 */
b4a29fac93 2009-08-10       drh:  "  __  ",
b4a29fac93 2009-08-10       drh:  " /  \\ ",
b4a29fac93 2009-08-10       drh:  "| () |",
b4a29fac93 2009-08-10       drh:  " \\__/ ",
b4a29fac93 2009-08-10       drh: 
b4a29fac93 2009-08-10       drh:  /* 1 */
b4a29fac93 2009-08-10       drh:  " _ ",
b4a29fac93 2009-08-10       drh:  "/ |",
b4a29fac93 2009-08-10       drh:  "| |",
b4a29fac93 2009-08-10       drh:  "|_|",
b4a29fac93 2009-08-10       drh: 
b4a29fac93 2009-08-10       drh:  /* 2 */
b4a29fac93 2009-08-10       drh:  " ___ ",
b4a29fac93 2009-08-10       drh:  "|_  )",
b4a29fac93 2009-08-10       drh:  " / / ",
b4a29fac93 2009-08-10       drh:  "/___|",
b4a29fac93 2009-08-10       drh: 
b4a29fac93 2009-08-10       drh:  /* 3 */
b4a29fac93 2009-08-10       drh:  " ____",
b4a29fac93 2009-08-10       drh:  "|__ /",
b4a29fac93 2009-08-10       drh:  " |_ \\",
b4a29fac93 2009-08-10       drh:  "|___/",
b4a29fac93 2009-08-10       drh: 
b4a29fac93 2009-08-10       drh:  /* 4 */
b4a29fac93 2009-08-10       drh:  " _ _  ",
b4a29fac93 2009-08-10       drh:  "| | | ",
b4a29fac93 2009-08-10       drh:  "|_  _|",
b4a29fac93 2009-08-10       drh:  "  |_| ",
b4a29fac93 2009-08-10       drh: 
b4a29fac93 2009-08-10       drh:  /* 5 */
b4a29fac93 2009-08-10       drh:  " ___ ",
b4a29fac93 2009-08-10       drh:  "| __|",
b4a29fac93 2009-08-10       drh:  "|__ \\",
b4a29fac93 2009-08-10       drh:  "|___/",
b4a29fac93 2009-08-10       drh: 
b4a29fac93 2009-08-10       drh:  /* 6 */
b4a29fac93 2009-08-10       drh:  "  __ ",
b4a29fac93 2009-08-10       drh:  " / / ",
b4a29fac93 2009-08-10       drh:  "/ _ \\",
b4a29fac93 2009-08-10       drh:  "\\___/",
b4a29fac93 2009-08-10       drh: 
b4a29fac93 2009-08-10       drh:  /* 7 */
b4a29fac93 2009-08-10       drh:  " ____ ",
b4a29fac93 2009-08-10       drh:  "|__  |",
b4a29fac93 2009-08-10       drh:  "  / / ",
b4a29fac93 2009-08-10       drh:  " /_/  ",
b4a29fac93 2009-08-10       drh: 
b4a29fac93 2009-08-10       drh:  /* 8 */
b4a29fac93 2009-08-10       drh:  " ___ ",
b4a29fac93 2009-08-10       drh:  "( _ )",
b4a29fac93 2009-08-10       drh:  "/ _ \\",
b4a29fac93 2009-08-10       drh:  "\\___/",
b4a29fac93 2009-08-10       drh: 
b4a29fac93 2009-08-10       drh:  /* 9 */
b4a29fac93 2009-08-10       drh:  " ___ ",
b4a29fac93 2009-08-10       drh:  "/ _ \\",
b4a29fac93 2009-08-10       drh:  "\\_, /",
b4a29fac93 2009-08-10       drh:  " /_/ ",
b4a29fac93 2009-08-10       drh: 
b4a29fac93 2009-08-10       drh:  /* A */
b4a29fac93 2009-08-10       drh:  "      ",
b4a29fac93 2009-08-10       drh:  "  /\\  ",
b4a29fac93 2009-08-10       drh:  " /  \\ ",
b4a29fac93 2009-08-10       drh:  "/_/\\_\\",
b4a29fac93 2009-08-10       drh: 
b4a29fac93 2009-08-10       drh:  /* B */
b4a29fac93 2009-08-10       drh:  " ___ ",
b4a29fac93 2009-08-10       drh:  "| _ )",
b4a29fac93 2009-08-10       drh:  "| _ \\",
b4a29fac93 2009-08-10       drh:  "|___/",
b4a29fac93 2009-08-10       drh: 
b4a29fac93 2009-08-10       drh:  /* C */
b4a29fac93 2009-08-10       drh:  "  ___ ",
b4a29fac93 2009-08-10       drh:  " / __|",
b4a29fac93 2009-08-10       drh:  "| (__ ",
b4a29fac93 2009-08-10       drh:  " \\___|",
b4a29fac93 2009-08-10       drh: 
b4a29fac93 2009-08-10       drh:  /* D */
b4a29fac93 2009-08-10       drh:  " ___  ",
b4a29fac93 2009-08-10       drh:  "|   \\ ",
b4a29fac93 2009-08-10       drh:  "| |) |",
b4a29fac93 2009-08-10       drh:  "|___/ ",
b4a29fac93 2009-08-10       drh: 
b4a29fac93 2009-08-10       drh:  /* E */
b4a29fac93 2009-08-10       drh:  " ___ ",
b4a29fac93 2009-08-10       drh:  "| __|",
b4a29fac93 2009-08-10       drh:  "| _| ",
b4a29fac93 2009-08-10       drh:  "|___|",
b4a29fac93 2009-08-10       drh: 
b4a29fac93 2009-08-10       drh:  /* F */
b4a29fac93 2009-08-10       drh:  " ___ ",
b4a29fac93 2009-08-10       drh:  "| __|",
b4a29fac93 2009-08-10       drh:  "| _| ",
b4a29fac93 2009-08-10       drh:  "|_|  ",
b4a29fac93 2009-08-10       drh: };
b4a29fac93 2009-08-10       drh: 
b4a29fac93 2009-08-10       drh: /*
b4a29fac93 2009-08-10       drh: ** Render a 32-bit unsigned integer as an 8-digit ascii-art hex number.
b4a29fac93 2009-08-10       drh: ** Space to hold the result is obtained from malloc() and should be freed
b4a29fac93 2009-08-10       drh: ** by the caller.
b4a29fac93 2009-08-10       drh: */
b4a29fac93 2009-08-10       drh: char *captcha_render(const char *zPw){
b4a29fac93 2009-08-10       drh:   char *z = malloc( 300 );
b4a29fac93 2009-08-10       drh:   int i, j, k, m;
b4a29fac93 2009-08-10       drh:   const char *zChar;
b4a29fac93 2009-08-10       drh: 
b4a29fac93 2009-08-10       drh:   k = 0;
b4a29fac93 2009-08-10       drh:   for(i=0; i<4; i++){
b4a29fac93 2009-08-10       drh:     for(j=0; j<8; j++){
b4a29fac93 2009-08-10       drh:       unsigned char v = hexValue(zPw[j]);
b4a29fac93 2009-08-10       drh:       zChar = azFont2[4*v + i];
b4a29fac93 2009-08-10       drh:       for(m=0; zChar[m]; m++){
b4a29fac93 2009-08-10       drh:         z[k++] = zChar[m];
b4a29fac93 2009-08-10       drh:       }
b4a29fac93 2009-08-10       drh:     }
b4a29fac93 2009-08-10       drh:     z[k++] = '\n';
b4a29fac93 2009-08-10       drh:   }
b4a29fac93 2009-08-10       drh:   z[k] = 0;
b4a29fac93 2009-08-10       drh:   return z;
b4a29fac93 2009-08-10       drh: }
b4a29fac93 2009-08-10       drh: #endif /* CAPTCHA==2 */
b4a29fac93 2009-08-10       drh: 
b4a29fac93 2009-08-10       drh: /*
b4a29fac93 2009-08-10       drh: ** COMMAND: test-captcha
b4a29fac93 2009-08-10       drh: */
b4a29fac93 2009-08-10       drh: void test_captcha(void){
b4a29fac93 2009-08-10       drh:   int i;
b4a29fac93 2009-08-10       drh:   unsigned int v;
b4a29fac93 2009-08-10       drh:   char *z;
b4a29fac93 2009-08-10       drh: 
b4a29fac93 2009-08-10       drh:   for(i=2; i<g.argc; i++){
b4a29fac93 2009-08-10       drh:     char zHex[30];
b4a29fac93 2009-08-10       drh:     v = (unsigned int)atoi(g.argv[i]);
b4a29fac93 2009-08-10       drh:     sprintf(zHex, "%x", v);
b4a29fac93 2009-08-10       drh:     z = captcha_render(zHex);
b4a29fac93 2009-08-10       drh:     printf("%s:\n%s", zHex, z);
b4a29fac93 2009-08-10       drh:     free(z);
b4a29fac93 2009-08-10       drh:   }
b4a29fac93 2009-08-10       drh: }
b4a29fac93 2009-08-10       drh: 
b4a29fac93 2009-08-10       drh: /*
b4a29fac93 2009-08-10       drh: ** Compute a seed value for a captcha.  The seed is public and is sent
b4a29fac93 2009-08-10       drh: ** has a hidden parameter with the page that contains the captcha.  Knowledge
b4a29fac93 2009-08-10       drh: ** of the seed is insufficient for determining the captcha without additional
b4a29fac93 2009-08-10       drh: ** information held only on the server and never revealed.
b4a29fac93 2009-08-10       drh: */
b4a29fac93 2009-08-10       drh: unsigned int captcha_seed(void){
b4a29fac93 2009-08-10       drh:   unsigned int x;
b4a29fac93 2009-08-10       drh:   sqlite3_randomness(sizeof(x), &x);
b4a29fac93 2009-08-10       drh:   x &= 0x7fffffff;
b4a29fac93 2009-08-10       drh:   return x;
b4a29fac93 2009-08-10       drh: }
b4a29fac93 2009-08-10       drh: 
b4a29fac93 2009-08-10       drh: /*
b4a29fac93 2009-08-10       drh: ** Translate a captcha seed value into the captcha password string.
b4a29fac93 2009-08-10       drh: */
b4a29fac93 2009-08-10       drh: char *captcha_decode(unsigned int seed){
b4a29fac93 2009-08-10       drh:   const char *zSecret;
b4a29fac93 2009-08-10       drh:   const char *z;
b4a29fac93 2009-08-10       drh:   Blob b;
b4a29fac93 2009-08-10       drh:   static char zRes[20];
b4a29fac93 2009-08-10       drh: 
b4a29fac93 2009-08-10       drh:   zSecret = db_get("captcha-secret", 0);
b4a29fac93 2009-08-10       drh:   if( zSecret==0 ){
b4a29fac93 2009-08-10       drh:     db_multi_exec(
b4a29fac93 2009-08-10       drh:       "REPLACE INTO config(name,value)"
b4a29fac93 2009-08-10       drh:       " VALUES('captcha-secret', lower(hex(randomblob(20))));"
b4a29fac93 2009-08-10       drh:     );
b4a29fac93 2009-08-10       drh:     zSecret = db_get("captcha-secret", 0);
b4a29fac93 2009-08-10       drh:     assert( zSecret!=0 );
b4a29fac93 2009-08-10       drh:   }
b4a29fac93 2009-08-10       drh:   blob_init(&b, 0, 0);
b4a29fac93 2009-08-10       drh:   blob_appendf(&b, "%s-%x", zSecret, seed);
b4a29fac93 2009-08-10       drh:   sha1sum_blob(&b, &b);
b4a29fac93 2009-08-10       drh:   z = blob_buffer(&b);
b4a29fac93 2009-08-10       drh:   memcpy(zRes, z, 8);
b4a29fac93 2009-08-10       drh:   zRes[8] = 0;
b4a29fac93 2009-08-10       drh:   return zRes;
b4a29fac93 2009-08-10       drh: }