Annotation of embedaddon/nginx/src/core/ngx_crypt.c, revision 1.1.1.1
1.1 misho 1:
2: /*
3: * Copyright (C) Maxim Dounin
4: */
5:
6:
7: #include <ngx_config.h>
8: #include <ngx_core.h>
9: #include <ngx_crypt.h>
10: #include <ngx_md5.h>
11: #if (NGX_HAVE_SHA1)
12: #include <ngx_sha1.h>
13: #endif
14:
15:
16: #if (NGX_CRYPT)
17:
18: static ngx_int_t ngx_crypt_apr1(ngx_pool_t *pool, u_char *key, u_char *salt,
19: u_char **encrypted);
20: static ngx_int_t ngx_crypt_plain(ngx_pool_t *pool, u_char *key, u_char *salt,
21: u_char **encrypted);
22:
23: #if (NGX_HAVE_SHA1)
24:
25: static ngx_int_t ngx_crypt_ssha(ngx_pool_t *pool, u_char *key, u_char *salt,
26: u_char **encrypted);
27: static ngx_int_t ngx_crypt_sha(ngx_pool_t *pool, u_char *key, u_char *salt,
28: u_char **encrypted);
29:
30: #endif
31:
32:
33: static u_char *ngx_crypt_to64(u_char *p, uint32_t v, size_t n);
34:
35:
36: ngx_int_t
37: ngx_crypt(ngx_pool_t *pool, u_char *key, u_char *salt, u_char **encrypted)
38: {
39: if (ngx_strncmp(salt, "$apr1$", sizeof("$apr1$") - 1) == 0) {
40: return ngx_crypt_apr1(pool, key, salt, encrypted);
41:
42: } else if (ngx_strncmp(salt, "{PLAIN}", sizeof("{PLAIN}") - 1) == 0) {
43: return ngx_crypt_plain(pool, key, salt, encrypted);
44:
45: #if (NGX_HAVE_SHA1)
46: } else if (ngx_strncmp(salt, "{SSHA}", sizeof("{SSHA}") - 1) == 0) {
47: return ngx_crypt_ssha(pool, key, salt, encrypted);
48:
49: } else if (ngx_strncmp(salt, "{SHA}", sizeof("{SHA}") - 1) == 0) {
50: return ngx_crypt_sha(pool, key, salt, encrypted);
51: #endif
52: }
53:
54: /* fallback to libc crypt() */
55:
56: return ngx_libc_crypt(pool, key, salt, encrypted);
57: }
58:
59:
60: static ngx_int_t
61: ngx_crypt_apr1(ngx_pool_t *pool, u_char *key, u_char *salt, u_char **encrypted)
62: {
63: ngx_int_t n;
64: ngx_uint_t i;
65: u_char *p, *last, final[16];
66: size_t saltlen, keylen;
67: ngx_md5_t md5, ctx1;
68:
69: /* Apache's apr1 crypt is Paul-Henning Kamp's md5 crypt with $apr1$ magic */
70:
71: keylen = ngx_strlen(key);
72:
73: /* true salt: no magic, max 8 chars, stop at first $ */
74:
75: salt += sizeof("$apr1$") - 1;
76: last = salt + 8;
77: for (p = salt; *p && *p != '$' && p < last; p++) { /* void */ }
78: saltlen = p - salt;
79:
80: /* hash key and salt */
81:
82: ngx_md5_init(&md5);
83: ngx_md5_update(&md5, key, keylen);
84: ngx_md5_update(&md5, (u_char *) "$apr1$", sizeof("$apr1$") - 1);
85: ngx_md5_update(&md5, salt, saltlen);
86:
87: ngx_md5_init(&ctx1);
88: ngx_md5_update(&ctx1, key, keylen);
89: ngx_md5_update(&ctx1, salt, saltlen);
90: ngx_md5_update(&ctx1, key, keylen);
91: ngx_md5_final(final, &ctx1);
92:
93: for (n = keylen; n > 0; n -= 16) {
94: ngx_md5_update(&md5, final, n > 16 ? 16 : n);
95: }
96:
97: ngx_memzero(final, sizeof(final));
98:
99: for (i = keylen; i; i >>= 1) {
100: if (i & 1) {
101: ngx_md5_update(&md5, final, 1);
102:
103: } else {
104: ngx_md5_update(&md5, key, 1);
105: }
106: }
107:
108: ngx_md5_final(final, &md5);
109:
110: for (i = 0; i < 1000; i++) {
111: ngx_md5_init(&ctx1);
112:
113: if (i & 1) {
114: ngx_md5_update(&ctx1, key, keylen);
115:
116: } else {
117: ngx_md5_update(&ctx1, final, 16);
118: }
119:
120: if (i % 3) {
121: ngx_md5_update(&ctx1, salt, saltlen);
122: }
123:
124: if (i % 7) {
125: ngx_md5_update(&ctx1, key, keylen);
126: }
127:
128: if (i & 1) {
129: ngx_md5_update(&ctx1, final, 16);
130:
131: } else {
132: ngx_md5_update(&ctx1, key, keylen);
133: }
134:
135: ngx_md5_final(final, &ctx1);
136: }
137:
138: /* output */
139:
140: *encrypted = ngx_pnalloc(pool, sizeof("$apr1$") - 1 + saltlen + 1 + 22 + 1);
141: if (*encrypted == NULL) {
142: return NGX_ERROR;
143: }
144:
145: p = ngx_cpymem(*encrypted, "$apr1$", sizeof("$apr1$") - 1);
146: p = ngx_copy(p, salt, saltlen);
147: *p++ = '$';
148:
149: p = ngx_crypt_to64(p, (final[ 0]<<16) | (final[ 6]<<8) | final[12], 4);
150: p = ngx_crypt_to64(p, (final[ 1]<<16) | (final[ 7]<<8) | final[13], 4);
151: p = ngx_crypt_to64(p, (final[ 2]<<16) | (final[ 8]<<8) | final[14], 4);
152: p = ngx_crypt_to64(p, (final[ 3]<<16) | (final[ 9]<<8) | final[15], 4);
153: p = ngx_crypt_to64(p, (final[ 4]<<16) | (final[10]<<8) | final[ 5], 4);
154: p = ngx_crypt_to64(p, final[11], 2);
155: *p = '\0';
156:
157: return NGX_OK;
158: }
159:
160:
161: static u_char *
162: ngx_crypt_to64(u_char *p, uint32_t v, size_t n)
163: {
164: static u_char itoa64[] =
165: "./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
166:
167: while (n--) {
168: *p++ = itoa64[v & 0x3f];
169: v >>= 6;
170: }
171:
172: return p;
173: }
174:
175:
176: static ngx_int_t
177: ngx_crypt_plain(ngx_pool_t *pool, u_char *key, u_char *salt, u_char **encrypted)
178: {
179: size_t len;
180: u_char *p;
181:
182: len = ngx_strlen(key);
183:
184: *encrypted = ngx_pnalloc(pool, sizeof("{PLAIN}") - 1 + len + 1);
185: if (*encrypted == NULL) {
186: return NGX_ERROR;
187: }
188:
189: p = ngx_cpymem(*encrypted, "{PLAIN}", sizeof("{PLAIN}") - 1);
190: ngx_memcpy(p, key, len + 1);
191:
192: return NGX_OK;
193: }
194:
195:
196: #if (NGX_HAVE_SHA1)
197:
198: static ngx_int_t
199: ngx_crypt_ssha(ngx_pool_t *pool, u_char *key, u_char *salt, u_char **encrypted)
200: {
201: size_t len;
202: ngx_int_t rc;
203: ngx_str_t encoded, decoded;
204: ngx_sha1_t sha1;
205:
206: /* "{SSHA}" base64(SHA1(key salt) salt) */
207:
208: /* decode base64 salt to find out true salt */
209:
210: encoded.data = salt + sizeof("{SSHA}") - 1;
211: encoded.len = ngx_strlen(encoded.data);
212:
213: len = ngx_max(ngx_base64_decoded_length(encoded.len), 20);
214:
215: decoded.data = ngx_pnalloc(pool, len);
216: if (decoded.data == NULL) {
217: return NGX_ERROR;
218: }
219:
220: rc = ngx_decode_base64(&decoded, &encoded);
221:
222: if (rc != NGX_OK || decoded.len < 20) {
223: decoded.len = 20;
224: }
225:
226: /* update SHA1 from key and salt */
227:
228: ngx_sha1_init(&sha1);
229: ngx_sha1_update(&sha1, key, ngx_strlen(key));
230: ngx_sha1_update(&sha1, decoded.data + 20, decoded.len - 20);
231: ngx_sha1_final(decoded.data, &sha1);
232:
233: /* encode it back to base64 */
234:
235: len = sizeof("{SSHA}") - 1 + ngx_base64_encoded_length(decoded.len) + 1;
236:
237: *encrypted = ngx_pnalloc(pool, len);
238: if (*encrypted == NULL) {
239: return NGX_ERROR;
240: }
241:
242: encoded.data = ngx_cpymem(*encrypted, "{SSHA}", sizeof("{SSHA}") - 1);
243: ngx_encode_base64(&encoded, &decoded);
244: encoded.data[encoded.len] = '\0';
245:
246: return NGX_OK;
247: }
248:
249:
250: static ngx_int_t
251: ngx_crypt_sha(ngx_pool_t *pool, u_char *key, u_char *salt, u_char **encrypted)
252: {
253: size_t len;
254: ngx_str_t encoded, decoded;
255: ngx_sha1_t sha1;
256: u_char digest[20];
257:
258: /* "{SHA}" base64(SHA1(key)) */
259:
260: decoded.len = sizeof(digest);
261: decoded.data = digest;
262:
263: ngx_sha1_init(&sha1);
264: ngx_sha1_update(&sha1, key, ngx_strlen(key));
265: ngx_sha1_final(digest, &sha1);
266:
267: len = sizeof("{SHA}") - 1 + ngx_base64_encoded_length(decoded.len) + 1;
268:
269: *encrypted = ngx_pnalloc(pool, len);
270: if (*encrypted == NULL) {
271: return NGX_ERROR;
272: }
273:
274: encoded.data = ngx_cpymem(*encrypted, "{SHA}", sizeof("{SHA}") - 1);
275: ngx_encode_base64(&encoded, &decoded);
276: encoded.data[encoded.len] = '\0';
277:
278: return NGX_OK;
279: }
280:
281: #endif /* NGX_HAVE_SHA1 */
282:
283: #endif /* NGX_CRYPT */
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>