src/core/ngx_crypt.c - nginx-1.7.10

Functions defined

Source code


  1. /*
  2. * Copyright (C) Maxim Dounin
  3. */


  4. #include <ngx_config.h>
  5. #include <ngx_core.h>
  6. #include <ngx_crypt.h>
  7. #include <ngx_md5.h>
  8. #if (NGX_HAVE_SHA1)
  9. #include <ngx_sha1.h>
  10. #endif


  11. #if (NGX_CRYPT)

  12. static ngx_int_t ngx_crypt_apr1(ngx_pool_t *pool, u_char *key, u_char *salt,
  13.     u_char **encrypted);
  14. static ngx_int_t ngx_crypt_plain(ngx_pool_t *pool, u_char *key, u_char *salt,
  15.     u_char **encrypted);

  16. #if (NGX_HAVE_SHA1)

  17. static ngx_int_t ngx_crypt_ssha(ngx_pool_t *pool, u_char *key, u_char *salt,
  18.     u_char **encrypted);
  19. static ngx_int_t ngx_crypt_sha(ngx_pool_t *pool, u_char *key, u_char *salt,
  20.     u_char **encrypted);

  21. #endif


  22. static u_char *ngx_crypt_to64(u_char *p, uint32_t v, size_t n);


  23. ngx_int_t
  24. ngx_crypt(ngx_pool_t *pool, u_char *key, u_char *salt, u_char **encrypted)
  25. {
  26.     if (ngx_strncmp(salt, "$apr1$", sizeof("$apr1$") - 1) == 0) {
  27.         return ngx_crypt_apr1(pool, key, salt, encrypted);

  28.     } else if (ngx_strncmp(salt, "{PLAIN}", sizeof("{PLAIN}") - 1) == 0) {
  29.         return ngx_crypt_plain(pool, key, salt, encrypted);

  30. #if (NGX_HAVE_SHA1)
  31.     } else if (ngx_strncmp(salt, "{SSHA}", sizeof("{SSHA}") - 1) == 0) {
  32.         return ngx_crypt_ssha(pool, key, salt, encrypted);

  33.     } else if (ngx_strncmp(salt, "{SHA}", sizeof("{SHA}") - 1) == 0) {
  34.         return ngx_crypt_sha(pool, key, salt, encrypted);
  35. #endif
  36.     }

  37.     /* fallback to libc crypt() */

  38.     return ngx_libc_crypt(pool, key, salt, encrypted);
  39. }


  40. static ngx_int_t
  41. ngx_crypt_apr1(ngx_pool_t *pool, u_char *key, u_char *salt, u_char **encrypted)
  42. {
  43.     ngx_int_t          n;
  44.     ngx_uint_t         i;
  45.     u_char            *p, *last, final[16];
  46.     size_t             saltlen, keylen;
  47.     ngx_md5_t          md5, ctx1;

  48.     /* Apache's apr1 crypt is Poul-Henning Kamp's md5 crypt with $apr1$ magic */

  49.     keylen = ngx_strlen(key);

  50.     /* true salt: no magic, max 8 chars, stop at first $ */

  51.     salt += sizeof("$apr1$") - 1;
  52.     last = salt + 8;
  53.     for (p = salt; *p && *p != '$' && p < last; p++) { /* void */ }
  54.     saltlen = p - salt;

  55.     /* hash key and salt */

  56.     ngx_md5_init(&md5);
  57.     ngx_md5_update(&md5, key, keylen);
  58.     ngx_md5_update(&md5, (u_char *) "$apr1$", sizeof("$apr1$") - 1);
  59.     ngx_md5_update(&md5, salt, saltlen);

  60.     ngx_md5_init(&ctx1);
  61.     ngx_md5_update(&ctx1, key, keylen);
  62.     ngx_md5_update(&ctx1, salt, saltlen);
  63.     ngx_md5_update(&ctx1, key, keylen);
  64.     ngx_md5_final(final, &ctx1);

  65.     for (n = keylen; n > 0; n -= 16) {
  66.         ngx_md5_update(&md5, final, n > 16 ? 16 : n);
  67.     }

  68.     ngx_memzero(final, sizeof(final));

  69.     for (i = keylen; i; i >>= 1) {
  70.         if (i & 1) {
  71.             ngx_md5_update(&md5, final, 1);

  72.         } else {
  73.             ngx_md5_update(&md5, key, 1);
  74.         }
  75.     }

  76.     ngx_md5_final(final, &md5);

  77.     for (i = 0; i < 1000; i++) {
  78.         ngx_md5_init(&ctx1);

  79.         if (i & 1) {
  80.             ngx_md5_update(&ctx1, key, keylen);

  81.         } else {
  82.             ngx_md5_update(&ctx1, final, 16);
  83.         }

  84.         if (i % 3) {
  85.             ngx_md5_update(&ctx1, salt, saltlen);
  86.         }

  87.         if (i % 7) {
  88.             ngx_md5_update(&ctx1, key, keylen);
  89.         }

  90.         if (i & 1) {
  91.             ngx_md5_update(&ctx1, final, 16);

  92.         } else {
  93.             ngx_md5_update(&ctx1, key, keylen);
  94.         }

  95.         ngx_md5_final(final, &ctx1);
  96.     }

  97.     /* output */

  98.     *encrypted = ngx_pnalloc(pool, sizeof("$apr1$") - 1 + saltlen + 1 + 22 + 1);
  99.     if (*encrypted == NULL) {
  100.         return NGX_ERROR;
  101.     }

  102.     p = ngx_cpymem(*encrypted, "$apr1$", sizeof("$apr1$") - 1);
  103.     p = ngx_copy(p, salt, saltlen);
  104.     *p++ = '$';

  105.     p = ngx_crypt_to64(p, (final[ 0]<<16) | (final[ 6]<<8) | final[12], 4);
  106.     p = ngx_crypt_to64(p, (final[ 1]<<16) | (final[ 7]<<8) | final[13], 4);
  107.     p = ngx_crypt_to64(p, (final[ 2]<<16) | (final[ 8]<<8) | final[14], 4);
  108.     p = ngx_crypt_to64(p, (final[ 3]<<16) | (final[ 9]<<8) | final[15], 4);
  109.     p = ngx_crypt_to64(p, (final[ 4]<<16) | (final[10]<<8) | final[ 5], 4);
  110.     p = ngx_crypt_to64(p, final[11], 2);
  111.     *p = '\0';

  112.     return NGX_OK;
  113. }


  114. static u_char *
  115. ngx_crypt_to64(u_char *p, uint32_t v, size_t n)
  116. {
  117.     static u_char   itoa64[] =
  118.         "./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";

  119.     while (n--) {
  120.        *p++ = itoa64[v & 0x3f];
  121.        v >>= 6;
  122.     }

  123.     return p;
  124. }


  125. static ngx_int_t
  126. ngx_crypt_plain(ngx_pool_t *pool, u_char *key, u_char *salt, u_char **encrypted)
  127. {
  128.     size_t   len;
  129.     u_char  *p;

  130.     len = ngx_strlen(key);

  131.     *encrypted = ngx_pnalloc(pool, sizeof("{PLAIN}") - 1 + len + 1);
  132.     if (*encrypted == NULL) {
  133.         return NGX_ERROR;
  134.     }

  135.     p = ngx_cpymem(*encrypted, "{PLAIN}", sizeof("{PLAIN}") - 1);
  136.     ngx_memcpy(p, key, len + 1);

  137.     return NGX_OK;
  138. }


  139. #if (NGX_HAVE_SHA1)

  140. static ngx_int_t
  141. ngx_crypt_ssha(ngx_pool_t *pool, u_char *key, u_char *salt, u_char **encrypted)
  142. {
  143.     size_t       len;
  144.     ngx_int_t    rc;
  145.     ngx_str_t    encoded, decoded;
  146.     ngx_sha1_t   sha1;

  147.     /* "{SSHA}" base64(SHA1(key salt) salt) */

  148.     /* decode base64 salt to find out true salt */

  149.     encoded.data = salt + sizeof("{SSHA}") - 1;
  150.     encoded.len = ngx_strlen(encoded.data);

  151.     len = ngx_max(ngx_base64_decoded_length(encoded.len), 20);

  152.     decoded.data = ngx_pnalloc(pool, len);
  153.     if (decoded.data == NULL) {
  154.         return NGX_ERROR;
  155.     }

  156.     rc = ngx_decode_base64(&decoded, &encoded);

  157.     if (rc != NGX_OK || decoded.len < 20) {
  158.         decoded.len = 20;
  159.     }

  160.     /* update SHA1 from key and salt */

  161.     ngx_sha1_init(&sha1);
  162.     ngx_sha1_update(&sha1, key, ngx_strlen(key));
  163.     ngx_sha1_update(&sha1, decoded.data + 20, decoded.len - 20);
  164.     ngx_sha1_final(decoded.data, &sha1);

  165.     /* encode it back to base64 */

  166.     len = sizeof("{SSHA}") - 1 + ngx_base64_encoded_length(decoded.len) + 1;

  167.     *encrypted = ngx_pnalloc(pool, len);
  168.     if (*encrypted == NULL) {
  169.         return NGX_ERROR;
  170.     }

  171.     encoded.data = ngx_cpymem(*encrypted, "{SSHA}", sizeof("{SSHA}") - 1);
  172.     ngx_encode_base64(&encoded, &decoded);
  173.     encoded.data[encoded.len] = '\0';

  174.     return NGX_OK;
  175. }


  176. static ngx_int_t
  177. ngx_crypt_sha(ngx_pool_t *pool, u_char *key, u_char *salt, u_char **encrypted)
  178. {
  179.     size_t      len;
  180.     ngx_str_t   encoded, decoded;
  181.     ngx_sha1_t  sha1;
  182.     u_char      digest[20];

  183.     /* "{SHA}" base64(SHA1(key)) */

  184.     decoded.len = sizeof(digest);
  185.     decoded.data = digest;

  186.     ngx_sha1_init(&sha1);
  187.     ngx_sha1_update(&sha1, key, ngx_strlen(key));
  188.     ngx_sha1_final(digest, &sha1);

  189.     len = sizeof("{SHA}") - 1 + ngx_base64_encoded_length(decoded.len) + 1;

  190.     *encrypted = ngx_pnalloc(pool, len);
  191.     if (*encrypted == NULL) {
  192.         return NGX_ERROR;
  193.     }

  194.     encoded.data = ngx_cpymem(*encrypted, "{SHA}", sizeof("{SHA}") - 1);
  195.     ngx_encode_base64(&encoded, &decoded);
  196.     encoded.data[encoded.len] = '\0';

  197.     return NGX_OK;
  198. }

  199. #endif /* NGX_HAVE_SHA1 */

  200. #endif /* NGX_CRYPT */