Return to ngx_crypt.c CVS log | Up to [ELWIX - Embedded LightWeight unIX -] / embedaddon / nginx / src / core |
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 */