2
0
Fork 0
mirror of https://git.sr.ht/~sircmpwn/mkproof synced 2024-03-29 11:20:08 +01:00

Implement everything

This commit is contained in:
Drew DeVault 2020-11-25 12:05:19 -05:00
parent 4267a36811
commit 8f5c12ace0
10 changed files with 272 additions and 9 deletions

12
README
View File

@ -38,13 +38,13 @@ challenge bytes.
Repeat the following algorithm to generate proofs until an argon2id key is found
whose first N hexadecimal digits are zero, where N is equal to the digits
parameter:
parameter divided by two:
1. Generate 16 random bytes (seed) and concatenate the seed and challenge bytes
to form an argon2id salt.
2. Run argon2id with the generated salt, and the memory and iteration parameters
provided by the challenge. The hash length and parallelism parameters shall
be respectively set to 32 and 1.
1. Generate 16 random bytes (password).
2. Run argon2id with the generated password, and the memory and iteration
parameters provided by the challenge, and the challenge bytes as the salt.
The hash length and parallelism parameters shall be respectively set to 32
and 1.
3. Encode the argon2id hash as hexadecimal.
When a suitable hash is found, encode the seed in hexadecimal. This is the proof

3
configure vendored
View File

@ -24,6 +24,7 @@ esac
mkchallenge() {
genrules mkchallenge \
src/random-$random.c \
src/util.c \
src/mkchallenge.c
}
@ -35,6 +36,7 @@ mkproof() {
argon2i/src/encoding.c \
argon2i/src/ref.c \
src/random-$random.c \
src/util.c \
src/mkproof.c
}
@ -45,6 +47,7 @@ checkproof() {
argon2i/src/blake2/blake2b.c \
argon2i/src/encoding.c \
argon2i/src/ref.c \
src/util.c \
src/checkproof.c
}

8
include/util.h Normal file
View File

@ -0,0 +1,8 @@
#ifndef UTIL_H
#define UTIL_H
#include <stddef.h>
void enchex(unsigned char *in, size_t inlen, char *out, size_t outlen);
int dechex(char *in, size_t inlen, unsigned char *out, size_t outlen);
#endif

View File

@ -1,8 +1,86 @@
#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "argon2.h"
#include "random.h"
#include "util.h"
static void
die(int check, char *why)
{
if (check) {
fprintf(stderr, "Error: %s\n", why);
exit(1);
}
}
int
main(int argc, char *argv[])
{
printf("checkproof\n");
if (argc != 3) {
fprintf(stderr, "Usage: %s <challenge> <proof>\n", argv[0]);
return 1;
}
int iters, memory, digits;
unsigned char salt[16];
char *challenge = argv[1];
char *algo = strtok(challenge, ":");
if (strcmp(algo, "argon2id") != 0) {
fprintf(stderr, "Error: unknown challenge type %s\n", algo);
return 1;
}
char *endptr;
char *iterstr = strtok(NULL, ":");
iters = strtoul(iterstr, &endptr, 10);
die(*endptr, "Invalid challenge");
char *memorystr = strtok(NULL, ":");
memory = strtoul(memorystr, &endptr, 10);
die(*endptr, "Invalid challenge");
char *digitsstr = strtok(NULL, ":");
digits = strtoul(digitsstr, &endptr, 10);
die(*endptr, "Invalid challenge");
char *saltstr = strtok(NULL, ":");
die(strlen(saltstr) != 32, "Invalid challenge");
int r = dechex(saltstr, strlen(saltstr), salt, sizeof(salt));
die(r == -1, "Invalid challenge");
unsigned char password[16];
unsigned char hash[32];
argon2_context context = {
.out = hash,
.outlen = sizeof(hash),
.salt = salt,
.saltlen = sizeof(salt),
.pwd = password,
.pwdlen = sizeof(password),
.t_cost = iters,
.m_cost = memory,
.lanes = 1,
.threads = 1,
.flags = ARGON2_DEFAULT_FLAGS,
};
die(strlen(argv[2]) != 32, "Invalid proof");
r = dechex(argv[2], strlen(argv[2]) + 1, password, sizeof(password));
die(r == -1, "Invalid challenge");
r = argon2id_ctx(&context);
die(r != 0, "argon2id failed\n");
for (int i = 0; i < digits / 2; ++i) {
if (hash[i] != 0) {
printf("proof: failed\n");
return 1;
}
}
printf("proof: ok\n");
return 0;
}

View File

@ -1,8 +1,51 @@
#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include "random.h"
#include "util.h"
#define ALGORITHM "argon2id"
#define ITERATIONS 5
#define MEMORY 12
static void
usage(char *argv_0)
{
fprintf(stderr, "Usage: %s [-d difficulty]\n", argv_0);
exit(1);
}
int
main(int argc, char *argv[])
{
printf("mkchallenge\n");
int digits = 8;
int c;
char *endptr;
while ((c = getopt(argc, argv, "d:")) != -1) {
switch (c) {
case 'd':
digits = strtoul(optarg, &endptr, 10);
if (*endptr) {
usage(argv[0]);
}
break;
}
}
if (optind < argc) {
usage(argv[0]);
}
unsigned char seed[16];
ssize_t n = get_random_bytes(seed, sizeof(seed));
assert(n == sizeof(seed));
char seedhex[33];
enchex(seed, sizeof(seed), seedhex, sizeof(seedhex));
printf("%s:%d:%d:%d:%s\n", ALGORITHM,
ITERATIONS, MEMORY, digits, seedhex);
return 0;
}

View File

@ -1,8 +1,107 @@
#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include "argon2.h"
#include "random.h"
#include "util.h"
static void
die(int check, char *why)
{
if (check) {
fprintf(stderr, "Error: %s\n", why);
exit(1);
}
}
int
main(int argc, char *argv[])
{
printf("mkproof\n");
if (argc != 2) {
fprintf(stderr, "Usage: %s <challenge>\n", argv[0]);
}
int iters, memory, digits;
unsigned char salt[16];
char *challenge = argv[1];
char *algo = strtok(challenge, ":");
if (strcmp(algo, "argon2id") != 0) {
fprintf(stderr, "Error: unknown challenge type %s\n", algo);
return 1;
}
char *endptr;
char *iterstr = strtok(NULL, ":");
iters = strtoul(iterstr, &endptr, 10);
die(*endptr, "Invalid challenge");
char *memorystr = strtok(NULL, ":");
memory = strtoul(memorystr, &endptr, 10);
die(*endptr, "Invalid challenge");
char *digitsstr = strtok(NULL, ":");
digits = strtoul(digitsstr, &endptr, 10);
die(*endptr, "Invalid challenge");
char *saltstr = strtok(NULL, ":");
die(strlen(saltstr) != 32, "Invalid challenge");
int r = dechex(saltstr, strlen(saltstr), salt, sizeof(salt));
die(r == -1, "Invalid challenge");
unsigned char password[16];
unsigned char hash[32];
argon2_context context = {
.out = hash,
.outlen = sizeof(hash),
.salt = salt,
.saltlen = sizeof(salt),
.pwd = password,
.pwdlen = sizeof(password),
.t_cost = iters,
.m_cost = memory,
.lanes = 1,
.threads = 1,
.flags = ARGON2_DEFAULT_FLAGS,
};
if (isatty(STDERR_FILENO)) {
// TODO: Provide a better estimate based on the difficulty
fprintf(stderr, "Generating a proof of work.\n");
fprintf(stderr, "This may take anywhere from tens of seconds to a few hours on slow computers.\n");
}
int nattempts = 0;
int valid = 0;
while (!valid) {
if (isatty(STDERR_FILENO)) {
fprintf(stderr, "\rAttempt %d", ++nattempts);
}
ssize_t b = get_random_bytes(password, sizeof(password));
assert(b == sizeof(password));
r = argon2id_ctx(&context);
die(r != 0, "argon2id failed\n");
valid = 1;
for (int i = 0; i < digits / 2; ++i) {
if (hash[i] != 0) {
valid = 0;
break;
}
}
}
if (isatty(STDERR_FILENO)) {
fprintf(stderr, "\nHere is your proof:\n");
}
char proof[33];
enchex(password, sizeof(password), proof, sizeof(proof));
printf("%s\n", proof);
return 0;
}

View File

@ -1,4 +1,5 @@
#include <stdlib.h>
#include "random.h"
ssize_t
get_random_bytes(unsigned char *buf, size_t nbytes)

View File

@ -1,4 +1,5 @@
#include <sys/random.h>
#include "random.h"
ssize_t
get_random_bytes(unsigned char *buf, size_t nbytes)

View File

@ -1,4 +1,5 @@
#include <stdio.h>
#include "random.h"
ssize_t
get_random_bytes(unsigned char *buf, size_t nbytes)

29
src/util.c Normal file
View File

@ -0,0 +1,29 @@
#include <assert.h>
#include <stddef.h>
#include <stdio.h>
#include "util.h"
void
enchex(unsigned char *in, size_t inlen, char *out, size_t outlen)
{
assert(outlen >= inlen * 2 + 1);
for (size_t i = 0; i < inlen; ++i) {
snprintf(&out[i * 2], 3, "%02x", in[i]);
}
}
int
dechex(char *in, size_t inlen, unsigned char *out, size_t outlen)
{
assert(outlen >= (inlen - 1) / 2);
for (size_t i = 0; i < outlen; ++i) {
unsigned int v;
int n = sscanf(&in[i * 2], "%02x", &v);
if (n != 1) {
return -1;
}
assert(v < 0x100);
out[i] = (unsigned char)v;
}
return outlen;
}