Make-initrd development discussion
 help / color / mirror / Atom feed
* [make-initrd] q: фича для зарыбливания RNG
@ 2021-07-05 11:11 Michael Shigorin
  2021-07-05 11:45 ` Alexey Gladkov
  0 siblings, 1 reply; 4+ messages in thread
From: Michael Shigorin @ 2021-07-05 11:11 UTC (permalink / raw)
  To: make-initrd

[-- Attachment #1: Type: text/plain, Size: 1673 bytes --]

	Здравствуйте.
Коллеги, в связи с очередной невменяемостью апстрима systemd
(по совместительству udevd), в v240 выразившейся в повышении
требований к качеству псевдослучайных чисел на ранней стадии
загрузки[1,2], и возникающих вследствие этого залипаний этой
самой ранней стадии загрузки в ожидании каких-либо событий
-- бывает достаточно нажать Shift или вставить USB-флэшку --
предлагаю реализовать фичу, которая бы обеспечивала начальную
инициализацию ядерного RNG с опорой на то, что при старте
может "дребезжать" (особенно при наличии хоть какого-то RTC).

У нас тут образовался хак на скору руку, но он прямо по
rc.sysinit и заведомо неоптимален, вследствие чего далее
был предложен такой вид кусочка на шелле:

---
{
# Initialize bash random seed using current time nanoseconds
# to avoid possible kernel pool usage
RANDOM=$((10#$(date "+%N") % 32768))
seed=$( { dmesg; ls -l /var/log /proc; } | md5_bin | od -h )
for ((i=0; i<64; i++)); do
  echo $seed $RANDOM $(date "+%s%N") | md5_bin
done > /dev/random
unset i seed
} &
---

или даже такой (но это ещё 128 форков):

---
{
export \
  RANDOM=$((10#$(date "+%N") % 32768)) \
  seed=$( { dmesg; ls -l /var/log /proc; } | md5_bin | od -h )
for ((i=0; i<64; i++)); do
  ( echo $seed $RANDOM $(date "+%s%N"); ls -l /proc ) | md5_bin
done > /dev/random
unset i seed
} &
---

Прилагаю хак и md5_bin.c, прошу совета:
* стоит ли так делать;
* как лучше собирать md5_bin имени ilyakurdyukov@;
* куда лучше поместить скрипт.

[1] http://systemd.io/RANDOM_SEEDS
[2] http://github.com/systemd/systemd/blob/v240/NEWS#L200

-- 
 ---- WBR, Michael Shigorin / http://altlinux.org
  ------ http://opennet.ru / http://anna-news.info

[-- Attachment #2: 0001-Avoid-randomness-related-udev-induced-boot-stalls.patch --]
[-- Type: text/x-patch, Size: 1472 bytes --]

>From 18fbcd9bde20a2b6baf37a7f1bf732dd39bcf3ee Mon Sep 17 00:00:00 2001
From: Michael Shigorin <mike@altlinux.org>
Date: Sun, 8 Nov 2020 19:32:53 +0300
Subject: [PATCH] Avoid randomness-related udev-induced boot stalls

Those responsible for breaking udevd even further don't
answer the question: why break what used to work before
"improvements"?

There are many architectures out there, and even those
on x86 aren't really doomed to just trust Intel's hwrng.

No reason to toss haveged here as we need a "show starter"
here, not a service.

So fill the 1024 byte long kernel enthropy pool (512*2 bytes,
$RANDOM is 0..2^16-1) with good enough "seed" while getrandom()
with GRND_INSECURE flag is not widely available yet (Linux 5.6+).

Implemented-by: Andrey Savchenko <bircoph@altlinux.org>
See-also: http://systemd.io/RANDOM_SEEDS
---
 data/etc/rc.d/rc.sysinit | 11 +++++++++++
 1 file changed, 11 insertions(+)

diff --git a/data/etc/rc.d/rc.sysinit b/data/etc/rc.d/rc.sysinit
index e95a6fd..30726b8 100755
--- a/data/etc/rc.d/rc.sysinit
+++ b/data/etc/rc.d/rc.sysinit
@@ -31,3 +31,14 @@ if shell_var_is_no "$quiet"; then
 		echo "INITRAMFS: version $VERSION_ID"
 	}
 fi
+
+{
+# Initialize bash random seed using current time nanoseconds
+# to avoid possible kernel pool usage
+RANDOM=$((10#$(date "+%N") % 32768))
+for ((i=0; i<512; i++)); do
+	n=$RANDOM
+	printf "\x$(printf "%x" $((n>>8)))\x$(printf "%x" $((n%256)))"
+done > /dev/random
+unset i n
+} &
-- 
2.25.4


[-- Attachment #3: md5_bin.c --]
[-- Type: text/plain, Size: 5350 bytes --]

#include <stdint.h>
#include <stdio.h>
#include <string.h>

typedef uint32_t u32;
typedef uint64_t u64;

#define F1(x, y, z)	(z ^ (x & (y ^ z)))
#define F2(x, y, z)	F1(z, x, y)
#define F3(x, y, z)	(x ^ y ^ z)
#define F4(x, y, z)	(y ^ (x | ~z))
#define MD5STEP(f, w, x, y, z, in, s) \
	(w += f(x, y, z) + in, w = (w<<s | w>>(32-s)) + x)

static void md5_transform(u32 *hash, u32 const *in) {
	u32 a, b, c, d;
	a = hash[0]; b = hash[1];
	c = hash[2]; d = hash[3];

	MD5STEP(F1, a, b, c, d, in[0] + 0xd76aa478, 7);
	MD5STEP(F1, d, a, b, c, in[1] + 0xe8c7b756, 12);
	MD5STEP(F1, c, d, a, b, in[2] + 0x242070db, 17);
	MD5STEP(F1, b, c, d, a, in[3] + 0xc1bdceee, 22);
	MD5STEP(F1, a, b, c, d, in[4] + 0xf57c0faf, 7);
	MD5STEP(F1, d, a, b, c, in[5] + 0x4787c62a, 12);
	MD5STEP(F1, c, d, a, b, in[6] + 0xa8304613, 17);
	MD5STEP(F1, b, c, d, a, in[7] + 0xfd469501, 22);
	MD5STEP(F1, a, b, c, d, in[8] + 0x698098d8, 7);
	MD5STEP(F1, d, a, b, c, in[9] + 0x8b44f7af, 12);
	MD5STEP(F1, c, d, a, b, in[10] + 0xffff5bb1, 17);
	MD5STEP(F1, b, c, d, a, in[11] + 0x895cd7be, 22);
	MD5STEP(F1, a, b, c, d, in[12] + 0x6b901122, 7);
	MD5STEP(F1, d, a, b, c, in[13] + 0xfd987193, 12);
	MD5STEP(F1, c, d, a, b, in[14] + 0xa679438e, 17);
	MD5STEP(F1, b, c, d, a, in[15] + 0x49b40821, 22);

	MD5STEP(F2, a, b, c, d, in[1] + 0xf61e2562, 5);
	MD5STEP(F2, d, a, b, c, in[6] + 0xc040b340, 9);
	MD5STEP(F2, c, d, a, b, in[11] + 0x265e5a51, 14);
	MD5STEP(F2, b, c, d, a, in[0] + 0xe9b6c7aa, 20);
	MD5STEP(F2, a, b, c, d, in[5] + 0xd62f105d, 5);
	MD5STEP(F2, d, a, b, c, in[10] + 0x02441453, 9);
	MD5STEP(F2, c, d, a, b, in[15] + 0xd8a1e681, 14);
	MD5STEP(F2, b, c, d, a, in[4] + 0xe7d3fbc8, 20);
	MD5STEP(F2, a, b, c, d, in[9] + 0x21e1cde6, 5);
	MD5STEP(F2, d, a, b, c, in[14] + 0xc33707d6, 9);
	MD5STEP(F2, c, d, a, b, in[3] + 0xf4d50d87, 14);
	MD5STEP(F2, b, c, d, a, in[8] + 0x455a14ed, 20);
	MD5STEP(F2, a, b, c, d, in[13] + 0xa9e3e905, 5);
	MD5STEP(F2, d, a, b, c, in[2] + 0xfcefa3f8, 9);
	MD5STEP(F2, c, d, a, b, in[7] + 0x676f02d9, 14);
	MD5STEP(F2, b, c, d, a, in[12] + 0x8d2a4c8a, 20);

	MD5STEP(F3, a, b, c, d, in[5] + 0xfffa3942, 4);
	MD5STEP(F3, d, a, b, c, in[8] + 0x8771f681, 11);
	MD5STEP(F3, c, d, a, b, in[11] + 0x6d9d6122, 16);
	MD5STEP(F3, b, c, d, a, in[14] + 0xfde5380c, 23);
	MD5STEP(F3, a, b, c, d, in[1] + 0xa4beea44, 4);
	MD5STEP(F3, d, a, b, c, in[4] + 0x4bdecfa9, 11);
	MD5STEP(F3, c, d, a, b, in[7] + 0xf6bb4b60, 16);
	MD5STEP(F3, b, c, d, a, in[10] + 0xbebfbc70, 23);
	MD5STEP(F3, a, b, c, d, in[13] + 0x289b7ec6, 4);
	MD5STEP(F3, d, a, b, c, in[0] + 0xeaa127fa, 11);
	MD5STEP(F3, c, d, a, b, in[3] + 0xd4ef3085, 16);
	MD5STEP(F3, b, c, d, a, in[6] + 0x04881d05, 23);
	MD5STEP(F3, a, b, c, d, in[9] + 0xd9d4d039, 4);
	MD5STEP(F3, d, a, b, c, in[12] + 0xe6db99e5, 11);
	MD5STEP(F3, c, d, a, b, in[15] + 0x1fa27cf8, 16);
	MD5STEP(F3, b, c, d, a, in[2] + 0xc4ac5665, 23);

	MD5STEP(F4, a, b, c, d, in[0] + 0xf4292244, 6);
	MD5STEP(F4, d, a, b, c, in[7] + 0x432aff97, 10);
	MD5STEP(F4, c, d, a, b, in[14] + 0xab9423a7, 15);
	MD5STEP(F4, b, c, d, a, in[5] + 0xfc93a039, 21);
	MD5STEP(F4, a, b, c, d, in[12] + 0x655b59c3, 6);
	MD5STEP(F4, d, a, b, c, in[3] + 0x8f0ccc92, 10);
	MD5STEP(F4, c, d, a, b, in[10] + 0xffeff47d, 15);
	MD5STEP(F4, b, c, d, a, in[1] + 0x85845dd1, 21);
	MD5STEP(F4, a, b, c, d, in[8] + 0x6fa87e4f, 6);
	MD5STEP(F4, d, a, b, c, in[15] + 0xfe2ce6e0, 10);
	MD5STEP(F4, c, d, a, b, in[6] + 0xa3014314, 15);
	MD5STEP(F4, b, c, d, a, in[13] + 0x4e0811a1, 21);
	MD5STEP(F4, a, b, c, d, in[4] + 0xf7537e82, 6);
	MD5STEP(F4, d, a, b, c, in[11] + 0xbd3af235, 10);
	MD5STEP(F4, c, d, a, b, in[2] + 0x2ad7d2bb, 15);
	MD5STEP(F4, b, c, d, a, in[9] + 0xeb86d391, 21);

	hash[0] += a; hash[1] += b;
	hash[2] += c; hash[3] += d;
}

#undef MD5STEP
#undef F4
#undef F3
#undef F2
#undef F1

struct md5_ctx {
	u32 hash[4], block[16];
	u64 byte_count;
};

static void md5_init(struct md5_ctx *ctx) {
	ctx->hash[0] = 0x67452301;
	ctx->hash[1] = 0xefcdab89;
	ctx->hash[2] = 0x98badcfe;
	ctx->hash[3] = 0x10325476;
	ctx->byte_count = 0;
}

static void md5_update(struct md5_ctx *ctx, const char *data, unsigned int len) {
	const u32 avail = 64 - (ctx->byte_count & 0x3f);

	ctx->byte_count += len;
	if (avail > len) {
		memcpy((char*)ctx->block + (64 - avail), data, len);
		return;
	}
	memcpy((char*)ctx->block + (64 - avail), data, avail);
	md5_transform(ctx->hash, ctx->block);
	data += avail; len -= avail;
	while (len >= 64) {
		memcpy(ctx->block, data, 64);
		md5_transform(ctx->hash, ctx->block);
		data += 64; len -= 64;
	}
	memcpy(ctx->block, data, len);
}

static void md5_final(struct md5_ctx *ctx, unsigned char *out) {
	const unsigned int offset = ctx->byte_count & 0x3f;
	char *p = (char*)ctx->block + offset;
	int padding = 56 - (offset + 1);

	*p++ = 0x80;
	if (padding < 0) {
		memset(p, 0, padding + 8);
		md5_transform(ctx->hash, ctx->block);
		p = (char*)ctx->block;
		padding = 56;
	}

	memset(p, 0, padding);
	ctx->block[14] = ctx->byte_count << 3;
	ctx->block[15] = ctx->byte_count >> 29;
	md5_transform(ctx->hash, ctx->block);
	memcpy(out, ctx->hash, 16);
	memset(ctx, 0, sizeof(struct md5_ctx));
}

int main() {
	int a; struct md5_ctx md5; unsigned char hash[16];
	md5_init(&md5);
	while ((a = getchar()) != EOF) { char c = a; md5_update(&md5, &c, 1); }
	md5_final(&md5, hash);
	return fwrite(hash, sizeof(hash), 1, stdout) != 1;
}


^ permalink raw reply	[flat|nested] 4+ messages in thread

end of thread, other threads:[~2021-07-05 16:21 UTC | newest]

Thread overview: 4+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2021-07-05 11:11 [make-initrd] q: фича для зарыбливания RNG Michael Shigorin
2021-07-05 11:45 ` Alexey Gladkov
2021-07-05 15:49   ` Michael Shigorin
2021-07-05 16:21     ` Alexey Gladkov

Make-initrd development discussion

This inbox may be cloned and mirrored by anyone:

	git clone --mirror http://lore.altlinux.org/make-initrd/0 make-initrd/git/0.git

	# If you have public-inbox 1.1+ installed, you may
	# initialize and index your mirror using the following commands:
	public-inbox-init -V2 make-initrd make-initrd/ http://lore.altlinux.org/make-initrd \
		make-initrd@lists.altlinux.org make-initrd@lists.altlinux.ru make-initrd@lists.altlinux.com
	public-inbox-index make-initrd

Example config snippet for mirrors.
Newsgroup available over NNTP:
	nntp://lore.altlinux.org/org.altlinux.lists.make-initrd


AGPL code for this site: git clone https://public-inbox.org/public-inbox.git