diff --git a/include/Makefile.am b/include/Makefile.am index 09cd60a..109f440 100644 --- a/include/Makefile.am +++ b/include/Makefile.am @@ -18,6 +18,7 @@ PCPEXPORT = pcp.h \ pcp/z85.h \ pcp/zmq_z85.h \ pcp/ed.h \ - pcp/base85.h + pcp/base85.h \ + pcp/buffer.h nobase_include_HEADERS = $(PCPEXPORT) diff --git a/include/pcp.h b/include/pcp.h index 13ffc04..326498e 100644 --- a/include/pcp.h +++ b/include/pcp.h @@ -6,6 +6,7 @@ extern "C" { #endif #include "pcp/base85.h" +#include "pcp/buffer.h" #include "pcp/config.h" #include "pcp/crypto.h" #include "pcp/defines.h" diff --git a/include/pcp/buffer.h b/include/pcp/buffer.h new file mode 100644 index 0000000..31db33d --- /dev/null +++ b/include/pcp/buffer.h @@ -0,0 +1,97 @@ +/* + This file is part of Pretty Curved Privacy (pcp1). + + Copyright (C) 2014 T.v.Dein. + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + + You can contact me by mail: . +*/ + +/* + + Flexible buffer management, idea from openssh/buffer.c. + This allows us to dissect buffers into parts at will + whithout the hassle of boundary checking in each and every + line. Therefore it is more secure, since this system wraps + all this stuff from us, so in case we're attemt to overflow + a buffer or the like, the buffer functions will catch this, + warn us and die. + +*/ + +#ifndef HAVE_PCP_BUFFER_H +#define HAVE_PCP_BUFFER_H + +#include "mem.h" +#include "util.h" +#include "defines.h" + +struct _pcp_buffer { + char *name; /* just for convenience in error messages and the + like, so we know which buffer cause trouble */ + uint8_t allocated; + size_t blocksize; + size_t size; + size_t offset; /* read position */ + size_t end; /* write position, data end */ + void *buf; +}; + +typedef struct _pcp_buffer Buffer; + +/* create a new buffer */ +Buffer *buffer_new(size_t blocksize, char *name); + +/* zero the buffer and free it, if allocated */ +void buffer_free(Buffer *b); + +/* zero the buffer, always called from buffer_free() */ +void buffer_clear(Buffer *b); + +/* add data to the buffer, memorize end position */ +void buffer_add(Buffer *b, const void *data, size_t len); + +/* resize the buffer if necessary */ +void buffer_resize(Buffer *b, size_t len); + +/* get some chunk of data from the buffer, starting from offset til len, + it doesn't allocate the returned data (void *buf, the 2nd argument). +*/ +size_t buffer_get(Buffer *b, void *buf, size_t len); + +/* same as buffer_get() but fetch some data chunk from somewhere + in the middle of the buffer */ +size_t buffer_extract(Buffer *b, void *buf, size_t offset, size_t len); + +/* dump the buffer contents to stderr */ +void buffer_dump(const Buffer *b); + +/* print buffer counters to stderr */ +void buffer_info(const Buffer *b); + +/* tell how much data there is in the buffer */ +size_t buffer_size(const Buffer *b); + +/* access the last byte(s) as numbers directly, save typing, + in contrast to buffer_get() it doesn't increment offset */ +uint8_t buffer_last8(Buffer *b); +uint16_t buffer_last16(Buffer *b); +uint32_t buffer_last32(Buffer *b); +uint64_t buffer_last64(Buffer *b); + +/* read from a file directly into a buffer object */ +size_t buffer_fd_read(Buffer *b, FILE *in, size_t len); + +#endif // HAVE_PCP_BUFFER_H diff --git a/libpcp/Makefile.am b/libpcp/Makefile.am index 53d0ad0..f67237f 100644 --- a/libpcp/Makefile.am +++ b/libpcp/Makefile.am @@ -30,6 +30,6 @@ libpcp1_la_SOURCES = mac.c mem.c pad.c version.c \ vault.c fatal.c jenhash.c digital_crc32.c \ crypto.c ed.c keyhash.c scrypt.c \ scrypt/crypto/sha256.c scrypt/crypto/crypto_scrypt-nosse.c \ - base85.c util.c + base85.c util.c buffer.c include_HEADERS = ../include/pcp.h diff --git a/libpcp/buffer.c b/libpcp/buffer.c new file mode 100644 index 0000000..71b2985 --- /dev/null +++ b/libpcp/buffer.c @@ -0,0 +1,158 @@ +/* + This file is part of Pretty Curved Privacy (pcp1). + + Copyright (C) 2014 T.v.Dein. + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + + You can contact me by mail: . +*/ + +#include "buffer.h" + +Buffer *buffer_new(size_t blocksize, char *name) { + Buffer *b = ucmalloc(sizeof(Buffer)); + b->buf = ucmalloc(blocksize); + b->name = ucmalloc(strlen(name)+1); + b->size = blocksize; + b->allocated = 1; + b->offset = 0; + b->end = 0; + b->blocksize = blocksize; + memcpy(b->name, name, strlen(name)+1); + return b; +} + +void buffer_free(Buffer *b) { + if(b != NULL) { + if(b->allocated > 0) { + buffer_clear(b); + free(b->buf); + free(b); + } + } +} + +void buffer_clear(Buffer *b) { + b->offset = 0; + memset(b->buf, 0, b->size); +} + +void buffer_add(Buffer *b, const void *data, size_t len) { + buffer_resize(b, len); + memcpy(b->buf + b->end, data, len); + b->end += len; +} + +void buffer_resize(Buffer *b, size_t len) { + if((b->end > 0 && b->end + len > b->size) || (b->end == 0 && len > b->size) ) { + /* increase by buf blocksize */ + size_t newsize = (((len / b->blocksize) +1) * b->blocksize) + b->size; + fprintf(stderr, "[buffer %s] resizing from %ld to %ld\n", b->name, b->size, newsize); + b->buf = ucrealloc(b->buf, b->size, newsize); + b->size = newsize; + } +} + +size_t buffer_get(Buffer *b, void *buf, size_t len) { + if(len > b->end - b->offset || len == 0) { + fatal("[buffer %s] attempt to read %ld data from buffer with size %ld %p at offset %ld", + len, b->size, b->offset); + return 0; + } + memcpy(buf, b->buf + b->offset, len); + b->offset += len; + return len; +} + +size_t buffer_extract(Buffer *b, void *buf, size_t offset, size_t len) { + if(len > b->end) { + fatal("[buffer %s] attempt to read %ld bytes past end of buffer at %ld\n", b->name, b->end - (b->offset + len), b->end); + return 0; + } + + if(offset > b->end) { + fatal("[buffer %s] attempt to read at offset %ld past len to read %ld\n", b->name, offset, b->end); + return 0; + } + + memcpy(buf, b->buf + offset, len); + return len - offset; +} + +void buffer_dump(const Buffer *b) { + _dump(b->name, b->buf, b->size); +} + +void buffer_info(const Buffer *b) { + fprintf(stderr, "blocksize: %ld\n", b->blocksize); + fprintf(stderr, " size: %ld\n", b->size); + fprintf(stderr, " offset: %ld\n", b->offset); + fprintf(stderr, " end: %ld\n", b->end); + fprintf(stderr, "allocated: %d\n", b->allocated); +} + +size_t buffer_size(const Buffer *b) { + return b->end; +} + +uint8_t buffer_last8(Buffer *b) { + uint8_t i; + if(buffer_extract(b, &i, b->end - 1, 1) > 0) + return i; + else + return 0; +} + +uint16_t buffer_last16(Buffer *b) { + uint16_t i; + if(buffer_extract(b, &i, b->end - 2, 2) > 0) + return i; + else + return 0; +} + +uint32_t buffer_last32(Buffer *b) { + uint32_t i; + if(buffer_extract(b, &i, b->end - 4, 4) > 0) + return i; + else + return 0; +} + +uint64_t buffer_last64(Buffer *b) { + uint64_t i; + if(buffer_extract(b, &i, b->end - 8, 8) > 0) + return i; + else + return 0; +} + +size_t buffer_fd_read(Buffer *b, FILE *in, size_t len) { + if(feof(in) || ferror(in)) { + return 0; + } + + void *data = ucmalloc(len); + + size_t s = fread(data, 1, len, in); + + if(s < len) { + fatal("[buffer %s] attemt to read %ld bytes from FILE, but got %ld only\n", b->name, len, s); + return 0; + } + + buffer_add(b, data, len); + return len; +} diff --git a/tests/Makefile.am b/tests/Makefile.am index e4398ea..584ca33 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -20,7 +20,7 @@ # AM_CFLAGS = -I../include/pcp -I../src -I../libpcp/scrypt/crypto -Wall -g -check_PROGRAMS = col invalidkeys pwhashes gencheader statictest cpptest +check_PROGRAMS = col invalidkeys pwhashes gencheader statictest cpptest buffertest gencheader_LDADD = ../libpcp/.libs/libpcp1.a gencheader_SOURCES = gencheader.c @@ -28,6 +28,9 @@ gencheader_SOURCES = gencheader.c statictest_LDADD = ../libpcp/.libs/libpcp1.a statictest_SOURCES = statictest.c +buffertest_LDADD = ../libpcp/.libs/libpcp1.a +buffertest_SOURCES = buffertest.c + col_LDADD = ../libpcp/.libs/libpcp1.a diff --git a/tests/buffertest.c b/tests/buffertest.c new file mode 100644 index 0000000..1f430b0 --- /dev/null +++ b/tests/buffertest.c @@ -0,0 +1,58 @@ +#include "buffertest.h" + +int main() { + Buffer *test = buffer_new(16, "test"); + + byte *a = ucmalloc(32); + byte *b = ucmalloc(32); + memset(a, 'A', 32); + memset(b, 'B', 32); + + fprintf(stderr, "initial\n"); + buffer_info(test); + + int i; + for(i=0; i<2; i++) { + fprintf(stderr, "\nadding As\n"); + buffer_add(test, a, 32); + buffer_info(test); + buffer_dump(test); + + fprintf(stderr, "\nadding Bs\n"); + buffer_add(test, b, 32); + buffer_info(test); + buffer_dump(test); + } + + free(a); + free(b); + + + size_t x; + size_t bs = buffer_size(test); + void *g = ucmalloc(32); + for(x=0; x < bs; x+=32) { + fprintf(stderr, "before get\n"); + buffer_info(test); + if(buffer_get(test, g, 32) > 0) { + fprintf(stderr, "after get\n"); + buffer_info(test); + _dump("got", g, 32); + } + fprintf(stderr, "\n"); + } + + buffer_extract(test, g, 28, 38); + _dump("extracted", g, 10); + + uint8_t c = buffer_last8(test); + fprintf(stderr, "last byte: %c\n", c); + + free(g); + + buffer_free(test); + + fatals_ifany(); + + return 0; +} diff --git a/tests/buffertest.h b/tests/buffertest.h new file mode 100644 index 0000000..41a92d2 --- /dev/null +++ b/tests/buffertest.h @@ -0,0 +1,6 @@ +#include +#include +#include + +#include "buffer.h" +