Compare commits

...

41 commits

Author SHA1 Message Date
Frank Denis
108ea640ba Require Zig 0.14 2025-03-11 19:06:46 +01:00
Frank Denis
c7d965e43a Update .gitignore 2025-03-11 19:04:58 +01:00
Frank Denis
428c18e08a Zig 0.14 compat 2025-03-11 19:04:40 +01:00
Frank Denis
32038530b7 Add a note about signify compatibility
Fixes #159
2025-03-11 18:43:41 +01:00
Chad Dougherty
e9631e8c67
Add a note in the man page about signify compatibility (#159)
based nearly verbatim on @jedisct1's explanation in the discussion of #59
2025-03-11 18:40:49 +01:00
Frank Denis
74365c0f51 Normalize Markdown files 2025-03-11 18:31:43 +01:00
Frank Denis
d5a2f02bc0 Look at possible include/lib paths for linuxbrew
Fixes #156
2025-01-29 23:05:34 +01:00
Frank Denis
4dd6fbf632 Use a list for possible include paths to be consistent with libraries 2025-01-29 23:02:34 +01:00
Frank Denis
41306e3e42 No need to set headerpad_max_install_names when linking statically 2025-01-29 18:28:41 +01:00
Frank Denis
090cc4752c Set headerpad_max_install_names only when linking libsodium 2025-01-29 18:27:40 +01:00
Rui Chen
b5cf334b42
build: fix mach-o relocation (#155)
Signed-off-by: Rui Chen <rui@chenrui.dev>
2025-01-29 18:27:25 +01:00
Frank Denis
c684406e21 Don't include nonexistent library paths
Introduced in 101e90a668 to make
Minisign build with Zig 0.13.

Fixes #153
2025-01-18 14:46:57 +01:00
Frank Denis
29a07eade0 Add compatibility with 32-bit targets (webassembly) 2025-01-16 13:36:56 +01:00
Frank Denis
90d46db240 Add the ability to override the libsodium install dirs 2025-01-16 12:55:52 +01:00
Frank Denis
101e90a668 Allow compilation with Zig 0.13 as well as 0.14
Fixes #150
2025-01-16 00:54:22 +01:00
Frank Denis
c165362385 Move libzodium files to a dedicated directory 2025-01-15 23:42:24 +01:00
Frank Denis
1c44ef601e Regen man page 2025-01-15 23:42:04 +01:00
Frank Denis
3c889ce7f3 Add a section title 2025-01-15 23:27:20 +01:00
Frank Denis
b85e15d45a Add build.zig.zon 2025-01-15 22:46:54 +01:00
Frank Denis
9896d072d4 Bump 2025-01-15 22:46:54 +01:00
Frank Denis
b393ff47b1 Let people compile with ReleaseFast if they want to 2025-01-15 22:46:54 +01:00
Frank Denis
c084f9ca38 without_libsodium -> without-libsodium 2025-01-15 22:46:54 +01:00
Frank Denis
c1c452560f Nits 2025-01-15 22:46:51 +01:00
Frank Denis
e0e86b4e4f Add -Dstatic 2025-01-15 22:46:51 +01:00
Frank Denis
12333fd7d1 Minisign is 10 years old 2025-01-15 22:46:51 +01:00
Frank Denis
952225f9b7 Import zodium.h 2025-01-15 22:46:51 +01:00
Frank Denis
e43b9ff13b Make libsodium optional 2025-01-15 22:11:52 +01:00
Frank Denis
e640be4b8f Indent 2025-01-15 22:07:37 +01:00
Frank Denis
a1c07cc277 Leverage root_module.linkSystemLibrary() 2025-01-15 21:03:56 +01:00
Frank Denis
285b53d52c Mention where the compiled binary is 2025-01-15 21:03:49 +01:00
Frank Denis
28612a431a Add issues.yml 2024-12-31 14:58:15 +01:00
Frank Denis
cbc79b3ece defineCMacro -> root_module.addCMacro 2024-12-20 12:21:03 +01:00
Frank Denis
55320cc84c 2024 2024-12-11 18:46:14 +01:00
Frank Denis
868785690f Add a Docker usage example
Fixes #132
2024-12-11 18:45:20 +01:00
Frank Denis
45478e1dd6 Udpate for Zig 0.13 2024-05-09 21:46:20 +02:00
Ryan Castellucci
996ea4fee3
exclude other unneeded code for VERIFY_ONLY (#139) 2024-04-02 08:11:27 +02:00
Frank Denis
573988d235 Update for zig-master 2024-01-04 12:24:31 +01:00
Isaac Yonemoto
5f96819f44
Add Elixir to minisign implementations (#138) 2023-12-18 18:50:08 +01:00
Frank Denis
ef2db96ae0 Breaking: wero-pad key identifiers
Fixes #137
2023-12-17 22:04:43 +01:00
Frank Denis
7d1116c5cc Zig 0.12 compat 2023-11-20 19:13:22 +01:00
Frank Denis
8aef018182 Update for Zig 0.11 2023-08-12 11:21:37 +02:00
19 changed files with 478 additions and 164 deletions

View file

@ -94,7 +94,7 @@ IncludeIsMainSourceRegex: ""
IndentCaseLabels: false
IndentCaseBlocks: false
IndentGotoLabels: true
IndentPPDirectives: None
IndentPPDirectives: AfterHash
IndentExternBlock: AfterExternBlock
IndentRequires: false
IndentWidth: 4

17
.github/workflows/issues.yml vendored Normal file
View file

@ -0,0 +1,17 @@
name: Close inactive issues
on:
schedule:
- cron: "30 1 * * *"
jobs:
close-issues:
runs-on: ubuntu-latest
permissions:
issues: write
pull-requests: write
steps:
- uses: actions/stale@v9
with:
stale-issue-message: "This issue is stale because it has been open for 30 days with no activity."
close-issue-message: "This issue was closed because it has been inactive for 14 days since being marked as stale."
repo-token: ${{ secrets.GITHUB_TOKEN }}

2
.gitignore vendored
View file

@ -23,5 +23,5 @@ CMakeFiles
Makefile
cmake_install.cmake
minisign
zig-cache
.zig-cache
zig-out

View file

@ -1,4 +1,4 @@
cmake_minimum_required(VERSION 2.8.12)
cmake_minimum_required(VERSION 3.10)
project(minisign C)
@ -7,7 +7,7 @@ set(CPACK_PACKAGE_VENDOR "Frank Denis")
set(CPACK_PACKAGE_DESCRIPTION_FILE "${CMAKE_CURRENT_SOURCE_DIR}/README.md")
set(CPACK_RESOURCE_FILE_LICENSE "${CMAKE_CURRENT_SOURCE_DIR}/LICENSE")
set(CPACK_PACKAGE_VERSION_MAJOR "0")
set(CPACK_PACKAGE_VERSION_MINOR "11")
set(CPACK_PACKAGE_VERSION_MINOR "12")
set(CPACK_PACKAGE_VERSION_PATCH "0")
set(
CPACK_SOURCE_PACKAGE_FILE_NAME

View file

@ -1,7 +1,7 @@
ISC LICENSE.
/*
* Copyright (c) 2015-2023
* Copyright (c) 2015-2025
* Frank Denis <j at pureftpd dot org>
*
* Permission to use, copy, modify, and/or distribute this software for any

106
README.md
View file

@ -1,7 +1,6 @@
![CodeQL scan](https://github.com/jedisct1/minisign/workflows/CodeQL%20scan/badge.svg)
Minisign
========
# Minisign
Minisign is a dead simple tool to sign files and verify signatures.
@ -13,25 +12,39 @@ public key:
RWQf6LRCGA9i53mlYecO4IzT51TGPpvWucNSCh1CBM0QTaLn73Y7GFO3
Compilation / installation
--------------------------
## Compilation / installation
## Using [Zig](https://ziglang.org):
## Building with Zig
Dependencies:
* [libsodium](https://libsodium.org/)
- [libsodium](https://libsodium.org/) (_optional_)
- [zig](https://ziglang.org)
Compilation:
Compilation with libsodium, dynamically linked (libsodium will need to be installed on the system for the command to run):
$ zig build -Drelease-safe
$ zig build -Doptimize=ReleaseSmall
## Using cmake and gcc or clang:
Compilation with libsodium, statically linked (libsodium will only be needed for compilation):
* [libsodium](https://libsodium.org/)
* cmake
* pkg-config
* gcc or clang
$ zig build -Doptimize=ReleaseSmall -Dstatic
Compilation without libsodium, no dependencies required:
$ zig build -Doptimize=ReleaseSmall -Dwithout-libsodium
The resulting binary can be found in `zig-out/bin/minisign`.
In all these examples, `ReleaseFast` can be replaced with `ReleaseSmall` to favor speed over size.
## Building with cmake and gcc or clang:
Dependencies:
- [libsodium](https://libsodium.org/) (_required_)
- cmake
- pkg-config
- gcc or clang
Compilation:
@ -49,6 +62,8 @@ or:
$ cmake -D BUILD_STATIC_EXECUTABLES=1 ..
## Pre-built packages
Minisign is also available in Homebrew:
$ brew install minisign
@ -65,6 +80,13 @@ Minisign is also available with docker:
$ docker run -i --rm jedisct1/minisign
For example, verifying a signature using the docker image can be done
with:
$ docker run -v .:/minisign -e HOME=/minisign -w /minisign \
-it --rm jedisct1/minisign \
-Vm file_to_verify -p minisign.pub
The image can be verified with the following cosign public key:
```text
@ -74,37 +96,37 @@ OQTDtJeciX9LF9hEbs1J1fzZHRdRhV4OTqcq0jTW9PXnrSSZlk1fbkE/5w==
-----END PUBLIC KEY-----
```
Additional tools, libraries and implementations
-----------------------------------------------
## Additional tools, libraries and implementations
* [minizign](https://github.com/jedisct1/zig-minisign) is a compact
implementation in Zig, that can also use ssh-encoded keys.
* [minisign-misc](https://github.com/JayBrown/minisign-misc) is a very
nice set of workflows and scripts for macOS to verify and sign files
with minisign.
* [go-minisign](https://github.com/jedisct1/go-minisign) is a small module
in Go to verify Minisign signatures.
* [rust-minisign](https://github.com/jedisct1/rust-minisign) is a Minisign
library written in pure Rust, that can be embedded in other applications.
* [rsign2](https://github.com/jedisct1/rsign2) is a reimplementation of
the command-line tool in Rust.
* [minisign (go)](https://github.com/aead/minisign) is a rewrite of Minisign
in the Go language. It reimplements the CLI but can also be used as a library.
* [minisign-verify](https://github.com/jedisct1/rust-minisign-verify) is
a small Rust crate to verify Minisign signatures.
* [minisign-net](https://github.com/bitbeans/minisign-net) is a .NET library
to handle and create Minisign signatures.
* [minisign](https://github.com/chm-diederichs/minisign) a Javascript
implementation.
* WebAssembly implementations of [rsign2](https://wapm.io/package/jedisct1/rsign2)
and [minisign-cli](https://wapm.io/package/jedisct1/minisign) are available on
WAPM.
* [minisign-php](https://github.com/soatok/minisign-php) is a PHP implementation.
* [py-minisign](https://github.com/x13a/py-minisign) is a Python
implementation.
- [minizign](https://github.com/jedisct1/zig-minisign) is a compact
implementation in Zig, that can also use ssh-encoded keys.
- [minisign-misc](https://github.com/JayBrown/minisign-misc) is a very
nice set of workflows and scripts for macOS to verify and sign files
with minisign.
- [go-minisign](https://github.com/jedisct1/go-minisign) is a small module
in Go to verify Minisign signatures.
- [rust-minisign](https://github.com/jedisct1/rust-minisign) is a Minisign
library written in pure Rust, that can be embedded in other applications.
- [rsign2](https://github.com/jedisct1/rsign2) is a reimplementation of
the command-line tool in Rust.
- [minisign (go)](https://github.com/aead/minisign) is a rewrite of Minisign
in the Go language. It reimplements the CLI but can also be used as a library.
- [minisign-verify](https://github.com/jedisct1/rust-minisign-verify) is
a small Rust crate to verify Minisign signatures.
- [minisign-net](https://github.com/bitbeans/minisign-net) is a .NET library
to handle and create Minisign signatures.
- [minisign](https://github.com/chm-diederichs/minisign) a Javascript
implementation.
- WebAssembly implementations of [rsign2](https://wapm.io/package/jedisct1/rsign2)
and [minisign-cli](https://wapm.io/package/jedisct1/minisign) are available on
WAPM.
- [minisign-php](https://github.com/soatok/minisign-php) is a PHP implementation.
- [py-minisign](https://github.com/x13a/py-minisign) is a Python
implementation.
- [minisign](https://hexdocs.pm/minisign/Minisign.html) is an Elixir implementation
(verification only)
Signature determinism
---------------------
## Signature determinism
This implementation uses deterministic signatures, unless libsodium
was compiled with the `ED25519_NONDETERMINISTIC` macro defined. This

View file

@ -1,5 +1,4 @@
#! /bin/sh
tar czpvf minisign-0.11.tar.gz $(git ls-files)
minisign -Sm minisign-0.11.tar.gz
tar czpvf minisign-0.12.tar.gz $(git ls-files)
minisign -Sm minisign-0.12.tar.gz

View file

@ -1,21 +1,80 @@
const builtin = @import("builtin");
const std = @import("std");
pub fn build(b: *std.build.Builder) !void {
var target = b.standardTargetOptions(.{});
const mode = b.standardReleaseOptions();
pub fn build(b: *std.Build) !void {
const target = b.standardTargetOptions(.{});
const optimize = b.standardOptimizeOption(.{});
const use_libzodium = b.option(bool, "without-libsodium", "Use the zig standard library instead of libsodium") orelse false;
const use_static_linking = b.option(bool, "static", "Statically link the binary") orelse false;
const minisign = b.addExecutable(.{
.name = "minisign",
.target = target,
.optimize = optimize,
.strip = true,
});
if (builtin.zig_version.major == 0 and builtin.zig_version.minor < 14) {
@compileError("Building requires Zig 0.14.0 or later");
}
// fix Mach-O relocation
minisign.headerpad_max_install_names = true;
const minisign = b.addExecutable("minisign", null);
minisign.setTarget(target);
minisign.setBuildMode(mode);
minisign.install();
minisign.linkLibC();
minisign.addLibraryPath("/opt/homebrew/lib");
minisign.addLibraryPath("/usr/local/lib");
minisign.linkSystemLibrary("sodium");
if (use_libzodium) {
var libzodium = lib: {
const libzodium_mod = b.createModule(.{
.root_source_file = b.path("src/libzodium/libzodium.zig"),
.target = target,
.optimize = optimize,
});
break :lib b.addStaticLibrary(.{
.name = "zodium",
.root_module = libzodium_mod,
.strip = true,
});
};
libzodium.linkLibC();
b.installArtifact(libzodium);
minisign.root_module.addCMacro("LIBZODIUM", "1");
minisign.linkLibrary(libzodium);
} else {
var override_pkgconfig = false;
if (std.posix.getenv("LIBSODIUM_INCLUDE_PATH")) |path| {
minisign.addSystemIncludePath(.{ .cwd_relative = path });
override_pkgconfig = true;
}
if (std.posix.getenv("LIBSODIUM_LIB_PATH")) |path| {
minisign.addLibraryPath(.{ .cwd_relative = path });
override_pkgconfig = true;
}
minisign.addIncludePath("src");
minisign.addSystemIncludePath("/opt/homebrew/include");
minisign.addSystemIncludePath("/usr/local/include");
minisign.defineCMacro("_GNU_SOURCE", "1");
minisign.addCSourceFiles(&.{ "src/base64.c", "src/get_line.c", "src/helpers.c", "src/minisign.c" }, &.{});
for ([_][]const u8{ "/opt/homebrew/include", "/home/linuxbrew/.linuxbrew/include", "/usr/local/include" }) |path| {
std.fs.accessAbsolute(path, .{}) catch continue;
minisign.addSystemIncludePath(.{ .cwd_relative = path });
}
for ([_][]const u8{ "/opt/homebrew/lib", "/home/linuxbrew/.linuxbrew/lib", "/usr/local/lib" }) |path| {
std.fs.accessAbsolute(path, .{}) catch continue;
minisign.addLibraryPath(.{ .cwd_relative = path });
}
if (!use_static_linking) {
minisign.headerpad_max_install_names = true; // required to compile using Homebrew, see https://github.com/jedisct1/minisign/pull/155
}
minisign.root_module.linkSystemLibrary(
"sodium",
.{
.use_pkg_config = if (override_pkgconfig) .no else .yes,
.preferred_link_mode = if (use_static_linking) .static else .dynamic,
},
);
}
minisign.addIncludePath(b.path("src"));
minisign.root_module.addCMacro("_GNU_SOURCE", "1");
const source_files = &.{ "src/base64.c", "src/get_line.c", "src/helpers.c", "src/minisign.c" };
minisign.addCSourceFiles(.{ .files = source_files });
b.installArtifact(minisign);
}

13
build.zig.zon Normal file
View file

@ -0,0 +1,13 @@
.{
.name = .minisign,
.version = "0.12.0",
.fingerprint = 0x280456c1fd373c55,
.paths = .{
"LICEMSE",
"README.md",
"build.zig",
"build.zig.zon",
"src",
"share",
},
}

View file

@ -1,7 +1,7 @@
.\" generated with Ronn/v0.7.3
.\" http://github.com/rtomayko/ronn/tree/0.7.3
.
.TH "MINISIGN" "1" "January 2023" "" ""
.TH "MINISIGN" "1" "March 2025" "" ""
.
.SH "NAME"
\fBminisign\fR \- A dead simple tool to sign files and verify signatures\.
@ -152,14 +152,17 @@ This requires the signature \fBmyfile\.txt\.minisig\fR to be present in the same
.P
The public key can either reside in a file (\fB\./minisign\.pub\fR by default) or be directly specified on the command line\.
.
.SH "Notes"
Signature files include an untrusted comment line that can be freely modified, even after signature creation\.
.SH "NOTES"
Signature files include an untrusted comment line that can be freely modified even after the signature is created\.
.
.P
They also include a second comment line, that cannot be modified without the secret key\.
They also include a second comment line that cannot be modified without the secret key\.
.
.P
Trusted comments can be used to add instructions or application\-specific metadata (intended file name, timestamps, resource identifiers, version numbers to prevent downgrade attacks)\.
Trusted comments can be used to add instructions or application\-specific metadata such as the intended file name, timestamps, resource identifiers, or version numbers to prevent downgrade attacks\.
.
.P
OpenBSD\'s \fBsignify(1)\fR is conceptually similar to Minisign\. Minisign creates signatures that can be verified by \fBsignify\fR; however, signatures created by \fBsignify\fR cannot be verified with Minisign because Minisign expects a trusted comment section to be present\. Trusted comments are crucial for describing what has been signed, in addition to merely confirming that a signature exists\.
.
.SH "AUTHOR"
Frank Denis (github [at] pureftpd [dot] org)

View file

@ -52,7 +52,7 @@ b64_to_bin(unsigned char *const bin, const char *b64, size_t bin_maxlen, size_t
REV64_NONE, REV64_NONE, REV64_NONE, REV64_NONE
};
const unsigned char *b64_u = (const unsigned char *) b64;
unsigned char * bin_w = bin;
unsigned char *bin_w = bin;
unsigned char mask = 0U;
unsigned char t0 = 0, t1 = 0, t2 = 0, t3 = 0;
uint32_t t = 0;

View file

@ -1,6 +1,6 @@
#if defined(__unix__) || (defined(__APPLE__) && defined(__MACH__)) || defined(__HAIKU__)
#include <sys/types.h>
# include <sys/types.h>
#endif
#include <assert.h>
@ -10,19 +10,19 @@
#include <string.h>
#if defined(__unix__) || (defined(__APPLE__) && defined(__MACH__)) || defined(__HAIKU__)
#include <fcntl.h>
#include <poll.h>
#include <termios.h>
#include <unistd.h>
# include <fcntl.h>
# include <poll.h>
# include <termios.h>
# include <unistd.h>
#elif defined(_WIN32)
#include <windows.h>
# include <windows.h>
#endif
#include "get_line.h"
#include "helpers.h"
#ifndef TCSAFLUSH
#define TCSAFLUSH 0
# define TCSAFLUSH 0
#endif
#ifndef VERIFY_ONLY
@ -33,7 +33,7 @@ disable_echo(void)
fflush(stdout);
fflush(stderr);
#if defined(__unix__) || (defined(__APPLE__) && defined(__MACH__)) || defined(__HAIKU__)
# if defined(__unix__) || (defined(__APPLE__) && defined(__MACH__)) || defined(__HAIKU__)
{
struct termios p;
@ -43,7 +43,7 @@ disable_echo(void)
p.c_lflag &= ~ECHO;
tcsetattr(0, TCSAFLUSH, &p);
}
#elif defined(_WIN32)
# elif defined(_WIN32)
{
HANDLE handle = GetStdHandle(STD_INPUT_HANDLE);
DWORD mode = 0;
@ -51,7 +51,7 @@ disable_echo(void)
GetConsoleMode(handle, &mode);
SetConsoleMode(handle, mode & ~ENABLE_ECHO_INPUT);
}
#endif
# endif
}
static void
@ -60,7 +60,7 @@ enable_echo(void)
fflush(stdout);
fflush(stderr);
#if defined(__unix__) || (defined(__APPLE__) && defined(__MACH__)) || defined(__HAIKU__)
# if defined(__unix__) || (defined(__APPLE__) && defined(__MACH__)) || defined(__HAIKU__)
{
struct termios p;
@ -70,7 +70,7 @@ enable_echo(void)
p.c_lflag |= ECHO;
tcsetattr(0, TCSAFLUSH, &p);
}
#elif defined(_WIN32)
# elif defined(_WIN32)
{
HANDLE handle = GetStdHandle(STD_INPUT_HANDLE);
DWORD mode = 0;
@ -78,7 +78,7 @@ enable_echo(void)
GetConsoleMode(handle, &mode);
SetConsoleMode(handle, mode | ENABLE_ECHO_INPUT);
}
#endif
# endif
}
int

View file

@ -1,10 +1,10 @@
#if defined(__unix__) || (defined(__APPLE__) && defined(__MACH__)) || defined(__HAIKU__)
#include <fcntl.h>
#include <sys/stat.h>
#include <sys/types.h>
# include <fcntl.h>
# include <sys/stat.h>
# include <sys/types.h>
#elif defined(_WIN32)
#include <direct.h>
# include <direct.h>
#endif
#include <errno.h>
@ -14,7 +14,11 @@
#include <stdlib.h>
#include <string.h>
#include <sodium.h>
#ifdef LIBZODIUM
# include "libzodium/sodium.h"
#else
# include <sodium.h>
#endif
#include "base64.h"
#include "helpers.h"
@ -100,7 +104,7 @@ xor_buf(unsigned char *dst, const unsigned char *src, size_t len)
int
xfprintf(FILE *fp, const char *format, ...)
{
char * out;
char *out;
size_t out_maxlen = 4096U;
int len;
va_list va;
@ -126,7 +130,7 @@ int
xfput_b64(FILE *fp, const unsigned char *bin, size_t bin_len)
{
const size_t b64_maxlen = (bin_len + 2) * 4 / 3 + 1;
char * b64;
char *b64;
b64 = xsodium_malloc(b64_maxlen);
if (bin_to_b64(b64, bin, b64_maxlen, bin_len) == NULL) {
@ -160,7 +164,7 @@ trim(char *str)
while (i-- > (size_t) 0U) {
if (str[i] == '\n') {
str[i] = 0;
t = 1;
t = 1;
} else if (str[i] == '\r') {
str[i] = 0;
}
@ -198,7 +202,7 @@ int
basedir_create_useronly(const char *file)
{
const char *basename;
char * dir;
char *dir;
int ret = -1;
dir = xstrdup(file);

View file

@ -6,12 +6,12 @@
#include <stdio.h>
#if !defined(__GNUC__) && !defined(__attribute__)
#define __attribute__(X)
# define __attribute__(X)
#endif
#ifdef _WIN32
#define DIR_SEP '\\'
# define DIR_SEP '\\'
#else
#define DIR_SEP '/'
# define DIR_SEP '/'
#endif
uint64_t le64_load(const unsigned char *p);

120
src/libzodium/libzodium.zig Normal file
View file

@ -0,0 +1,120 @@
const std = @import("std");
const crypto = std.crypto;
const mem = std.mem;
const Ed25519 = crypto.sign.Ed25519;
export fn sodium_init() callconv(.C) c_int {
return 0;
}
export fn sodium_memzero(pnt: [*c]u8, len: usize) callconv(.C) void {
crypto.utils.secureZero(u8, pnt[0..len]);
}
export fn randombytes_buf(pnt: [*c]u8, len: usize) callconv(.C) void {
crypto.random.bytes(pnt[0..len]);
}
export fn sodium_malloc(len: usize) callconv(.C) ?*anyopaque {
return std.c.malloc(len);
}
export fn sodium_free(pnt: ?*anyopaque) callconv(.C) void {
return std.c.free(pnt);
}
export fn crypto_pwhash_scryptsalsa208sha256(
out: [*c]u8,
outlen: c_ulonglong,
passwd: [*c]const u8,
passwdlen: c_ulonglong,
salt: [*c]const u8,
opslimit: c_ulonglong,
memlimit: usize,
) callconv(.C) c_int {
crypto.pwhash.scrypt.kdf(
std.heap.c_allocator,
out[0..@intCast(outlen)],
passwd[0..@intCast(passwdlen)],
salt[0..32],
crypto.pwhash.scrypt.Params.fromLimits(opslimit, memlimit),
) catch return -1;
return 0;
}
const crypto_generichash_state = crypto.hash.blake2.Blake2b512;
export fn crypto_generichash_init(
state: *crypto_generichash_state,
_: [*c]const u8,
_: usize,
outlen: usize,
) c_int {
state.* = crypto.hash.blake2.Blake2b512.init(.{ .expected_out_bits = outlen * 8 });
return 0;
}
export fn crypto_generichash_update(
state: *crypto_generichash_state,
in: [*c]const u8,
inlen: c_ulonglong,
) c_int {
state.*.update(in[0..@intCast(inlen)]);
return 0;
}
export fn crypto_generichash_final(
state: *crypto_generichash_state,
out: [*c]u8,
outlen: usize,
) c_int {
var h: [64]u8 = undefined;
state.*.final(&h);
@memcpy(out[0..outlen], h[0..outlen]);
return 0;
}
export fn crypto_sign_keypair(pk: [*c]u8, sk: [*c]u8) callconv(.C) c_int {
const kp = if (std.meta.hasFn(Ed25519.KeyPair, "generate")) Ed25519.KeyPair.generate() else (Ed25519.KeyPair.create(null) catch return -1);
pk[0..32].* = kp.public_key.toBytes();
sk[0..64].* = kp.secret_key.toBytes();
return 0;
}
export fn crypto_sign_detached(
sig_bytes: [*c]u8,
_: [*c]c_ulonglong,
m: [*c]const u8,
mlen: c_ulonglong,
sk_bytes: [*c]const u8,
) callconv(.C) c_int {
const sk = Ed25519.SecretKey.fromBytes(sk_bytes[0..64].*) catch return -1;
const kp = Ed25519.KeyPair.fromSecretKey(sk) catch return -1;
var noise: [Ed25519.noise_length]u8 = undefined;
crypto.random.bytes(&noise);
const s = kp.sign(m[0..@intCast(mlen)], noise) catch return -1;
sig_bytes[0..64].* = s.toBytes();
return 0;
}
export fn crypto_sign_verify_detached(
sig_bytes: [*c]const u8,
m: [*c]const u8,
mlen: c_ulonglong,
pk_bytes: [*c]const u8,
) callconv(.C) c_int {
const pk = Ed25519.PublicKey.fromBytes(pk_bytes[0..32].*) catch return -1;
const sig = Ed25519.Signature.fromBytes(sig_bytes[0..64].*);
sig.verify(m[0..@intCast(mlen)], pk) catch return 1;
return 0;
}
export fn sodium_bin2hex(
hex: [*c]u8,
hex_maxlen: usize,
bin: [*c]const u8,
bin_len: usize,
) callconv(.C) [*c]u8 {
_ = std.fmt.bufPrint(hex[0..hex_maxlen], "{s}", .{std.fmt.fmtSliceHexLower(bin[0..bin_len])}) catch return null;
return hex;
}

62
src/libzodium/sodium.h Normal file
View file

@ -0,0 +1,62 @@
#pragma once
#include <stddef.h>
int sodium_init(void) __attribute__((warn_unused_result));
;
void sodium_memzero(void* const pnt, const size_t len);
void randombytes_buf(void* const buf, const size_t size) __attribute__((nonnull));
void* sodium_malloc(const size_t size) __attribute__((malloc));
void sodium_free(void* ptr);
#define crypto_pwhash_scryptsalsa208sha256_SALTBYTES 32U
#define crypto_pwhash_scryptsalsa208sha256_OPSLIMIT_MIN 32768U
#define crypto_pwhash_scryptsalsa208sha256_MEMLIMIT_MIN 16777216U
#define crypto_pwhash_scryptsalsa208sha256_OPSLIMIT_SENSITIVE 33554432U
#define crypto_pwhash_scryptsalsa208sha256_MEMLIMIT_SENSITIVE 1073741824U
int crypto_pwhash_scryptsalsa208sha256(unsigned char* const out,
unsigned long long outlen,
const char* const passwd,
unsigned long long passwdlen,
const unsigned char* const salt,
unsigned long long opslimit,
size_t memlimit) __attribute__((warn_unused_result))
__attribute__((nonnull));
typedef struct crypto_generichash_state {
unsigned char opaque[512];
} crypto_generichash_state;
#define crypto_generichash_BYTES_MAX 64U
#define crypto_generichash_BYTES 32U
int crypto_generichash_init(crypto_generichash_state* state, const unsigned char* key,
const size_t keylen, const size_t outlen) __attribute__((nonnull(1)));
int crypto_generichash_update(crypto_generichash_state* state,
const unsigned char* in,
unsigned long long inlen) __attribute__((nonnull(1)));
int crypto_generichash_final(crypto_generichash_state* state, unsigned char* out,
const size_t outlen) __attribute__((nonnull));
#define crypto_sign_SECRETKEYBYTES 64
#define crypto_sign_PUBLICKEYBYTES 32
#define crypto_sign_BYTES 64
int crypto_sign_keypair(unsigned char* pk, unsigned char* sk) __attribute__((nonnull));
int crypto_sign_detached(unsigned char* sig, unsigned long long* siglen_p, const unsigned char* m,
unsigned long long mlen, const unsigned char* sk)
__attribute__((nonnull(1, 5)));
int crypto_sign_verify_detached(const unsigned char* sig,
const unsigned char* m,
unsigned long long mlen,
const unsigned char* pk) __attribute__((warn_unused_result))
__attribute__((nonnull(1, 4)));

View file

@ -1,8 +1,8 @@
<!---
This man page can be generated using ronn - https://rtomayko.github.io/ronn/
-->
minisign(1) -- A dead simple tool to sign files and verify signatures.
======================================================================
# minisign(1) -- A dead simple tool to sign files and verify signatures.
## SYNOPSIS
@ -26,47 +26,46 @@ It is portable, lightweight, and uses the highly secure [Ed25519](http://ed25519
These options control the actions of `minisign`.
* `-G`:
Generate a new key pair
* `-C`:
Change/remove the password of a secret key
* `-R`:
Recreate a public key file from a secret key file
* `-S`:
Sign files
* `-V`:
Verify that a signature is valid for a given file
* `-H`:
Requires the input to be prehashed
* `-l`:
Sign using the legacy format
* `-m <file>`:
File to sign/verify
* `-o`:
Combined with -V, output the file content after verification
* `-p <pubkey_file>`:
Public key file (default: ./minisign.pub)
* `-P <pubkey>`:
Public key, as a base64 string
* `-s <seckey_file>`:
Secret key file (default: ~/.minisign/minisign.key)
* `-W`:
Do not encrypt/decrypt the secret key with a password
* `-x <sig_file>`:
Signature file (default: &lt;file&gt;.minisig)
* `-c <comment>`:
Add a one-line untrusted comment
* `-t <comment>`:
Add a one-line trusted comment
* `-q`:
Quiet mode, suppress output
* `-Q`:
Pretty quiet mode, only print the trusted comment
* `-f`:
Force. Combined with -G, overwrite a previous key pair
* `-v`:
Display version number
- `-G`:
Generate a new key pair
- `-C`:
Change/remove the password of a secret key
- `-R`:
Recreate a public key file from a secret key file
- `-S`:
Sign files
- `-V`:
Verify that a signature is valid for a given file
- `-H`:
Requires the input to be prehashed
- `-l`:
Sign using the legacy format
- `-m <file>`:
File to sign/verify
- `-o`:
Combined with -V, output the file content after verification
- `-p <pubkey_file>`:
Public key file (default: ./minisign.pub)
- `-P <pubkey>`:
Public key, as a base64 string
- `-s <seckey_file>`:
Secret key file (default: ~/.minisign/minisign.key)
- `-W`:
Do not encrypt/decrypt the secret key with a password
- `-x <sig_file>`:
Signature file (default: &lt;file&gt;.minisig)
- `-c <comment>`:
Add a one-line untrusted comment
- `-t <comment>`:
Add a one-line trusted comment
- `-q`:
Quiet mode, suppress output
- `-Q`:
Pretty quiet mode, only print the trusted comment
- `-f`:
Force. Combined with -G, overwrite a previous key pair
- `-v`:
Display version number
## EXAMPLES
@ -79,7 +78,7 @@ The public key is printed and put into the `minisign.pub` file. The secret key i
Signing files
$ `minisign` -Sm myfile.txt
$ `minisign` -Sm myfile.txt myfile2.txt *.c
$ `minisign` -Sm myfile.txt myfile2.txt \*.c
Or to include a comment in the signature, that will be verified and displayed when verifying the file:
@ -89,7 +88,7 @@ The secret key is loaded from `${MINISIGN_CONFIG_DIR}/minisign.key`, `~/.minisig
Verifying a file
$ `minisign` -Vm myfile.txt -P &lt;pubkey&gt;
$ `minisign` -Vm myfile.txt -P &lt;pubkey&gt;
or
@ -99,13 +98,15 @@ This requires the signature `myfile.txt.minisig` to be present in the same direc
The public key can either reside in a file (`./minisign.pub` by default) or be directly specified on the command line.
## Notes
## NOTES
Signature files include an untrusted comment line that can be freely modified, even after signature creation.
Signature files include an untrusted comment line that can be freely modified even after the signature is created.
They also include a second comment line, that cannot be modified without the secret key.
They also include a second comment line that cannot be modified without the secret key.
Trusted comments can be used to add instructions or application-specific metadata (intended file name, timestamps, resource identifiers, version numbers to prevent downgrade attacks).
Trusted comments can be used to add instructions or application-specific metadata such as the intended file name, timestamps, resource identifiers, or version numbers to prevent downgrade attacks.
OpenBSD's `signify(1)` is conceptually similar to Minisign. Minisign creates signatures that can be verified by `signify`; however, signatures created by `signify` cannot be verified with Minisign because Minisign expects a trusted comment section to be present. Trusted comments are crucial for describing what has been signed, in addition to merely confirming that a signature exists.
## AUTHOR

View file

@ -10,7 +10,11 @@
#include <time.h>
#include <unistd.h>
#include <sodium.h>
#ifdef LIBZODIUM
# include "libzodium/sodium.h"
#else
# include <sodium.h>
#endif
#include "base64.h"
#include "get_line.h"
@ -289,6 +293,7 @@ pubkey_load(const char *pk_file, const char *pubkey_s)
exit_msg("A public key is required");
}
#ifndef VERIFY_ONLY
static void
seckey_compute_chk(unsigned char chk[crypto_generichash_BYTES], const SeckeyStruct *seckey_struct)
{
@ -302,7 +307,6 @@ seckey_compute_chk(unsigned char chk[crypto_generichash_BYTES], const SeckeyStru
crypto_generichash_final(&hs, chk, sizeof seckey_struct->keynum_sk.chk);
}
#ifndef VERIFY_ONLY
static void
decrypt_key(SeckeyStruct *const seckey_struct, unsigned char chk[crypto_generichash_BYTES])
{
@ -461,9 +465,9 @@ verify(PubkeyStruct *pubkey_struct, const char *message_file, const char *sig_fi
if (memcmp(sig_struct->keynum, pubkey_struct->keynum_pk.keynum, sizeof sig_struct->keynum) !=
0) {
fprintf(stderr,
"Signature key id in %s is %" PRIX64
"Signature key id in %s is %016" PRIX64
"\n"
"but the key id in the public key is %" PRIX64 "\n",
"but the key id in the public key is %016" PRIX64 "\n",
sig_file, le64_load(sig_struct->keynum),
le64_load(pubkey_struct->keynum_pk.keynum));
exit(1);
@ -662,7 +666,7 @@ write_pk_file(const char *pk_file, const PubkeyStruct *pubkey_struct)
if ((fp = fopen(pk_file, "w")) == NULL) {
exit_err(pk_file);
}
xfprintf(fp, COMMENT_PREFIX "minisign public key %" PRIX64 "\n",
xfprintf(fp, COMMENT_PREFIX "minisign public key %016" PRIX64 "\n",
le64_load(pubkey_struct->keynum_pk.keynum));
xfput_b64(fp, (const unsigned char *) (const void *) pubkey_struct, sizeof *pubkey_struct);
xfclose(fp);
@ -829,20 +833,28 @@ main(int argc, char **argv)
#ifndef VERIFY_ONLY
char *sk_file = sig_default_skfile();
#endif
const char *sig_file = NULL;
const char *message_file = NULL;
const char *comment = NULL;
const char *pubkey_s = NULL;
const char *trusted_comment = NULL;
unsigned char opt_seen[16] = { 0 };
const char *sig_file = NULL;
const char *message_file = NULL;
#ifndef VERIFY_ONLY
const char *comment = NULL;
#endif
const char *pubkey_s = NULL;
#ifndef VERIFY_ONLY
const char *trusted_comment = NULL;
#endif
unsigned char opt_seen[16] = { 0 };
int opt_flag;
int quiet = 0;
int output = 0;
int force = 0;
int allow_legacy = 1;
int sign_legacy = 0;
int unencrypted_key = 0;
Action action = ACTION_NONE;
int quiet = 0;
int output = 0;
#ifndef VERIFY_ONLY
int force = 0;
#endif
int allow_legacy = 1;
#ifndef VERIFY_ONLY
int sign_legacy = 0;
int unencrypted_key = 0;
#endif
Action action = ACTION_NONE;
while ((opt_flag = getopt(argc, argv, getopt_options)) != -1) {
switch (opt_flag) {
@ -891,9 +903,11 @@ main(int argc, char **argv)
case 'H':
allow_legacy = 0;
break;
#ifndef VERIFY_ONLY
case 'l':
sign_legacy = 1;
break;
#endif
case 'm':
message_file = optarg;
break;

View file

@ -20,7 +20,7 @@
#define SIG_DEFAULT_PKFILE "minisign.pub"
#define SIG_DEFAULT_SKFILE "minisign.key"
#define SIG_SUFFIX ".minisig"
#define VERSION_STRING "minisign 0.11"
#define VERSION_STRING "minisign 0.12"
typedef struct KeynumSK_ {
unsigned char keynum[KEYNUMBYTES];