Back to home page

Nginx displayed by LXR

Source navigation ]
Diff markup ]
Identifier search ]
general search ]
 
 
Version: nginx-1.15.12 ]​[ nginx-1.16.0 ]​

0001 
0002 /*
0003  * Copyright (C) Maxim Dounin
0004  */
0005 
0006 
0007 #include <ngx_config.h>
0008 #include <ngx_core.h>
0009 #include <ngx_crypt.h>
0010 #include <ngx_md5.h>
0011 #include <ngx_sha1.h>
0012 
0013 
0014 #if (NGX_CRYPT)
0015 
0016 static ngx_int_t ngx_crypt_apr1(ngx_pool_t *pool, u_char *key, u_char *salt,
0017     u_char **encrypted);
0018 static ngx_int_t ngx_crypt_plain(ngx_pool_t *pool, u_char *key, u_char *salt,
0019     u_char **encrypted);
0020 static ngx_int_t ngx_crypt_ssha(ngx_pool_t *pool, u_char *key, u_char *salt,
0021     u_char **encrypted);
0022 static ngx_int_t ngx_crypt_sha(ngx_pool_t *pool, u_char *key, u_char *salt,
0023     u_char **encrypted);
0024 
0025 
0026 static u_char *ngx_crypt_to64(u_char *p, uint32_t v, size_t n);
0027 
0028 
0029 ngx_int_t
0030 ngx_crypt(ngx_pool_t *pool, u_char *key, u_char *salt, u_char **encrypted)
0031 {
0032     if (ngx_strncmp(salt, "$apr1$", sizeof("$apr1$") - 1) == 0) {
0033         return ngx_crypt_apr1(pool, key, salt, encrypted);
0034 
0035     } else if (ngx_strncmp(salt, "{PLAIN}", sizeof("{PLAIN}") - 1) == 0) {
0036         return ngx_crypt_plain(pool, key, salt, encrypted);
0037 
0038     } else if (ngx_strncmp(salt, "{SSHA}", sizeof("{SSHA}") - 1) == 0) {
0039         return ngx_crypt_ssha(pool, key, salt, encrypted);
0040 
0041     } else if (ngx_strncmp(salt, "{SHA}", sizeof("{SHA}") - 1) == 0) {
0042         return ngx_crypt_sha(pool, key, salt, encrypted);
0043     }
0044 
0045     /* fallback to libc crypt() */
0046 
0047     return ngx_libc_crypt(pool, key, salt, encrypted);
0048 }
0049 
0050 
0051 static ngx_int_t
0052 ngx_crypt_apr1(ngx_pool_t *pool, u_char *key, u_char *salt, u_char **encrypted)
0053 {
0054     ngx_int_t          n;
0055     ngx_uint_t         i;
0056     u_char            *p, *last, final[16];
0057     size_t             saltlen, keylen;
0058     ngx_md5_t          md5, ctx1;
0059 
0060     /* Apache's apr1 crypt is Poul-Henning Kamp's md5 crypt with $apr1$ magic */
0061 
0062     keylen = ngx_strlen(key);
0063 
0064     /* true salt: no magic, max 8 chars, stop at first $ */
0065 
0066     salt += sizeof("$apr1$") - 1;
0067     last = salt + 8;
0068     for (p = salt; *p && *p != '$' && p < last; p++) { /* void */ }
0069     saltlen = p - salt;
0070 
0071     /* hash key and salt */
0072 
0073     ngx_md5_init(&md5);
0074     ngx_md5_update(&md5, key, keylen);
0075     ngx_md5_update(&md5, (u_char *) "$apr1$", sizeof("$apr1$") - 1);
0076     ngx_md5_update(&md5, salt, saltlen);
0077 
0078     ngx_md5_init(&ctx1);
0079     ngx_md5_update(&ctx1, key, keylen);
0080     ngx_md5_update(&ctx1, salt, saltlen);
0081     ngx_md5_update(&ctx1, key, keylen);
0082     ngx_md5_final(final, &ctx1);
0083 
0084     for (n = keylen; n > 0; n -= 16) {
0085         ngx_md5_update(&md5, final, n > 16 ? 16 : n);
0086     }
0087 
0088     ngx_memzero(final, sizeof(final));
0089 
0090     for (i = keylen; i; i >>= 1) {
0091         if (i & 1) {
0092             ngx_md5_update(&md5, final, 1);
0093 
0094         } else {
0095             ngx_md5_update(&md5, key, 1);
0096         }
0097     }
0098 
0099     ngx_md5_final(final, &md5);
0100 
0101     for (i = 0; i < 1000; i++) {
0102         ngx_md5_init(&ctx1);
0103 
0104         if (i & 1) {
0105             ngx_md5_update(&ctx1, key, keylen);
0106 
0107         } else {
0108             ngx_md5_update(&ctx1, final, 16);
0109         }
0110 
0111         if (i % 3) {
0112             ngx_md5_update(&ctx1, salt, saltlen);
0113         }
0114 
0115         if (i % 7) {
0116             ngx_md5_update(&ctx1, key, keylen);
0117         }
0118 
0119         if (i & 1) {
0120             ngx_md5_update(&ctx1, final, 16);
0121 
0122         } else {
0123             ngx_md5_update(&ctx1, key, keylen);
0124         }
0125 
0126         ngx_md5_final(final, &ctx1);
0127     }
0128 
0129     /* output */
0130 
0131     *encrypted = ngx_pnalloc(pool, sizeof("$apr1$") - 1 + saltlen + 1 + 22 + 1);
0132     if (*encrypted == NULL) {
0133         return NGX_ERROR;
0134     }
0135 
0136     p = ngx_cpymem(*encrypted, "$apr1$", sizeof("$apr1$") - 1);
0137     p = ngx_copy(p, salt, saltlen);
0138     *p++ = '$';
0139 
0140     p = ngx_crypt_to64(p, (final[ 0]<<16) | (final[ 6]<<8) | final[12], 4);
0141     p = ngx_crypt_to64(p, (final[ 1]<<16) | (final[ 7]<<8) | final[13], 4);
0142     p = ngx_crypt_to64(p, (final[ 2]<<16) | (final[ 8]<<8) | final[14], 4);
0143     p = ngx_crypt_to64(p, (final[ 3]<<16) | (final[ 9]<<8) | final[15], 4);
0144     p = ngx_crypt_to64(p, (final[ 4]<<16) | (final[10]<<8) | final[ 5], 4);
0145     p = ngx_crypt_to64(p, final[11], 2);
0146     *p = '\0';
0147 
0148     return NGX_OK;
0149 }
0150 
0151 
0152 static u_char *
0153 ngx_crypt_to64(u_char *p, uint32_t v, size_t n)
0154 {
0155     static u_char   itoa64[] =
0156         "./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
0157 
0158     while (n--) {
0159         *p++ = itoa64[v & 0x3f];
0160         v >>= 6;
0161     }
0162 
0163     return p;
0164 }
0165 
0166 
0167 static ngx_int_t
0168 ngx_crypt_plain(ngx_pool_t *pool, u_char *key, u_char *salt, u_char **encrypted)
0169 {
0170     size_t   len;
0171     u_char  *p;
0172 
0173     len = ngx_strlen(key);
0174 
0175     *encrypted = ngx_pnalloc(pool, sizeof("{PLAIN}") - 1 + len + 1);
0176     if (*encrypted == NULL) {
0177         return NGX_ERROR;
0178     }
0179 
0180     p = ngx_cpymem(*encrypted, "{PLAIN}", sizeof("{PLAIN}") - 1);
0181     ngx_memcpy(p, key, len + 1);
0182 
0183     return NGX_OK;
0184 }
0185 
0186 
0187 static ngx_int_t
0188 ngx_crypt_ssha(ngx_pool_t *pool, u_char *key, u_char *salt, u_char **encrypted)
0189 {
0190     size_t       len;
0191     ngx_int_t    rc;
0192     ngx_str_t    encoded, decoded;
0193     ngx_sha1_t   sha1;
0194 
0195     /* "{SSHA}" base64(SHA1(key salt) salt) */
0196 
0197     /* decode base64 salt to find out true salt */
0198 
0199     encoded.data = salt + sizeof("{SSHA}") - 1;
0200     encoded.len = ngx_strlen(encoded.data);
0201 
0202     len = ngx_max(ngx_base64_decoded_length(encoded.len), 20);
0203 
0204     decoded.data = ngx_pnalloc(pool, len);
0205     if (decoded.data == NULL) {
0206         return NGX_ERROR;
0207     }
0208 
0209     rc = ngx_decode_base64(&decoded, &encoded);
0210 
0211     if (rc != NGX_OK || decoded.len < 20) {
0212         decoded.len = 20;
0213     }
0214 
0215     /* update SHA1 from key and salt */
0216 
0217     ngx_sha1_init(&sha1);
0218     ngx_sha1_update(&sha1, key, ngx_strlen(key));
0219     ngx_sha1_update(&sha1, decoded.data + 20, decoded.len - 20);
0220     ngx_sha1_final(decoded.data, &sha1);
0221 
0222     /* encode it back to base64 */
0223 
0224     len = sizeof("{SSHA}") - 1 + ngx_base64_encoded_length(decoded.len) + 1;
0225 
0226     *encrypted = ngx_pnalloc(pool, len);
0227     if (*encrypted == NULL) {
0228         return NGX_ERROR;
0229     }
0230 
0231     encoded.data = ngx_cpymem(*encrypted, "{SSHA}", sizeof("{SSHA}") - 1);
0232     ngx_encode_base64(&encoded, &decoded);
0233     encoded.data[encoded.len] = '\0';
0234 
0235     return NGX_OK;
0236 }
0237 
0238 
0239 static ngx_int_t
0240 ngx_crypt_sha(ngx_pool_t *pool, u_char *key, u_char *salt, u_char **encrypted)
0241 {
0242     size_t      len;
0243     ngx_str_t   encoded, decoded;
0244     ngx_sha1_t  sha1;
0245     u_char      digest[20];
0246 
0247     /* "{SHA}" base64(SHA1(key)) */
0248 
0249     decoded.len = sizeof(digest);
0250     decoded.data = digest;
0251 
0252     ngx_sha1_init(&sha1);
0253     ngx_sha1_update(&sha1, key, ngx_strlen(key));
0254     ngx_sha1_final(digest, &sha1);
0255 
0256     len = sizeof("{SHA}") - 1 + ngx_base64_encoded_length(decoded.len) + 1;
0257 
0258     *encrypted = ngx_pnalloc(pool, len);
0259     if (*encrypted == NULL) {
0260         return NGX_ERROR;
0261     }
0262 
0263     encoded.data = ngx_cpymem(*encrypted, "{SHA}", sizeof("{SHA}") - 1);
0264     ngx_encode_base64(&encoded, &decoded);
0265     encoded.data[encoded.len] = '\0';
0266 
0267     return NGX_OK;
0268 }
0269 
0270 #endif /* NGX_CRYPT */