kee

Offline IOU signer with QR as transport
git clone git://holbrook.no/kee-gtk4.git
Info | Log | Files | Refs | README | LICENSE

transport.c (8046B)


      1 #include <stddef.h>
      2 #include <stdlib.h>
      3 #include <string.h>
      4 
      5 #include <b64/cencode.h>
      6 #include <b64/cdecode.h>
      7 #include <zlib.h>
      8 
      9 #include "transport.h"
     10 #include "ledger.h"
     11 #include "debug.h"
     12 
     13 
     14 static int pack_compress(char *in, size_t in_len, char *out, size_t *out_len) {
     15 	int r;
     16 	z_stream z;
     17 
     18 	z.zalloc = Z_NULL;
     19 	z.zfree = Z_NULL;
     20 	z.opaque = Z_NULL;
     21 	z.data_type = Z_TEXT;
     22 	z.next_in = (unsigned char*)in;
     23 	z.avail_in = in_len;
     24 	z.next_out = (unsigned char*)out;
     25 	z.avail_out = *out_len;
     26 
     27 	r = deflateInit(&z, Z_BEST_COMPRESSION);
     28 	if (r != Z_OK) {
     29 		return 1;
     30 	}
     31 	r = deflate(&z, Z_FINISH);
     32 	if (r != Z_STREAM_END) {
     33 		return 2;
     34 	}
     35 	*out_len = z.total_out;
     36 
     37 	return 0;
     38 }
     39 
     40 static int pack_encode(char *in, size_t in_len, char *out, size_t *out_len) {
     41 	char *p;
     42 	int r;
     43 	base64_encodestate bst;
     44 
     45 	base64_init_encodestate(&bst);
     46 
     47 	p = out;
     48 	r = base64_encode_block(in, in_len, p, &bst);
     49 	if (r == 0) {
     50 		return 1;
     51 	}
     52 	*out_len = r;
     53 	p += r;
     54 	r = base64_encode_blockend(p, &bst);
     55 	if (r == 0) {
     56 		return 1;
     57 	}
     58 	*out_len += r;
     59 
     60 	return 0;
     61 
     62 }
     63 
     64 static int unpack_decompress(char *in, size_t in_len, char *out, size_t *out_len) {
     65 	int r;
     66 	z_stream z;
     67 
     68 	z.zalloc = Z_NULL;
     69 	z.zfree = Z_NULL;
     70 	z.opaque = Z_NULL;
     71 	z.data_type = Z_TEXT;
     72 	z.next_in = (unsigned char*)in;
     73 	z.avail_in = in_len;
     74 	z.next_out = (unsigned char*)out;
     75 	z.avail_out = *out_len;
     76 
     77 	r = inflateInit(&z);
     78 	if (r != Z_OK) {
     79 		return 1;
     80 	}
     81 	r = inflate(&z, Z_FINISH);
     82 	if (r != Z_STREAM_END) {
     83 		return 2;
     84 	}
     85 	*out_len = z.total_out;
     86 
     87 	return 0;
     88 }
     89 
     90 static int unpack_decode(char *in, size_t in_len, char *out, size_t *out_len) {
     91 	int r;
     92 	base64_decodestate dst;
     93 
     94 	base64_init_decodestate(&dst);
     95 	r = base64_decode_block(in, in_len, out, &dst);
     96 	if (r == 0) {
     97 		return 1;	
     98 	}
     99 	*out_len = r;
    100 
    101 	return 0;
    102 }
    103 
    104 int pack(char *in, size_t in_len, char *out, size_t *out_len) {
    105 	int r;
    106 	char *buf;
    107 
    108 	buf = malloc(*out_len);
    109 
    110 	r = pack_compress(in, in_len, buf, out_len);
    111 	if (r) {
    112 		free(buf);	
    113 		return ERR_FAIL;
    114 	}
    115 	
    116 	r = pack_encode(buf, *out_len, out, out_len);
    117 	if (r) {
    118 		free(buf);	
    119 		return ERR_FAIL;
    120 	}
    121 	if (*(out+*out_len-1) == 0x0a) {
    122 		*(out+*out_len-1) = 0;
    123 		(*out_len)--;	
    124 	}
    125 
    126 	free(buf);
    127 	return ERR_OK;
    128 }
    129 
    130 int unpack(char *in, size_t in_len, char *out, size_t *out_len) {
    131 	int r;
    132 	char *buf;
    133 	size_t c;
    134 
    135 	buf = malloc(*out_len);
    136 
    137 	c = *out_len;
    138 	r = unpack_decode(in, in_len, buf, &c);
    139 	if (r) {
    140 		free(buf);	
    141 		return ERR_FAIL;
    142 	}
    143 
    144 	r = unpack_decompress(buf, c, out, out_len);
    145 	if (r) {
    146 		free(buf);	
    147 		return ERR_FAIL;
    148 	}
    149 
    150 	free(buf);
    151 	return ERR_OK;
    152 }
    153 
    154 /// \todo implement checksum
    155 int kee_transport_single(struct kee_transport_t *trans, enum kee_transport_mode_e mode, char cmd, size_t data_len) {
    156 	memset(trans, 0, sizeof(struct kee_transport_t));
    157 	if (cmd >= KEE_N_CMD) {
    158 		return ERR_INVALID_CMD;	
    159 	}
    160 	if (data_len == 0) {
    161 		trans->chunker.data_len = KEE_TRANSPORT_CHUNK_MAX_SIZE;
    162 	} else {
    163 		trans->chunker.data_len = data_len + 1;
    164 	}
    165 	trans->data = trans->chunker.data;
    166 	trans->cmd = (char*)trans->data;
    167 	trans->mode = mode;
    168 	*(trans->cmd) = cmd;
    169 	trans->chunker.crsr = 1;
    170 
    171 	return ERR_OK;
    172 }
    173 
    174 //int kee_transport_import(struct kee_transport_t *trans, enum kee_transport_mode_e mode, const char *data, size_t data_len) {
    175 //int kee_transport_import(struct kee_transport_t *trans, enum kee_transport_mode_e mode) {
    176 //	memset(trans, 0, sizeof(struct kee_transport_t));
    177 //	//memcpy(trans->chunker.data, data, data_len);
    178 //	//if (*data & KEE_CMD_CHUNKED) {
    179 //	//	return ERR_UNSUPPORTED;
    180 //	//}
    181 //	trans->chunker.crsr = 1;
    182 //	trans->chunker.data_len = KEE_TRANSPORT_CHUNK_MAX_SIZE;
    183 //	trans->mode = mode;
    184 //	*trans->cmd = KEE_CMD_IMPORT;
    185 //
    186 //	return ERR_OK;
    187 //}
    188 
    189 void kee_transport_set_response(struct kee_transport_t *trans) {
    190 	if (trans->state == 0) {
    191 		*trans->cmd |= KEE_CMD_SIGN_RESPONSE;
    192 	}
    193 }
    194 
    195 int kee_transport_write(struct kee_transport_t *trans, const char *in, size_t in_len) {
    196 	if (trans->state) {
    197 		return ERR_FAIL;
    198 	}
    199 	memcpy(trans->data + trans->chunker.crsr, in, in_len);
    200 	trans->chunker.crsr += in_len;
    201 	return ERR_OK;
    202 }
    203 
    204 /// \todo consider pass validation function
    205 /// \todo implement chunking
    206 int kee_transport_next(struct kee_transport_t *trans, char *out, size_t *out_len) {
    207 	int r;
    208 	size_t l;
    209 	size_t remaining;
    210 
    211 	if (trans->state) {
    212 		if (trans->state > 1) {
    213 			return ERR_FAIL;
    214 		}
    215 	} else {
    216 		trans->chunker.data_len = trans->chunker.crsr;
    217 		trans->chunker.crsr = 0;
    218 		trans->state = 1;
    219 	}
    220 
    221 	remaining = trans->chunker.data_len - trans->chunker.crsr;
    222 	if (remaining < KEE_TRANSPORT_CHUNK_MAX_SIZE - 1) {
    223 		l = remaining;
    224 	} else {
    225 		return 1; // unimplemented
    226 		//l = KEE_TRANSPORT_CHUNK_SIZE;
    227 	}
    228 
    229 	/// \todo when chunking, dont forget this as a separate step before start to chunk
    230 	switch (trans->mode) {
    231 		case KEE_TRANSPORT_BASE64:
    232 			r = pack(trans->chunker.data, l, out, out_len);
    233 			if (r) {
    234 				return ERR_FAIL;
    235 			}
    236 			break;
    237 		case KEE_TRANSPORT_RAW:
    238 			memcpy(out, trans->chunker.data, l);
    239 			break;
    240 		default:
    241 			return ERR_FAIL;
    242 	}
    243 	return 0;	
    244 }
    245 
    246 
    247 int kee_transport_read(struct kee_transport_t *trans, char *out, size_t *out_len) {
    248 	int r;
    249 
    250 	if (*trans->cmd == KEE_CMD_IMPORT) {
    251 		trans->data++;
    252 	}
    253 
    254 	switch (trans->mode) {
    255 		case KEE_TRANSPORT_BASE64:
    256 			r = unpack(trans->data, trans->chunker.data_len, out, out_len);
    257 			if (r) {
    258 				return ERR_FAIL;
    259 			}
    260 			break;
    261 		case KEE_TRANSPORT_RAW:
    262 			memcpy(out, trans->data, trans->chunker.data_len);
    263 			break;
    264 		default:
    265 			return ERR_FAIL;
    266 	}
    267 
    268 	if (*trans->cmd == KEE_CMD_IMPORT) {
    269 		/// \todo handle this crop better, should not require any of these copies
    270 		*trans->cmd = *out;
    271 		memcpy(trans->data, out+1, *out_len);
    272 		(*out_len)--;
    273 		memcpy(out, trans->data, *out_len);
    274 	}
    275 
    276 	return ERR_OK;
    277 }
    278 
    279 //
    280 //// make sure reported sizes add up to data boundary
    281 //static int validate_multi(char *data, size_t data_len) {
    282 //	char *p;
    283 //	size_t c;
    284 //	unsigned short l;
    285 //
    286 //	c = 0;
    287 //	p = data;
    288 //	while (c < data_len - 1) {
    289 //		memcpy(&l, p, sizeof(unsigned short));
    290 //		if (l == 0) {
    291 //			break;
    292 //		}
    293 //		if (is_le()) {
    294 //			flip_endian(2, &l);
    295 //		}
    296 //		c += l + sizeof(unsigned short);
    297 //		p += c;
    298 //	}
    299 //	if (p == data) {
    300 //		return ERR_FAIL;
    301 //	}
    302 //	return c != data_len - 1;
    303 //}
    304 //
    305 ///// \todo check state
    306 //int kee_transport_validate(struct kee_transport_t *trans) {
    307 //	int r;
    308 //	char cmd;
    309 //
    310 //	cmd = *trans->cmd & 0x1f;
    311 //
    312 //	if (cmd == 0) {
    313 //		r = validate_multi(trans->chunker.data + 1, trans->chunker.data_len);	
    314 //		if (r) {
    315 //			return ERR_FAIL;
    316 //		}	
    317 //	}
    318 //	return ERR_OK;
    319 //}
    320 
    321 
    322 //int kee_transport_encode_ledger(struct kee_transport_t *trans_ledger, struct kee_transport_t *trans_item, struct kee_transport_t *trans_out, enum kee_transport_mode_e mode) {
    323 //	int r;
    324 //	char *p;
    325 //	unsigned short part_length;
    326 //	size_t l;
    327 //	size_t c;
    328 //	char *out;
    329 //
    330 //	l = sizeof(unsigned short);
    331 //	out = malloc(trans_ledger->chunker.data_len + trans_item->chunker.data_len + (l * 2) + 1);
    332 //	// only use raw mode for this, since we are joining data
    333 //	if (trans_ledger->mode != KEE_TRANSPORT_RAW) {
    334 //		return ERR_FAIL;
    335 //	}
    336 //	if (trans_item->mode != KEE_TRANSPORT_RAW) {
    337 //		return ERR_FAIL;
    338 //	}
    339 //	c = 0;
    340 //	p = out;
    341 //	part_length = (unsigned short)trans_ledger->chunker.data_len;
    342 //	r = to_endian(TO_ENDIAN_BIG, 2, &part_length);
    343 //	if (r) {
    344 //		return ERR_FAIL;
    345 //	}
    346 //	memcpy(p, &part_length, l);
    347 //	p += sizeof(unsigned short);
    348 //	c += l;
    349 //	memcpy(p, trans_ledger->chunker.data, trans_ledger->chunker.data_len);
    350 //	p += trans_ledger->chunker.data_len;
    351 //	c += trans_ledger->chunker.data_len;
    352 //
    353 //	part_length = (unsigned short)trans_item->chunker.data_len;
    354 //	r = to_endian(TO_ENDIAN_BIG, 2, &part_length);
    355 //	if (r) {
    356 //		return ERR_FAIL;
    357 //	}
    358 //	memcpy(p, &part_length, l);
    359 //	p += l;
    360 //	c += l;
    361 //	memcpy(p, trans_item->chunker.data, trans_item->chunker.data_len);
    362 //	p += trans_item->chunker.data_len;
    363 //	c += trans_item->chunker.data_len;
    364 //
    365 //	r = kee_transport_single(trans_out, mode, KEE_CMD_PACKED, c);
    366 //	if (r) {
    367 //		return ERR_FAIL;
    368 //	}
    369 //	r = kee_transport_write(trans_out, out, c);
    370 //	if (r) {
    371 //		return ERR_FAIL;
    372 //	}
    373 //
    374 //	free(out);
    375 //
    376 //	return ERR_OK;
    377 //}