/* Packet sending/recieving. The packet construction and crypto happens in filters.cpp (C) 2004 Jack Lloyd , Todd MacDermid */ #include using namespace Botan; #include #include #define CUT_NONCE_LEN 16 #define CUT_HMAC_LEN 20 extern "C" { /* static void dump(const char* name, const MemoryRegion& x) { printf("%s = ", name); for(u32bit j = 0; j != x.size(); j++) printf("%02X", x[j]); printf("\n"); } */ int cutlass_send_process(cutlass_t* cut_handle, conn_t* conn, const struct cutlass_packet_hdr* hdr, const uint8_t* payload, uint16_t payload_len) { if((NULL == cut_handle) || (NULL == conn) || (NULL == hdr)) { cutlass_sysmsg(cut_handle, CUT_ERROR, "cutlass_send_process: " "invalid arguments: NULL ptr(s)\n"); return -1; } try { if(payload == NULL && payload_len) throw Exception("cutlass_send_process: Payload is NULL but " "payload_len != 0. WTF?!?"); Pipe* send_pipe = static_cast(conn->keyset.send_proc); if(!send_pipe) throw Exception("Outbound crypto system not initialized"); send_pipe->start_msg(); send_pipe->write(hdr->cut_type); send_pipe->write(hdr->channel_id); send_pipe->write(payload, payload_len); send_pipe->end_msg(); SecureVector packet = send_pipe->read_all(Pipe::LAST_MESSAGE); /* Following code stolen from cutlass_send in utils.c */ ssize_t sent_out = 0; if(conn->socket > 0) sent_out = send(conn->socket, packet, packet.size(), 0); else sent_out = sendto(cut_handle->listen_socket, packet, packet.size(), 0, (struct sockaddr *)&(conn->remote_addr), sizeof(struct sockaddr_in)); cutlass_sysmsg(cut_handle, CUT_SUPAA_DEBUG, "cutlass_send_process message sent\n"); if(sent_out != (ssize_t)packet.size()) { cutlass_sysmsg(cut_handle, CUT_ERROR, "send/sendto failed: %s", strerror(errno)); } } catch(std::exception& e) { cutlass_sysmsg(cut_handle, CUT_ERROR, "cutlass_send_process failed: %s\n", e.what()); return -1; } catch(...) /* just in case */ { cutlass_sysmsg(cut_handle, CUT_ERROR, "cutlass_send_process failed: (unknown)\n"); return -1; } return 0; } uint8_t* cutlass_recv_process(conn_t* conn, cutlass_packet_hdr* hdr, const uint8_t* in_packet, uint16_t in_size) { try { if(conn->keyset.opaque_mac_send == 0) // FIXME throw Exception("cutlass_recv_process: Connection keyset was NULL"); /* split it into nonce, ciphertext, and MAC */ InitializationVector iv(in_packet, CUT_NONCE_LEN); // first 16 bytes MemoryVector mac_recv(in_packet + in_size - CUT_HMAC_LEN, CUT_HMAC_LEN); if(in_size < CUT_HDR_LEN + CUT_NONCE_LEN + CUT_HMAC_LEN) throw Exception("cutlass_recv_process: Truncated packet recieved"); const byte* ciphertext = in_packet + CUT_NONCE_LEN; u32bit ciphertext_len = in_size - CUT_NONCE_LEN - CUT_HMAC_LEN; Pipe* cipher = static_cast(conn->keyset.opaque_cipher_recv); Pipe* mac = static_cast(conn->keyset.opaque_mac_recv); Keyed_Filter* cipher_obj = static_cast(conn->keyset.opaque_cipher_filter_recv); cipher_obj->set_iv(iv); /* cipher is always a CTR mode cipher, so encryption==decryption */ cipher->process_msg(ciphertext, ciphertext_len); SecureVector plain = cipher->read_all(cipher->message_count()-1); mac->process_msg(plain); SecureVector mac_computed = mac->read_all(mac->message_count()-1); if(mac_recv != mac_computed) { /* dump("mac_recv", mac_recv); dump("mac_comp", mac_computed); */ throw Integrity_Failure("Recieved and computed MACs did not match"); } /* We will only reach this point if a legit sender who has our MAC keys is messing with us and sent us a too-short packet on purpose */ if(plain.size() < CUT_HDR_LEN) throw Exception("Recieved plaintext is too small"); /* MAC is valid, unpack stuff */ hdr->cut_type = plain[0]; hdr->channel_id = plain[1]; hdr->length = make_u16bit(plain[2], plain[3]); if(hdr->length > plain.size() - CUT_HDR_LEN) throw Exception("Length in header field too large for this packet"); /* The difference between hdr->length and plain.size() [if any] is the amount of chaff that was added to the packet, ignore all that crap. */ byte* copy_of_plain = (byte*)malloc(hdr->length); if(!copy_of_plain) throw Exception("Memory exhausted, malloc failed"); memcpy(copy_of_plain, plain.begin() + CUT_HDR_LEN, hdr->length); return copy_of_plain; } catch(Integrity_Failure& e) { cutlass_sysmsg(0, CUT_SUPAA_DEBUG, "cutlass_recv_process failed: %s\n", e.what()); return NULL; } catch(std::exception& e) { cutlass_sysmsg(0, CUT_DEBUG, "cutlass_recv_process failed: %s\n", e.what()); return NULL; } catch(...) /* just in case */ { cutlass_sysmsg(0, CUT_DEBUG, "cutlass_recv_process failed: (unknown)\n"); return NULL; } fprintf(stderr, "reached HERE!\n"); return NULL; // should never reach here } }