src/core/ngx_crypt.c - nginx source code

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. #include <ngx_sha1.h>


  9. #if (NGX_CRYPT)

  10. static ngx_int_t ngx_crypt_apr1(ngx_pool_t *pool, u_char *key, u_char *salt,
  11.     u_char **encrypted);
  12. static ngx_int_t ngx_crypt_plain(ngx_pool_t *pool, u_char *key, u_char *salt,
  13.     u_char **encrypted);
  14. static ngx_int_t ngx_crypt_ssha(ngx_pool_t *pool, u_char *key, u_char *salt,
  15.     u_char **encrypted);
  16. static ngx_int_t ngx_crypt_sha(ngx_pool_t *pool, u_char *key, u_char *salt,
  17.     u_char **encrypted);


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


  19. ngx_int_t
  20. ngx_crypt(ngx_pool_t *pool, u_char *key, u_char *salt, u_char **encrypted)
  21. {
  22.     if (ngx_strncmp(salt, "$apr1$", sizeof("$apr1$") - 1) == 0) {
  23.         return ngx_crypt_apr1(pool, key, salt, encrypted);

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

  26.     } else if (ngx_strncmp(salt, "{SSHA}", sizeof("{SSHA}") - 1) == 0) {
  27.         return ngx_crypt_ssha(pool, key, salt, encrypted);

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

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

  32.     return ngx_libc_crypt(pool, key, salt, encrypted);
  33. }


  34. static ngx_int_t
  35. ngx_crypt_apr1(ngx_pool_t *pool, u_char *key, u_char *salt, u_char **encrypted)
  36. {
  37.     ngx_int_t          n;
  38.     ngx_uint_t         i;
  39.     u_char            *p, *last, final[16];
  40.     size_t             saltlen, keylen;
  41.     ngx_md5_t          md5, ctx1;

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

  43.     keylen = ngx_strlen(key);

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

  45.     salt += sizeof("$apr1$") - 1;
  46.     last = salt + 8;
  47.     for (p = salt; *p && *p != '$' && p < last; p++) { /* void */ }
  48.     saltlen = p - salt;

  49.     /* hash key and salt */

  50.     ngx_md5_init(&md5);
  51.     ngx_md5_update(&md5, key, keylen);
  52.     ngx_md5_update(&md5, (u_char *) "$apr1$", sizeof("$apr1$") - 1);
  53.     ngx_md5_update(&md5, salt, saltlen);

  54.     ngx_md5_init(&ctx1);
  55.     ngx_md5_update(&ctx1, key, keylen);
  56.     ngx_md5_update(&ctx1, salt, saltlen);
  57.     ngx_md5_update(&ctx1, key, keylen);
  58.     ngx_md5_final(final, &ctx1);

  59.     for (n = keylen; n > 0; n -= 16) {
  60.         ngx_md5_update(&md5, final, n > 16 ? 16 : n);
  61.     }

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

  63.     for (i = keylen; i; i >>= 1) {
  64.         if (i & 1) {
  65.             ngx_md5_update(&md5, final, 1);

  66.         } else {
  67.             ngx_md5_update(&md5, key, 1);
  68.         }
  69.     }

  70.     ngx_md5_final(final, &md5);

  71.     for (i = 0; i < 1000; i++) {
  72.         ngx_md5_init(&ctx1);

  73.         if (i & 1) {
  74.             ngx_md5_update(&ctx1, key, keylen);

  75.         } else {
  76.             ngx_md5_update(&ctx1, final, 16);
  77.         }

  78.         if (i % 3) {
  79.             ngx_md5_update(&ctx1, salt, saltlen);
  80.         }

  81.         if (i % 7) {
  82.             ngx_md5_update(&ctx1, key, keylen);
  83.         }

  84.         if (i & 1) {
  85.             ngx_md5_update(&ctx1, final, 16);

  86.         } else {
  87.             ngx_md5_update(&ctx1, key, keylen);
  88.         }

  89.         ngx_md5_final(final, &ctx1);
  90.     }

  91.     /* output */

  92.     *encrypted = ngx_pnalloc(pool, sizeof("$apr1$") - 1 + saltlen + 1 + 22 + 1);
  93.     if (*encrypted == NULL) {
  94.         return NGX_ERROR;
  95.     }

  96.     p = ngx_cpymem(*encrypted, "$apr1$", sizeof("$apr1$") - 1);
  97.     p = ngx_copy(p, salt, saltlen);
  98.     *p++ = '$';

  99.     p = ngx_crypt_to64(p, (final[ 0]<<16) | (final[ 6]<<8) | final[12], 4);
  100.     p = ngx_crypt_to64(p, (final[ 1]<<16) | (final[ 7]<<8) | final[13], 4);
  101.     p = ngx_crypt_to64(p, (final[ 2]<<16) | (final[ 8]<<8) | final[14], 4);
  102.     p = ngx_crypt_to64(p, (final[ 3]<<16) | (final[ 9]<<8) | final[15], 4);
  103.     p = ngx_crypt_to64(p, (final[ 4]<<16) | (final[10]<<8) | final[ 5], 4);
  104.     p = ngx_crypt_to64(p, final[11], 2);
  105.     *p = '\0';

  106.     return NGX_OK;
  107. }


  108. static u_char *
  109. ngx_crypt_to64(u_char *p, uint32_t v, size_t n)
  110. {
  111.     static u_char   itoa64[] =
  112.         "./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";

  113.     while (n--) {
  114.         *p++ = itoa64[v & 0x3f];
  115.         v >>= 6;
  116.     }

  117.     return p;
  118. }


  119. static ngx_int_t
  120. ngx_crypt_plain(ngx_pool_t *pool, u_char *key, u_char *salt, u_char **encrypted)
  121. {
  122.     size_t   len;
  123.     u_char  *p;

  124.     len = ngx_strlen(key);

  125.     *encrypted = ngx_pnalloc(pool, sizeof("{PLAIN}") - 1 + len + 1);
  126.     if (*encrypted == NULL) {
  127.         return NGX_ERROR;
  128.     }

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

  131.     return NGX_OK;
  132. }


  133. static ngx_int_t
  134. ngx_crypt_ssha(ngx_pool_t *pool, u_char *key, u_char *salt, u_char **encrypted)
  135. {
  136.     size_t       len;
  137.     ngx_int_t    rc;
  138.     ngx_str_t    encoded, decoded;
  139.     ngx_sha1_t   sha1;

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

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

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

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

  145.     decoded.data = ngx_pnalloc(pool, len);
  146.     if (decoded.data == NULL) {
  147.         return NGX_ERROR;
  148.     }

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

  150.     if (rc != NGX_OK || decoded.len < 20) {
  151.         decoded.len = 20;
  152.     }

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

  154.     ngx_sha1_init(&sha1);
  155.     ngx_sha1_update(&sha1, key, ngx_strlen(key));
  156.     ngx_sha1_update(&sha1, decoded.data + 20, decoded.len - 20);
  157.     ngx_sha1_final(decoded.data, &sha1);

  158.     /* encode it back to base64 */

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

  160.     *encrypted = ngx_pnalloc(pool, len);
  161.     if (*encrypted == NULL) {
  162.         return NGX_ERROR;
  163.     }

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

  167.     return NGX_OK;
  168. }


  169. static ngx_int_t
  170. ngx_crypt_sha(ngx_pool_t *pool, u_char *key, u_char *salt, u_char **encrypted)
  171. {
  172.     size_t      len;
  173.     ngx_str_t   encoded, decoded;
  174.     ngx_sha1_t  sha1;
  175.     u_char      digest[20];

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

  177.     decoded.len = sizeof(digest);
  178.     decoded.data = digest;

  179.     ngx_sha1_init(&sha1);
  180.     ngx_sha1_update(&sha1, key, ngx_strlen(key));
  181.     ngx_sha1_final(digest, &sha1);

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

  183.     *encrypted = ngx_pnalloc(pool, len);
  184.     if (*encrypted == NULL) {
  185.         return NGX_ERROR;
  186.     }

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

  190.     return NGX_OK;
  191. }

  192. #endif /* NGX_CRYPT */