+ int i;
+ u_int32_t count, salt, l, r0, r1, keybuf[2];
+ u_char *p, *q;
+ static char output[21];
+
+ if (!des_initialised)
+ des_init();
+
+ /*
+ * Copy the key, shifting each character up by one bit
+ * and padding with zeros.
+ */
+ q = (u_char *)keybuf;
+ while (q - (u_char *)keybuf - 8) {
+ *q++ = *key << 1;
+ if (*key != '\0')
+ key++;
+ }
+ if (des_setkey((char *)keybuf))
+ return(NULL);
+
+ if (*setting == _PASSWORD_EFMT1) {
+ /*
+ * "new"-style:
+ * setting - underscore, 4 bytes of count, 4 bytes of salt
+ * key - unlimited characters
+ */
+ for (i = 1, count = 0L; i < 5; i++)
+ count |= ascii_to_bin(setting[i]) << ((i - 1) * 6);
+
+ for (i = 5, salt = 0L; i < 9; i++)
+ salt |= ascii_to_bin(setting[i]) << ((i - 5) * 6);
+
+ while (*key) {
+ /*
+ * Encrypt the key with itself.
+ */
+ if (des_cipher((char *)keybuf, (char *)keybuf, 0L, 1))
+ return(NULL);
+ /*
+ * And XOR with the next 8 characters of the key.
+ */
+ q = (u_char *)keybuf;
+ while (q - (u_char *)keybuf - 8 && *key)
+ *q++ ^= *key++ << 1;
+
+ if (des_setkey((char *)keybuf))
+ return(NULL);
+ }
+ strncpy(output, setting, 9);
+
+ /*
+ * Double check that we weren't given a short setting.
+ * If we were, the above code will probably have created
+ * wierd values for count and salt, but we don't really care.
+ * Just make sure the output string doesn't have an extra
+ * NUL in it.
+ */
+ output[9] = '\0';
+ p = (u_char *)output + strlen(output);
+ } else {
+ /*
+ * "old"-style:
+ * setting - 2 bytes of salt
+ * key - up to 8 characters
+ */
+ count = 25;
+
+ salt = (ascii_to_bin(setting[1]) << 6)
+ | ascii_to_bin(setting[0]);
+
+ output[0] = setting[0];
+ /*
+ * If the encrypted password that the salt was extracted from
+ * is only 1 character long, the salt will be corrupted. We
+ * need to ensure that the output string doesn't have an extra
+ * NUL in it!
+ */
+ output[1] = setting[1] ? setting[1] : output[0];
+
+ p = (u_char *)output + 2;
+ }
+ setup_salt(salt);
+ /*
+ * Do it.
+ */
+ if (do_des(0L, 0L, &r0, &r1, (int)count))
+ return(NULL);
+ /*
+ * Now encode the result...
+ */
+ l = (r0 >> 8);
+ *p++ = ascii64[(l >> 18) & 0x3f];
+ *p++ = ascii64[(l >> 12) & 0x3f];
+ *p++ = ascii64[(l >> 6) & 0x3f];
+ *p++ = ascii64[l & 0x3f];
+
+ l = (r0 << 16) | ((r1 >> 16) & 0xffff);
+ *p++ = ascii64[(l >> 18) & 0x3f];
+ *p++ = ascii64[(l >> 12) & 0x3f];
+ *p++ = ascii64[(l >> 6) & 0x3f];
+ *p++ = ascii64[l & 0x3f];
+
+ l = r1 << 2;
+ *p++ = ascii64[(l >> 12) & 0x3f];
+ *p++ = ascii64[(l >> 6) & 0x3f];
+ *p++ = ascii64[l & 0x3f];
+ *p = 0;
+
+ return(output);
+}
+/* END: https://github.com/freebsd/freebsd/blob/master/secure/lib/libcrypt/crypt-des.c */
+
+
+/* START: https://github.com/freebsd/freebsd/blob/master/lib/libcrypt/crypt-md5.c */
+char *
+crypt_md5(const char *pw, const char *salt)
+{
+ MD5_CTX ctx,ctx1;
+ unsigned long l;
+ int sl, pl;
+ u_int i;
+ u_char final[MD5_SIZE];
+ static const char *sp, *ep;
+ static char passwd[120], *p;
+ static const char *magic = "$1$";
+
+ /* Refine the Salt first */
+ sp = salt;
+
+ /* If it starts with the magic string, then skip that */
+ if(!strncmp(sp, magic, strlen(magic)))
+ sp += strlen(magic);
+
+ /* It stops at the first '$', max 8 chars */
+ for(ep = sp; *ep && *ep != '$' && ep < (sp + 8); ep++)
+ continue;
+
+ /* get the length of the true salt */
+ sl = ep - sp;
+
+ MD5Init(&ctx);
+
+ /* The password first, since that is what is most unknown */
+ MD5Update(&ctx, (const u_char *)pw, strlen(pw));
+
+ /* Then our magic string */
+ MD5Update(&ctx, (const u_char *)magic, strlen(magic));
+
+ /* Then the raw salt */
+ MD5Update(&ctx, (const u_char *)sp, (u_int)sl);
+
+ /* Then just as many characters of the MD5(pw,salt,pw) */
+ MD5Init(&ctx1);
+ MD5Update(&ctx1, (const u_char *)pw, strlen(pw));
+ MD5Update(&ctx1, (const u_char *)sp, (u_int)sl);
+ MD5Update(&ctx1, (const u_char *)pw, strlen(pw));
+ MD5Final(final, &ctx1);
+ for(pl = (int)strlen(pw); pl > 0; pl -= MD5_SIZE)
+ MD5Update(&ctx, (const u_char *)final,
+ (u_int)(pl > MD5_SIZE ? MD5_SIZE : pl));
+
+ /* Don't leave anything around in vm they could use. */
+ memset(final, 0, sizeof(final));
+
+ /* Then something really weird... */
+ for (i = strlen(pw); i; i >>= 1)
+ if(i & 1)
+ MD5Update(&ctx, (const u_char *)final, 1);
+ else
+ MD5Update(&ctx, (const u_char *)pw, 1);
+
+ /* Now make the output string */
+ strcpy(passwd, magic);
+ strncat(passwd, sp, (u_int)sl);
+ strcat(passwd, "$");
+
+ MD5Final(final, &ctx);
+
+ /*
+ * and now, just to make sure things don't run too fast
+ * On a 60 Mhz Pentium this takes 34 msec, so you would
+ * need 30 seconds to build a 1000 entry dictionary...
+ */
+ for(i = 0; i < 1000; i++) {
+ MD5Init(&ctx1);
+ if(i & 1)
+ MD5Update(&ctx1, (const u_char *)pw, strlen(pw));
+ else
+ MD5Update(&ctx1, (const u_char *)final, MD5_SIZE);
+
+ if(i % 3)
+ MD5Update(&ctx1, (const u_char *)sp, (u_int)sl);
+
+ if(i % 7)
+ MD5Update(&ctx1, (const u_char *)pw, strlen(pw));
+
+ if(i & 1)
+ MD5Update(&ctx1, (const u_char *)final, MD5_SIZE);
+ else
+ MD5Update(&ctx1, (const u_char *)pw, strlen(pw));
+ MD5Final(final, &ctx1);
+ }
+
+ p = passwd + strlen(passwd);
+
+ l = (final[ 0]<<16) | (final[ 6]<<8) | final[12];
+ _crypt_to64(p, l, 4); p += 4;
+ l = (final[ 1]<<16) | (final[ 7]<<8) | final[13];
+ _crypt_to64(p, l, 4); p += 4;
+ l = (final[ 2]<<16) | (final[ 8]<<8) | final[14];
+ _crypt_to64(p, l, 4); p += 4;
+ l = (final[ 3]<<16) | (final[ 9]<<8) | final[15];
+ _crypt_to64(p, l, 4); p += 4;
+ l = (final[ 4]<<16) | (final[10]<<8) | final[ 5];
+ _crypt_to64(p, l, 4); p += 4;
+ l = final[11];
+ _crypt_to64(p, l, 2); p += 2;
+ *p = '\0';
+
+ /* Don't leave anything around in vm they could use. */
+ memset(final, 0, sizeof(final));
+
+ return (passwd);
+}
+/* END: https://github.com/freebsd/freebsd/blob/master/lib/libcrypt/crypt-md5.c */
+
+
+/* START: https://github.com/freebsd/freebsd/blob/master/lib/libcrypt/crypt-sha256.c */
+static const char sha256_salt_prefix[] = "$5$";
+
+/* Prefix for optional rounds specification. */
+static const char sha256_rounds_prefix[] = "rounds=";
+
+/* Maximum salt string length. */
+#define SALT_LEN_MAX 16
+/* Default number of rounds if not explicitly specified. */
+#define ROUNDS_DEFAULT 5000
+/* Minimum number of rounds. */
+#define ROUNDS_MIN 1000
+/* Maximum number of rounds. */
+#define ROUNDS_MAX 999999999
+
+static char *
+crypt_sha256_r(const char *key, const char *salt, char *buffer, int buflen)
+{
+ u_long srounds;
+ int n;
+ uint8_t alt_result[32], temp_result[32];
+ SHA256_CTX ctx, alt_ctx;
+ size_t salt_len, key_len, cnt, rounds;
+ char *cp, *copied_key, *copied_salt, *p_bytes, *s_bytes, *endp;
+ const char *num;
+ bool rounds_custom;
+
+ copied_key = NULL;
+ copied_salt = NULL;
+
+ /* Default number of rounds. */
+ rounds = ROUNDS_DEFAULT;
+ rounds_custom = false;
+
+ /* Find beginning of salt string. The prefix should normally always
+ * be present. Just in case it is not. */
+ if (strncmp(sha256_salt_prefix, salt, sizeof(sha256_salt_prefix) - 1) == 0)
+ /* Skip salt prefix. */
+ salt += sizeof(sha256_salt_prefix) - 1;
+
+ if (strncmp(salt, sha256_rounds_prefix, sizeof(sha256_rounds_prefix) - 1)
+ == 0) {
+ num = salt + sizeof(sha256_rounds_prefix) - 1;
+ srounds = strtoul(num, &endp, 10);
+
+ if (*endp == '$') {
+ salt = endp + 1;
+ rounds = MAX(ROUNDS_MIN, MIN(srounds, ROUNDS_MAX));
+ rounds_custom = true;
+ }
+ }
+
+ salt_len = MIN(strcspn(salt, "$"), SALT_LEN_MAX);
+ key_len = strlen(key);
+
+ /* Prepare for the real work. */
+ SHA256_Init(&ctx);
+
+ /* Add the key string. */
+ SHA256_Update(&ctx, key, key_len);
+
+ /* The last part is the salt string. This must be at most 8
+ * characters and it ends at the first `$' character (for
+ * compatibility with existing implementations). */
+ SHA256_Update(&ctx, salt, salt_len);
+
+ /* Compute alternate SHA256 sum with input KEY, SALT, and KEY. The
+ * final result will be added to the first context. */
+ SHA256_Init(&alt_ctx);
+
+ /* Add key. */
+ SHA256_Update(&alt_ctx, key, key_len);
+
+ /* Add salt. */
+ SHA256_Update(&alt_ctx, salt, salt_len);
+
+ /* Add key again. */
+ SHA256_Update(&alt_ctx, key, key_len);
+
+ /* Now get result of this (32 bytes) and add it to the other context. */
+ SHA256_Final(alt_result, &alt_ctx);
+
+ /* Add for any character in the key one byte of the alternate sum. */
+ for (cnt = key_len; cnt > 32; cnt -= 32)
+ SHA256_Update(&ctx, alt_result, 32);
+ SHA256_Update(&ctx, alt_result, cnt);
+
+ /* Take the binary representation of the length of the key and for
+ * every 1 add the alternate sum, for every 0 the key. */
+ for (cnt = key_len; cnt > 0; cnt >>= 1)
+ if ((cnt & 1) != 0)
+ SHA256_Update(&ctx, alt_result, 32);
+ else
+ SHA256_Update(&ctx, key, key_len);
+
+ /* Create intermediate result. */
+ SHA256_Final(alt_result, &ctx);
+
+ /* Start computation of P byte sequence. */
+ SHA256_Init(&alt_ctx);
+
+ /* For every character in the password add the entire password. */
+ for (cnt = 0; cnt < key_len; ++cnt)
+ SHA256_Update(&alt_ctx, key, key_len);
+
+ /* Finish the digest. */
+ SHA256_Final(temp_result, &alt_ctx);
+
+ /* Create byte sequence P. */
+ cp = p_bytes = alloca(key_len);
+ for (cnt = key_len; cnt >= 32; cnt -= 32) {
+ memcpy(cp, temp_result, 32);
+ cp += 32;
+ }
+ memcpy(cp, temp_result, cnt);
+
+ /* Start computation of S byte sequence. */
+ SHA256_Init(&alt_ctx);
+
+ /* For every character in the password add the entire password. */
+ for (cnt = 0; cnt < 16 + alt_result[0]; ++cnt)
+ SHA256_Update(&alt_ctx, salt, salt_len);
+
+ /* Finish the digest. */
+ SHA256_Final(temp_result, &alt_ctx);
+
+ /* Create byte sequence S. */
+ cp = s_bytes = alloca(salt_len);
+ for (cnt = salt_len; cnt >= 32; cnt -= 32) {
+ memcpy(cp, temp_result, 32);
+ cp += 32;
+ }
+ memcpy(cp, temp_result, cnt);
+
+ /* Repeatedly run the collected hash value through SHA256 to burn CPU
+ * cycles. */
+ for (cnt = 0; cnt < rounds; ++cnt) {
+ /* New context. */
+ SHA256_Init(&ctx);
+
+ /* Add key or last result. */
+ if ((cnt & 1) != 0)
+ SHA256_Update(&ctx, p_bytes, key_len);
+ else
+ SHA256_Update(&ctx, alt_result, 32);
+
+ /* Add salt for numbers not divisible by 3. */
+ if (cnt % 3 != 0)
+ SHA256_Update(&ctx, s_bytes, salt_len);
+
+ /* Add key for numbers not divisible by 7. */
+ if (cnt % 7 != 0)
+ SHA256_Update(&ctx, p_bytes, key_len);
+
+ /* Add key or last result. */
+ if ((cnt & 1) != 0)
+ SHA256_Update(&ctx, alt_result, 32);
+ else
+ SHA256_Update(&ctx, p_bytes, key_len);
+
+ /* Create intermediate result. */
+ SHA256_Final(alt_result, &ctx);
+ }
+
+ /* Now we can construct the result string. It consists of three
+ * parts. */
+ cp = stpncpy(buffer, sha256_salt_prefix, MAX(0, buflen));
+ buflen -= sizeof(sha256_salt_prefix) - 1;
+
+ if (rounds_custom) {
+ n = snprintf(cp, MAX(0, buflen), "%s%zu$",
+ sha256_rounds_prefix, rounds);
+
+ cp += n;
+ buflen -= n;
+ }
+
+ cp = stpncpy(cp, salt, MIN((size_t)MAX(0, buflen), salt_len));
+ buflen -= MIN((size_t)MAX(0, buflen), salt_len);
+
+ if (buflen > 0) {
+ *cp++ = '$';
+ --buflen;
+ }
+
+ b64_from_24bit(alt_result[0], alt_result[10], alt_result[20], 4, &buflen, &cp);
+ b64_from_24bit(alt_result[21], alt_result[1], alt_result[11], 4, &buflen, &cp);
+ b64_from_24bit(alt_result[12], alt_result[22], alt_result[2], 4, &buflen, &cp);
+ b64_from_24bit(alt_result[3], alt_result[13], alt_result[23], 4, &buflen, &cp);
+ b64_from_24bit(alt_result[24], alt_result[4], alt_result[14], 4, &buflen, &cp);
+ b64_from_24bit(alt_result[15], alt_result[25], alt_result[5], 4, &buflen, &cp);
+ b64_from_24bit(alt_result[6], alt_result[16], alt_result[26], 4, &buflen, &cp);
+ b64_from_24bit(alt_result[27], alt_result[7], alt_result[17], 4, &buflen, &cp);
+ b64_from_24bit(alt_result[18], alt_result[28], alt_result[8], 4, &buflen, &cp);
+ b64_from_24bit(alt_result[9], alt_result[19], alt_result[29], 4, &buflen, &cp);
+ b64_from_24bit(0, alt_result[31], alt_result[30], 3, &buflen, &cp);
+ if (buflen <= 0) {
+ errno = ERANGE;
+ buffer = NULL;
+ }
+ else
+ *cp = '\0'; /* Terminate the string. */
+
+ /* Clear the buffer for the intermediate result so that people
+ * attaching to processes or reading core dumps cannot get any
+ * information. We do it in this way to clear correct_words[] inside
+ * the SHA256 implementation as well. */
+ SHA256_Init(&ctx);
+ SHA256_Final(alt_result, &ctx);
+ memset(temp_result, '\0', sizeof(temp_result));
+ memset(p_bytes, '\0', key_len);
+ memset(s_bytes, '\0', salt_len);
+ memset(&ctx, '\0', sizeof(ctx));
+ memset(&alt_ctx, '\0', sizeof(alt_ctx));
+ if (copied_key != NULL)
+ memset(copied_key, '\0', key_len);
+ if (copied_salt != NULL)
+ memset(copied_salt, '\0', salt_len);
+
+ return buffer;
+}
+
+/* This entry point is equivalent to crypt(3). */
+char* crypt_sha256(const char *key, const char *salt)
+{
+ /* We don't want to have an arbitrary limit in the size of the
+ * password. We can compute an upper bound for the size of the
+ * result in advance and so we can prepare the buffer we pass to
+ * `crypt_sha256_r'. */
+ static char *buffer;
+ static int buflen;
+ int needed;
+ char *new_buffer;
+
+ needed = (sizeof(sha256_salt_prefix) - 1
+ + sizeof(sha256_rounds_prefix) + 9 + 1
+ + strlen(salt) + 1 + 43 + 1);
+
+ if (buflen < needed) {
+ new_buffer = (char *)realloc(buffer, needed);
+
+ if (new_buffer == NULL)
+ return NULL;
+
+ buffer = new_buffer;
+ buflen = needed;
+ }
+
+ return crypt_sha256_r(key, salt, buffer, buflen);
+}
+/* END: https://github.com/freebsd/freebsd/blob/master/lib/libcrypt/crypt-sha256.c */
+
+
+/* START: https://github.com/freebsd/freebsd/blob/master/lib/libcrypt/crypt-sha512.c */
+/* Define our magic string to mark salt for SHA512 "encryption" replacement. */
+static const char sha512_salt_prefix[] = "$6$";
+
+/* Prefix for optional rounds specification. */
+static const char sha512_rounds_prefix[] = "rounds=";
+
+/* Maximum salt string length. */
+#define SALT_LEN_MAX 16
+/* Default number of rounds if not explicitly specified. */
+#define ROUNDS_DEFAULT 5000
+/* Minimum number of rounds. */
+#define ROUNDS_MIN 1000
+/* Maximum number of rounds. */
+#define ROUNDS_MAX 999999999
+
+static char *
+crypt_sha512_r(const char *key, const char *salt, char *buffer, int buflen)
+{
+ u_long srounds;
+ int n;
+ uint8_t alt_result[64], temp_result[64];
+ SHA512_CTX ctx, alt_ctx;
+ size_t salt_len, key_len, cnt, rounds;
+ char *cp, *copied_key, *copied_salt, *p_bytes, *s_bytes, *endp;
+ const char *num;
+ bool rounds_custom;
+
+ copied_key = NULL;
+ copied_salt = NULL;
+
+ /* Default number of rounds. */
+ rounds = ROUNDS_DEFAULT;
+ rounds_custom = false;
+
+ /* Find beginning of salt string. The prefix should normally always
+ * be present. Just in case it is not. */
+ if (strncmp(sha512_salt_prefix, salt, sizeof(sha512_salt_prefix) - 1) == 0)
+ /* Skip salt prefix. */
+ salt += sizeof(sha512_salt_prefix) - 1;
+
+ if (strncmp(salt, sha512_rounds_prefix, sizeof(sha512_rounds_prefix) - 1)
+ == 0) {
+ num = salt + sizeof(sha512_rounds_prefix) - 1;
+ srounds = strtoul(num, &endp, 10);
+
+ if (*endp == '$') {
+ salt = endp + 1;
+ rounds = MAX(ROUNDS_MIN, MIN(srounds, ROUNDS_MAX));
+ rounds_custom = true;
+ }
+ }
+
+ salt_len = MIN(strcspn(salt, "$"), SALT_LEN_MAX);
+ key_len = strlen(key);
+
+ /* Prepare for the real work. */
+ SHA512_Init(&ctx);
+
+ /* Add the key string. */
+ SHA512_Update(&ctx, key, key_len);
+
+ /* The last part is the salt string. This must be at most 8
+ * characters and it ends at the first `$' character (for
+ * compatibility with existing implementations). */
+ SHA512_Update(&ctx, salt, salt_len);
+
+ /* Compute alternate SHA512 sum with input KEY, SALT, and KEY. The
+ * final result will be added to the first context. */
+ SHA512_Init(&alt_ctx);
+
+ /* Add key. */
+ SHA512_Update(&alt_ctx, key, key_len);
+
+ /* Add salt. */
+ SHA512_Update(&alt_ctx, salt, salt_len);
+
+ /* Add key again. */
+ SHA512_Update(&alt_ctx, key, key_len);
+
+ /* Now get result of this (64 bytes) and add it to the other context. */
+ SHA512_Final(alt_result, &alt_ctx);
+
+ /* Add for any character in the key one byte of the alternate sum. */
+ for (cnt = key_len; cnt > 64; cnt -= 64)
+ SHA512_Update(&ctx, alt_result, 64);
+ SHA512_Update(&ctx, alt_result, cnt);
+
+ /* Take the binary representation of the length of the key and for
+ * every 1 add the alternate sum, for every 0 the key. */
+ for (cnt = key_len; cnt > 0; cnt >>= 1)
+ if ((cnt & 1) != 0)
+ SHA512_Update(&ctx, alt_result, 64);
+ else
+ SHA512_Update(&ctx, key, key_len);
+
+ /* Create intermediate result. */
+ SHA512_Final(alt_result, &ctx);
+
+ /* Start computation of P byte sequence. */
+ SHA512_Init(&alt_ctx);
+
+ /* For every character in the password add the entire password. */
+ for (cnt = 0; cnt < key_len; ++cnt)
+ SHA512_Update(&alt_ctx, key, key_len);
+
+ /* Finish the digest. */
+ SHA512_Final(temp_result, &alt_ctx);
+
+ /* Create byte sequence P. */
+ cp = p_bytes = alloca(key_len);
+ for (cnt = key_len; cnt >= 64; cnt -= 64) {
+ memcpy(cp, temp_result, 64);
+ cp += 64;
+ }
+ memcpy(cp, temp_result, cnt);
+
+ /* Start computation of S byte sequence. */
+ SHA512_Init(&alt_ctx);
+
+ /* For every character in the password add the entire password. */
+ for (cnt = 0; cnt < 16 + alt_result[0]; ++cnt)
+ SHA512_Update(&alt_ctx, salt, salt_len);
+
+ /* Finish the digest. */
+ SHA512_Final(temp_result, &alt_ctx);
+
+ /* Create byte sequence S. */
+ cp = s_bytes = alloca(salt_len);
+ for (cnt = salt_len; cnt >= 64; cnt -= 64) {
+ memcpy(cp, temp_result, 64);
+ cp += 64;
+ }
+ memcpy(cp, temp_result, cnt);
+
+ /* Repeatedly run the collected hash value through SHA512 to burn CPU
+ * cycles. */
+ for (cnt = 0; cnt < rounds; ++cnt) {
+ /* New context. */
+ SHA512_Init(&ctx);
+
+ /* Add key or last result. */
+ if ((cnt & 1) != 0)
+ SHA512_Update(&ctx, p_bytes, key_len);
+ else
+ SHA512_Update(&ctx, alt_result, 64);
+
+ /* Add salt for numbers not divisible by 3. */
+ if (cnt % 3 != 0)
+ SHA512_Update(&ctx, s_bytes, salt_len);
+
+ /* Add key for numbers not divisible by 7. */
+ if (cnt % 7 != 0)
+ SHA512_Update(&ctx, p_bytes, key_len);
+
+ /* Add key or last result. */
+ if ((cnt & 1) != 0)
+ SHA512_Update(&ctx, alt_result, 64);
+ else
+ SHA512_Update(&ctx, p_bytes, key_len);
+
+ /* Create intermediate result. */
+ SHA512_Final(alt_result, &ctx);
+ }
+
+ /* Now we can construct the result string. It consists of three
+ * parts. */
+ cp = stpncpy(buffer, sha512_salt_prefix, MAX(0, buflen));
+ buflen -= sizeof(sha512_salt_prefix) - 1;
+
+ if (rounds_custom) {
+ n = snprintf(cp, MAX(0, buflen), "%s%zu$",
+ sha512_rounds_prefix, rounds);
+
+ cp += n;
+ buflen -= n;
+ }
+
+ cp = stpncpy(cp, salt, MIN((size_t)MAX(0, buflen), salt_len));
+ buflen -= MIN((size_t)MAX(0, buflen), salt_len);
+
+ if (buflen > 0) {
+ *cp++ = '$';
+ --buflen;
+ }
+
+ b64_from_24bit(alt_result[0], alt_result[21], alt_result[42], 4, &buflen, &cp);
+ b64_from_24bit(alt_result[22], alt_result[43], alt_result[1], 4, &buflen, &cp);
+ b64_from_24bit(alt_result[44], alt_result[2], alt_result[23], 4, &buflen, &cp);
+ b64_from_24bit(alt_result[3], alt_result[24], alt_result[45], 4, &buflen, &cp);
+ b64_from_24bit(alt_result[25], alt_result[46], alt_result[4], 4, &buflen, &cp);
+ b64_from_24bit(alt_result[47], alt_result[5], alt_result[26], 4, &buflen, &cp);
+ b64_from_24bit(alt_result[6], alt_result[27], alt_result[48], 4, &buflen, &cp);
+ b64_from_24bit(alt_result[28], alt_result[49], alt_result[7], 4, &buflen, &cp);
+ b64_from_24bit(alt_result[50], alt_result[8], alt_result[29], 4, &buflen, &cp);
+ b64_from_24bit(alt_result[9], alt_result[30], alt_result[51], 4, &buflen, &cp);
+ b64_from_24bit(alt_result[31], alt_result[52], alt_result[10], 4, &buflen, &cp);
+ b64_from_24bit(alt_result[53], alt_result[11], alt_result[32], 4, &buflen, &cp);
+ b64_from_24bit(alt_result[12], alt_result[33], alt_result[54], 4, &buflen, &cp);
+ b64_from_24bit(alt_result[34], alt_result[55], alt_result[13], 4, &buflen, &cp);
+ b64_from_24bit(alt_result[56], alt_result[14], alt_result[35], 4, &buflen, &cp);
+ b64_from_24bit(alt_result[15], alt_result[36], alt_result[57], 4, &buflen, &cp);
+ b64_from_24bit(alt_result[37], alt_result[58], alt_result[16], 4, &buflen, &cp);
+ b64_from_24bit(alt_result[59], alt_result[17], alt_result[38], 4, &buflen, &cp);
+ b64_from_24bit(alt_result[18], alt_result[39], alt_result[60], 4, &buflen, &cp);
+ b64_from_24bit(alt_result[40], alt_result[61], alt_result[19], 4, &buflen, &cp);
+ b64_from_24bit(alt_result[62], alt_result[20], alt_result[41], 4, &buflen, &cp);
+ b64_from_24bit(0, 0, alt_result[63], 2, &buflen, &cp);
+
+ if (buflen <= 0) {
+ errno = ERANGE;
+ buffer = NULL;
+ }
+ else
+ *cp = '\0'; /* Terminate the string. */
+
+ /* Clear the buffer for the intermediate result so that people
+ * attaching to processes or reading core dumps cannot get any
+ * information. We do it in this way to clear correct_words[] inside
+ * the SHA512 implementation as well. */
+ SHA512_Init(&ctx);
+ SHA512_Final(alt_result, &ctx);
+ memset(temp_result, '\0', sizeof(temp_result));
+ memset(p_bytes, '\0', key_len);
+ memset(s_bytes, '\0', salt_len);
+ memset(&ctx, '\0', sizeof(ctx));
+ memset(&alt_ctx, '\0', sizeof(alt_ctx));
+ if (copied_key != NULL)
+ memset(copied_key, '\0', key_len);
+ if (copied_salt != NULL)
+ memset(copied_salt, '\0', salt_len);
+
+ return buffer;
+}
+
+/* This entry point is equivalent to crypt(3). */
+char *
+crypt_sha512(const char *key, const char *salt)
+{
+ /* We don't want to have an arbitrary limit in the size of the
+ * password. We can compute an upper bound for the size of the
+ * result in advance and so we can prepare the buffer we pass to
+ * `crypt_sha512_r'. */
+ static char *buffer;
+ static int buflen;
+ int needed;
+ char *new_buffer;
+
+ needed = (sizeof(sha512_salt_prefix) - 1
+ + sizeof(sha512_rounds_prefix) + 9 + 1
+ + strlen(salt) + 1 + 86 + 1);
+
+ if (buflen < needed) {
+ new_buffer = (char *)realloc(buffer, needed);
+
+ if (new_buffer == NULL)
+ return NULL;
+
+ buffer = new_buffer;
+ buflen = needed;
+ }
+
+ return crypt_sha512_r(key, salt, buffer, buflen);
+}
+/* END: https://github.com/freebsd/freebsd/blob/master/lib/libcrypt/crypt-sha512.c */
+
+
+/** From https://github.com/freebsd/freebsd/blob/master/lib/libcrypt/crypt.c */
+static const struct crypt_format {
+ const char* const name;
+ const char* const magic;
+ char* (*const func)(char const*, char const*);
+} crypt_formats[] = {
+ { "des", "_", crypt_des },
+ { "md5", "$1$", crypt_md5 },
+ { "sha256", "$5$", crypt_sha256 },
+ { "sha512", "$6$", crypt_sha512 },
+ { NULL, NULL, NULL }
+};
+
+
+char* crypt(const char* key, const char* salt)
+{
+ int len;
+ const struct crypt_format *cf;
+
+ for (cf = crypt_formats; cf->name != NULL; ++cf) {
+ if (cf->magic != NULL && strstr(salt, cf->magic) == salt) {
+ return cf->func(key, salt);
+ }
+ }
+
+ len = strlen(salt);
+ if ((len == 13 || len == 2) && strspn(salt, DES_SALT_ALPHABET) == len) {
+ return (crypt_des(key, salt));
+ }
+
+ return crypt_formats[0].func(key, salt);