sigchk

sign and check files using ed25519
git clone git://z3bra.org/sick
Log | Files | Refs | Submodules | README | LICENSE

commit 2cc37382d30d01ed7473ac6441f9adddf589bc4f
parent f94d4e87ddf859286ec5bffb6ff9b1d4fadc4e8b
Author: z3bra <willyatmailoodotorg>
Date:   Fri May  6 15:21:02 2016

Rename sick to sigchk

Diffstat:
 README   |  14 +-
 mkfile   |  16 +--
 sick.c   | 400 +----------------------------------------------------------------
 sigchk.c | 400 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-
 4 files changed, 415 insertions(+), 415 deletions(-)

diff --git a/README b/README @@ -1,14 +1,14 @@ -# sick +# sigchk Sign and check files using ed25519. -sick(1) will let your generate private/public key pairs, sign files using your +sigchk(1) will let your generate private/public key pairs, sign files using your private key, and check a file signature using public keys stored in a keyring. ## Generating keys To generate a key pair, run - $ sick -g alice + $ sigchk -g alice It will create the files `alice.key`, which is the private key, and `alice.pub`, the public key. @@ -18,17 +18,17 @@ If you don't provide any name "ed25519" will be used as a default name. To sign a file, you need to provide the path to your private key: - $ sick -s -f ~/.keys/priv/alice.key /tmp/archive.tar.bz2 + $ sigchk -s -f ~/.keys/priv/alice.key /tmp/archive.tar.bz2 This will create a 64 bytes signature and append it after the file. If you try to sign it again, you will get the following error: - $ sick -s -f ~/.keys/priv/alice.key /tmp/archive.tar.bz2 + $ sigchk -s -f ~/.keys/priv/alice.key /tmp/archive.tar.bz2 /tmp/archive.tar.bz2: Already signed ## Checking signatures -sick(1) uses a keyring to check signatures. The keyring is simply a directory +sigchk(1) uses a keyring to check signatures. The keyring is simply a directory containing the public keys you trust: $ find ~/.keys/trusted -type f @@ -38,7 +38,7 @@ containing the public keys you trust: Once your public key is in your keyring, you can start checking files with: - $ sick /tmp/archive.tar.bz2 + $ sigchk /tmp/archive.tar.bz2 /tmp/archive.tar.bz2 If the signature check is successful, the path to the file is printed to diff --git a/mkfile b/mkfile @@ -2,22 +2,22 @@ ED25519_SRC = `{find ed25519/src -name '*.c'} -SRC = sick.c ${ED25519_SRC} +SRC = sigchk.c ${ED25519_SRC} OBJ = ${SRC:%.c=%.o} -sick: $OBJ - ${CC} $OBJ ${LDFLAGS} ${LIBS} -o sick +sigchk: $OBJ + ${CC} $OBJ ${LDFLAGS} ${LIBS} -o sigchk %.o: %.c ${CC} ${CFLAGS} -c $stem.c -o $stem.o clean:V: - rm -f $OBJ sick + rm -f $OBJ sigchk -install:V: sick +install:V: sigchk mkdir -p ${DESTDIR}${PREFIX}/bin - cp sick ${DESTDIR}${PREFIX}/bin/sick - chmod 755 ${DESTDIR}${PREFIX}/bin/sick + cp sigchk ${DESTDIR}${PREFIX}/bin/sigchk + chmod 755 ${DESTDIR}${PREFIX}/bin/sigchk uninstall:V: - rm ${DESTDIR}${PREFIX}/bin/sick + rm ${DESTDIR}${PREFIX}/bin/sigchk diff --git a/sick.c b/sick.c @@ -1,400 +0,0 @@ -#include <dirent.h> -#include <limits.h> -#include <fcntl.h> -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <sys/stat.h> -#include <sys/types.h> -#include <unistd.h> - -#include "arg.h" -#include "ed25519.h" - -#define PUBSIZ 32 -#define PRIVSIZ ((PUBSIZ) * 2) -#define SIGSIZ 64 - -#define MAGIC "0xdeadca7" -#define DEFAULT_ALIAS "ed25519" -#define KEYRING (getenv("KEYRING")?getenv("KEYRING"):"./keyring") - -enum { - ACTION_INVALID = -1, - ACTION_NONE = 0, - ACTION_GENKEY, - ACTION_SIGN, - ACTION_CHECK, - ACTION_UNSIGN, - ACTION_DEFAULT = ACTION_CHECK -}; - -void usage(); -char *base_name(char *path); -int is_signed(const char *file); -unsigned char *read_sig(const char *file); -int unsign(const char *file); -int keygen(const char *alias); -int sign(const char *file, const char *key); -int verify(const char *file, const char *key); -int check(const char *file, char *keyring); - -char *argv0; -int verbose = 0; - -void -usage() -{ - fprintf(stderr, "usage: %s [-f key] [-cgsuv] [file]\n", argv0); - exit(1); -} - -char * -base_name(char *path) -{ - char *b = strrchr(path, '/'); - return b ? b + 1 : path; -} - -int -is_signed(const char *file) -{ - int fd = 0, is_magic = -1; - struct stat sb; - char *magic = NULL; - - if (stat(file, &sb) < 0) { - perror(file); - return -1; - } - - magic = malloc(strlen(MAGIC)); - if (magic == NULL) - return -1; - - fd = open(file, O_RDONLY); - lseek(fd, sb.st_size - 64 - strlen(MAGIC), SEEK_SET); - if (read(fd, magic, strlen(MAGIC)) < (unsigned int)strlen(MAGIC)) { - perror(file); - close(fd); - return -1; - } - close(fd); - - is_magic = strcmp(magic, MAGIC); - - if (verbose) - printf("%s: %s\n", file, is_magic ? "not signed" : "signed"); - - free(magic); - return is_magic; -} - -unsigned char * -read_sig(const char *file) -{ - int fd = 0; - struct stat sb; - static unsigned char sig[64]; - - if (stat(file, &sb) < 0) { - perror(file); - return NULL; - } - - fd = open(file, O_RDONLY); - lseek(fd, sb.st_size - 64, SEEK_SET); - if (read(fd, sig, 64) < 64) { - perror(file); - close(fd); - return NULL; - } - close(fd); - - return sig; -} - - -/* - * Fucking yankees took the revoke() name... - * Truncate a file to remove the signature. Will only perform if the magic - * string is found - */ -int -unsign(const char *file) -{ - size_t len = 0; - struct stat sb; - - if (is_signed(file) != 0) { - return -1; - } - - if (stat(file, &sb) < 0) { - perror(file); - return -1; - } - - len = sb.st_size - 64 - strlen(MAGIC); - - if (truncate(file, len) < 0) { - perror(file); - return -1; - } - return 0; -} - -int -keygen(const char *alias) -{ - int fd = 0; - size_t len = 0; - char file[PATH_MAX]; - unsigned char pub[PUBSIZ], priv[PRIVSIZ], seed[PUBSIZ]; - - len = strnlen(alias, PATH_MAX); - - ed25519_create_seed(seed); - ed25519_create_keypair(pub, priv, seed); - - memset(file, 0, PATH_MAX); - memcpy(file, alias, len); - - /* write pubkey to a file name <alias>.pub */ - memcpy(file+len, ".pub", 4); - if (verbose) - printf("Creating public key: %s\n", file); - fd = open(file, O_CREAT|O_WRONLY|O_TRUNC, 0644); - if (fd < 0) { - perror(file); - return fd; - } - if (write(fd, pub, PUBSIZ) < PUBSIZ) { - perror(file); - return -1; - } - close(fd); - - /* write privkey to a file name <alias>.key */ - memcpy(file+len, ".key", 4); - if (verbose) - printf("Creating private key: %s\n", file); - fd = open(file, O_CREAT|O_WRONLY|O_TRUNC, 0600); - if (fd < 0) { - perror(file); - return fd; - } - if (write(fd, priv, PRIVSIZ) < PRIVSIZ) { - perror(file); - return -1; - } - close(fd); - - return 0; -} - -int -sign(const char *file, const char *key) -{ - int fd = 0; - size_t len = 0; - char *tmp, *base = NULL; - unsigned char sig[64], priv[PRIVSIZ], *msg = NULL; - - /* set the file basename as the message for signing */ - tmp = strdup(file); - base = base_name(tmp); - len = strnlen(base, PATH_MAX); - msg = malloc(len + 1); - if (msg == NULL) { - perror("malloc"); - return -1; - } - memset(msg, 0, len + 1); - memcpy(msg, base, len); - free(tmp); - - /* read private key content into the priv[] buffer */ - fd = open(key, O_RDONLY); - if (fd < 0) { - perror(key); - free(msg); - return fd; - } - if (read(fd, priv, PRIVSIZ) < PRIVSIZ) { - perror(key); - free(msg); - return -1; - } - close(fd); - - ed25519_sign(sig, msg, len + 1, priv); - - /* write signature at the end of the file */ - if (verbose) - printf("Appending signature to %s\n", file); - fd = open(file, O_WRONLY|O_APPEND); - if (fd < 0) { - perror(file); - free(msg); - return fd; - } - if (write(fd, MAGIC, strlen(MAGIC)) < (unsigned int)strlen(MAGIC)) { - perror(file); - free(msg); - return -1; - } - if (write(fd, sig, 64) < 64) { - perror(file); - free(msg); - return -1; - } - close(fd); - - free(msg); - return 0; -} - -int -verify(const char *file, const char *key) -{ - int fd = 0, check = 0; - size_t len = 0; - char *base = NULL, *tmp; - unsigned char sig[64], pub[PRIVSIZ], *msg = NULL; - - memcpy(sig, read_sig(file), 64); - - /* read the content of the public key into the pub[] buffer */ - fd = open(key, O_RDONLY); - if (fd < 0) { - perror(key); - return fd; - } - if (read(fd, pub, PUBSIZ) < PUBSIZ) { - perror(key); - return -1; - } - close(fd); - - /* the message is the sigfile's base name */ - tmp = strdup(file); - base = base_name(tmp); - len = strnlen(base, PATH_MAX); - msg = malloc(len + 1); - memset(msg, 0, len + 1); - memcpy(msg, base, len); - free(tmp); - - check = ed25519_verify(sig, msg, len + 1, pub) ? 0 : -1; - - if (verbose) - printf("%s: %s\n", key, check == 0 ? "VERIFIED" : "FAILED"); - - free (msg); - return check; -} - -int -check(const char *file, char *keyring) -{ - size_t len = 0; - DIR *dirp = NULL; - struct dirent *dt = NULL; - char path[PATH_MAX]; - - if (is_signed(file) != 0) - { - return -1; - } - - dirp = opendir(keyring); - if (dirp == NULL) { - perror(keyring); - return -1; - } - - if (verbose) - printf(": %s\n", keyring); - - while ((dt = readdir(dirp)) != NULL) { - if (dt->d_type == DT_REG) { - len = strnlen(keyring, PATH_MAX); - memset(path, 0, PATH_MAX); - memcpy(path, keyring, len); - path[len] = '/'; - memcpy(path+len+1, dt->d_name, dt->d_reclen); - if (verify(file, path) == 0) { - closedir(dirp); - return 0; - } - } - } - - closedir(dirp); - return -1; -} - -int -main(int argc, char **argv) -{ - int action = ACTION_DEFAULT; - const char *key = NULL; - char keyring[PATH_MAX]; - - memset(keyring, 0, PATH_MAX); - memcpy(keyring, KEYRING, strnlen(KEYRING, PATH_MAX)); - - ARGBEGIN{ - case 'c': - action = ACTION_CHECK; - break; - case 'f': - key = EARGF(usage(argv0)); - break; - case 'g': - key = argc > 1 ? ARGF() : NULL; - action = ACTION_GENKEY; - break; - case 's': - action = ACTION_SIGN; - break; - case 'u': - action = ACTION_UNSIGN; - break; - case 'v': - verbose = 1; - break; - default: - usage(); - }ARGEND; - - switch(action) { - case ACTION_CHECK: - if (check(*argv, keyring) == 0) { - if (!verbose) - puts(*argv); - } else { - return 1; - } - break; - case ACTION_GENKEY: - keygen(key ? key : DEFAULT_ALIAS); - break; - case ACTION_UNSIGN: - unsign(*argv); - break; - case ACTION_SIGN: - if (is_signed(*argv) != 0) { - sign(*argv, key ? key : DEFAULT_ALIAS ".key"); - } else { - fprintf(stderr, "%s: Already signed\n", *argv); - return -1; - } - break; - default: - usage(); - } - - return 0; -} diff --git a/sigchk.c b/sigchk.c @@ -0,0 +1,400 @@ +#include <dirent.h> +#include <limits.h> +#include <fcntl.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <sys/stat.h> +#include <sys/types.h> +#include <unistd.h> + +#include "arg.h" +#include "ed25519.h" + +#define PUBSIZ 32 +#define PRIVSIZ ((PUBSIZ) * 2) +#define SIGSIZ 64 + +#define MAGIC "0xdeadca7" +#define DEFAULT_ALIAS "ed25519" +#define KEYRING (getenv("KEYRING")?getenv("KEYRING"):"./keyring") + +enum { + ACTION_INVALID = -1, + ACTION_NONE = 0, + ACTION_GENKEY, + ACTION_SIGN, + ACTION_CHECK, + ACTION_UNSIGN, + ACTION_DEFAULT = ACTION_CHECK +}; + +void usage(); +char *base_name(char *path); +int is_signed(const char *file); +unsigned char *read_sig(const char *file); +int unsign(const char *file); +int keygen(const char *alias); +int sign(const char *file, const char *key); +int verify(const char *file, const char *key); +int check(const char *file, char *keyring); + +char *argv0; +int verbose = 0; + +void +usage() +{ + fprintf(stderr, "usage: %s [-f key] [-cgsuv] [file]\n", argv0); + exit(1); +} + +char * +base_name(char *path) +{ + char *b = strrchr(path, '/'); + return b ? b + 1 : path; +} + +int +is_signed(const char *file) +{ + int fd = 0, is_magic = -1; + struct stat sb; + char *magic = NULL; + + if (stat(file, &sb) < 0) { + perror(file); + return -1; + } + + magic = malloc(strlen(MAGIC)); + if (magic == NULL) + return -1; + + fd = open(file, O_RDONLY); + lseek(fd, sb.st_size - 64 - strlen(MAGIC), SEEK_SET); + if (read(fd, magic, strlen(MAGIC)) < (unsigned int)strlen(MAGIC)) { + perror(file); + close(fd); + return -1; + } + close(fd); + + is_magic = strcmp(magic, MAGIC); + + if (verbose) + printf("%s: %s\n", file, is_magic ? "not signed" : "signed"); + + free(magic); + return is_magic; +} + +unsigned char * +read_sig(const char *file) +{ + int fd = 0; + struct stat sb; + static unsigned char sig[64]; + + if (stat(file, &sb) < 0) { + perror(file); + return NULL; + } + + fd = open(file, O_RDONLY); + lseek(fd, sb.st_size - 64, SEEK_SET); + if (read(fd, sig, 64) < 64) { + perror(file); + close(fd); + return NULL; + } + close(fd); + + return sig; +} + + +/* + * Fucking yankees took the revoke() name... + * Truncate a file to remove the signature. Will only perform if the magic + * string is found + */ +int +unsign(const char *file) +{ + size_t len = 0; + struct stat sb; + + if (is_signed(file) != 0) { + return -1; + } + + if (stat(file, &sb) < 0) { + perror(file); + return -1; + } + + len = sb.st_size - 64 - strlen(MAGIC); + + if (truncate(file, len) < 0) { + perror(file); + return -1; + } + return 0; +} + +int +keygen(const char *alias) +{ + int fd = 0; + size_t len = 0; + char file[PATH_MAX]; + unsigned char pub[PUBSIZ], priv[PRIVSIZ], seed[PUBSIZ]; + + len = strnlen(alias, PATH_MAX); + + ed25519_create_seed(seed); + ed25519_create_keypair(pub, priv, seed); + + memset(file, 0, PATH_MAX); + memcpy(file, alias, len); + + /* write pubkey to a file name <alias>.pub */ + memcpy(file+len, ".pub", 4); + if (verbose) + printf("Creating public key: %s\n", file); + fd = open(file, O_CREAT|O_WRONLY|O_TRUNC, 0644); + if (fd < 0) { + perror(file); + return fd; + } + if (write(fd, pub, PUBSIZ) < PUBSIZ) { + perror(file); + return -1; + } + close(fd); + + /* write privkey to a file name <alias>.key */ + memcpy(file+len, ".key", 4); + if (verbose) + printf("Creating private key: %s\n", file); + fd = open(file, O_CREAT|O_WRONLY|O_TRUNC, 0600); + if (fd < 0) { + perror(file); + return fd; + } + if (write(fd, priv, PRIVSIZ) < PRIVSIZ) { + perror(file); + return -1; + } + close(fd); + + return 0; +} + +int +sign(const char *file, const char *key) +{ + int fd = 0; + size_t len = 0; + char *tmp, *base = NULL; + unsigned char sig[64], priv[PRIVSIZ], *msg = NULL; + + /* set the file basename as the message for signing */ + tmp = strdup(file); + base = base_name(tmp); + len = strnlen(base, PATH_MAX); + msg = malloc(len + 1); + if (msg == NULL) { + perror("malloc"); + return -1; + } + memset(msg, 0, len + 1); + memcpy(msg, base, len); + free(tmp); + + /* read private key content into the priv[] buffer */ + fd = open(key, O_RDONLY); + if (fd < 0) { + perror(key); + free(msg); + return fd; + } + if (read(fd, priv, PRIVSIZ) < PRIVSIZ) { + perror(key); + free(msg); + return -1; + } + close(fd); + + ed25519_sign(sig, msg, len + 1, priv); + + /* write signature at the end of the file */ + if (verbose) + printf("Appending signature to %s\n", file); + fd = open(file, O_WRONLY|O_APPEND); + if (fd < 0) { + perror(file); + free(msg); + return fd; + } + if (write(fd, MAGIC, strlen(MAGIC)) < (unsigned int)strlen(MAGIC)) { + perror(file); + free(msg); + return -1; + } + if (write(fd, sig, 64) < 64) { + perror(file); + free(msg); + return -1; + } + close(fd); + + free(msg); + return 0; +} + +int +verify(const char *file, const char *key) +{ + int fd = 0, check = 0; + size_t len = 0; + char *base = NULL, *tmp; + unsigned char sig[64], pub[PRIVSIZ], *msg = NULL; + + memcpy(sig, read_sig(file), 64); + + /* read the content of the public key into the pub[] buffer */ + fd = open(key, O_RDONLY); + if (fd < 0) { + perror(key); + return fd; + } + if (read(fd, pub, PUBSIZ) < PUBSIZ) { + perror(key); + return -1; + } + close(fd); + + /* the message is the sigfile's base name */ + tmp = strdup(file); + base = base_name(tmp); + len = strnlen(base, PATH_MAX); + msg = malloc(len + 1); + memset(msg, 0, len + 1); + memcpy(msg, base, len); + free(tmp); + + check = ed25519_verify(sig, msg, len + 1, pub) ? 0 : -1; + + if (verbose) + printf("%s: %s\n", key, check == 0 ? "VERIFIED" : "FAILED"); + + free (msg); + return check; +} + +int +check(const char *file, char *keyring) +{ + size_t len = 0; + DIR *dirp = NULL; + struct dirent *dt = NULL; + char path[PATH_MAX]; + + if (is_signed(file) != 0) + { + return -1; + } + + dirp = opendir(keyring); + if (dirp == NULL) { + perror(keyring); + return -1; + } + + if (verbose) + printf(": %s\n", keyring); + + while ((dt = readdir(dirp)) != NULL) { + if (dt->d_type == DT_REG) { + len = strnlen(keyring, PATH_MAX); + memset(path, 0, PATH_MAX); + memcpy(path, keyring, len); + path[len] = '/'; + memcpy(path+len+1, dt->d_name, dt->d_reclen); + if (verify(file, path) == 0) { + closedir(dirp); + return 0; + } + } + } + + closedir(dirp); + return -1; +} + +int +main(int argc, char **argv) +{ + int action = ACTION_DEFAULT; + const char *key = NULL; + char keyring[PATH_MAX]; + + memset(keyring, 0, PATH_MAX); + memcpy(keyring, KEYRING, strnlen(KEYRING, PATH_MAX)); + + ARGBEGIN{ + case 'c': + action = ACTION_CHECK; + break; + case 'f': + key = EARGF(usage(argv0)); + break; + case 'g': + key = argc > 1 ? ARGF() : NULL; + action = ACTION_GENKEY; + break; + case 's': + action = ACTION_SIGN; + break; + case 'u': + action = ACTION_UNSIGN; + break; + case 'v': + verbose = 1; + break; + default: + usage(); + }ARGEND; + + switch(action) { + case ACTION_CHECK: + if (check(*argv, keyring) == 0) { + if (!verbose) + puts(*argv); + } else { + return 1; + } + break; + case ACTION_GENKEY: + keygen(key ? key : DEFAULT_ALIAS); + break; + case ACTION_UNSIGN: + unsign(*argv); + break; + case ACTION_SIGN: + if (is_signed(*argv) != 0) { + sign(*argv, key ? key : DEFAULT_ALIAS ".key"); + } else { + fprintf(stderr, "%s: Already signed\n", *argv); + return -1; + } + break; + default: + usage(); + } + + return 0; +}