1 /*
2 * This software is Copyright (c) 2017, Dhiru Kholia <dhiru.kholia at gmail.com>,
3 * and it is hereby released to the general public under the following terms:
4 *
5 * Redistribution and use in source and binary forms, with or without modification,
6 * are permitted.
7 *
8 * References,
9 *
10 * https://tools.ietf.org/html/rfc5802
11 * https://tools.ietf.org/html/rfc7677
12 * https://wiki.xmpp.org/web/SASLandSCRAM-SHA-1
13 *
14 * Hash format -> $scram$0$iterations$salt-len$salt-in-hex$hash
15 */
16
17 #if FMT_EXTERNS_H
18 extern struct fmt_main fmt_xmpp_scram;
19 #elif FMT_REGISTERS_H
20 john_register_one(&fmt_xmpp_scram);
21 #else
22
23 #include <string.h>
24
25 #ifdef _OPENMP
26 #include <omp.h>
27 #endif
28
29 #include "arch.h"
30 #include "misc.h"
31 #include "memory.h"
32 #include "common.h"
33 #include "formats.h"
34 #include "johnswap.h"
35 #include "sha.h"
36 #include "hmac_sha.h"
37 #include "simd-intrinsics.h"
38 #include "pbkdf2_hmac_sha1.h"
39
40 #if defined SIMD_COEF_32
41 #define SIMD_KEYS (SIMD_COEF_32 * SIMD_PARA_SHA1)
42 #endif
43
44 #define FORMAT_LABEL "xmpp-scram"
45 #define FORMAT_NAME ""
46 #define ALGORITHM_NAME "XMPP SCRAM PBKDF2-SHA1 " SHA1_ALGORITHM_NAME
47 #define PLAINTEXT_LENGTH 125
48 #define HASH_LENGTH 28
49 #define SALT_SIZE sizeof(struct custom_salt)
50 #define SALT_ALIGN sizeof(uint32_t)
51 #define BINARY_SIZE 20
52 #define BINARY_ALIGN sizeof(uint32_t)
53 #define BENCHMARK_COMMENT ""
54 #define BENCHMARK_LENGTH 0x107
55 #define FORMAT_TAG "$xmpp-scram$"
56 #define FORMAT_TAG_LENGTH (sizeof(FORMAT_TAG) - 1)
57
58 #if !defined(SIMD_COEF_32)
59 #define MIN_KEYS_PER_CRYPT 1
60 #define MAX_KEYS_PER_CRYPT 4
61 #else
62 #define MIN_KEYS_PER_CRYPT SIMD_KEYS
63 #define MAX_KEYS_PER_CRYPT (SIMD_KEYS * 2)
64 #endif
65
66 #ifndef OMP_SCALE
67 #define OMP_SCALE 16 // Tuned w/ MKPC for core i7
68 #endif
69
70 static struct fmt_tests tests[] = {
71 // hash generated by prosody-0.9.12 (taken from a .dat file)
72 {"$xmpp-scram$0$4096$36$37333536663261622d613666622d346333642d396232622d626432646237633338343064$38f79a6e3e64c07f731570d531ec05365aa05306", "openwall123"},
73 // ejabberd-16.01 generated hash from "ejabberdctl dump output.txt" processed with ejabberd2john.py
74 {"$xmpp-scram$0$4096$16$4f67aec1bd53f5f2f74652e69a3b8f32$4aec3caa8ace5180efa7a671092646c041ab1496", "qwerty"},
75 // ejabberd hash with a space in password
76 {"$xmpp-scram$0$4096$16$1f7fcb384d5bcc61dfb1231ae1b32a2f$a2d076d56b0152ed557ad7d38fce93159bc63c9b", "password 123"},
77 // openfire 4.1.6 hash, manually extracted from the database
78 {"$xmpp-scram$0$4096$24$bc1bd6638a1231ffd54f608983425eacf729d8455a469197$aee9254762b23a3950fd7c803caab5f6654587c8", "openwall123"},
79 {NULL}
80 };
81
82 static struct custom_salt {
83 uint32_t saltlen;
84 uint32_t iterations;
85 uint32_t type;
86 unsigned char salt[64+1];
87 } *cur_salt;
88
89 static char (*saved_key)[PLAINTEXT_LENGTH + 1];
90 static uint32_t (*crypt_out)[BINARY_SIZE / sizeof(uint32_t)];
91
init(struct fmt_main * self)92 static void init(struct fmt_main *self)
93 {
94 omp_autotune(self, OMP_SCALE);
95
96 saved_key = mem_calloc(self->params.max_keys_per_crypt,
97 sizeof(*saved_key));
98 crypt_out = mem_calloc(self->params.max_keys_per_crypt,
99 sizeof(*crypt_out));
100 }
101
done(void)102 static void done(void)
103 {
104 MEM_FREE(crypt_out);
105 MEM_FREE(saved_key);
106 }
107
valid(char * ciphertext,struct fmt_main * self)108 static int valid(char *ciphertext, struct fmt_main *self)
109 {
110 char *ctcopy, *keeptr, *p;
111 int res, extra;
112
113 if (strncmp(ciphertext, FORMAT_TAG, FORMAT_TAG_LENGTH) != 0)
114 return 0;
115 ctcopy = strdup(ciphertext);
116 keeptr = ctcopy;
117 ctcopy += FORMAT_TAG_LENGTH;
118 if ((p = strtokm(ctcopy, "$")) == NULL) /* internal type */
119 goto err;
120 if (!isdec(p))
121 goto err;
122 if (atoi(p) != 0)
123 goto err;
124 if ((p = strtokm(NULL, "$")) == NULL) /* iterations */
125 goto err;
126 if (!isdec(p))
127 goto err;
128 if ((p = strtokm(NULL, "$")) == NULL) /* salten */
129 goto err;
130 if (!isdec(p))
131 goto err;
132 res = atoi(p);
133 if (res > 64)
134 goto err;
135 if ((p = strtokm(NULL, "$")) == NULL) /* salt */
136 goto err;
137 if (hexlenl(p, &extra) != res * 2 || extra)
138 goto err;
139 if ((p = strtokm(NULL, "$")) == NULL) /* hash */
140 goto err;
141 if (hexlenl(p, &extra) != BINARY_SIZE * 2 || extra)
142 goto err;
143
144 MEM_FREE(keeptr);
145 return 1;
146
147 err:
148 MEM_FREE(keeptr);
149 return 0;
150 }
151
get_salt(char * ciphertext)152 static void *get_salt(char *ciphertext)
153 {
154 static struct custom_salt cs;
155 char *ctcopy, *keeptr, *p;
156 int i;
157
158 memset(&cs, 0, sizeof(cs));
159 ctcopy = strdup(ciphertext);
160 keeptr = ctcopy;;
161 ctcopy += FORMAT_TAG_LENGTH;
162 p = strtokm(ctcopy, "$");
163 cs.type = atoi(p);
164 p = strtokm(NULL, "$");
165 cs.iterations = atoi(p);
166 p = strtokm(NULL, "$");
167 cs.saltlen = atoi(p);
168 p = strtokm(NULL, "$");
169 for (i = 0; i < cs.saltlen; i++) {
170 cs.salt[i] = (atoi16[ARCH_INDEX(*p)] << 4) | atoi16[ARCH_INDEX(p[1])];
171 p += 2;
172 }
173
174 MEM_FREE(keeptr);
175
176 return (void *)&cs;
177 }
178
get_binary(char * ciphertext)179 static void *get_binary(char *ciphertext)
180 {
181 static union {
182 unsigned char c[BINARY_SIZE + 1];
183 ARCH_WORD dummy;
184 } buf;
185 unsigned char *out = buf.c;
186 char *p;
187 int i;
188
189 p = strrchr(ciphertext, '$') + 1;
190 for (i = 0; i < BINARY_SIZE; i++) {
191 out[i] = (atoi16[ARCH_INDEX(*p)] << 4) | atoi16[ARCH_INDEX(p[1])];
192 p += 2;
193 }
194
195 return out;
196 }
197
set_salt(void * salt)198 static void set_salt(void *salt)
199 {
200 cur_salt = (struct custom_salt *)salt;
201 }
202
203 #define COMMON_GET_HASH_VAR crypt_out
204 #include "common-get-hash.h"
205
crypt_all(int * pcount,struct db_salt * salt)206 static int crypt_all(int *pcount, struct db_salt *salt)
207 {
208 int index;
209 const int count = *pcount;
210
211 #ifdef _OPENMP
212 #pragma omp parallel for
213 #endif
214 for (index = 0; index < count; index += MIN_KEYS_PER_CRYPT) {
215 #if !defined (SIMD_COEF_32)
216 unsigned char out[BINARY_SIZE];
217 SHA_CTX ctx;
218
219 pbkdf2_sha1((unsigned char*)saved_key[index],
220 strlen(saved_key[index]), cur_salt->salt,
221 cur_salt->saltlen, cur_salt->iterations, out,
222 BINARY_SIZE, 0);
223
224 hmac_sha1(out, BINARY_SIZE, (unsigned char*)"Client Key", 10, out, BINARY_SIZE);
225 SHA1_Init(&ctx);
226 SHA1_Update(&ctx, out, BINARY_SIZE);
227 SHA1_Final((unsigned char*)crypt_out[index], &ctx);
228 #else
229 SHA_CTX ctx;
230 int i;
231 unsigned char *pin[SIMD_KEYS];
232 int lens[SIMD_KEYS];
233 unsigned char out_[SIMD_KEYS][BINARY_SIZE], *out[SIMD_KEYS];
234
235 for (i = 0; i < SIMD_KEYS; ++i) {
236 pin[i] = (unsigned char*)saved_key[index+i];
237 lens[i] = strlen(saved_key[index+i]);
238 out[i] = out_[i];
239 }
240
241 pbkdf2_sha1_sse((const unsigned char **)pin, lens, cur_salt->salt,
242 cur_salt->saltlen, cur_salt->iterations, out,
243 BINARY_SIZE, 0);
244
245 for (i = 0; i < SIMD_KEYS; ++i) {
246 hmac_sha1(out[i], BINARY_SIZE, (unsigned char*)"Client Key", 10, out[i], BINARY_SIZE);
247 SHA1_Init(&ctx);
248 SHA1_Update(&ctx, out[i], BINARY_SIZE);
249 SHA1_Final((unsigned char*)crypt_out[index+i], &ctx);
250 }
251 #endif
252 }
253 return count;
254 }
255
cmp_all(void * binary,int count)256 static int cmp_all(void *binary, int count)
257 {
258 int index;
259
260 for (index = 0; index < count; index++)
261 if (!memcmp(binary, crypt_out[index], ARCH_SIZE))
262 return 1;
263 return 0;
264 }
265
cmp_one(void * binary,int index)266 static int cmp_one(void *binary, int index)
267 {
268 return !memcmp(binary, crypt_out[index], BINARY_SIZE);
269 }
270
cmp_exact(char * source,int index)271 static int cmp_exact(char *source, int index)
272 {
273 return 1;
274 }
275
set_key(char * key,int index)276 static void set_key(char *key, int index)
277 {
278 strnzcpy(saved_key[index], key, sizeof(*saved_key));
279 }
280
get_key(int index)281 static char *get_key(int index)
282 {
283 return saved_key[index];
284 }
285
286 struct fmt_main fmt_xmpp_scram = {
287 {
288 FORMAT_LABEL,
289 FORMAT_NAME,
290 ALGORITHM_NAME,
291 BENCHMARK_COMMENT,
292 BENCHMARK_LENGTH,
293 0,
294 PLAINTEXT_LENGTH,
295 BINARY_SIZE,
296 BINARY_ALIGN,
297 SALT_SIZE,
298 SALT_ALIGN,
299 MIN_KEYS_PER_CRYPT,
300 MAX_KEYS_PER_CRYPT,
301 FMT_CASE | FMT_8_BIT | FMT_OMP,
302 { NULL },
303 { FORMAT_TAG },
304 tests
305 }, {
306 init,
307 done,
308 fmt_default_reset,
309 fmt_default_prepare,
310 valid,
311 fmt_default_split,
312 get_binary,
313 get_salt,
314 { NULL },
315 fmt_default_source,
316 {
317 fmt_default_binary_hash_0,
318 fmt_default_binary_hash_1,
319 fmt_default_binary_hash_2,
320 fmt_default_binary_hash_3,
321 fmt_default_binary_hash_4,
322 fmt_default_binary_hash_5,
323 fmt_default_binary_hash_6
324 },
325 fmt_default_salt_hash,
326 NULL,
327 set_salt,
328 set_key,
329 get_key,
330 fmt_default_clear_keys,
331 crypt_all,
332 {
333 #define COMMON_GET_HASH_LINK
334 #include "common-get-hash.h"
335 },
336 cmp_all,
337 cmp_one,
338 cmp_exact
339 }
340 };
341
342 #endif /* plugin stanza */
343