diff --git a/.ikc3_history b/.ikc3_history
index 4ff57e3..a1725c1 100644
--- a/.ikc3_history
+++ b/.ikc3_history
@@ -1,19 +1,3 @@
-type(0)
-type(-1)
-def operator_muul = %KC3.Operator{sym: :****, symbol_value: fn (a, b) { a * a + b * b }
-}
-3 **** 5
-3 * 3 + 5 * 5
-system(["ls", "-l"])
-tem(["ls", "-l"])
-human_size(2024024)
-to_lisp
-to_lisp(quote 1 + 1)
-to_lisp(quote 1 + 1 * 2 / 3 - 4)
-to_lisp(quote a = ?; a <- 1; a)
-Facts.database()
-a = Facts.database()
-(Facts) a
a = Facts.env_db()
(Facts) a
db = ^ a
@@ -97,3 +81,19 @@ Crypt.check_password("plop", hash)
hash = Crypt.hash_password("Plop")
Crypt.check_password("plop", hash)
Crypt.check_password("Plop", hash)
+Crypt.sha512("Plop", "$6$rounds=12345$")
+Crypt.sha512("Plop", "$6$rounds=12345$abcde")
+Crypt.sha512("Plop", "$6$rounds=12345$abcd")
+Crypt.sha512("Plop", "$6$rounds=12345$abc0123456789$")
+Crypt.sha512("Plop", "$6$rounds=1234$abc0123456789$")
+Crypt.sha512("Plop", "$6$")
+152 - 37
+Crypt.sha512("Plop", "$6$")
+Crypt.sha512("Plop", "$6$rounds=1234$abc0123456789$")
+hash = Crypt.sha512("Plop", "$6$rounds=1234$abc0123456789$")
+hash2 = Crypt.sha512("Plop", hash)
+hash == hash2
+hash = Crypt.sha512("Plop", "$6$rounds=1234$abc0123456789$")
+h2 = Crypt.sha512("Plop", hash)
+h2 = Crypt.sha512("Plop2", hash)
+Crypt.sha512_hash_password("Plop")
diff --git a/lib/kc3/0.1/crypt.kc3 b/lib/kc3/0.1/crypt.kc3
index ff41af6..786b6a9 100644
--- a/lib/kc3/0.1/crypt.kc3
+++ b/lib/kc3/0.1/crypt.kc3
@@ -5,4 +5,15 @@ defmodule Crypt do
def hash_password = cfn Str "crypt_hash_password" (Str, Result)
+ def sha512 = cfn Str "crypt_sha512" (Str, Str, Result)
+
+ def sha512_hash_password = fn (password) {
+ salt = Str.random_base64(16)
+ sha512(password, "$6$rounds=123456$#{salt}$")
+ }
+
+ def sha512_check_password = fn (password, hash) {
+ hash == sha512(password, hash)
+ }
+
end
diff --git a/libkc3/crypt.h b/libkc3/crypt.h
index 9b791d0..f630c07 100644
--- a/libkc3/crypt.h
+++ b/libkc3/crypt.h
@@ -24,5 +24,7 @@
bool * crypt_check_password (const s_str *pass, const s_str *hash,
bool *dest);
s_str * crypt_hash_password (const s_str *pass, s_str *dest);
+s_str * crypt_sha512 (const s_str *key, const s_str *setting,
+ s_str *dest);
#endif /* LIBKC3_CRYPT_H */
diff --git a/libkc3/crypt_sha512.c b/libkc3/crypt_sha512.c
index 2c0a676..f475663 100644
--- a/libkc3/crypt_sha512.c
+++ b/libkc3/crypt_sha512.c
@@ -11,6 +11,9 @@
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
+#include "assert.h"
+#include "io.h"
+#include "str.h"
#include "types.h"
/* public domain sha512 implementation based on fips180-3 */
@@ -29,33 +32,70 @@ typedef struct sha512 {
#define R0(x) (ror(x, 1) ^ ror(x, 8) ^ (x >> 7))
#define R1(x) (ror(x, 19) ^ ror(x, 61) ^ (x >> 6))
-static const u64 K[80] = {
- 0x428a2f98d728ae22ULL, 0x7137449123ef65cdULL, 0xb5c0fbcfec4d3b2fULL, 0xe9b5dba58189dbbcULL,
- 0x3956c25bf348b538ULL, 0x59f111f1b605d019ULL, 0x923f82a4af194f9bULL, 0xab1c5ed5da6d8118ULL,
- 0xd807aa98a3030242ULL, 0x12835b0145706fbeULL, 0x243185be4ee4b28cULL, 0x550c7dc3d5ffb4e2ULL,
- 0x72be5d74f27b896fULL, 0x80deb1fe3b1696b1ULL, 0x9bdc06a725c71235ULL, 0xc19bf174cf692694ULL,
- 0xe49b69c19ef14ad2ULL, 0xefbe4786384f25e3ULL, 0x0fc19dc68b8cd5b5ULL, 0x240ca1cc77ac9c65ULL,
- 0x2de92c6f592b0275ULL, 0x4a7484aa6ea6e483ULL, 0x5cb0a9dcbd41fbd4ULL, 0x76f988da831153b5ULL,
- 0x983e5152ee66dfabULL, 0xa831c66d2db43210ULL, 0xb00327c898fb213fULL, 0xbf597fc7beef0ee4ULL,
- 0xc6e00bf33da88fc2ULL, 0xd5a79147930aa725ULL, 0x06ca6351e003826fULL, 0x142929670a0e6e70ULL,
- 0x27b70a8546d22ffcULL, 0x2e1b21385c26c926ULL, 0x4d2c6dfc5ac42aedULL, 0x53380d139d95b3dfULL,
- 0x650a73548baf63deULL, 0x766a0abb3c77b2a8ULL, 0x81c2c92e47edaee6ULL, 0x92722c851482353bULL,
- 0xa2bfe8a14cf10364ULL, 0xa81a664bbc423001ULL, 0xc24b8b70d0f89791ULL, 0xc76c51a30654be30ULL,
- 0xd192e819d6ef5218ULL, 0xd69906245565a910ULL, 0xf40e35855771202aULL, 0x106aa07032bbd1b8ULL,
- 0x19a4c116b8d2d0c8ULL, 0x1e376c085141ab53ULL, 0x2748774cdf8eeb99ULL, 0x34b0bcb5e19b48a8ULL,
- 0x391c0cb3c5c95a63ULL, 0x4ed8aa4ae3418acbULL, 0x5b9cca4f7763e373ULL, 0x682e6ff3d6b2b8a3ULL,
- 0x748f82ee5defb2fcULL, 0x78a5636f43172f60ULL, 0x84c87814a1f0ab72ULL, 0x8cc702081a6439ecULL,
- 0x90befffa23631e28ULL, 0xa4506cebde82bde9ULL, 0xbef9a3f7b2c67915ULL, 0xc67178f2e372532bULL,
- 0xca273eceea26619cULL, 0xd186b8c721c0c207ULL, 0xeada7dd6cde0eb1eULL, 0xf57d4f7fee6ed178ULL,
- 0x06f067aa72176fbaULL, 0x0a637dc5a2c898a6ULL, 0x113f9804bef90daeULL, 0x1b710b35131c471bULL,
- 0x28db77f523047d84ULL, 0x32caab7b40c72493ULL, 0x3c9ebe0a15c9bebcULL, 0x431d67c49c100d4cULL,
- 0x4cc5d4becb3e42b6ULL, 0x597f299cfc657e2aULL, 0x5fcb6fab3ad6faecULL, 0x6c44198c4a475817ULL
-};
+#define KEY_MAX 256
+#define SALT_MAX 16
+#define ROUNDS_DEFAULT 12345
+#define ROUNDS_MIN 1000
+#define ROUNDS_MAX 9999999
+
+static const u8 b64[] =
+ "./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
+
+static const u64 k[80] = { 0x428a2f98d728ae22ULL, 0x7137449123ef65cdULL,
+ 0xb5c0fbcfec4d3b2fULL, 0xe9b5dba58189dbbcULL,
+ 0x3956c25bf348b538ULL, 0x59f111f1b605d019ULL,
+ 0x923f82a4af194f9bULL, 0xab1c5ed5da6d8118ULL,
+ 0xd807aa98a3030242ULL, 0x12835b0145706fbeULL,
+ 0x243185be4ee4b28cULL, 0x550c7dc3d5ffb4e2ULL,
+ 0x72be5d74f27b896fULL, 0x80deb1fe3b1696b1ULL,
+ 0x9bdc06a725c71235ULL, 0xc19bf174cf692694ULL,
+ 0xe49b69c19ef14ad2ULL, 0xefbe4786384f25e3ULL,
+ 0x0fc19dc68b8cd5b5ULL, 0x240ca1cc77ac9c65ULL,
+ 0x2de92c6f592b0275ULL, 0x4a7484aa6ea6e483ULL,
+ 0x5cb0a9dcbd41fbd4ULL, 0x76f988da831153b5ULL,
+ 0x983e5152ee66dfabULL, 0xa831c66d2db43210ULL,
+ 0xb00327c898fb213fULL, 0xbf597fc7beef0ee4ULL,
+ 0xc6e00bf33da88fc2ULL, 0xd5a79147930aa725ULL,
+ 0x06ca6351e003826fULL, 0x142929670a0e6e70ULL,
+ 0x27b70a8546d22ffcULL, 0x2e1b21385c26c926ULL,
+ 0x4d2c6dfc5ac42aedULL, 0x53380d139d95b3dfULL,
+ 0x650a73548baf63deULL, 0x766a0abb3c77b2a8ULL,
+ 0x81c2c92e47edaee6ULL, 0x92722c851482353bULL,
+ 0xa2bfe8a14cf10364ULL, 0xa81a664bbc423001ULL,
+ 0xc24b8b70d0f89791ULL, 0xc76c51a30654be30ULL,
+ 0xd192e819d6ef5218ULL, 0xd69906245565a910ULL,
+ 0xf40e35855771202aULL, 0x106aa07032bbd1b8ULL,
+ 0x19a4c116b8d2d0c8ULL, 0x1e376c085141ab53ULL,
+ 0x2748774cdf8eeb99ULL, 0x34b0bcb5e19b48a8ULL,
+ 0x391c0cb3c5c95a63ULL, 0x4ed8aa4ae3418acbULL,
+ 0x5b9cca4f7763e373ULL, 0x682e6ff3d6b2b8a3ULL,
+ 0x748f82ee5defb2fcULL, 0x78a5636f43172f60ULL,
+ 0x84c87814a1f0ab72ULL, 0x8cc702081a6439ecULL,
+ 0x90befffa23631e28ULL, 0xa4506cebde82bde9ULL,
+ 0xbef9a3f7b2c67915ULL, 0xc67178f2e372532bULL,
+ 0xca273eceea26619cULL, 0xd186b8c721c0c207ULL,
+ 0xeada7dd6cde0eb1eULL, 0xf57d4f7fee6ed178ULL,
+ 0x06f067aa72176fbaULL, 0x0a637dc5a2c898a6ULL,
+ 0x113f9804bef90daeULL, 0x1b710b35131c471bULL,
+ 0x28db77f523047d84ULL, 0x32caab7b40c72493ULL,
+ 0x3c9ebe0a15c9bebcULL, 0x431d67c49c100d4cULL,
+ 0x4cc5d4becb3e42b6ULL, 0x597f299cfc657e2aULL,
+ 0x5fcb6fab3ad6faecULL, 0x6c44198c4a475817ULL };
static u64 ror (u64 n, s32 k);
static void process_block (s_sha512 *s, const u8 *buf);
+static void sha512_update (s_sha512 *s, const void *m, u64 len);
-static void pad (struct sha512 *s)
+/* hash n bytes of the repeated md message digest */
+static void hash_md (s_sha512 *s, u32 n, const void *md)
+{
+ unsigned int i;
+ for (i = n; i > 64; i -= 64)
+ sha512_update(s, md, 64);
+ sha512_update(s, md, i);
+}
+
+static void pad (s_sha512 *s)
{
u32 r = s->len % 128;
s->buf[r++] = 0x80;
@@ -64,7 +104,7 @@ static void pad (struct sha512 *s)
r = 0;
process_block(s, s->buf);
}
- memset(s->buf + r, 0, 120 - r);
+ explicit_bzero(s->buf + r, 120 - r);
s->len *= 8;
s->buf[120] = s->len >> 56;
s->buf[121] = s->len >> 48;
@@ -79,21 +119,34 @@ static void pad (struct sha512 *s)
static void process_block (s_sha512 *s, const u8 *buf)
{
- u64 W[80], t1, t2, a, b, c, d, e, f, g, h;
+ u64 a;
+ u64 b;
+ u64 c;
+ u64 d;
+ u64 e;
+ u64 f;
+ u64 g;
+ u64 h;
s32 i;
-
- for (i = 0; i < 16; i++) {
- W[i] = (uint64_t) buf[8 * i] << 56;
- W[i] |= (uint64_t) buf[8 * i + 1] << 48;
- W[i] |= (uint64_t) buf[8 * i + 2] << 40;
- W[i] |= (uint64_t) buf[8 * i + 3] << 32;
- W[i] |= (uint64_t) buf[8 * i + 4] << 24;
- W[i] |= (uint64_t) buf[8 * i + 5] << 16;
- W[i] |= (uint64_t) buf[8 * i + 6] << 8;
- W[i] |= buf[8 * i + 7];
+ u64 t1;
+ u64 t2;
+ u64 w[80];
+ i = 0;
+ while (i < 16) {
+ w[i] = (uint64_t) buf[8 * i] << 56;
+ w[i] |= (uint64_t) buf[8 * i + 1] << 48;
+ w[i] |= (uint64_t) buf[8 * i + 2] << 40;
+ w[i] |= (uint64_t) buf[8 * i + 3] << 32;
+ w[i] |= (uint64_t) buf[8 * i + 4] << 24;
+ w[i] |= (uint64_t) buf[8 * i + 5] << 16;
+ w[i] |= (uint64_t) buf[8 * i + 6] << 8;
+ w[i] |= buf[8 * i + 7];
+ i++;
+ }
+ while (i < 80) {
+ w[i] = R1(w[i - 2]) + w[i - 7] + R0(w[i - 15]) + w[i - 16];
+ i++;
}
- for (; i < 80; i++)
- W[i] = R1(W[i - 2]) + W[i - 7] + R0(W[i - 15]) + W[i - 16];
a = s->h[0];
b = s->h[1];
c = s->h[2];
@@ -102,8 +155,9 @@ static void process_block (s_sha512 *s, const u8 *buf)
f = s->h[5];
g = s->h[6];
h = s->h[7];
- for (i = 0; i < 80; i++) {
- t1 = h + S1(e) + Ch(e, f, g) + K[i] + W[i];
+ i = 0;
+ while (i < 80) {
+ t1 = h + S1(e) + Ch(e, f, g) + k[i] + w[i];
t2 = S0(a) + Maj(a, b, c);
h = g;
g = f;
@@ -113,6 +167,7 @@ static void process_block (s_sha512 *s, const u8 *buf)
c = b;
b = a;
a = t1 + t2;
+ i++;
}
s->h[0] += a;
s->h[1] += b;
@@ -124,12 +179,12 @@ static void process_block (s_sha512 *s, const u8 *buf)
s->h[7] += h;
}
-static uint64_t ror (u64 n, s32 k)
+static u64 ror (u64 n, s32 k)
{
- return (n >> k) | (n << (64-k));
+ return (n >> k) | (n << (64 - k));
}
-static void sha512_init(struct sha512 *s)
+static void sha512_init (s_sha512 *s)
{
s->len = 0;
s->h[0] = 0x6a09e667f3bcc908ULL;
@@ -142,28 +197,30 @@ static void sha512_init(struct sha512 *s)
s->h[7] = 0x5be0cd19137e2179ULL;
}
-static void sha512_sum(struct sha512 *s, uint8_t *md)
+static void sha512_sum (s_sha512 *s, u8 *md)
{
- int i;
-
+ s32 i;
pad(s);
- for (i = 0; i < 8; i++) {
- md[8*i] = s->h[i] >> 56;
- md[8*i+1] = s->h[i] >> 48;
- md[8*i+2] = s->h[i] >> 40;
- md[8*i+3] = s->h[i] >> 32;
- md[8*i+4] = s->h[i] >> 24;
- md[8*i+5] = s->h[i] >> 16;
- md[8*i+6] = s->h[i] >> 8;
- md[8*i+7] = s->h[i];
+ i = 0;
+ while (i < 8) {
+ md[8 * i] = s->h[i] >> 56;
+ md[8 * i + 1] = s->h[i] >> 48;
+ md[8 * i + 2] = s->h[i] >> 40;
+ md[8 * i + 3] = s->h[i] >> 32;
+ md[8 * i + 4] = s->h[i] >> 24;
+ md[8 * i + 5] = s->h[i] >> 16;
+ md[8 * i + 6] = s->h[i] >> 8;
+ md[8 * i + 7] = s->h[i];
+ i++;
}
}
-static void sha512_update(struct sha512 *s, const void *m, unsigned long len)
+static void sha512_update (s_sha512 *s, const void *m, u64 len)
{
- const uint8_t *p = m;
- unsigned r = s->len % 128;
-
+ const u8 *p;
+ u32 r;
+ p = m;
+ r = s->len % 128;
s->len += len;
if (r) {
if (len < 128 - r) {
@@ -175,14 +232,14 @@ static void sha512_update(struct sha512 *s, const void *m, unsigned long len)
p += 128 - r;
process_block(s, s->buf);
}
- for (; len >= 128; len -= 128, p += 128)
+ while (len >= 128) {
process_block(s, p);
+ len -= 128;
+ p += 128;
+ }
memcpy(s->buf, p, len);
}
-static const unsigned char b64[] =
- "./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
-
static char * to64 (char *s, u32 u, s32 n)
{
while (--n >= 0) {
@@ -192,49 +249,34 @@ static char * to64 (char *s, u32 u, s32 n)
return s;
}
-/* key limit is not part of the original design, added for DoS protection.
- * rounds limit has been lowered (versus the reference/spec), also for DoS
- * protection. runtime is O(klen^2 + klen*rounds) */
-#define KEY_MAX 256
-#define SALT_MAX 16
-#define ROUNDS_DEFAULT 5000
-#define ROUNDS_MIN 1000
-#define ROUNDS_MAX 9999999
-
-/* hash n bytes of the repeated md message digest */
-static void hash_md (struct sha512 *s, unsigned int n, const void *md)
-{
- unsigned int i;
- for (i = n; i > 64; i -= 64)
- sha512_update(s, md, 64);
- sha512_update(s, md, i);
-}
-
static char * sha512_crypt(const char *key, const char *setting, char *output)
{
struct sha512 ctx;
- unsigned char md[64], kmd[64], smd[64];
- unsigned int i, r, klen, slen;
+ u8 md[64];
+ u32 i;
+ u32 r;
+ u32 klen;
+ u8 kmd[64];
+ u32 slen;
+ u8 smd[64];
char rounds[20] = "";
const char *salt;
char *p;
-
/* reject large keys */
- for (i = 0; i <= KEY_MAX && key[i]; i++);
+ i = 0;
+ while (i <= KEY_MAX && key[i])
+ i++;
if (i > KEY_MAX)
return 0;
klen = i;
-
/* setting: $6$rounds=n$salt$ (rounds=n$ and closing $ are optional) */
if (strncmp(setting, "$6$", 3) != 0)
return 0;
salt = setting + 3;
-
r = ROUNDS_DEFAULT;
if (strncmp(salt, "rounds=", sizeof("rounds=") - 1) == 0) {
unsigned long u;
char *end;
-
/*
* this is a deviation from the reference:
* bad rounds setting is rejected if it is
@@ -248,7 +290,7 @@ static char * sha512_crypt(const char *key, const char *setting, char *output)
* the host's value of ULONG_MAX.
*/
salt += sizeof "rounds=" - 1;
- if (!isdigit(*salt))
+ if (! isdigit(*salt))
return 0;
u = strtoul(salt, &end, 10);
if (*end != '$')
@@ -261,7 +303,7 @@ static char * sha512_crypt(const char *key, const char *setting, char *output)
else
r = u;
/* needed when rounds is zero prefixed or out of bounds */
- sprintf(rounds, "rounds=%u$", r);
+ snprintf(rounds, sizeof(rounds), "rounds=%u$", r);
}
for (i = 0; i < SALT_MAX && salt[i] && salt[i] != '$'; i++)
@@ -360,18 +402,35 @@ static char * sha512_crypt(const char *key, const char *setting, char *output)
return output;
}
-char *__crypt_sha512(const char *key, const char *setting, char *output)
+s_str * crypt_sha512 (const s_str *key, const s_str *setting,
+ s_str *dest)
{
static const char testkey[] = "Xy01@#\x01\x02\x80\x7f\xff\r\n\x81\t !";
static const char testsetting[] = "$6$rounds=1234$abc0123456789$";
- static const char testhash[] = "$6$rounds=1234$abc0123456789$BCpt8zLrc/RcyuXmCDOE1ALqMXB2MH6n1g891HhFj8.w7LxGv.FTkqq6Vxc/km3Y0jE0j24jY5PIv/oOu6reg1";
+ static const char testhash[] = "$6$rounds=1234$abc0123456789$BCpt8zLrc/RcyuXmCDOE1ALqMXB2MH6n1g891HhFj8.w7LxGv.FTkqq6Vxc/km3Y0jE0j24jY5PIv/oOu6reg1";
char testbuf[128];
- char *p, *q;
-
- p = sha512_crypt(key, setting, output);
- /* self test and stack cleanup */
+ char *q;
+ char outbuf[128];
+ char *p;
+ assert(key);
+ assert(setting);
+ assert(dest);
+ p = sha512_crypt(key->ptr.pchar, setting->ptr.pchar, outbuf);
q = sha512_crypt(testkey, testsetting, testbuf);
- if (!p || q != testbuf || memcmp(testbuf, testhash, sizeof testhash))
- return "*";
- return p;
+ if (p != outbuf) {
+ err_puts("crypt_sha512: sha512_crypt p");
+ assert(! "crypt_sha512: sha512_crypt p");
+ return NULL;
+ }
+ if (q != testbuf) {
+ err_puts("crypt_sha512: sha512_crypt q");
+ assert(! "crypt_sha512: sha512_crypt q");
+ return NULL;
+ }
+ if (memcmp(testbuf, testhash, sizeof(testhash))) {
+ err_puts("crypt_sha512: memcmp");
+ assert(! "crypt_sha512: memcmp");
+ return NULL;
+ }
+ return str_init_copy_1(dest, outbuf);
}
diff --git a/libkc3/kc3.c b/libkc3/kc3.c
index b02f0b0..729bcf3 100644
--- a/libkc3/kc3.c
+++ b/libkc3/kc3.c
@@ -49,6 +49,12 @@ const s_str g_kc3_bases_hexadecimal[2] = {{{NULL}, 16,
{"0123456789abcdef"}},
{{NULL}, 16,
{"0123456789ABCDEF"}}};
+const s_str g_kc3_base64 = {{NULL}, 64, {"ABCDEFGHIJKLMNOPQRSTUVWXYZ"
+ "abcdefghijklmnopqrstuvwxyz"
+ "0123456789+/"}};
+const s_str g_kc3_base64url = {{NULL}, 64, {"ABCDEFGHIJKLMNOPQRSTUVWXYZ"
+ "abcdefghijklmnopqrstuvwxyz"
+ "0123456789-_"}};
sw g_kc3_exit_code = 1;
void kc3_system_pipe_exec (s32 pipe_fd, char **argv,
diff --git a/libkc3/kc3_main.h b/libkc3/kc3_main.h
index 3effab5..1761696 100644
--- a/libkc3/kc3_main.h
+++ b/libkc3/kc3_main.h
@@ -22,6 +22,8 @@ extern const s_str g_kc3_base_octal;
extern const s_str g_kc3_base_decimal;
extern const s_str g_kc3_base_hexadecimal;
extern const s_str g_kc3_bases_hexadecimal[2];
+extern const s_str g_kc3_base64;
+extern const s_str g_kc3_base64url;
extern const char *g_kc3_license;
extern sw g_kc3_exit_code;
diff --git a/libkc3/str.c b/libkc3/str.c
index 9f71c6e..e75c21e 100644
--- a/libkc3/str.c
+++ b/libkc3/str.c
@@ -10,6 +10,7 @@
* AUTHOR BE CONSIDERED LIABLE FOR THE USE AND PERFORMANCE OF
* THIS SOFTWARE.
*/
+#include <math.h>
#include <stdarg.h>
#include <string.h>
#include "alloc.h"
@@ -30,12 +31,14 @@
#include "call.h"
#include "character.h"
#include "ident.h"
+#include "kc3_main.h"
#include "list.h"
#include "operator.h"
#include "str.h"
#include "sym.h"
#include "tag.h"
#include "tag_type.h"
+#include "uw.h"
#define DEF_STR_INIT(name, type) \
s_str * str_init_ ## name (s_str *str, type x) \
@@ -583,6 +586,74 @@ DEF_STR_INIT_PTR(list, const s_list * const *)
DEF_STR_INIT_STRUCT(map)
DEF_STR_INIT_PTR(ptr, const u_ptr_w *)
DEF_STR_INIT_PTR(ptr_free, const u_ptr_w *)
+
+s_str * str_init_random_base64 (const s_tag *len, s_str *dest)
+{
+ const s_sym *type;
+ char *random_bytes;
+ uw random_bytes_len;
+ char *result;
+ uw result_len;
+ uw i;
+ uw j;
+ uw k;
+ uw u;
+ type = &g_sym_Uw;
+ if (! uw_init_cast(&result_len, &type, len)) {
+ err_write_1("str_init_random_base64: cannot cast to Uw: ");
+ err_inspect_tag(len);
+ err_write_1("\n");
+ return NULL;
+ }
+ random_bytes_len = ceil(log2(pow(64, result_len)) / 8);
+ if (! (random_bytes = alloc(random_bytes_len)))
+ return NULL;
+ if (! (result = alloc(result_len + 1))) {
+ free(random_bytes);
+ return NULL;
+ }
+ arc4random_buf(random_bytes, random_bytes_len);
+ i = 0;
+ j = 0;
+ while (i + 3 <= random_bytes_len &&
+ j < result_len) {
+ u = ((random_bytes[i] << 16) +
+ (random_bytes[i + 1] << 8) +
+ random_bytes[i + 2]);
+ k = 0;
+ while (k < 4 &&
+ j < result_len) {
+ result[j] = g_kc3_base64url.ptr.pchar[u % 64];
+ u /= 64;
+ j++;
+ k++;
+ }
+ }
+ if (random_bytes_len - i == 2) {
+ u = ((random_bytes[i] << 8) +
+ random_bytes[i + 1]);
+ k = 0;
+ while (j < result_len) {
+ result[j] = g_kc3_base64url.ptr.pchar[u % 64];
+ u /= 64;
+ j++;
+ k++;
+ }
+ }
+ else if (random_bytes_len - i == 1) {
+ u = random_bytes[i];
+ k = 0;
+ while (j < result_len) {
+ result[j] = g_kc3_base64url.ptr.pchar[u % 64];
+ u /= 64;
+ j++;
+ k++;
+ }
+ }
+ free(random_bytes);
+ return str_init(dest, result, result_len, result);
+}
+
DEF_STR_INIT_INT(s8)
DEF_STR_INIT_INT(s16)
DEF_STR_INIT_INT(s32)
diff --git a/libkc3/str.h b/libkc3/str.h
index 6f1653f..f96d5e6 100644
--- a/libkc3/str.h
+++ b/libkc3/str.h
@@ -62,6 +62,7 @@ PROTOTYPE_STR_INIT(list, const s_list * const *);
PROTOTYPE_STR_INIT_STRUCT(map);
PROTOTYPE_STR_INIT(ptr, const u_ptr_w *);
PROTOTYPE_STR_INIT(ptr_free, const u_ptr_w *);
+s_str * str_init_random_base64 (const s_tag *len, s_str *dest);
PROTOTYPE_STR_INIT_INT(s8);
PROTOTYPE_STR_INIT_INT(s16);
PROTOTYPE_STR_INIT_INT(s32);