diff options
author | Jérémy Zurcher <jeremy@asynk.ch> | 2010-07-09 12:32:17 +0200 |
---|---|---|
committer | Jérémy Zurcher <jeremy@asynk.ch> | 2010-07-09 12:32:17 +0200 |
commit | 6c027b4de25a529908be895e7ff19236f4002a57 (patch) | |
tree | f70d3a400bbb9ba8a83e9d4ffcaa4b6e367fc8bb /crypto_buffer_get.c | |
download | crypto-6c027b4de25a529908be895e7ff19236f4002a57.zip crypto-6c027b4de25a529908be895e7ff19236f4002a57.tar.gz |
initial commit, resurrect one of my realy old projects
Diffstat (limited to 'crypto_buffer_get.c')
-rw-r--r-- | crypto_buffer_get.c | 182 |
1 files changed, 182 insertions, 0 deletions
diff --git a/crypto_buffer_get.c b/crypto_buffer_get.c new file mode 100644 index 0000000..33e99f0 --- /dev/null +++ b/crypto_buffer_get.c @@ -0,0 +1,182 @@ +#include <errno.h> +#include <stdio.h> +#include <string.h> +#include <unistd.h> + +#include "crypto_buffer.h" + + +/* after this s->e_ptr and s->e_end are updated */ +static int firstread(crypto_buffer *s) +{ + register u8 *ptr1, *ptr2, *buffer; + register u32 size; + u32 r, i; + + /* look for the 0x5a block */ + buffer = s->e_buffer; + size = s->block_size; + for(;;){ + ptr1 = ptr2 = buffer; + r = s->op(s->fd, buffer, s->e_len); + if (r == 0) return 0; /* end of file */ + if (r == -1){ + if (errno == EINTR) continue; /* reread */ + return r; /* read error */ + } + if (r <= (size << 1)) return -1; /* no data */ + i = r; + do{ + i -= (ptr1-ptr2); + if (i==0) { ptr2 = NULL; break; } /* force reread */ + ptr2 = memchr(ptr1, 0x5a, i); + if (ptr2 == NULL) break; /* reread */ + ptr1 = ptr2; + for(;;) { if(*ptr1++!=0x5a) break; } + }while(ptr1-ptr2 < size); + if (ptr2 != NULL) break; + } + /* now ptr2 points to the 0x5a block */ + ptr2 += size; + /* decrypt info */ + s->cipher(&s->ctx,buffer, ptr2); + s->data_st.bytes = ((struct info *)buffer)->bytes; + s->data_st.strlen = ((struct info *)buffer)->strlen; + s->e_ptr = ptr2 + size; + r -= (size << 1); + i = s->e_ptr - (u8*)s->e_data - size; + if(i>0){ + memmove(s->e_ptr-i, s->e_ptr, r-i); + s->e_ptr -= i; + if(s->op(s->fd, s->e_ptr+r-i, i)<=0) return r; /* really bad */ + } + s->e_end = s->e_ptr + r; + return r; +} + + +/* after this s->e_ptr and s->e_end are updated */ +static int oneread(crypto_buffer *s) +{ + int r; + for (;;) { + r = s->op(s->fd,s->e_buffer,s->e_len); + if (r == -1) if (errno == EINTR) continue; + s->e_ptr = s->e_buffer; + s->e_end = s->e_ptr + r; + return r; + } +} + + +/* after this s->e_ptr is updated */ +static int eatinfo(crypto_buffer *s, u8* start) +{ + register u32 size; + register u8* buffer; + register u8* current; + int ret; + + /* be really carefull */ + current = start; + size = s->block_size; + buffer = s->e_buffer; + if(current == s->e_end){ + ret = oneread(s); + if(ret<=0) return ret; /* error */ + current = buffer; + } + /* TODO ?? verify that it's a magic block */ + current += size; /* jump over 0x5a block */ + if(current == s->e_end){ + ret = oneread(s); + if(ret<=0) return ret; /* error */ + current = buffer; + } + s->cipher(&s->ctx,buffer,current); + s->data_st.bytes = ((struct info *)buffer)->bytes; + s->data_st.strlen = ((struct info *)buffer)->strlen; + current += size; /* jump over info */ + if(current == s->e_end){ + ret = oneread(s); + if(ret<=0) return ret; /* error */ + current = buffer; + } + s->e_ptr = current; + return 1; +} + + +/* afer this s->c_ptr is updated */ +static int getthis(crypto_buffer *s, u8 *buf, u32 len) +{ + int available; + + available = s->c_end - s->c_ptr; + if (len > available) len = available; + memcpy(buf, s->c_ptr, len); + s->c_ptr += len; + return len; +} + + +int crypto_buffer_get(crypto_buffer *s, u8 *buf, u32 len) +{ + register u32 need; + register u32 size; + register u8* e_end; + register u8* e_ptr; + int r, ret; + + r = 0; + need = len; + size = s->block_size; + if(s->e_ptr == s->e_buffer){ + ret = firstread(s); + if(ret <=0) return ret; + } + if (s->c_ptr != s->c_buffer){ /* TODO maybe else if */ + r = getthis(s,buf,need); + if (r == need )return r; + need -= r; + buf += r; + } + /* now s->c_buffer is empty */ + e_end = s->e_end; + e_ptr = s->e_ptr; + while(need){ + if(e_ptr == e_end){ + /* buffer empty */ + ret = oneread(s); + if(ret < 0) return ret; + if(ret == 0) return r; + e_ptr = s->e_ptr; + e_end = s->e_end; + } + if(s->data_st.bytes == 0) { + /* end of raw encrypted data */ + ret = eatinfo(s,e_ptr); + if(ret < 0) return ret; + if(ret == 0) return r; + e_ptr = s->e_ptr; + } + s->cipher(&s->ctx, s->c_buffer, e_ptr); + s->data_st.bytes -= size; + e_ptr += size; + /* now c_buffer is full */ + if(s->data_st.strlen < size){ + /* non fully used block */ + s->c_ptr = s->c_end - s->data_st.strlen; + memmove(s->c_ptr, s->c_buffer, s->data_st.strlen); + } else { + s->data_st.strlen -= size; + s->c_ptr = s->c_buffer; + } + ret = getthis(s,buf,need); + need -= ret; + buf += ret; + r+= ret; + } + s->e_ptr = e_ptr; + return r; +} |