Mercurial > hg > nginx-quic
comparison src/core/ngx_crypt.c @ 3922:9c057d5e1c27
"$apr1", "{PLAIN}", and "{SSHA}" password methods in auth basic module
patch by Maxim Dounin
author | Igor Sysoev <igor@sysoev.ru> |
---|---|
date | Mon, 16 May 2011 14:54:50 +0000 |
parents | |
children | 14622ee4fa08 |
comparison
equal
deleted
inserted
replaced
3921:bab3488bd113 | 3922:9c057d5e1c27 |
---|---|
1 | |
2 /* | |
3 * Copyright (C) Maxim Dounin | |
4 */ | |
5 | |
6 | |
7 #include <ngx_config.h> | |
8 #include <ngx_core.h> | |
9 #include <ngx_md5.h> | |
10 #if (NGX_HAVE_SHA1) | |
11 #include <ngx_sha1.h> | |
12 #endif | |
13 | |
14 | |
15 static ngx_int_t ngx_crypt_apr1(ngx_pool_t *pool, u_char *key, u_char *salt, | |
16 u_char **encrypted); | |
17 static ngx_int_t ngx_crypt_plain(ngx_pool_t *pool, u_char *key, u_char *salt, | |
18 u_char **encrypted); | |
19 | |
20 #if (NGX_HAVE_SHA1) | |
21 | |
22 static ngx_int_t ngx_crypt_ssha(ngx_pool_t *pool, u_char *key, u_char *salt, | |
23 u_char **encrypted); | |
24 | |
25 #endif | |
26 | |
27 | |
28 static u_char *ngx_crypt_to64(u_char *p, uint32_t v, size_t n); | |
29 | |
30 | |
31 ngx_int_t | |
32 ngx_crypt(ngx_pool_t *pool, u_char *key, u_char *salt, u_char **encrypted) | |
33 { | |
34 if (ngx_strncmp(salt, "$apr1$", sizeof("$apr1$") - 1) == 0) { | |
35 return ngx_crypt_apr1(pool, key, salt, encrypted); | |
36 | |
37 } else if (ngx_strncmp(salt, "{PLAIN}", sizeof("{PLAIN}") - 1) == 0) { | |
38 return ngx_crypt_plain(pool, key, salt, encrypted); | |
39 | |
40 #if (NGX_HAVE_SHA1) | |
41 } else if (ngx_strncmp(salt, "{SSHA}", sizeof("{SSHA}") - 1) == 0) { | |
42 return ngx_crypt_ssha(pool, key, salt, encrypted); | |
43 #endif | |
44 } | |
45 | |
46 /* fallback to libc crypt() */ | |
47 | |
48 return ngx_libc_crypt(pool, key, salt, encrypted); | |
49 } | |
50 | |
51 | |
52 static ngx_int_t | |
53 ngx_crypt_apr1(ngx_pool_t *pool, u_char *key, u_char *salt, u_char **encrypted) | |
54 { | |
55 ngx_int_t n; | |
56 ngx_uint_t i; | |
57 u_char *p, *last, final[16]; | |
58 size_t saltlen, keylen; | |
59 ngx_md5_t md5, ctx1; | |
60 | |
61 /* Apache's apr1 crypt is Paul-Henning Kamp's md5 crypt with $apr1$ magic */ | |
62 | |
63 keylen = ngx_strlen(key); | |
64 | |
65 /* true salt: no magic, max 8 chars, stop at first $ */ | |
66 | |
67 salt += sizeof("$apr1$") - 1; | |
68 last = salt + 8; | |
69 for (p = salt; *p && *p != '$' && p < last; p++) { /* void */ } | |
70 saltlen = p - salt; | |
71 | |
72 /* hash key and salt */ | |
73 | |
74 ngx_md5_init(&md5); | |
75 ngx_md5_update(&md5, key, keylen); | |
76 ngx_md5_update(&md5, "$apr1$", sizeof("$apr1$") - 1); | |
77 ngx_md5_update(&md5, salt, saltlen); | |
78 | |
79 ngx_md5_init(&ctx1); | |
80 ngx_md5_update(&ctx1, key, keylen); | |
81 ngx_md5_update(&ctx1, salt, saltlen); | |
82 ngx_md5_update(&ctx1, key, keylen); | |
83 ngx_md5_final(final, &ctx1); | |
84 | |
85 for (n = keylen; n > 0; n -= 16) { | |
86 ngx_md5_update(&md5, final, n > 16 ? 16 : n); | |
87 } | |
88 | |
89 ngx_memzero(final, sizeof(final)); | |
90 | |
91 for (i = keylen; i; i >>= 1) { | |
92 if (i & 1) { | |
93 ngx_md5_update(&md5, final, 1); | |
94 | |
95 } else { | |
96 ngx_md5_update(&md5, key, 1); | |
97 } | |
98 } | |
99 | |
100 ngx_md5_final(final, &md5); | |
101 | |
102 for (i = 0; i < 1000; i++) { | |
103 ngx_md5_init(&ctx1); | |
104 | |
105 if (i & 1) { | |
106 ngx_md5_update(&ctx1, key, keylen); | |
107 | |
108 } else { | |
109 ngx_md5_update(&ctx1, final, 16); | |
110 } | |
111 | |
112 if (i % 3) { | |
113 ngx_md5_update(&ctx1, salt, saltlen); | |
114 } | |
115 | |
116 if (i % 7) { | |
117 ngx_md5_update(&ctx1, key, keylen); | |
118 } | |
119 | |
120 if (i & 1) { | |
121 ngx_md5_update(&ctx1, final, 16); | |
122 | |
123 } else { | |
124 ngx_md5_update(&ctx1, key, keylen); | |
125 } | |
126 | |
127 ngx_md5_final(final, &ctx1); | |
128 } | |
129 | |
130 /* output */ | |
131 | |
132 *encrypted = ngx_pnalloc(pool, sizeof("$apr1$") - 1 + saltlen + 16 + 1); | |
133 if (*encrypted == NULL) { | |
134 return NGX_ERROR; | |
135 } | |
136 | |
137 p = ngx_cpymem(*encrypted, "$apr1$", sizeof("$apr1$") - 1); | |
138 p = ngx_copy(p, salt, saltlen); | |
139 *p++ = '$'; | |
140 | |
141 p = ngx_crypt_to64(p, (final[ 0]<<16) | (final[ 6]<<8) | final[12], 4); | |
142 p = ngx_crypt_to64(p, (final[ 1]<<16) | (final[ 7]<<8) | final[13], 4); | |
143 p = ngx_crypt_to64(p, (final[ 2]<<16) | (final[ 8]<<8) | final[14], 4); | |
144 p = ngx_crypt_to64(p, (final[ 3]<<16) | (final[ 9]<<8) | final[15], 4); | |
145 p = ngx_crypt_to64(p, (final[ 4]<<16) | (final[10]<<8) | final[ 5], 4); | |
146 p = ngx_crypt_to64(p, final[11], 2); | |
147 *p = '\0'; | |
148 | |
149 return NGX_OK; | |
150 } | |
151 | |
152 | |
153 static u_char * | |
154 ngx_crypt_to64(u_char *p, uint32_t v, size_t n) | |
155 { | |
156 static u_char itoa64[] = | |
157 "./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"; | |
158 | |
159 while (n--) { | |
160 *p++ = itoa64[v & 0x3f]; | |
161 v >>= 6; | |
162 } | |
163 | |
164 return p; | |
165 } | |
166 | |
167 | |
168 static ngx_int_t | |
169 ngx_crypt_plain(ngx_pool_t *pool, u_char *key, u_char *salt, u_char **encrypted) | |
170 { | |
171 size_t len; | |
172 u_char *p; | |
173 | |
174 len = ngx_strlen(key); | |
175 | |
176 *encrypted = ngx_pnalloc(pool, sizeof("{PLAIN}") - 1 + len + 1); | |
177 if (*encrypted == NULL) { | |
178 return NGX_ERROR; | |
179 } | |
180 | |
181 p = ngx_cpymem(*encrypted, "{PLAIN}", sizeof("{PLAIN}") - 1); | |
182 ngx_memcpy(p, key, len + 1); | |
183 | |
184 return NGX_OK; | |
185 } | |
186 | |
187 | |
188 #if (NGX_HAVE_SHA1) | |
189 | |
190 static ngx_int_t | |
191 ngx_crypt_ssha(ngx_pool_t *pool, u_char *key, u_char *salt, u_char **encrypted) | |
192 { | |
193 size_t len; | |
194 ngx_str_t encoded, decoded; | |
195 ngx_sha1_t sha1; | |
196 | |
197 /* "{SSHA}" base64(SHA1(key salt) salt) */ | |
198 | |
199 /* decode base64 salt to find out true salt */ | |
200 | |
201 encoded.data = salt + sizeof("{SSHA}") - 1; | |
202 encoded.len = ngx_strlen(encoded.data); | |
203 | |
204 decoded.data = ngx_pnalloc(pool, ngx_base64_decoded_length(encoded.len)); | |
205 if (decoded.data == NULL) { | |
206 return NGX_ERROR; | |
207 } | |
208 | |
209 ngx_decode_base64(&decoded, &encoded); | |
210 | |
211 /* update SHA1 from key and salt */ | |
212 | |
213 ngx_sha1_init(&sha1); | |
214 ngx_sha1_update(&sha1, key, ngx_strlen(key)); | |
215 ngx_sha1_update(&sha1, decoded.data + 20, decoded.len - 20); | |
216 ngx_sha1_final(decoded.data, &sha1); | |
217 | |
218 /* encode it back to base64 */ | |
219 | |
220 len = sizeof("{SSHA}") - 1 + ngx_base64_encoded_length(decoded.len) + 1; | |
221 | |
222 *encrypted = ngx_pnalloc(pool, len); | |
223 if (*encrypted == NULL) { | |
224 return NGX_ERROR; | |
225 } | |
226 | |
227 encoded.data = ngx_cpymem(*encrypted, "{SSHA}", sizeof("{SSHA}") - 1); | |
228 ngx_encode_base64(&encoded, &decoded); | |
229 encoded.data[encoded.len] = '\0'; | |
230 | |
231 return NGX_OK; | |
232 } | |
233 | |
234 #endif /* NGX_HAVE_SHA1 */ |