GcaptchaZ

GcaptchaZ Commit Details

Date:2012-11-08 19:18:12 (8 years 26 days ago)
Author:Grégory Soutadé
Branch:master
Commit:59fd57bc074b31e440734865a371f79fb480e6eb
Message:Initial commit

Changes:
AMakefile (full)
Agcaptchaz.c (full)
Agenerate_captcha.sh (full)
Ascrawl.ttf

File differences

Makefile
1
2
3
gcaptchaz: gcaptchaz.c
gcc $^ -o $@ -lm -lfreetype -lpng -lgd -ggdb -Wall
gcaptchaz.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
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;
}
generate_captcha.sh
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
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"

Archive Download the corresponding diff file

Branches