Groonga 3.0.9 Source Code Document
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Pages
ngx_crypt.c
Go to the documentation of this file.
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 
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 + 16 + 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 */