/* * TEA Total Copyright (c) Alex Holden 2000, 2001. * * This code is public domain; you can do whatever you want with it, though I * would prefer you to contribute any bug fixes back to me if possible. * This software comes with NO WARRANTY WHATSOEVER, not even the implied * warranties of merchantability and fitness for a particular purpose. * * teaprot.c: Handles the TEA Total packet protocol. */ #include #include #include "teatotal.h" #include "teaprot.h" #include "btea.h" /* * Chooses the initial sequence number. This should probably be made harder to * guess. */ void choose_start_seq(teastate *state) { struct timeval tv; gettimeofday(&tv, NULL); state->seq = tv.tv_usec; } /* * Reads a TEA header, makes sure that it is valid and a version that we can * understand, and determine the byte order of the stream. */ int read_header(teastate *state) { int i; /* Read the header and packet length word */ #ifdef BUILD_BASE64 if(state->base64) i = base64_read(state->b64, state->pkt, HEADER_LEN + 4); else #endif i = safe_read(state->infd, state->pkt, HEADER_LEN + 4); if(!i) return 1; /* End of file */ if(i != HEADER_LEN + 4) return -1; /* Read error */ /* Check for the TEA magic number first */ if(memcmp(state->pkt->hdr, TEA_HEADER, HEADER_LEN)) return -1; /* Check that it uses a supported encoding */ if((state->pkt->encoding != ENC_TEA) #ifdef BUILD_HUFFMAN && (state->pkt->encoding != ENC_TEA_HUFF) #endif ) return -1; /* Check that the byte order is valid */ if((state->pkt->byte_order != LENDIAN) && (state->pkt->byte_order != BENDIAN)) return -1; return 0; /* Success */ } /* * Reads a block of encrypted data from the input stream, decrypts it, and * writes the result to the output stream. */ int decode_block(teastate *state) { int aligned_len, i; u16 pktlen; u32 seq; /* Try to read the packet header and return if it failed */ if((i = read_header(state))) return i; /* Read the packet length word and convert it to the local byte order * if necessary */ if(state->pkt->byte_order == HOST_BYTE_ORDER) pktlen = state->pkt->datalen; else pktlen = (((state->pkt->datalen & 0xff00) >> 8) | ((state->pkt->datalen & 0x00ff) << 8)); /* Check that the packet isn't too big */ if(pktlen > MAXPKTLEN + 4) die("Packet too big"); /* Data blocks are always an exact number of 32 bit words */ aligned_len = pktlen + (pktlen % 4) + 4; /* Read the encrypted (and possibly compressed) data */ #ifdef BUILD_BASE64 if(state->base64) { if(base64_read(state->b64, &state->pkt->seq, aligned_len) < aligned_len) return -1; /* Read error */ } else #endif if(safe_read(state->infd, &state->pkt->seq, aligned_len) < aligned_len) return -1; /* Read error */ /* decrypt the data, handling reversed byte order if necessary */ if(state->pkt->byte_order == HOST_BYTE_ORDER) btea(&state->pkt->seq, state->k, aligned_len / 4, 1, 0); else btea(&state->pkt->seq, state->k, aligned_len / 4, 1, 1); #ifdef BUILD_HUFFMAN /* If the data is compressed, try to decompress it */ if(state->pkt->encoding == ENC_TEA_HUFF) { /* If this is the first compressed packet we've got, * initialise the huffstate structure */ if(!state->compress) { state->compress = 1; state->huff = huff_init(MAXPKTLEN + 4); state->huff->inbuf = (u8 *) &state->pkt->seq; } if((i = huffdec(state->huff, pktlen)) == -1) die("Packet decompression failed"); pktlen = i - 4; memcpy(&state->pkt->seq, state->huff->outbuf, i); } #endif /* Read the sequence number and convert the byte order if necessary */ seq = state->pkt->seq; if(state->pkt->byte_order != HOST_BYTE_ORDER) seq = swapu32(seq); /* Check the sequence number is correct */ if(state->first_block) state->seq = seq; else if(seq != ++state->seq) die("Decoding error"); state->first_block = 0; /* Write out the decrypted data, without the sequence number */ if(safe_write(state->outfd, state->pkt->data, pktlen) != pktlen) return -2; /* Write error */ return 0; /* Success */ } /* * Reads a block of data from the input stream, encrypts it, and writes the * result to the output stream. */ int encode_block(teastate *state) { int i, block_len, clen; /* Copy the TEA header into the packet */ memcpy(state->pkt->hdr, TEA_HEADER, HEADER_LEN); /* Set the header's byte order field to our local byte order */ state->pkt->byte_order = HOST_BYTE_ORDER; /* Read a block of up to MAXPKTLEN bytes */ i = safe_read(state->infd, state->pkt->data, MAXPKTLEN); if(i < 0) return -1; /* Read error */ if(i == 0) return 1; /* End of file */ /* Set the sequence number */ state->pkt->seq = state->seq++; #ifdef BUILD_HUFFMAN if(state->compress && ((clen = huffenc(state->huff, i + 4)) != -1)) { state->pkt->encoding = ENC_TEA_HUFF; i = clen; memcpy(&state->pkt->seq, state->huff->outbuf, i); } else state->pkt->encoding = ENC_TEA; #else state->pkt->encoding = ENC_TEA; #endif /* Set the packet length word */ state->pkt->datalen = i; /* The block is always an exact number of 32 bit words and includes * the 4 byte sequence word. */ block_len = 4 + i + (i % 4); /* encrypt the data */ btea(&state->pkt->seq, state->k, block_len / 4, 0, 0); /* The entire packet includes both the encrypted data and the header */ block_len += HEADER_LEN + 4; #ifdef BUILD_BASE64 /* If Base64 encoding is enabled, write the data to the b64 engine */ if(state->base64) { if(base64_write(state->b64, state->pkt, block_len) != block_len) return -2; /* Write error */ return 0; /* Otherwise, just write it directly out */ } else #endif if(safe_write(state->outfd, state->pkt, block_len) != block_len) return -2; /* Write error */ return 0; /* Success */ }