summaryrefslogtreecommitdiffstats
path: root/crypto_buffer_get.c
diff options
context:
space:
mode:
authorJérémy Zurcher <jeremy@asynk.ch>2010-07-09 12:32:17 +0200
committerJérémy Zurcher <jeremy@asynk.ch>2010-07-09 12:32:17 +0200
commit6c027b4de25a529908be895e7ff19236f4002a57 (patch)
treef70d3a400bbb9ba8a83e9d4ffcaa4b6e367fc8bb /crypto_buffer_get.c
downloadcrypto-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.c182
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;
+}