Annotation of embedaddon/nginx/src/core/ngx_crypt.c, revision 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>