Initial commit
This commit is contained in:
commit
59fd57bc07
3
Makefile
Normal file
3
Makefile
Normal file
|
@ -0,0 +1,3 @@
|
|||
|
||||
gcaptchaz: gcaptchaz.c
|
||||
gcc $^ -o $@ -lm -lfreetype -lpng -lgd -ggdb -Wall
|
253
gcaptchaz.c
Normal file
253
gcaptchaz.c
Normal file
|
@ -0,0 +1,253 @@
|
|||
#include <sys/time.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
#include <gd.h>
|
||||
#include <gdfontl.h>
|
||||
|
||||
/*
|
||||
This code is only a C implementation (with some minor modifications) of this captcha generator :
|
||||
http://logz.org/captchaz/
|
||||
|
||||
Copyright November 2012 Grégory Soutadé
|
||||
Copyright July 2007 Loz
|
||||
|
||||
LICENCE : Copyleft, Licence Art Libre (http://artlibre.org/licence/lal)
|
||||
|
||||
Modifications :
|
||||
* Group letters
|
||||
* Add another layer for letter rendering (more confusing)
|
||||
* Change start, not appropriate for big fonts
|
||||
* Change min/max font size
|
||||
|
||||
You need libgd2-xpm-dev package
|
||||
|
||||
It's recommanded the included font "scrawl.ttf"
|
||||
*/
|
||||
|
||||
#define MAX(a, b) (((a) >= (b)) ? (a) : (b))
|
||||
|
||||
// If not defined
|
||||
/* int overflow2(int a, int b) */
|
||||
/* { */
|
||||
/* if(a < 0 || b < 0) { */
|
||||
/* fprintf(stderr, "gd warning: one parameter to a memory allocation multiplication is negative, failing operation gracefully\n"); */
|
||||
/* return 1; */
|
||||
/* } */
|
||||
/* if(b == 0) */
|
||||
/* return 0; */
|
||||
/* if(a > 0xFFFFFFFF / b) { */
|
||||
/* fprintf(stderr, "gd warning: product of memory allocation multiplication would exceed INT_MAX, failing operation gracefully\n"); */
|
||||
/* return 1; */
|
||||
/* } */
|
||||
/* return 0; */
|
||||
/* } */
|
||||
|
||||
static int my_rand(int min, int max)
|
||||
{
|
||||
int val;
|
||||
struct timeval tv;
|
||||
static unsigned int seed = 0;
|
||||
int interval;
|
||||
|
||||
if (seed == 0)
|
||||
{
|
||||
gettimeofday(&tv, NULL);
|
||||
seed = tv.tv_usec;
|
||||
}
|
||||
|
||||
val = rand_r(&seed);
|
||||
|
||||
if (min < 0)
|
||||
{
|
||||
if (max < 0)
|
||||
interval = -(min-max);
|
||||
else
|
||||
interval = max-min;
|
||||
}
|
||||
else
|
||||
interval = max-min;
|
||||
|
||||
val = (int)(((double)val/(double)RAND_MAX)*(double)(interval));
|
||||
|
||||
val += min;
|
||||
|
||||
/* printf("rand [%d..%d] %d\n", min, max, val); */
|
||||
|
||||
return val;
|
||||
}
|
||||
|
||||
static inline int random_color(gdImagePtr im, int a, int b) {
|
||||
return gdImageColorAllocate(im, my_rand(a,b), my_rand(a,b), my_rand(a,b));
|
||||
}
|
||||
|
||||
static int generate_captcha(int width, int height, int inverse, char* font, char* phrase, char* out)
|
||||
{
|
||||
gdImagePtr im;
|
||||
int R, c1, c2;
|
||||
int wd, x, y, w1, w2, limit, n, p, r, g, b;
|
||||
int size, half, len;
|
||||
double rotation;
|
||||
char letter[2] = {0, 0};
|
||||
int brect[8];
|
||||
char* error;
|
||||
const double rad = 3.14/(double)180;
|
||||
|
||||
// initialize in-memory image with gd library
|
||||
im = gdImageCreateTrueColor(width, height);
|
||||
|
||||
R = (inverse) ? 0xFF : 0x00;
|
||||
|
||||
gdImageFilledRectangle(im, 0, 0, width, height, random_color(im, 222^R, 255^R));
|
||||
|
||||
c1 = my_rand(150^R, 185^R);
|
||||
c2 = my_rand(195^R, 230^R);
|
||||
|
||||
// encolour bg
|
||||
wd=20; x=0;
|
||||
while (x < width)
|
||||
{
|
||||
gdImageFilledRectangle(im, x, 0, x+wd, height, random_color(im, 222^R, 255^R));
|
||||
x += wd;
|
||||
wd += MAX(10, my_rand(0, 20) - 10);
|
||||
}
|
||||
|
||||
// make interesting background I, lines
|
||||
wd=4; w1=0; w2=0;
|
||||
for(x=0; x<width; x+=wd)
|
||||
{
|
||||
if (x < width)
|
||||
gdImageLine(im, x+w1, 0, x+w2, height-1, random_color(im, c1, c2));
|
||||
|
||||
if (x < height)
|
||||
gdImageLine(im, 0, x-w2, width-1, x-w1, random_color(im, c1, c2));
|
||||
|
||||
wd += my_rand(0, 8)-4;
|
||||
if (wd < 1) wd = 2;
|
||||
w1 += my_rand(0, 8)-4;
|
||||
w2 += my_rand(0, 8)-4;
|
||||
|
||||
if ((x > height) && (x > height)) // ???
|
||||
break;
|
||||
}
|
||||
|
||||
// more disturbing II, random letters
|
||||
limit = my_rand(30, 90);
|
||||
for(n=0; n<limit; n++)
|
||||
{
|
||||
letter[0] = my_rand(31, 125); // only one letter
|
||||
size = my_rand(5, height/2);
|
||||
half = size / 2;
|
||||
x = my_rand(-half, width+half);
|
||||
y = my_rand(half, height);
|
||||
rotation = my_rand(60, 300);
|
||||
c1 = random_color(im, 130^R, 240^R);
|
||||
error = gdImageStringFT(im, brect, c1, font, size, rotation, x, y, letter);
|
||||
if (error)
|
||||
{
|
||||
fprintf(stderr, "%s, font is %s\n", error, font);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
// add the real text to it
|
||||
len = strlen(phrase);
|
||||
w1 = 10;
|
||||
w2 = width / (height/4); // Change start, not appropriate for big fonts
|
||||
x = w2;
|
||||
|
||||
for(p=0; p<len; p++)
|
||||
{
|
||||
letter[0] = phrase[p];
|
||||
size = my_rand(height/4, height/3); // Change min/max font size
|
||||
half = size / 2;
|
||||
rotation = (double)my_rand(-33, 33)*rad;
|
||||
y = my_rand(size+3, height-3);
|
||||
/* x = w1 + w2*p; */
|
||||
w1 += my_rand(-width/90, width/40);
|
||||
r = my_rand(30, 99) ; g = my_rand(30, 99) ; b = my_rand(30, 99);
|
||||
c1 = gdImageColorAllocate(im, r*1^R, g*1^R, b*1^R);
|
||||
c2 = gdImageColorAllocate(im, r*2^R, g*2^R, b*2^R);
|
||||
gdImageStringFT(im, brect, c2, font, size, rotation, x+1, y, letter);
|
||||
gdImageStringFT(im, brect, c1, font, size, rotation, x, y-1, letter);
|
||||
// Add another layer
|
||||
gdImageStringFT(im, brect, c1, font, size, rotation, x+2, y+2, letter);
|
||||
// Group letters
|
||||
x += size;
|
||||
}
|
||||
|
||||
FILE* f= fopen(out, "wb");
|
||||
|
||||
if (!f)
|
||||
{
|
||||
fprintf(stderr, "Error opening %s\n", out);
|
||||
return 1;
|
||||
}
|
||||
|
||||
gdImagePng(im, f);
|
||||
fclose(f);
|
||||
|
||||
gdImageDestroy(im);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void usage()
|
||||
{
|
||||
printf("gcpatchaz is a command line captcha generator\n\n");
|
||||
printf("usage : gcpatchaz [options]\n");
|
||||
printf("\t-w WIDTH\n");
|
||||
printf("\t-h HEIGHT\n");
|
||||
printf("\t-o OUT.PNG\n");
|
||||
printf("\t-f FONT\n");
|
||||
printf("\t-s STRING\n");
|
||||
printf("\t-i : inverse\n");
|
||||
printf("\t-h : help\n");
|
||||
}
|
||||
|
||||
int main(int argc, char** argv)
|
||||
{
|
||||
int opt;
|
||||
int width=180, height=40;
|
||||
char* out = "captcha.png", *font = "ttf-japanese-gothic.ttf", *string = NULL;
|
||||
int inverse= 0;
|
||||
int i, res;
|
||||
|
||||
while ((opt = getopt(argc, argv, "w:H:o:f:s:ih")) != -1)
|
||||
{
|
||||
switch(opt)
|
||||
{
|
||||
case 'w': width = atoi(optarg); break;
|
||||
case 'H': height = atoi(optarg); break;
|
||||
case 'o': out = optarg; break;
|
||||
case 'f': font = optarg; break;
|
||||
case 's': string = strdup(optarg); break;
|
||||
case 'i': inverse = 1; break;
|
||||
case 'h':
|
||||
usage();
|
||||
return 0;
|
||||
default:
|
||||
usage();
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (string == NULL)
|
||||
{
|
||||
string = malloc(6);
|
||||
for(i=0; i<5; i++)
|
||||
{
|
||||
string[i] = my_rand(65, 90);
|
||||
}
|
||||
string[i] = 0;
|
||||
}
|
||||
|
||||
res = generate_captcha(width, height, inverse, font, string, out);
|
||||
|
||||
if (res == 0)
|
||||
printf("Captcha generated for text \"%s\"\n", string);
|
||||
|
||||
free(string);
|
||||
|
||||
return 0;
|
||||
}
|
56
generate_captcha.sh
Executable file
56
generate_captcha.sh
Executable file
|
@ -0,0 +1,56 @@
|
|||
#!/bin/bash
|
||||
|
||||
#
|
||||
# Simple script to generate a captcha and rename it with
|
||||
# the captcha's value encrypted (AES 128) with a md5 of the AES key.
|
||||
# This allow to retrieve captcha's value only with its name
|
||||
# if you have the right AES key and also to use a passphrase.
|
||||
#
|
||||
# The script also contains a visual verification to avoid
|
||||
# generating hard to resolve captchas.
|
||||
#
|
||||
# Parameters :
|
||||
# generate_captcha.sh OUT_DIR PASSPHRASE
|
||||
#
|
||||
|
||||
# Get parameters
|
||||
out=$1
|
||||
pass=$2
|
||||
do_check=1
|
||||
|
||||
# Verify parameters
|
||||
[ -z "$out" ] && out="."
|
||||
[ -z "$pass" ] && pass="AAA"
|
||||
[ ! -e $out ] && mkdir $out
|
||||
|
||||
# Generate captcha
|
||||
res=`./gcaptchaz -f ./scrawl.ttf -o "$out/captcha.png"`
|
||||
echo $res | grep "Captcha generated" > /dev/null
|
||||
if [ ! $? -eq 0 ] ; then
|
||||
echo $res
|
||||
exit 1
|
||||
fi
|
||||
|
||||
text=`echo $res | cut -d\" -f2`
|
||||
|
||||
# Do verification
|
||||
if [ $do_check -eq 1 ] ; then
|
||||
emacs "$out/captcha.png"
|
||||
|
||||
echo -n "Enter CAPTCHA value : "
|
||||
read user
|
||||
|
||||
if [ "$user" != "$text" ] ; then
|
||||
echo "CAPTCHA failed"
|
||||
rm -f "$out/captcha.png"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "CAPTCHA OK"
|
||||
fi
|
||||
|
||||
# Encrypt captcha's value to generate captcha's name
|
||||
key=`echo -n $pass | md5sum | cut -d' ' -f1`
|
||||
enc=`echo -n $text | openssl enc -aes-128-ecb -nosalt -K $key -iv $key`
|
||||
enc=`echo -n $enc | hexdump -e '"%02x"'`
|
||||
mv "$out/captcha.png" "$out/$enc.png"
|
BIN
scrawl.ttf
Normal file
BIN
scrawl.ttf
Normal file
Binary file not shown.
Loading…
Reference in New Issue
Block a user