aboutsummaryrefslogtreecommitdiffstats
path: root/librecrypt_realise_salts.c
diff options
context:
space:
mode:
Diffstat (limited to 'librecrypt_realise_salts.c')
-rw-r--r--librecrypt_realise_salts.c151
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 */