#include "includes.h"
#include "dbutil.h"
#include "buffer.h"
#define BUF_MAX_INCR 1000000000
#define BUF_MAX_SIZE 1000000000
#define BUF_MAX_MPINT (8240 / 8)
buffer* buf_new(unsigned
int
size) {
buffer* buf;
if
(size > BUF_MAX_SIZE) {
dropbear_exit(
"buf->size too big"
);
}
buf = (buffer*)m_malloc(
sizeof
(buffer)+size);
if
(size > 0) {
buf->data = (unsigned
char
*)buf +
sizeof
(buffer);
}
else
{
buf->data = NULL;
}
buf->size = size;
return
buf;
}
void
buf_free(buffer* buf) {
m_free(buf);
}
void
buf_burn(buffer* buf) {
m_burn(buf->data, buf->size);
}
buffer* buf_resize(buffer *buf, unsigned
int
newsize) {
if
(newsize > BUF_MAX_SIZE) {
dropbear_exit(
"buf->size too big"
);
}
buf = m_realloc(buf,
sizeof
(buffer)+newsize);
buf->data = (unsigned
char
*)buf +
sizeof
(buffer);
buf->size = newsize;
buf->len = MIN(newsize, buf->len);
buf->pos = MIN(newsize, buf->pos);
return
buf;
}
buffer* buf_newcopy(buffer* buf) {
buffer* ret;
ret = buf_new(buf->len);
ret->len = buf->len;
if
(buf->len > 0) {
memcpy
(ret->data, buf->data, buf->len);
}
return
ret;
}
void
buf_setlen(buffer* buf, unsigned
int
len) {
if
(len > buf->size) {
dropbear_exit(
"Bad buf_setlen"
);
}
buf->len = len;
}
void
buf_incrlen(buffer* buf, unsigned
int
incr) {
if
(incr > BUF_MAX_INCR || buf->len + incr > buf->size) {
dropbear_exit(
"Bad buf_incrlen"
);
}
buf->len += incr;
}
void
buf_setpos(buffer* buf, unsigned
int
pos) {
if
(pos > buf->len) {
dropbear_exit(
"Bad buf_setpos"
);
}
buf->pos = pos;
}
void
buf_incrwritepos(buffer* buf, unsigned
int
incr) {
if
(incr > BUF_MAX_INCR || buf->pos + incr > buf->size) {
dropbear_exit(
"Bad buf_incrwritepos"
);
}
buf->pos += incr;
if
(buf->pos > buf->len) {
buf->len = buf->pos;
}
}
void
buf_incrpos(buffer* buf,
int
incr) {
if
(incr > BUF_MAX_INCR
|| incr < -BUF_MAX_INCR
|| (unsigned
int
)((
int
)buf->pos + incr) > buf->len
|| ((
int
)buf->pos + incr) < 0) {
dropbear_exit(
"Bad buf_incrpos"
);
}
buf->pos += incr;
}
unsigned
char
buf_getbyte(buffer* buf) {
if
(buf->pos >= buf->len) {
dropbear_exit(
"Bad buf_getbyte"
);
}
return
buf->data[buf->pos++];
}
unsigned
char
buf_getbool(buffer* buf) {
unsigned
char
b;
b = buf_getbyte(buf);
if
(b != 0)
b = 1;
return
b;
}
void
buf_putbyte(buffer* buf, unsigned
char
val) {
if
(buf->pos >= buf->len) {
buf_incrlen(buf, 1);
}
buf->data[buf->pos] = val;
buf->pos++;
}
unsigned
char
* buf_getptr(buffer* buf, unsigned
int
len) {
if
(len > BUF_MAX_INCR || buf->pos + len > buf->len) {
dropbear_exit(
"Bad buf_getptr"
);
}
return
&buf->data[buf->pos];
}
unsigned
char
* buf_getwriteptr(buffer* buf, unsigned
int
len) {
if
(len > BUF_MAX_INCR || buf->pos + len > buf->size) {
dropbear_exit(
"Bad buf_getwriteptr"
);
}
return
&buf->data[buf->pos];
}
char
* buf_getstring(buffer* buf, unsigned
int
*retlen) {
unsigned
int
len;
char
* ret;
len = buf_getint(buf);
if
(len > MAX_STRING_LEN) {
dropbear_exit(
"String too long"
);
}
if
(retlen != NULL) {
*retlen = len;
}
ret = m_malloc(len+1);
memcpy
(ret, buf_getptr(buf, len), len);
buf_incrpos(buf, len);
ret[len] =
'\0'
;
return
ret;
}
buffer * buf_getstringbuf(buffer *buf) {
buffer *ret = NULL;
unsigned
int
len = buf_getint(buf);
if
(len > MAX_STRING_LEN) {
dropbear_exit(
"String too long"
);
}
ret = buf_new(len);
memcpy
(buf_getwriteptr(ret, len), buf_getptr(buf, len), len);
buf_incrpos(buf, len);
buf_incrlen(ret, len);
return
ret;
}
void
buf_eatstring(buffer *buf) {
buf_incrpos( buf, buf_getint(buf) );
}
unsigned
int
buf_getint(buffer* buf) {
unsigned
int
ret;
LOAD32H(ret, buf_getptr(buf, 4));
buf_incrpos(buf, 4);
return
ret;
}
void
buf_putint(buffer* buf,
int
unsigned val) {
STORE32H(val, buf_getwriteptr(buf, 4));
buf_incrwritepos(buf, 4);
}
void
buf_putstring(buffer* buf,
const
char
* str, unsigned
int
len) {
buf_putint(buf, len);
buf_putbytes(buf, (
const
unsigned
char
*)str, len);
}
void
buf_putbufstring(buffer *buf,
const
buffer* buf_str) {
buf_putstring(buf, (
const
char
*)buf_str->data, buf_str->len);
}
void
buf_putbytes(buffer *buf,
const
unsigned
char
*bytes, unsigned
int
len) {
memcpy
(buf_getwriteptr(buf, len), bytes, len);
buf_incrwritepos(buf, len);
}
void
buf_putmpint(buffer* buf, mp_int * mp) {
unsigned
int
len, pad = 0;
TRACE2((
"enter buf_putmpint"
))
dropbear_assert(mp != NULL);
if
(SIGN(mp) == MP_NEG) {
dropbear_exit(
"negative bignum"
);
}
if
(USED(mp) == 1 && DIGIT(mp, 0) == 0) {
len = 0;
}
else
{
len = mp_count_bits(mp);
pad = (len%8 == 0) ? 1 : 0;
len = len / 8 + 1;
}
buf_putint(buf, len);
if
(len > 0) {
if
(pad) {
buf_putbyte(buf, 0x00);
}
if
(mp_to_unsigned_bin(mp, buf_getwriteptr(buf, len-pad)) != MP_OKAY) {
dropbear_exit(
"mpint error"
);
}
buf_incrwritepos(buf, len-pad);
}
TRACE2((
"leave buf_putmpint"
))
}
int
buf_getmpint(buffer* buf, mp_int* mp) {
unsigned
int
len;
len = buf_getint(buf);
if
(len == 0) {
mp_zero(mp);
return
DROPBEAR_SUCCESS;
}
if
(len > BUF_MAX_MPINT) {
return
DROPBEAR_FAILURE;
}
if
(*buf_getptr(buf, 1) & (1 << (CHAR_BIT-1))) {
return
DROPBEAR_FAILURE;
}
if
(mp_read_unsigned_bin(mp, buf_getptr(buf, len), len) != MP_OKAY) {
return
DROPBEAR_FAILURE;
}
buf_incrpos(buf, len);
return
DROPBEAR_SUCCESS;
}