Merge pull request #369 from libtom/demo/aesgcm

Add aesgcm demo
This commit is contained in:
Steffen Jaeckel 2018-03-27 19:39:13 +02:00 committed by GitHub
commit 8b6d9dba76
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 443 additions and 2 deletions

2
.gitignore vendored
View File

@ -22,6 +22,8 @@ doc/crypt.pdf
doc/refman.pdf
# *nix/windows test executables
aesgcm
aesgcm.exe
constants
constants.exe
ltcrypt

146
demos/aesgcm.c Normal file
View File

@ -0,0 +1,146 @@
/* LibTomCrypt, modular cryptographic library -- Tom St Denis
*
* LibTomCrypt is a library that provides various cryptographic
* algorithms in a highly modular and flexible manner.
*
* The library is free for all purposes without any express
* guarantee it works.
*/
/**
@file aesgcm.c
AES128-GCM demo - file en-&decryption, Steffen Jaeckel
Uses the format: |ciphertext|tag-16-bytes|
*/
#define _GNU_SOURCE
#include <tomcrypt.h>
#include <stdio.h>
#include <stdint.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <dirent.h>
#include <string.h>
#include <errno.h>
#include <fcntl.h>
#include <unistd.h>
#include "gcm-file/gcm_filehandle.c"
#include "gcm-file/gcm_file.c"
static off_t fsize(const char *filename)
{
struct stat st;
if (stat(filename, &st) == 0) return st.st_size;
return -1;
}
static int mv(const char *old_name, const char *new_name)
{
int fd;
if (rename(old_name, new_name) == -1) return -1;
fd = open(new_name, 0);
if (fd == -1) return -1;
if (fsync(fd) != 0) goto OUT;
syncfs(fd);
OUT:
close(fd);
return 0;
}
/* https://stackoverflow.com/a/23898449 */
static void scan_hex(const char* str, uint8_t* bytes, size_t blen)
{
uint8_t pos;
uint8_t idx0;
uint8_t idx1;
const uint8_t hashmap[] =
{
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, /* 01234567 */
0x08, 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 89:;<=>? */
0x00, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x00, /* @ABCDEFG */
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* HIJKLMNO */
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* PQRSTUVW */
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* XYZ[\]^_ */
0x00, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x00, /* `abcdefg */
};
for (pos = 0; ((pos < (blen*2)) && (pos < strlen(str))); pos += 2)
{
idx0 = (uint8_t)(str[pos+0] & 0x1F) ^ 0x10;
idx1 = (uint8_t)(str[pos+1] & 0x1F) ^ 0x10;
bytes[pos/2] = (uint8_t)(hashmap[idx0] << 4) | hashmap[idx1];
}
}
static void die(int ret)
{
fprintf(stderr, "Usage: aesgcm <-e|-d> <infile> <outfile> <96 char hex-string 'IV | key'>\n");
exit(ret);
}
int main(int argc, char **argv)
{
int ret = 0, err, arg, direction, res, tmp;
size_t keylen;
uint8_t keybuf[48] = {0};
char *out = NULL;
const char *mode, *in_file, *out_file, *key_string;
if (argc < 5) die(__LINE__);
arg = 1;
mode = argv[arg++];
in_file = argv[arg++];
out_file = argv[arg++];
key_string = argv[arg++];
if(strcmp(mode, "-d") == 0) direction = GCM_DECRYPT;
else if(strcmp(mode, "-e") == 0) direction = GCM_ENCRYPT;
else die(__LINE__);
if (fsize(in_file) <= 0) die(__LINE__);
keylen = strlen(key_string);
if (keylen != 96) die(__LINE__);
scan_hex(key_string, keybuf, sizeof(keybuf));
register_all_ciphers();
if(asprintf(&out, "%s-XXXXXX", out_file) < 0) die(__LINE__);
if((tmp = mkstemp(out)) == -1) {
ret = __LINE__;
goto cleanup;
}
close(tmp);
if((err = gcm_file(find_cipher("aes"), &keybuf[16], 32, keybuf, 16, NULL, 0, in_file, out, 16, direction, &res)) != CRYPT_OK) {
fprintf(stderr, "boooh %s\n", error_to_string(err));
ret = __LINE__;
goto cleanup;
}
if(res != 1) {
ret = __LINE__;
}
else
{
if (mv(out, out_file) != 0) ret = __LINE__;
}
cleanup:
if(ret != 0) unlink(out);
free(out);
return ret;
}
/* ref: $Format:%D$ */
/* git commit: $Format:%H$ */
/* commit time: $Format:%ai$ */

91
demos/gcm-file/gcm_file.c Normal file
View File

@ -0,0 +1,91 @@
/* LibTomCrypt, modular cryptographic library -- Tom St Denis
*
* LibTomCrypt is a library that provides various cryptographic
* algorithms in a highly modular and flexible manner.
*
* The library is free for all purposes without any express
* guarantee it works.
*/
#include "tomcrypt.h"
/**
@file gcm_file.c
GCM process a file, Steffen Jaeckel
*/
#ifdef LTC_GCM_MODE
#ifndef LTC_NO_FILE
/**
Process a file.
c.f. gcm_filehandle() for basic documentation.
It is possible, that in error-cases the 'out' file
will be created and after the error occurred it will
be removed again.
@param cipher Index of cipher to use
@param key The secret key
@param keylen The length of the secret key
@param IV The initial vector
@param IVlen The length of the initial vector
@param adata The additional authentication data (header)
@param adatalen The length of the adata
@param in The input file
@param out The output file
@param taglen The MAC tag length
@param direction Encrypt or Decrypt mode (GCM_ENCRYPT or GCM_DECRYPT)
@return CRYPT_OK on success
*/
int gcm_file( int cipher,
const unsigned char *key, unsigned long keylen,
const unsigned char *IV, unsigned long IVlen,
const unsigned char *adata, unsigned long adatalen,
const char *in,
const char *out,
unsigned long taglen,
int direction,
int *res)
{
int err;
FILE *f_in = NULL, *f_out = NULL;
LTC_ARGCHK(in != NULL);
LTC_ARGCHK(out != NULL);
LTC_ARGCHK(res != NULL);
f_in = fopen(in, "rb");
if (f_in == NULL) {
err = CRYPT_FILE_NOTFOUND;
goto LBL_ERR;
}
f_out = fopen(out, "w+b");
if (f_out == NULL) {
err = CRYPT_FILE_NOTFOUND;
goto LBL_ERR;
}
err = gcm_filehandle(cipher, key, keylen, IV, IVlen, adata, adatalen, f_in, f_out, taglen, direction, res);
LBL_ERR:
if (f_out != NULL && fclose(f_out) != 0) {
err = CRYPT_ERROR;
}
if (*res != 1) {
remove(out);
}
if (f_in != NULL && fclose(f_in) != 0) {
err = CRYPT_ERROR;
}
return err;
}
#endif
#endif
/* ref: $Format:%D$ */
/* git commit: $Format:%H$ */
/* commit time: $Format:%ai$ */

View File

@ -0,0 +1,201 @@
/* LibTomCrypt, modular cryptographic library -- Tom St Denis
*
* LibTomCrypt is a library that provides various cryptographic
* algorithms in a highly modular and flexible manner.
*
* The library is free for all purposes without any express
* guarantee it works.
*/
#include "tomcrypt.h"
/**
@file gcm_filehandle.c
GCM process a filehandle, Steffen Jaeckel
*/
#ifdef LTC_GCM_MODE
#ifndef LTC_NO_FILE
#if defined(_MSC_VER)
#define ftruncate _chsize
#else
#include <unistd.h>
#endif
/**
Process a filehandle.
This uses the widely established scheme where the tag is appended
to the ciphertext.
encrypted_file = aesgcm(plain_file) | aesgcm_tag(plain_file)
Depending on 'direction' this function does:
Encrypt file 'in' to 'out' and append the tag of length 'taglen'
to 'out'.
or
Decrypt file 'in' to 'out' and check the tag of length 'taglen'
and strip the tag from 'in'.
In error-cases 'out' will be zeroed out first and then truncated to
a length of 0.
@param cipher Index of cipher to use
@param key The secret key
@param keylen The length of the secret key
@param IV The initial vector
@param IVlen The length of the initial vector
@param adata The additional authentication data (header)
@param adatalen The length of the adata
@param in The input file
@param out The output file
@param taglen The MAC tag length
@param direction Encrypt or Decrypt mode (GCM_ENCRYPT or GCM_DECRYPT)
@return CRYPT_OK on success
*/
int gcm_filehandle( int cipher,
const unsigned char *key, unsigned long keylen,
const unsigned char *IV, unsigned long IVlen,
const unsigned char *adata, unsigned long adatalen,
FILE *in,
FILE *out,
unsigned long taglen,
int direction,
int *res)
{
void *orig;
gcm_state *gcm;
int err;
unsigned char *buf, tag[16];
size_t x, tot_data;
unsigned long tag_len;
LTC_ARGCHK(in != NULL);
LTC_ARGCHK(out != NULL);
LTC_ARGCHK(res != NULL);
*res = 0;
if ((err = cipher_is_valid(cipher)) != CRYPT_OK) {
return err;
}
#ifndef LTC_GCM_TABLES_SSE2
orig = gcm = XMALLOC(sizeof(*gcm));
#else
orig = gcm = XMALLOC(sizeof(*gcm) + 16);
#endif
if (gcm == NULL) {
return CRYPT_MEM;
}
if ((buf = XMALLOC(LTC_FILE_READ_BUFSIZE)) == NULL) {
XFREE(gcm);
return CRYPT_MEM;
}
/* Force GCM to be on a multiple of 16 so we can use 128-bit aligned operations
* note that we only modify gcm and keep orig intact. This code is not portable
* but again it's only for SSE2 anyways, so who cares?
*/
#ifdef LTC_GCM_TABLES_SSE2
if ((unsigned long)gcm & 15) {
gcm = (gcm_state *)((unsigned long)gcm + (16 - ((unsigned long)gcm & 15)));
}
#endif
if ((err = gcm_init(gcm, cipher, key, keylen)) != CRYPT_OK) {
goto LBL_ERR;
}
if ((err = gcm_add_iv(gcm, IV, IVlen)) != CRYPT_OK) {
goto LBL_ERR;
}
if ((err = gcm_add_aad(gcm, adata, adatalen)) != CRYPT_OK) {
goto LBL_ERR;
}
fseek(in, 0, SEEK_END);
tot_data = ftell(in);
if (direction == GCM_DECRYPT) {
tot_data -= taglen;
}
rewind(in);
do {
x = MIN(tot_data, LTC_FILE_READ_BUFSIZE);
x = fread(buf, 1, x, in);
tot_data -= x;
if ((err = gcm_process(gcm, buf, (unsigned long)x, buf, direction)) != CRYPT_OK) {
goto LBL_CLEANBUF;
}
if(fwrite(buf, 1, x, out) != x) {
err = CRYPT_ERROR;
goto LBL_CLEANBUF;
}
} while (x == LTC_FILE_READ_BUFSIZE);
tag_len = taglen;
if ((err = gcm_done(gcm, tag, &tag_len)) != CRYPT_OK) {
goto LBL_CLEANBUF;
}
if (tag_len != taglen) {
err = CRYPT_ERROR;
goto LBL_CLEANBUF;
}
if (direction == GCM_DECRYPT) {
x = fread(buf, 1, taglen, in);
if (x != taglen) {
err = CRYPT_ERROR;
goto LBL_CLEANBUF;
}
if (XMEM_NEQ(buf, tag, taglen) == 0) {
*res = 1;
}
} else {
if(fwrite(tag, 1, taglen, out) != taglen) {
err = CRYPT_ERROR;
goto LBL_CLEANBUF;
}
*res = 1;
}
LBL_CLEANBUF:
zeromem(buf, LTC_FILE_READ_BUFSIZE);
zeromem(tag, sizeof(tag));
LBL_ERR:
#ifdef LTC_CLEAN_STACK
#ifndef LTC_GCM_TABLES_SSE2
zeromem(orig, sizeof(*gcm));
#else
zeromem(orig, sizeof(*gcm) + 16);
#endif
#endif
if(*res == 0) {
x = ftell(out);
rewind(out);
while((size_t)ftell(out) < x) {
fwrite(buf, 1, LTC_FILE_READ_BUFSIZE, out);
}
if(ftruncate(fileno(out), 0)) {
/* well, what shall we do here... */
}
}
fflush(out);
XFREE(buf);
XFREE(orig);
return err;
}
#endif
#endif
/* ref: $Format:%D$ */
/* git commit: $Format:%H$ */
/* commit time: $Format:%ai$ */

View File

@ -147,9 +147,10 @@ USEABLE_DEMOS = ltcrypt sizes constants
TEST_DEMOS = small tv_gen
# Demos that are in one config broken
# openssl-enc - can't be build with LTC_EASY
# aesgcm - can't be built with LTC_EASY
# openssl-enc - can't be built with LTC_EASY
# timing - not really broken, but older gcc builds spit warnings
BROKEN_DEMOS = openssl-enc timing
BROKEN_DEMOS = aesgcm openssl-enc timing
# Combine demos in groups
UNBROKEN_DEMOS = $(TEST_DEMOS) $(USEABLE_DEMOS) $(USEFUL_DEMOS)