2 * Copyright (C) Ilari Liusvaara 2009-2010
4 * This code is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as
6 * published by the Free Software Foundation.
11 #include <gnutls/gnutls.h>
20 #include "git-compat-util.h"
25 printf("gits-generate-srp-verifier: Generate SRP verifiers for\n");
26 printf("password authentication\n");
27 printf("Command line:\n");
29 printf("\tThis help\n");
31 printf("Note: Server needs SRP verifier in order to do password\n");
32 printf("authentication. Usernames are assigned by repostiory\n");
33 printf("hosting admin, just using arbitrary names doesn't work.\n");
41 const char *f_generator
;
45 struct field fields
[] = {
47 "standard 1024 bit field", "2",
48 "Ewl2hcjiutMd3Fu2lgFnUXWSc67TVyy2vwYCKoS9MLsrdJVT9RgWTCuEqWJrfB6uE"
49 "3LsE9GkOlaZabS7M29sj5TnzUqOLJMjiwEzArfiLr9WbMRANlF68N5AVLcPWvNx6Z"
50 "jl3m5Scp0BzJBz9TkgfhzKJZ.WtP3Mv/67I/0wmRZ"
53 "standard 1536 bit field", "2",
54 "dUyyhxav9tgnyIg65wHxkzkb7VIPh4o0lkwfOKiPp4rVJrzLRYVBtb76gKlaO7ef5"
55 "LYGEw3G.4E0jbMxcYBetDy2YdpiP/3GWJInoBbvYHIRO9uBuxgsFKTKWu7RnR7yTa"
56 "u/IrFTdQ4LY/q.AvoCzMxV0PKvD9Odso/LFIItn8PbTov3VMn/ZEH2SqhtpBUkWtm"
57 "cIkEflhX/YY/fkBKfBbe27/zUaKUUZEUYZ2H2nlCL60.JIPeZJSzsu/xHDVcx"
60 "standard 2048 bit field", "2",
61 "2iQzj1CagQc/5ctbuJYLWlhtAsPHc7xWVyCPAKFRLWKADpASkqe9djWPFWTNTdeJt"
62 "L8nAhImCn3Sr/IAdQ1FrGw0WvQUstPx3FO9KNcXOwisOQ1VlL.gheAHYfbYyBaxXL"
63 ".NcJx9TUwgWDT0hRzFzqSrdGGTN3FgSTA1v4QnHtEygNj3eZ.u0MThqWUaDiP87nq"
64 "ha7XnT66bkTCkQ8.7T8L4KZjIImrNrUftedTTBi.WCi.zlrBxDuOM0da0JbUkQlXq"
65 "vp0yvJAPpC11nxmmZOAbQOywZGmu9nhZNuwTlxjfIro0FOdthaDTuZRL9VL7MRPUD"
72 unsigned char xfact
[16] = {
73 0x9D, 0x0F, 0x49, 0xD4,
74 0x73, 0x88, 0xC7, 0xFF,
75 0xFD, 0x24, 0x6A, 0x0F,
76 0x94, 0x78, 0x0C, 0x14
79 unsigned char rnd
[16] = {
80 0x00, 0x00, 0x00, 0x00,
81 0x00, 0x00, 0x00, 0x00,
82 0x00, 0x00, 0x00, 0x00,
83 0x00, 0x00, 0x00, 0x00
86 static void add(unsigned char *res
, unsigned char *a
, unsigned char *b
)
88 unsigned char carry
= 0;
91 for (i
= 0; i
< 16; i
++) {
92 unsigned char newcarry
= 0;
94 if ((unsigned char)(a
[i
] + b
[i
]) < a
[i
])
97 if (res
[i
] + carry
< res
[i
])
105 for (i
= 0; i
< 16; i
++) {
108 if ((unsigned char)(res
[i
] + carry
) < res
[i
])
114 for (i
= 1; i
< 16; i
++)
119 for (i
= 1; i
< 16; i
++)
129 unsigned char xfact2
[16];
130 unsigned char xfact4
[16];
131 unsigned char xfact5
[16];
132 add(xfact2
, xfact
, xfact
);
133 add(xfact4
, xfact2
, xfact2
);
134 add(xfact5
, xfact4
, xfact
);
135 memcpy(xfact
, xfact5
, 16);
138 void update_rnd(unsigned char ch
)
140 unsigned char rndt
[16];
142 for (i
= 0; i
< 8; i
++) {
144 add(rndt
, rnd
, xfact
);
145 memcpy(rnd
, rndt
, 16);
151 void update_rnd_str(const char *ch
)
154 update_rnd((unsigned char)*(ch
++));
158 void decode_element(gnutls_datum_t
*decode
, const char *encoded
)
161 gnutls_datum_t _base64
;
162 size_t base64len
, reslen
, reslen2
;
164 base64len
= strlen(encoded
);
165 reslen2
= reslen
= (3 * base64len
+ 1) / 4;
167 _base64
.data
= (unsigned char*)encoded
;
168 _base64
.size
= base64len
;
170 decode
->size
= reslen
;
171 decode
->data
= xmalloc(reslen
);
172 s
= gnutls_srp_base64_decode(&_base64
, (char*)decode
->data
, &reslen2
);
174 die("Unable to decode base64 data");
175 else if (reslen
!= reslen2
)
176 die("Base64 dlength calculation incorrect. Calculated %lu, "
177 "got %lu", (unsigned long)reslen
, (unsigned long)reslen2
);
180 unsigned char *encode_element(gnutls_datum_t
*data
)
186 reslen2
= (4 * data
->size
+ 2) / 3;
188 res
= xmalloc(reslen2
+ 1);
189 s
= gnutls_srp_base64_encode(data
, (char*)res
, &reslen2
);
191 die("Unable to encode base64 data");
196 char *generate_srp_line(const char *username
,
197 const char *password
, const char *junk
, struct field
*field
)
204 char *retline
= NULL
;
205 unsigned char *encoded_salt
;
206 unsigned char *encoded_verifier
;
207 update_rnd_str(username
);
208 update_rnd_str(":::::");
209 update_rnd_str(junk
);
213 decode_element(&g
, field
->f_generator
);
214 decode_element(&n
, field
->f_prime
);
216 s
= gnutls_srp_verifier(username
, password
, &salt
, &g
, &n
, &res
);
218 die("Unable to generate SRP verifier: %s",
221 encoded_verifier
= encode_element(&res
);
222 encoded_salt
= encode_element(&salt
);
224 retline
= xmalloc(5 + strlen(username
) +
225 strlen((char*)encoded_salt
) +
226 strlen((char*)encoded_verifier
) +
227 strlen(field
->f_generator
) +
228 strlen(field
->f_prime
));
230 strcat(retline
, username
);
231 strcat(retline
, ":");
232 strcat(retline
, (char*)encoded_salt
);
233 strcat(retline
, ":");
234 strcat(retline
, (char*)encoded_verifier
);
235 strcat(retline
, ":");
236 strcat(retline
, field
->f_generator
);
237 strcat(retline
, ":");
238 strcat(retline
, field
->f_prime
);
240 free(encoded_verifier
);
251 static void flush_to_file(FILE *out
, const char *srpline
)
253 char linebuffer
[LINELEN
+ 2];
255 linebuffer
[LINELEN
] = '\\';
256 linebuffer
[LINELEN
+ 1] = '\0';
260 strncpy(linebuffer
, srpline
, LINELEN
);
263 linebuffer
[LINELEN
] = '\0';
268 fprintf(out
, "%s\n", linebuffer
);
277 fd
= open("/dev/urandom", O_RDONLY
);
283 r
= read(fd
, rnd
+ fill
, 16 - fill
);
284 if (r
< 0 && errno
!= EINTR
&& errno
!= EAGAIN
) {
298 int main(int argc
, char **argv
)
301 char *username
= NULL
;
302 char *password
= NULL
;
303 char *password2
= NULL
;
311 if (argc
> 1 && !strcmp(argv
[1], "--help"))
316 username
= prompt_string("Enter username", 0);
318 fprintf(stderr
, "Error: Bad username\n");
326 junk
= prompt_string("Enter some garbage from keyboard (min 32 "
328 if (strlen(junk
) < 32) {
329 fprintf(stderr
, "Error: Garbage needs to be at least "
338 password
= prompt_string("Enter password", 1);
339 password2
= prompt_string("Enter password again", 1);
340 if (strcmp(password
, password2
)) {
341 fprintf(stderr
, "Error: Passwords don't match\n");
342 goto passwords_again
;
347 for (midx
= 0; fields
[midx
].f_name
; midx
++) {
348 printf("%i) %s\n", midx
+ 1, fields
[midx
].f_name
);
350 field
= prompt_string("Pick field", 0);
351 idx
= (int)strtoul(field
, &end
, 10) - 1;
352 if (idx
< 0 || idx
>= midx
|| !*field
|| *end
) {
353 printf("%i %i %i %i\n", idx
, midx
, *field
, *end
);
354 fprintf(stderr
, "Error: Invalid choice\n");
359 file
= prompt_string("Filename to save as (enter for dump to "
363 fd
= open_create_dirs(file
, O_CREAT
| O_EXCL
| O_WRONLY
, 0600);
365 fprintf(stderr
, "Can't open '%s': %s\n", file
,
369 filp
= xfdopen(fd
, "w");
372 ans
= generate_srp_line(username
, password
, junk
, fields
+ idx
);
373 flush_to_file(filp
, ans
);