#include #include #include #include #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; }