diff options
Diffstat (limited to '')
| -rw-r--r-- | librecrypt_realise_salts.c | 151 |
1 files changed, 151 insertions, 0 deletions
diff --git a/librecrypt_realise_salts.c b/librecrypt_realise_salts.c new file mode 100644 index 0000000..a4204a6 --- /dev/null +++ b/librecrypt_realise_salts.c @@ -0,0 +1,151 @@ +/* See LICENSE file for copyright and license details. */ +#include "common.h" +#ifndef TEST + + +ssize_t +librecrypt_realise_salts(char *restrict out_buffer, size_t size, const char *settings, + ssize_t (*rng)(void *out, size_t n, void *user), void *user) +{ + const char *lut; + char pad; + int strict_pad, has_asterisk, nul_term = 0; + size_t i, j, n, min, ret = 0u; + size_t count, digit, q, r, left, mid, right; + + if (size) { + nul_term = 1; + size -= 1u; + } + + for (;;) { + for (; *settings == LIBRECRYPT_ALGORITHM_LINK_DELIMITER; settings++) { + if (size) { + *out_buffer++ = LIBRECRYPT_ALGORITHM_LINK_DELIMITER; + size -= 1u; + } + ret += 1u; + } + + if (!*settings) + break; + + has_asterisk = 0; + for (n = 0u; settings[n] && settings[n] != LIBRECRYPT_ALGORITHM_LINK_DELIMITER; n++) + if (settings[n] == '*') + has_asterisk = 1; + + if (!has_asterisk) { + min = size < n ? size : n; + memcpy(out_buffer, settings, min); + out_buffer += min; + settings = &settings[n]; + ret += n; + continue; + } + + if (*settings == '*') { + errno = EINVAL; + return -1; + } + + lut = librecrypt_get_encoding(settings, n, &pad, &strict_pad, 0); + if (!lut) + return -1; + pad = strict_pad ? pad : '\0'; + + for (i = 0; i < n;) { + if (settings[i] != '*') { + if (size) { + *out_buffer++ = settings[i]; + size -= 1u; + } + ret += 1u; + i++; + continue; + } + + if (++i == n) { + if (size) { + *out_buffer++ = '*'; + size -= 1u; + } + ret += 1u; + break; + } + if ('0' > settings[i] || settings[i] > '9') { + if (size) { + *out_buffer++ = '*'; + size -= 1u; + } + ret += 1u; + continue; + } + + count = 0; + for (; i < n && '0' <= settings[i] && settings[i] <= '9'; i++) { + digit = (size_t)(settings[i] - '0'); + if (count > ((size_t)SSIZE_MAX - digit) / 10u) + goto erange; + count *= 10u; + count += digit; + } + + q = count / 3u; + r = count % 3u; + mid = r ? r + 1u : 0u; + right = (!r ? 0u : pad ? 4u : r + 1u); + if (q > ((size_t)SSIZE_MAX - right) / 4u) + goto erange; + left = q * 4u; + ret += left + mid + right; + + left += mid; + if (left > size) { + left = size; + mid = 0; + } + if (librecrypt_fill_with_random_(out_buffer, left, rng, user)) + return -1; + for (j = 0; j < left; j++) + out_buffer[j] = lut[((unsigned char *)out_buffer)[j]]; + if (mid) + out_buffer[j] = lut[((unsigned char *)out_buffer)[j] & (r == 1u ? ~15u : ~3u)]; + out_buffer = &out_buffer[left]; + size -= left; + + if (right > size) + right = size; + for (j = 0; j < right; j++) + out_buffer[right] = pad; + out_buffer = &out_buffer[right]; + size -= right; + } + } + + if (nul_term) + *out_buffer = '\0'; + if (ret > (size_t)SSIZE_MAX) + goto erange; + return (ssize_t)ret; + +erange: + errno = ERANGE; + return -1; +} + + +#else + + +int +main(void) +{ + SET_UP_ALARM(); + + return 0; +} + + +#endif +/* TODO test */ |
