Beispiel #1
0
// Check datagram for valid HMAC
bool sptps_verify_datagram(sptps_t *s, const void *data, size_t len) {
	if (!s->instate)
		return error(s, EIO, "SPTPS state not ready to verify this datagram");

	if(len < 21)
		return error(s, EIO, "Received short packet in sptps_verify_datagram");

	uint32_t seqno;
	memcpy(&seqno, data, 4);
	seqno = ntohl(seqno);
	// TODO: check whether seqno makes sense, to avoid CPU intensive decrypt

	char buffer[len];
	size_t outlen;
	return chacha_poly1305_decrypt(s->incipher, seqno, data + 4, len - 4, buffer, &outlen);
}
Beispiel #2
0
// Decrypts ctxt, stores as an encoded uint8
int decrypt_phrase(dheluks_ctx_t *ctx, dheluks_pkg_t *pkg, dheluks_kys_t *skr, dheluks_txt_t *txt) {

	uint8_t dig[DIGEST_SIZE];

	chacha_poly1305_set_key(&ctx->ciph, skr->sharekey); //set key

	chacha_poly1305_set_nonce(&ctx->ciph, pkg->nonce); //set nonce

	chacha_poly1305_decrypt(&ctx->ciph, pkg->csize, txt->plntxt, pkg->cphtxt); //decrypt

	chacha_poly1305_digest(&ctx->ciph, DIGEST_SIZE, dig);

	if (not_equal(dig, pkg->digest, DIGEST_SIZE, "Message authentication failed.")) //if the digests aren't equal,
		return -1; //return an error

	return 0;

}
Beispiel #3
0
// Receive incoming data. Check if it contains a complete record, if so, handle it.
bool sptps_receive_data(sptps_t *s, const void *data, size_t len) {
	if(!s->state)
		return error(s, EIO, "Invalid session state zero");

	if(s->datagram)
		return sptps_receive_data_datagram(s, data, len);

	while(len) {
		// First read the 2 length bytes.
		if(s->buflen < 2) {
			size_t toread = 2 - s->buflen;
			if(toread > len)
				toread = len;

			memcpy(s->inbuf + s->buflen, data, toread);

			s->buflen += toread;
			len -= toread;
			data += toread;

			// Exit early if we don't have the full length.
			if(s->buflen < 2)
				return true;

			// Get the length bytes

			memcpy(&s->reclen, s->inbuf, 2);
			s->reclen = ntohs(s->reclen);

			// If we have the length bytes, ensure our buffer can hold the whole request.
			s->inbuf = realloc(s->inbuf, s->reclen + 19UL);
			if(!s->inbuf)
				return error(s, errno, strerror(errno));

			// Exit early if we have no more data to process.
			if(!len)
				return true;
		}

		// Read up to the end of the record.
		size_t toread = s->reclen + (s->instate ? 19UL : 3UL) - s->buflen;
		if(toread > len)
			toread = len;

		memcpy(s->inbuf + s->buflen, data, toread);
		s->buflen += toread;
		len -= toread;
		data += toread;

		// If we don't have a whole record, exit.
		if(s->buflen < s->reclen + (s->instate ? 19UL : 3UL))
			return true;

		// Update sequence number.

		uint32_t seqno = s->inseqno++;

		// Check HMAC and decrypt.
		if(s->instate) {
			if(!chacha_poly1305_decrypt(s->incipher, seqno, s->inbuf + 2UL, s->reclen + 17UL, s->inbuf + 2UL, NULL))
				return error(s, EINVAL, "Failed to decrypt and verify record");
		}

		// Append a NULL byte for safety.
		s->inbuf[s->reclen + 3UL] = 0;

		uint8_t type = s->inbuf[2];

		if(type < SPTPS_HANDSHAKE) {
			if(!s->instate)
				return error(s, EIO, "Application record received before handshake finished");
			if(!s->receive_record(s->handle, type, s->inbuf + 3, s->reclen))
				return false;
		} else if(type == SPTPS_HANDSHAKE) {
			if(!receive_handshake(s, s->inbuf + 3, s->reclen))
				return false;
		} else {
			return error(s, EIO, "Invalid record type %d", type);
		}

		s->buflen = 0;
	}

	return true;
}
Beispiel #4
0
// Receive incoming data, datagram version.
static bool sptps_receive_data_datagram(sptps_t *s, const void *vdata, size_t len) {
	const char *data = vdata;

	if(len < (s->instate ? 21 : 5))
		return error(s, EIO, "Received short packet in sptps_receive_data_datagram");

	uint32_t seqno;
	memcpy(&seqno, data, 4);
	seqno = ntohl(seqno);

	if(!s->instate) {
		if(seqno != s->inseqno)
			return error(s, EIO, "Invalid packet seqno: %d != %d", seqno, s->inseqno);

		s->inseqno = seqno + 1;

		uint8_t type = data[4];

		if(type != SPTPS_HANDSHAKE)
			return error(s, EIO, "Application record received before handshake finished");

		return receive_handshake(s, data + 5, len - 5);
	}

	// Decrypt

	char buffer[len];

	size_t outlen;

	if(!chacha_poly1305_decrypt(s->incipher, seqno, data + 4, len - 4, buffer, &outlen))
		return error(s, EIO, "Failed to decrypt and verify packet");

	// Replay protection using a sliding window of configurable size.
	// s->inseqno is expected sequence number
	// seqno is received sequence number
	// s->late[] is a circular buffer, a 1 bit means a packet has not been received yet
	// The circular buffer contains bits for sequence numbers from s->inseqno - s->replaywin * 8 to (but excluding) s->inseqno.
	if(s->replaywin) {
		if(seqno != s->inseqno) {
			if(seqno >= s->inseqno + s->replaywin * 8) {
				// TODO: Prevent packets that jump far ahead of the queue from causing many others to be dropped.
				warning(s, "Lost %d packets\n", seqno - s->inseqno);
				// Mark all packets in the replay window as being late.
				memset(s->late, 255, s->replaywin);
			} else if (seqno < s->inseqno) {
				// If the sequence number is farther in the past than the bitmap goes, or if the packet was already received, drop it.
				if((s->inseqno >= s->replaywin * 8 && seqno < s->inseqno - s->replaywin * 8) || !(s->late[(seqno / 8) % s->replaywin] & (1 << seqno % 8)))
					return error(s, EIO, "Received late or replayed packet, seqno %d, last received %d\n", seqno, s->inseqno);
			} else {
				// We missed some packets. Mark them in the bitmap as being late.
				for(int i = s->inseqno; i < seqno; i++)
					s->late[(i / 8) % s->replaywin] |= 1 << i % 8;
			}
		}

		// Mark the current packet as not being late.
		s->late[(seqno / 8) % s->replaywin] &= ~(1 << seqno % 8);
	}

	if(seqno >= s->inseqno)
		s->inseqno = seqno + 1;

	if(!s->inseqno)
		s->received = 0;
	else
		s->received++;

	// Append a NULL byte for safety.
	buffer[len - 20] = 0;

	uint8_t type = buffer[0];

	if(type < SPTPS_HANDSHAKE) {
		if(!s->instate)
			return error(s, EIO, "Application record received before handshake finished");
		if(!s->receive_record(s->handle, type, buffer + 1, len - 21))
			abort();
	} else if(type == SPTPS_HANDSHAKE) {
		if(!receive_handshake(s, buffer + 1, len - 21))
			abort();
	} else {
		return error(s, EIO, "Invalid record type %d", type);
	}

	return true;
}