mirror of
https://git.sr.ht/~sircmpwn/mkproof
synced 2024-03-29 11:20:08 +01:00
Implement everything
This commit is contained in:
parent
4267a36811
commit
8f5c12ace0
12
README
12
README
|
@ -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
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
101
src/mkproof.c
101
src/mkproof.c
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
#include <stdlib.h>
|
||||
#include "random.h"
|
||||
|
||||
ssize_t
|
||||
get_random_bytes(unsigned char *buf, size_t nbytes)
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
#include <sys/random.h>
|
||||
#include "random.h"
|
||||
|
||||
ssize_t
|
||||
get_random_bytes(unsigned char *buf, size_t nbytes)
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
#include <stdio.h>
|
||||
#include "random.h"
|
||||
|
||||
ssize_t
|
||||
get_random_bytes(unsigned char *buf, size_t nbytes)
|
||||
|
|
|
@ -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;
|
||||
}
|
Loading…
Reference in New Issue