Buildroot Archive on lore.kernel.org
 help / color / mirror / Atom feed
* [Buildroot] [PATCH v2] package/agec: new package
@ 2026-06-19  9:20 Peter Korsgaard
  0 siblings, 0 replies; only message in thread
From: Peter Korsgaard @ 2026-06-19  9:20 UTC (permalink / raw)
  To: buildroot; +Cc: Thomas Petazzoni

Agec is a simple file encryption tool that implements the
age format in C with minimal dependencies. The tool supports
asymmetric encryption based on X25519, and a passphrase
encryption based on scrypt.

https://git.sr.ht/~min/agec
https://age-encryption.org

Encryption is silently broken for files <35 bytes, so add a patch submitted
upstream to fix that.

Signed-off-by: Peter Korsgaard <peter@korsgaard.com>
---
Changes since v1:
- Add patch submitted upstream fixing encryption of files <35 bytes
- Add runtime test

 DEVELOPERS                                    |  2 +
 package/Config.in                             |  1 +
 ...mor-do-not-set-eof-for-35-byte-files.patch | 35 +++++++++++
 package/agec/Config.in                        | 10 +++
 package/agec/agec.hash                        |  3 +
 package/agec/agec.mk                          | 24 ++++++++
 support/testing/tests/package/test_agec.py    | 61 +++++++++++++++++++
 7 files changed, 136 insertions(+)
 create mode 100644 package/agec/0001-io.c-isarmor-do-not-set-eof-for-35-byte-files.patch
 create mode 100644 package/agec/Config.in
 create mode 100644 package/agec/agec.hash
 create mode 100644 package/agec/agec.mk
 create mode 100644 support/testing/tests/package/test_agec.py

diff --git a/DEVELOPERS b/DEVELOPERS
index d591c62805..7bc4768ca7 100644
--- a/DEVELOPERS
+++ b/DEVELOPERS
@@ -2647,6 +2647,7 @@ F:	configs/orangepi_pc_defconfig
 F:	configs/orangepi_r1_defconfig
 F:	configs/sheevaplug_defconfig
 F:	configs/visionfive_defconfig
+F:	package/agec/
 F:	package/bats-core/
 F:	package/dfu-programmer/
 F:	package/docker-compose/
@@ -2681,6 +2682,7 @@ F:	package/triggerhappy/
 F:	package/ugetty/
 F:	package/wireguard-linux-compat/
 F:	package/wireguard-tools/
+F:	support/testing/tests/package/test_agec.py
 F:	support/testing/tests/package/test_docker_compose.py
 F:	support/testing/tests/package/test_python_hid.py
 
diff --git a/package/Config.in b/package/Config.in
index 96e113e226..b8374fbab5 100644
--- a/package/Config.in
+++ b/package/Config.in
@@ -2728,6 +2728,7 @@ comment "Shells"
 	source "package/nushell/Config.in"
 	source "package/zsh/Config.in"
 comment "Utilities"
+	source "package/agec/Config.in"
 	source "package/apg/Config.in"
 	source "package/at/Config.in"
 	source "package/bash-completion/Config.in"
diff --git a/package/agec/0001-io.c-isarmor-do-not-set-eof-for-35-byte-files.patch b/package/agec/0001-io.c-isarmor-do-not-set-eof-for-35-byte-files.patch
new file mode 100644
index 0000000000..fa4af2a9c0
--- /dev/null
+++ b/package/agec/0001-io.c-isarmor-do-not-set-eof-for-35-byte-files.patch
@@ -0,0 +1,35 @@
+From eb8ccfe5bb32273226d80236caab7a9386d71071 Mon Sep 17 00:00:00 2001
+From: Peter Korsgaard <peter@korsgaard.com>
+Date: Thu, 18 Jun 2026 15:12:38 +0200
+Subject: [PATCH] io.c: isarmor(): do not set eof for <35 byte files
+
+Encryption is silently broken for <35 byte files since commit b374d8de5a
+("stop reading after first EOF"), as readall() sets the eof flag when it was
+unable to read the entire 35 bytes in isarmor(), causing bread() to return
+EOF and ignore the <35 bytes already read.
+
+Fix it by only setting the eof flag in isarmor() if nothing could be read.
+
+Upstream: mailed to amin@firemail.cc
+Signed-off-by: Peter Korsgaard <peter@korsgaard.com>
+---
+ io.c | 3 +--
+ 1 file changed, 1 insertion(+), 2 deletions(-)
+
+diff --git a/io.c b/io.c
+index 15ed4f7..2773022 100644
+--- a/io.c
++++ b/io.c
+@@ -128,8 +128,7 @@ isarmor(Ibuf *b)
+ 	nr = readall(b->fd, b->buf, sizeof(armorfirst) - 1, &b->eof);
+ 	if(nr == -1)
+ 		return -1;
+-	if(nr == 0)
+-		b->eof = 1;
++	b->eof = (nr == 0);
+ 	b->size = nr;
+ 	if((usize)nr < sizeof(armorfirst) - 1)
+ 		return 0;
+-- 
+2.47.3
+
diff --git a/package/agec/Config.in b/package/agec/Config.in
new file mode 100644
index 0000000000..8ca9240917
--- /dev/null
+++ b/package/agec/Config.in
@@ -0,0 +1,10 @@
+config BR2_PACKAGE_AGEC
+	bool "agec"
+	select BR2_PACKAGE_OPENSSL
+	help
+	  Agec is a simple file encryption tool that implements the
+	  age format in C with minimal dependencies. The tool supports
+	  asymmetric encryption based on X25519, and a passphrase
+	  encryption based on scrypt.
+
+	  https://git.sr.ht/~min/agec
diff --git a/package/agec/agec.hash b/package/agec/agec.hash
new file mode 100644
index 0000000000..0b6982f913
--- /dev/null
+++ b/package/agec/agec.hash
@@ -0,0 +1,3 @@
+# Locally calculated
+sha256  97958ff82eaa6aa89328f4319d585e362130168c478cf6a85ba3f4d05e453669  0.1.0.tar.gz
+sha256  f7f37a8bb7d993825b10f5ce2838c1c452d902eda63cd180fdabc7c3a5dd0341  LICENSE
diff --git a/package/agec/agec.mk b/package/agec/agec.mk
new file mode 100644
index 0000000000..b19eac94a4
--- /dev/null
+++ b/package/agec/agec.mk
@@ -0,0 +1,24 @@
+################################################################################
+#
+# agec
+#
+################################################################################
+
+AGEC_VERSION = 0.1.0
+AGEC_SOURCE = $(AGEC_VERSION).tar.gz
+AGEC_SITE = https://git.sr.ht/~min/agec/archive
+AGEC_LICENSE = BSD-0-Clause
+AGEC_LICENSE_FILES = LICENSE
+AGEC_DEPENDENCIES = host-pkgconf openssl
+
+define AGEC_BUILD_CMDS
+	$(MAKE) -C $(@D) $(TARGET_CONFIGURE_OPTS) \
+		LIBS="`$(PKG_CONFIG_HOST_BINARY) --libs openssl`"
+endef
+
+define AGEC_INSTALL_TARGET_CMDS
+	$(MAKE) -C $(@D) $(TARGET_CONFIGURE_OPTS) \
+		PREFIX=$(TARGET_DIR)/usr install
+endef
+
+$(eval $(generic-package))
diff --git a/support/testing/tests/package/test_agec.py b/support/testing/tests/package/test_agec.py
new file mode 100644
index 0000000000..7f43e60b1f
--- /dev/null
+++ b/support/testing/tests/package/test_agec.py
@@ -0,0 +1,61 @@
+import os
+
+import infra.basetest
+
+
+class TestAgec(infra.basetest.BRTest):
+    config = infra.basetest.BASIC_TOOLCHAIN_CONFIG + """
+    BR2_PACKAGE_AGEC=y
+    BR2_TARGET_ROOTFS_CPIO=y
+    """
+
+    # generate keypair in file and return pubkey
+    def generate_keypair(self, filename):
+        self.assertRunOk(f"agec-keygen > {filename}")
+
+        output, exit_code = self.emulator.run(f"agec-keygen -y < {filename}")
+        self.assertEqual(exit_code, 0)
+        pubkey = output[0].strip()
+        self.assertNotEqual(pubkey, "")
+        return pubkey
+
+    def test_run(self):
+        cpio_file = os.path.join(self.builddir, "images", "rootfs.cpio")
+        self.emulator.boot(arch="armv5",
+                           kernel="builtin",
+                           options=["-initrd", cpio_file])
+        self.emulator.login()
+
+        # We define two keypairs
+        key1 = "/tmp/key1.txt"
+        key2 = "/tmp/key2.txt"
+
+        # And files to work on
+        orig_file = "/bin/busybox"
+        decrypted_file = "/tmp/busybox"
+        encrypted_file = decrypted_file + ".age"
+
+        # should output a valid looking keypair to stdout
+        output, exit_code = self.emulator.run("agec-keygen")
+        self.assertEqual(exit_code, 0)
+        self.assertIn("public key:", output[0])
+        self.assertIn("AGE-SECRET-KEY-", output[1])
+
+        # generate keypairs and extract pubkeys
+        pubkey1 = self.generate_keypair(key1)
+        pubkey2 = self.generate_keypair(key2)
+
+        # encrypt file
+        self.assertRunOk(f"agec -r {pubkey1} {orig_file} > {encrypted_file}")
+
+        # should be encrypted
+        self.assertRunNotOk(f"cmp {orig_file} {encrypted_file}")
+
+        # should be decryptable with key1
+        self.assertRunOk(f"agec -d -i {key1} {encrypted_file} > {decrypted_file}")
+
+        # and equal to original
+        self.assertRunOk(f"cmp {orig_file} {decrypted_file} ")
+
+        # should NOT be decryptable with key2
+        self.assertRunNotOk(f"agec -d -i {key2} {encrypted_file} > {decrypted_file}")
-- 
2.47.3

_______________________________________________
buildroot mailing list
buildroot@buildroot.org
https://lists.buildroot.org/mailman/listinfo/buildroot

^ permalink raw reply related	[flat|nested] only message in thread

only message in thread, other threads:[~2026-06-19  9:20 UTC | newest]

Thread overview: (only message) (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-06-19  9:20 [Buildroot] [PATCH v2] package/agec: new package Peter Korsgaard

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox