auth: add HMAC implementation
This allows for checking the SHA-512 implementation against Wycheproof via the HMAC tests.
This commit is contained in:
		
							parent
							
								
									216ef8f940
								
							
						
					
					
						commit
						ad42d99e0b
					
				
					 9 changed files with 554 additions and 5 deletions
				
			
		|  | @ -1,5 +1,5 @@ | |||
| LC_SRCS+=	aead.c aead_chacha20_poly1305.c | ||||
| LC_SRCS+=	auth.c auth_poly1305.c | ||||
| LC_SRCS+=	auth.c auth_hmac.c auth_poly1305.c | ||||
| LC_SRCS+=	cipher.c cipher_chacha20.c | ||||
| LC_SRCS+=	hash.c hash_sha384_sha512.c | ||||
| LC_SRCS+=	impl_chacha20.c impl_poly1305.c impl_sha512.c | ||||
|  |  | |||
							
								
								
									
										7
									
								
								README
									
										
									
									
									
								
							
							
						
						
									
										7
									
								
								README
									
										
									
									
									
								
							|  | @ -28,6 +28,7 @@ Hash | |||
| Authentication | ||||
| -------------- | ||||
| 
 | ||||
| - [x] HMAC | ||||
| - [x] Poly1305 | ||||
| 
 | ||||
| Ciphers | ||||
|  | @ -86,5 +87,7 @@ AEAD | |||
| - [ ] Salsa20-Poly1305 (no Wycherproof test vector suite) | ||||
| - [ ] XSalsa20-Poly1305 (no Wycherproof test vector suite) | ||||
| 
 | ||||
| KDF? | ||||
| ---- | ||||
| KDF | ||||
| --- | ||||
| 
 | ||||
| - [ ] HKDF | ||||
|  |  | |||
							
								
								
									
										178
									
								
								auth_hmac.c
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										178
									
								
								auth_hmac.c
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,178 @@ | |||
| /*
 | ||||
|  * Copyright (c) 2024 Lucas Gabriel Vuotto <lucas@lgv5.net> | ||||
|  * | ||||
|  * Permission to use, copy, modify, and distribute this software for any | ||||
|  * purpose with or without fee is hereby granted, provided that the above | ||||
|  * copyright notice and this permission notice appear in all copies. | ||||
|  * | ||||
|  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES | ||||
|  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | ||||
|  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR | ||||
|  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | ||||
|  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN | ||||
|  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF | ||||
|  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | ||||
|  */ | ||||
| 
 | ||||
| #include <stdlib.h> | ||||
| 
 | ||||
| #include "lilcrypto.h" | ||||
| #include "auth.h" | ||||
| #include "hash.h" | ||||
| #include "auth_hmac.h" | ||||
| #include "impl_hmac.h" | ||||
| #include "impl_sha512.h" | ||||
| 
 | ||||
| #include "util.h" | ||||
| 
 | ||||
| 
 | ||||
| #define HMAC_IPAD		UINT8_C(0x36) | ||||
| #define HMAC_OPAD		UINT8_C(0x5c) | ||||
| 
 | ||||
| 
 | ||||
| static int | ||||
| hmac_common_init(void *arg, const uint8_t *key, size_t keylen) | ||||
| { | ||||
| 	struct hmac_ctx	*ctx = arg; | ||||
| 	uint8_t		 ikeypad[HMAC_BLOCKSZ_MAX]; | ||||
| 	size_t		 i, olen; | ||||
| 
 | ||||
| 	if (keylen > ctx->blocksz) { | ||||
| 		if (!lc_hash_init(ctx->hctx) || | ||||
| 		    !lc_hash_update(ctx->hctx, key, keylen) || | ||||
| 		    !lc_hash_final(ctx->hctx, ctx->key, &olen)) | ||||
| 			return 0; | ||||
| 	} else { | ||||
| 		for (i = 0; i < keylen; i++) | ||||
| 			ctx->key[i] = key[i]; | ||||
| 		for (; i < ctx->blocksz; i++) | ||||
| 			ctx->key[i] = 0; | ||||
| 	} | ||||
| 
 | ||||
| 	for (i = 0; i < ctx->blocksz; i++) | ||||
| 		ikeypad[i] = ctx->key[i] ^ HMAC_IPAD; | ||||
| 
 | ||||
| 	return lc_hash_init(ctx->hctx) && | ||||
| 	    lc_hash_update(ctx->hctx, ikeypad, ctx->blocksz); | ||||
| } | ||||
| 
 | ||||
| int | ||||
| hmac_sha384_sha512_init(void *arg, const uint8_t *key, size_t keylen) | ||||
| { | ||||
| 	struct hmac_ctx	*ctx = arg; | ||||
| 
 | ||||
| 	ctx->blocksz = SHA512_CHUNK; | ||||
| 
 | ||||
| 	return hmac_common_init(ctx, key, keylen); | ||||
| } | ||||
| 
 | ||||
| int | ||||
| hmac_update(void *arg, const uint8_t *in, size_t inlen) | ||||
| { | ||||
| 	struct hmac_ctx	*ctx = arg; | ||||
| 
 | ||||
| 	return lc_hash_update(ctx->hctx, in, inlen); | ||||
| } | ||||
| 
 | ||||
| int | ||||
| hmac_final(void *arg, uint8_t *out, size_t *outlen) | ||||
| { | ||||
| 	struct hmac_ctx		*ctx = arg; | ||||
| 	struct lc_hash_ctx	*hctx; | ||||
| 	uint8_t		 m[HMAC_BLOCKSZ_MAX], okeypad[HMAC_BLOCKSZ_MAX]; | ||||
| 	size_t		 i, olen; | ||||
| 	int		 rc; | ||||
| 
 | ||||
| 	if (out == NULL) { | ||||
| 		(void)lc_hash_final(ctx->hctx, NULL, outlen); | ||||
| 		return 1; | ||||
| 	} | ||||
| 
 | ||||
| 	hctx = ctx->hctx; | ||||
| 
 | ||||
| 	*outlen = 0; | ||||
| 	for (i = 0; i < ctx->blocksz; i++) | ||||
| 		okeypad[i] = ctx->key[i] ^ HMAC_OPAD; | ||||
| 
 | ||||
| 	rc = lc_hash_final(ctx->hctx, m, &olen) && | ||||
| 	    lc_hash_init(ctx->hctx) && | ||||
| 	    lc_hash_update(ctx->hctx, okeypad, ctx->blocksz) && | ||||
| 	    lc_hash_update(ctx->hctx, m, olen) && | ||||
| 	    lc_hash_final(ctx->hctx, out, outlen); | ||||
| 
 | ||||
| 	lc_scrub(ctx, sizeof(*ctx)); | ||||
| 	ctx->hctx = hctx; | ||||
| 
 | ||||
| 	return rc; | ||||
| } | ||||
| 
 | ||||
| static void * | ||||
| hmac_common_ctx_new(const struct lc_hash_impl *impl) | ||||
| { | ||||
| 	struct hmac_ctx	*ctx; | ||||
| 
 | ||||
| 	ctx = malloc(sizeof(*ctx)); | ||||
| 	if (ctx == NULL) | ||||
| 		return NULL; | ||||
| 	ctx->hctx = lc_hash_ctx_new(impl); | ||||
| 	if (ctx->hctx == NULL) { | ||||
| 		free(ctx); | ||||
| 		return NULL; | ||||
| 	} | ||||
| 
 | ||||
| 	return ctx; | ||||
| } | ||||
| 
 | ||||
| static void * | ||||
| hmac_sha384_ctx_new(void) | ||||
| { | ||||
| 	return hmac_common_ctx_new(lc_hash_impl_sha384()); | ||||
| } | ||||
| 
 | ||||
| static void * | ||||
| hmac_sha512_ctx_new(void) | ||||
| { | ||||
| 	return hmac_common_ctx_new(lc_hash_impl_sha512()); | ||||
| } | ||||
| 
 | ||||
| static void | ||||
| hmac_ctx_free(void *arg) | ||||
| { | ||||
| 	struct hmac_ctx	*ctx = arg; | ||||
| 
 | ||||
| 	if (ctx != NULL) | ||||
| 		lc_hash_ctx_free(ctx->hctx); | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| static struct lc_auth_impl	hmac_sha384_impl = { | ||||
| 	.init = &hmac_sha384_sha512_init, | ||||
| 	.update = &hmac_update, | ||||
| 	.final = &hmac_final, | ||||
| 	.auth = NULL, | ||||
| 
 | ||||
| 	.ctx_new = &hmac_sha384_ctx_new, | ||||
| 	.ctx_free = &hmac_ctx_free, | ||||
| }; | ||||
| 
 | ||||
| static struct lc_auth_impl	hmac_sha512_impl = { | ||||
| 	.init = &hmac_sha384_sha512_init, | ||||
| 	.update = &hmac_update, | ||||
| 	.final = &hmac_final, | ||||
| 	.auth = NULL, | ||||
| 
 | ||||
| 	.ctx_new = &hmac_sha512_ctx_new, | ||||
| 	.ctx_free = &hmac_ctx_free, | ||||
| }; | ||||
| 
 | ||||
| const struct lc_auth_impl * | ||||
| lc_auth_impl_hmac_sha384(void) | ||||
| { | ||||
| 	return &hmac_sha384_impl; | ||||
| } | ||||
| 
 | ||||
| const struct lc_auth_impl * | ||||
| lc_auth_impl_hmac_sha512(void) | ||||
| { | ||||
| 	return &hmac_sha512_impl; | ||||
| } | ||||
							
								
								
									
										23
									
								
								auth_hmac.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										23
									
								
								auth_hmac.h
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,23 @@ | |||
| /*
 | ||||
|  * Copyright (c) 2024 Lucas Gabriel Vuotto <lucas@lgv5.net> | ||||
|  * | ||||
|  * Permission to use, copy, modify, and distribute this software for any | ||||
|  * purpose with or without fee is hereby granted, provided that the above | ||||
|  * copyright notice and this permission notice appear in all copies. | ||||
|  * | ||||
|  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES | ||||
|  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | ||||
|  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR | ||||
|  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | ||||
|  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN | ||||
|  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF | ||||
|  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | ||||
|  */ | ||||
| 
 | ||||
| #include <stddef.h> | ||||
| #include <stdint.h> | ||||
| 
 | ||||
| 
 | ||||
| int	hmac_sha384_sha512_init(void *, const uint8_t *, size_t); | ||||
| int	hmac_update(void *, const uint8_t *, size_t); | ||||
| int	hmac_final(void *, uint8_t *, size_t *); | ||||
							
								
								
									
										30
									
								
								impl_hmac.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										30
									
								
								impl_hmac.h
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,30 @@ | |||
| /*
 | ||||
|  * Copyright (c) 2024 Lucas Gabriel Vuotto <lucas@lgv5.net> | ||||
|  * | ||||
|  * Permission to use, copy, modify, and distribute this software for any | ||||
|  * purpose with or without fee is hereby granted, provided that the above | ||||
|  * copyright notice and this permission notice appear in all copies. | ||||
|  * | ||||
|  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES | ||||
|  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | ||||
|  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR | ||||
|  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | ||||
|  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN | ||||
|  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF | ||||
|  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | ||||
|  */ | ||||
| 
 | ||||
| #include <stddef.h> | ||||
| #include <stdint.h> | ||||
| 
 | ||||
| #include "lilcrypto.h" | ||||
| 
 | ||||
| 
 | ||||
| #define HMAC_BLOCKSZ_MAX	128 | ||||
| 
 | ||||
| 
 | ||||
| struct hmac_ctx { | ||||
| 	struct lc_hash_ctx	*hctx; | ||||
| 	size_t			 blocksz; | ||||
| 	uint8_t			 key[HMAC_BLOCKSZ_MAX]; | ||||
| }; | ||||
|  | @ -82,6 +82,8 @@ struct lc_auth_ctx	*lc_auth_ctx_new(const struct lc_auth_impl *); | |||
| void			 lc_auth_ctx_free(struct lc_auth_ctx *); | ||||
| 
 | ||||
| const struct lc_auth_impl	*lc_auth_impl_poly1305(void); | ||||
| const struct lc_auth_impl	*lc_auth_impl_hmac_sha384(void); | ||||
| const struct lc_auth_impl	*lc_auth_impl_hmac_sha512(void); | ||||
| 
 | ||||
| 
 | ||||
| /*
 | ||||
|  |  | |||
|  | @ -1,17 +1,19 @@ | |||
| .PATH:	${.CURDIR}/.. | ||||
| 
 | ||||
| AEAD=	wycheproof_aead | ||||
| MAC=	wycheproof_mac | ||||
| 
 | ||||
| PROGS=	${AEAD} | ||||
| PROGS=	${AEAD} ${MAC} | ||||
| NOMAN=	noman | ||||
| 
 | ||||
| SRCS_wycheproof_aead=	wycheproof_aead.c | ||||
| SRCS_wycheproof_mac=	wycheproof_mac.c | ||||
| 
 | ||||
| DPADD+=	${.CURDIR}/../lib/obj/liblilcrypto.a | ||||
| LDADD+=	${.CURDIR}/../lib/obj/liblilcrypto.a | ||||
| 
 | ||||
| 
 | ||||
| tests: all tests-aead | ||||
| tests: all tests-aead tests-mac | ||||
| 
 | ||||
| tests-aead: | ||||
| .ifndef WYCHEPROOF_DIR | ||||
|  | @ -23,4 +25,16 @@ tests-aead: | |||
| 	    ${WYCHEPROOF_DIR}/testvectors_v1/chacha20_poly1305_test.json | ||||
| .endfor | ||||
| 
 | ||||
| tests-mac: | ||||
| .ifndef WYCHEPROOF_DIR | ||||
| 	@echo Undefined WYCHEPROOF_DIR; false | ||||
| .endif | ||||
| .for p in ${MAC} | ||||
| 	perl ${.CURDIR}/mac.pl ${TESTOPTS} -x ./${p} \
 | ||||
| 	    ${WYCHEPROOF_DIR}/testvectors/hmac_sha384_test.json \
 | ||||
| 	    ${WYCHEPROOF_DIR}/testvectors_v1/hmac_sha384_test.json \
 | ||||
| 	    ${WYCHEPROOF_DIR}/testvectors/hmac_sha512_test.json \
 | ||||
| 	    ${WYCHEPROOF_DIR}/testvectors_v1/hmac_sha512_test.json | ||||
| .endfor | ||||
| 
 | ||||
| .include <bsd.prog.mk> | ||||
|  |  | |||
							
								
								
									
										66
									
								
								wycheproof/mac.pl
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										66
									
								
								wycheproof/mac.pl
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,66 @@ | |||
| #!/usr/bin/env perl | ||||
| use v5.38;; | ||||
| use strict; | ||||
| use warnings; | ||||
| 
 | ||||
| use Getopt::Std; | ||||
| use JSON::PP; | ||||
| 
 | ||||
| my $progname = $0 =~ s@.*/@@r; | ||||
| 
 | ||||
| sub slurp ($fh) { local $/; <$fh> } | ||||
| 
 | ||||
| sub usage () | ||||
| { | ||||
| 	say STDERR "Usage: $progname -x runner json_file [json_files ...]"; | ||||
| 	exit 1; | ||||
| } | ||||
| 
 | ||||
| sub main () | ||||
| { | ||||
| 	my %opts; | ||||
| 	my $rc = 0; | ||||
| 
 | ||||
| 	getopts("vx:", \%opts) && @ARGV > 0 or usage; | ||||
| 	usage unless defined $opts{"x"}; | ||||
| 
 | ||||
| 	for my $f (@ARGV) { | ||||
| 		open(my $fh, "<", $f) or die "open failed: $!"; | ||||
| 
 | ||||
| 		my $json = decode_json(slurp($fh)); | ||||
| 		for my $testgroup ($json->{testGroups}->@*) { | ||||
| 			for my $test ($testgroup->{tests}->@*) { | ||||
| 				my @args; | ||||
| 
 | ||||
| 				push(@args, $json->{algorithm}); | ||||
| 				push(@args, "-K", $testgroup->{keySize}); | ||||
| 				push(@args, "-k", $test->{key}); | ||||
| 				push(@args, "-m", $test->{msg}); | ||||
| 				push(@args, "-T", $testgroup->{tagSize}); | ||||
| 				push(@args, "-t", $test->{tag}); | ||||
| 				push(@args, "-v") if $opts{"v"}; | ||||
| 
 | ||||
| 				open(my $th, "-|", $opts{"x"}, @args) or die; | ||||
| 				my $result = slurp($th); | ||||
| 				close($th); | ||||
| 
 | ||||
| 				chomp($result); | ||||
| 				if ($result ne $test->{result}) { | ||||
| 					$rc = 1; | ||||
| 					say STDERR "case $test->{tcId}: ", | ||||
| 					    "expected $test->{result}: ", | ||||
| 					    "$test->{comment} [", | ||||
| 					    join(",", $test->{flags}->@*), | ||||
| 					    "]"; | ||||
| 				} | ||||
| 			} | ||||
| 		} | ||||
| 
 | ||||
| 		close($fh); | ||||
| 	} | ||||
| 
 | ||||
| 	say "ALL TESTS PASSED!" if $rc == 0; | ||||
| 	return $rc; | ||||
| } | ||||
| 
 | ||||
| exit main; | ||||
							
								
								
									
										233
									
								
								wycheproof_mac.c
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										233
									
								
								wycheproof_mac.c
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,233 @@ | |||
| /*
 | ||||
|  * Copyright (c) 2024 Lucas Gabriel Vuotto <lucas@lgv5.net> | ||||
|  * | ||||
|  * Permission to use, copy, modify, and distribute this software for any | ||||
|  * purpose with or without fee is hereby granted, provided that the above | ||||
|  * copyright notice and this permission notice appear in all copies. | ||||
|  * | ||||
|  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES | ||||
|  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | ||||
|  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR | ||||
|  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | ||||
|  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN | ||||
|  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF | ||||
|  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | ||||
|  */ | ||||
| 
 | ||||
| #include <ctype.h> | ||||
| #include <err.h> | ||||
| #include <limits.h> | ||||
| #include <stdio.h> | ||||
| #include <stdlib.h> | ||||
| #include <string.h> | ||||
| #include <unistd.h> | ||||
| 
 | ||||
| #include "lilcrypto.h" | ||||
| 
 | ||||
| 
 | ||||
| #define nelems(_a)	(sizeof((_a)) / sizeof((_a)[0])) | ||||
| 
 | ||||
| 
 | ||||
| static inline uint8_t | ||||
| hex2num(char s) | ||||
| { | ||||
| 	return s >= 'A' ? 10 + (s >= 'a' ? s - 'a' : s - 'A') : s - '0'; | ||||
| } | ||||
| 
 | ||||
| static int | ||||
| hexparse(const char *s, uint8_t *out, size_t *outlen) | ||||
| { | ||||
| 	size_t	l; | ||||
| 
 | ||||
| 	l = strlen(s); | ||||
| 	if (l % 2 != 0) | ||||
| 		return 0; | ||||
| 
 | ||||
| 	if (out == NULL) { | ||||
| 		*outlen = l / 2; | ||||
| 		return 1; | ||||
| 	} | ||||
| 
 | ||||
| 	*outlen = 0; | ||||
| 	while (*s != '\0') { | ||||
| 		if (!isxdigit(s[0]) || !isxdigit(s[1])) | ||||
| 			return 0; | ||||
| 		*out++ = (hex2num(s[0]) << 4) | hex2num(s[1]); | ||||
| 		(*outlen)++; | ||||
| 		s += 2; | ||||
| 	} | ||||
| 
 | ||||
| 	return 1; | ||||
| } | ||||
| 
 | ||||
| struct kwimpl { | ||||
| 	const char			*kw; | ||||
| 	const struct lc_auth_impl	*(*impl)(void); | ||||
| }; | ||||
| 
 | ||||
| static int | ||||
| kwimpl_cmp(const void *k0, const void *h0) | ||||
| { | ||||
| 	const struct kwimpl	*h = h0; | ||||
| 	const char		*k = k0; | ||||
| 
 | ||||
| 	return strcmp(k, h->kw); | ||||
| } | ||||
| 
 | ||||
| static const struct lc_auth_impl * | ||||
| kw2impl(const char *s) | ||||
| { | ||||
| 	/* Needs to be sorted. */ | ||||
| 	static const struct kwimpl	tbl[] = { | ||||
| 		{ "HMACSHA384", &lc_auth_impl_hmac_sha384 }, | ||||
| 		{ "HMACSHA512", &lc_auth_impl_hmac_sha512 }, | ||||
| 	}; | ||||
| 	struct kwimpl	*match; | ||||
| 
 | ||||
| 	match = bsearch(s, tbl, nelems(tbl), sizeof(struct kwimpl), | ||||
| 	    &kwimpl_cmp); | ||||
| 
 | ||||
| 	return match != NULL ? match->impl() : NULL; | ||||
| } | ||||
| 
 | ||||
| static void | ||||
| usage(void) | ||||
| { | ||||
| 	fprintf(stderr, "Usage: %s [options]\n", getprogname()); | ||||
| 	exit(1); | ||||
| } | ||||
| 
 | ||||
| int | ||||
| main(int argc, char *argv[]) | ||||
| { | ||||
| 	const struct lc_auth_impl	*impl; | ||||
| 	struct lc_auth_ctx		*ctx; | ||||
| 	uint8_t		*key, *msg, *tag, *buf; | ||||
| 	const char	*errstr; | ||||
| 	size_t		 keylen, msglen, taglen; | ||||
| 	size_t		 keylenarg, taglenarg; | ||||
| 	size_t		 l, olen; | ||||
| 	int		 Kflag, kflag, mflag, Tflag, tflag; | ||||
| 	int		 ch, verbose; | ||||
| 
 | ||||
| 	if (argc < 2) | ||||
| 		usage(); | ||||
| 
 | ||||
| 	impl = kw2impl(argv[1]); | ||||
| 	if (impl == NULL) | ||||
| 		errx(1, "unsupported algorithm: %s", argv[1]); | ||||
| 
 | ||||
| 	optind = 2; | ||||
| 	Kflag = kflag = mflag = Tflag = tflag = 0; | ||||
| 	verbose = 0; | ||||
| 	while ((ch = getopt(argc, argv, "K:k:m:T:t:v")) != -1) { | ||||
| 		switch (ch) { | ||||
| 		case 'K': | ||||
| 			Kflag = 1; | ||||
| 			keylenarg = strtonum(optarg, 0, LLONG_MAX, &errstr); | ||||
| 			if (errstr != NULL) | ||||
| 				errx(1, "keylen is %s: %s", errstr, optarg); | ||||
| 			if (keylenarg % 8 != 0) | ||||
| 				errx(1, "unsupport K value: %zu", keylenarg); | ||||
| 			keylenarg /= 8; | ||||
| 			break; | ||||
| 		case 'k': | ||||
| 			kflag = 1; | ||||
| 			(void)hexparse(optarg, NULL, &keylen); | ||||
| 			if (keylen != 0) { | ||||
| 				key = malloc(keylen); | ||||
| 				if (key == NULL) | ||||
| 					err(1, "out of memory"); | ||||
| 			} else | ||||
| 				key = NULL; | ||||
| 			if (!hexparse(optarg, key, &l) || l != keylen) | ||||
| 				errx(1, "invalid hex string: %s", optarg); | ||||
| 			break; | ||||
| 		case 'm': | ||||
| 			mflag = 1; | ||||
| 			(void)hexparse(optarg, NULL, &msglen); | ||||
| 			if (msglen != 0) { | ||||
| 				msg = malloc(msglen); | ||||
| 				if (msg == NULL) | ||||
| 					err(1, "out of memory"); | ||||
| 			} else | ||||
| 				msg = NULL; | ||||
| 			if (!hexparse(optarg, msg, &l) || l != msglen) | ||||
| 				errx(1, "invalid hex string: %s", optarg); | ||||
| 			break; | ||||
| 		case 'T': | ||||
| 			Tflag = 1; | ||||
| 			taglenarg = strtonum(optarg, 0, LLONG_MAX, &errstr); | ||||
| 			if (errstr != NULL) | ||||
| 				errx(1, "taglen is %s: %s", errstr, optarg); | ||||
| 			taglenarg /= 8; | ||||
| 			break; | ||||
| 		case 't': | ||||
| 			tflag = 1; | ||||
| 			(void)hexparse(optarg, NULL, &taglen); | ||||
| 			if (taglen != 0) { | ||||
| 				tag = malloc(taglen); | ||||
| 				if (tag == NULL) | ||||
| 					err(1, "out of memory"); | ||||
| 			} else | ||||
| 				tag = NULL; | ||||
| 			if (!hexparse(optarg, tag, &l) || l != taglen) | ||||
| 				errx(1, "invalid hex string: %s", optarg); | ||||
| 			break; | ||||
| 		case 'v': | ||||
| 			verbose = 1; | ||||
| 			break; | ||||
| 		default: | ||||
| 			usage(); | ||||
| 			break; | ||||
| 		} | ||||
| 	} | ||||
| 	argc -= optind; | ||||
| 	argv += optind; | ||||
| 
 | ||||
| 	if (!(Kflag && kflag && mflag && Tflag && tflag)) | ||||
| 		errx(1, "missing required arguments"); | ||||
| 
 | ||||
| 	ctx = lc_auth_ctx_new(impl); | ||||
| 	if (ctx == NULL) | ||||
| 		errx(1, "can't allocate ctx"); | ||||
| 	if (!lc_auth_init(ctx, key, keylenarg) || | ||||
| 	    !lc_auth_update(ctx, msg, msglen) || | ||||
| 	    !lc_auth_final(ctx, NULL, &olen)) { | ||||
| 		puts("invalid"); | ||||
| 		return 1; | ||||
| 	} | ||||
| 
 | ||||
| 	buf = malloc(olen); | ||||
| 	if (buf == NULL) | ||||
| 		err(1, "out of memory"); | ||||
| 
 | ||||
| 	if (!lc_auth_final(ctx, buf, &olen)) { | ||||
| 		puts("invalid"); | ||||
| 		return 1; | ||||
| 	} | ||||
| 
 | ||||
| 	/*
 | ||||
| 	 * Tests include truncated output. Skip checking olen as it'll always | ||||
| 	 * be the full-length hash. | ||||
| 	 */ | ||||
| 	if (taglen != taglenarg || | ||||
| 	    lc_ct_cmp(buf, tag, taglen) != 0) { | ||||
| 		if (verbose) { | ||||
| 			fprintf(stderr, "tag (%zu, %zu, %zu)\n", taglen, | ||||
| 			    taglenarg, olen); | ||||
| 			lc_hexdump_fp(stderr, tag, taglen); | ||||
| 			fprintf(stderr, "\n"); | ||||
| 			lc_hexdump_fp(stderr, buf, olen); | ||||
| 			fprintf(stderr, "\n"); | ||||
| 		} | ||||
| 		puts("invalid"); | ||||
| 		return 1; | ||||
| 	} | ||||
| 
 | ||||
| 	free(buf); | ||||
| 	lc_auth_ctx_free(ctx); | ||||
| 
 | ||||
| 	puts("valid"); | ||||
| 	return 0; | ||||
| } | ||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue