+
+ssize_t crypt_hex_to_bytes(const char *hex, char **result, int safe_alloc)
+{
+ char buf[3] = "xx\0", *endp, *bytes;
+ size_t i, len;
+
+ len = strlen(hex);
+ if (len % 2)
+ return -EINVAL;
+ len /= 2;
+
+ bytes = safe_alloc ? crypt_safe_alloc(len) : malloc(len);
+ if (!bytes)
+ return -ENOMEM;
+
+ for (i = 0; i < len; i++) {
+ memcpy(buf, &hex[i * 2], 2);
+ bytes[i] = strtoul(buf, &endp, 16);
+ if (endp != &buf[2]) {
+ safe_alloc ? crypt_safe_free(bytes) : free(bytes);
+ return -EINVAL;
+ }
+ }
+ *result = bytes;
+ return i;
+}
+
+/*
+ * Device size string parsing, suffixes:
+ * s|S - 512 bytes sectors
+ * k |K |m |M |g |G |t |T - 1024 base
+ * kiB|KiB|miB|MiB|giB|GiB|tiB|TiB - 1024 base
+ * kb |KB |mM |MB |gB |GB |tB |TB - 1000 base
+ */
+int crypt_string_to_size(struct crypt_device *cd, const char *s, uint64_t *size)
+{
+ char *endp = NULL;
+ size_t len;
+ uint64_t mult_base, mult, tmp;
+
+ *size = strtoull(s, &endp, 10);
+ if (!isdigit(s[0]) ||
+ (errno == ERANGE && *size == ULLONG_MAX) ||
+ (errno != 0 && *size == 0))
+ return -EINVAL;
+
+ if (!endp || !*endp)
+ return 0;
+
+ len = strlen(endp);
+ /* Allow "B" and "iB" suffixes */
+ if (len > 3 ||
+ (len == 3 && (endp[1] != 'i' || endp[2] != 'B')) ||
+ (len == 2 && endp[1] != 'B'))
+ return -EINVAL;
+
+ if (len == 1 || len == 3)
+ mult_base = 1024;
+ else
+ mult_base = 1000;
+
+ mult = 1;
+ switch (endp[0]) {
+ case 's':
+ case 'S': mult = 512;
+ break;
+ case 't':
+ case 'T': mult *= mult_base;
+ /* Fall through */
+ case 'g':
+ case 'G': mult *= mult_base;
+ /* Fall through */
+ case 'm':
+ case 'M': mult *= mult_base;
+ /* Fall through */
+ case 'k':
+ case 'K': mult *= mult_base;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ tmp = *size * mult;
+ if ((tmp / *size) != mult) {
+ log_dbg("Device size overflow.");
+ return -EINVAL;
+ }
+
+ *size = tmp;
+ return 0;
+}