summaryrefslogtreecommitdiffstats
path: root/crypto_buffer_put.c
blob: 35c7730914768510f79595022780218352d2bfcc (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
#include <errno.h>
#include <string.h>

#include "crypto_buffer.h"


/* s->data_st must have been set */
/* after this s->e_ptr is updated */
static int allwrite(crypto_buffer *s)
{
	u8 *buffer;
	int w, bytes;

	buffer = s->e_buffer;
	bytes = s->data_st.bytes + (s->block_size << 1);
	s->cipher(&s->ctx,(u8*)s->e_data,(u8*)&s->data_st);
	while (bytes) {
		w = s->op(s->fd,buffer,bytes);
		if (w == -1) {
			if (errno == EINTR) continue;
			return -1; /* note that some data may have been written */
		}
		if (w == 0) ; /* luser's fault */
		buffer += w;
		bytes -= w;
	}
	s->e_ptr = (u8*)s->e_data + s->block_size;
	return 0;
}


/* after this s->e_ptr and s->c_ptr are updated */
int crypto_buffer_flush(crypto_buffer *s)
{
	register u32 len, len2;
	register u8* e_ptr;

	len = s->e_len;
	e_ptr = s->e_ptr;
	if(e_ptr == s->e_end) {
		s->data_st.bytes = s->data_st.strlen = len;
		if (allwrite(s) == -1) return -1;
		e_ptr = s->e_ptr;
	}
	len2 = len = e_ptr + s->e_len - s->e_end;	/* used bytes in e_buffer */
	if(s->c_ptr != s->c_buffer){
		s->cipher(&s->ctx, e_ptr, s->c_buffer);
		len += s->block_size;
		len2 += s->c_ptr - s->c_buffer;
	}
	s->data_st.bytes = len;
	s->data_st.strlen = len2;
	if (allwrite(s) == -1) return -1;
	s->c_ptr = s->c_buffer;
	return 0;
}

int crypto_buffer_put(crypto_buffer *s,const u8 *buf,u32 len)
{
	register u32 size;
	register u8* e_ptr;
	register u8* e_end;
	u32 free;

	free = s->c_end - s->c_ptr;
	if (len > free) {
		if(free){
			memcpy(s->c_ptr, buf, free);
			buf += free;
			len -= free;
		}
		/* now c_buffer is full */
		e_ptr = s->e_ptr;
		e_end = s->e_end;
		size = s->block_size;
		if(e_ptr == e_end) {
			/* e_buffer full */
			s->data_st.bytes = s->data_st.strlen = s->e_len;
			if (allwrite(s) == -1) return -1;
			e_ptr = s->e_ptr;
		}
		s->cipher(&s->ctx, e_ptr, s->c_buffer);
		e_ptr += size;
		s->c_ptr =  s->c_buffer;
		/* now c_buffer is empty */
		while(len > size){
			if(e_ptr == e_end) {
				s->data_st.bytes = s->data_st.strlen = s->e_len;
				if (allwrite(s) == -1) return -1;
				e_ptr = s->e_ptr;
			}
			s->cipher(&s->ctx, e_ptr, buf);
			e_ptr += size;
			buf += size;
			len -= size;
		}
		/* don't forget */
		s->e_ptr = e_ptr;
	}
	/* now len < s->block_size + s->c_buffer - s->c_ptr */
	if(len){
		memcpy(s->c_ptr, buf, len);
		s->c_ptr += len;
	}
	return 0;
}

int crypto_buffer_putflush(crypto_buffer *s,const u8 *buf,u32 len)
{
	if (crypto_buffer_put(s, buf, len) == -1) return -1;
	return crypto_buffer_flush(s);
}