Example #1
0
struct ibuf *
ikev2_msg_decrypt(struct iked *env, struct iked_sa *sa,
    struct ibuf *msg, struct ibuf *src)
{
	ssize_t			 ivlen, encrlen, integrlen, blocklen,
				    outlen, tmplen;
	uint8_t			 pad = 0, *ptr;
	struct ibuf		*integr, *encr, *tmp = NULL, *out = NULL;
	off_t			 ivoff, encroff, integroff;

	if (sa == NULL ||
	    sa->sa_encr == NULL ||
	    sa->sa_integr == NULL) {
		log_debug("%s: invalid SA", __func__);
		print_hex(ibuf_data(src), 0, ibuf_size(src));
		goto done;
	}

	if (!sa->sa_hdr.sh_initiator) {
		encr = sa->sa_key_iencr;
		integr = sa->sa_key_iauth;
	} else {
		encr = sa->sa_key_rencr;
		integr = sa->sa_key_rauth;
	}

	blocklen = cipher_length(sa->sa_encr);
	ivlen = cipher_ivlength(sa->sa_encr);
	ivoff = 0;
	integrlen = hash_length(sa->sa_integr);
	integroff = ibuf_size(src) - integrlen;
	encroff = ivlen;
	encrlen = ibuf_size(src) - integrlen - ivlen;

	if (encrlen < 0 || integroff < 0) {
		log_debug("%s: invalid integrity value", __func__);
		goto done;
	}

	log_debug("%s: IV length %zd", __func__, ivlen);
	print_hex(ibuf_data(src), 0, ivlen);
	log_debug("%s: encrypted payload length %zd", __func__, encrlen);
	print_hex(ibuf_data(src), encroff, encrlen);
	log_debug("%s: integrity checksum length %zd", __func__, integrlen);
	print_hex(ibuf_data(src), integroff, integrlen);

	/*
	 * Validate packet checksum
	 */
	if ((tmp = ibuf_new(NULL, ibuf_length(integr))) == NULL)
		goto done;

	hash_setkey(sa->sa_integr, integr->buf, ibuf_length(integr));
	hash_init(sa->sa_integr);
	hash_update(sa->sa_integr, ibuf_data(msg),
	    ibuf_size(msg) - integrlen);
	hash_final(sa->sa_integr, tmp->buf, &tmplen);

	if (memcmp(tmp->buf, ibuf_data(src) + integroff, integrlen) != 0) {
		log_debug("%s: integrity check failed", __func__);
		goto done;
	}

	log_debug("%s: integrity check succeeded", __func__);
	print_hex(tmp->buf, 0, tmplen);

	ibuf_release(tmp);
	tmp = NULL;

	/*
	 * Decrypt the payload and strip any padding
	 */
	if ((encrlen % blocklen) != 0) {
		log_debug("%s: unaligned encrypted payload", __func__);
		goto done;
	}

	cipher_setkey(sa->sa_encr, encr->buf, ibuf_length(encr));
	cipher_setiv(sa->sa_encr, ibuf_data(src) + ivoff, ivlen);
	cipher_init_decrypt(sa->sa_encr);

	if ((out = ibuf_new(NULL, cipher_outlength(sa->sa_encr,
	    encrlen))) == NULL)
		goto done;

	if ((outlen = ibuf_length(out)) != 0) {
		cipher_update(sa->sa_encr, ibuf_data(src) + encroff, encrlen,
		    ibuf_data(out), &outlen);

		ptr = ibuf_seek(out, outlen - 1, 1);
		pad = *ptr;
	}

	log_debug("%s: decrypted payload length %zd/%zd padding %d",
	    __func__, outlen, encrlen, pad);
	print_hex(ibuf_data(out), 0, ibuf_size(out));

	if (ibuf_setsize(out, outlen) != 0)
		goto done;

	ibuf_release(src);
	return (out);
 done:
	ibuf_release(tmp);
	ibuf_release(out);
	ibuf_release(src);
	return (NULL);
}
Example #2
0
struct ibuf *
ikev2_msg_encrypt(struct iked *env, struct iked_sa *sa, struct ibuf *src)
{
    size_t			 len, ivlen, encrlen, integrlen, blocklen,
                     outlen;
    uint8_t			*buf, pad = 0, *ptr;
    struct ibuf		*encr, *dst = NULL, *out = NULL;

    buf = ibuf_data(src);
    len = ibuf_size(src);

    log_debug("%s: decrypted length %zu", __func__, len);
    print_hex(buf, 0, len);

    if (sa == NULL ||
            sa->sa_encr == NULL ||
            sa->sa_integr == NULL) {
        log_debug("%s: invalid SA", __func__);
        goto done;
    }

    if (sa->sa_hdr.sh_initiator)
        encr = sa->sa_key_iencr;
    else
        encr = sa->sa_key_rencr;

    blocklen = cipher_length(sa->sa_encr);
    ivlen = cipher_ivlength(sa->sa_encr);
    integrlen = hash_length(sa->sa_integr);
    encrlen = roundup(len + sizeof(pad), blocklen);
    pad = encrlen - (len + sizeof(pad));

    /*
     * Pad the payload and encrypt it
     */
    if (pad) {
        if ((ptr = ibuf_advance(src, pad)) == NULL)
            goto done;
        arc4random_buf(ptr, pad);
    }
    if (ibuf_add(src, &pad, sizeof(pad)) != 0)
        goto done;

    log_debug("%s: padded length %zu", __func__, ibuf_size(src));
    print_hex(ibuf_data(src), 0, ibuf_size(src));

    cipher_setkey(sa->sa_encr, encr->buf, ibuf_length(encr));
    cipher_setiv(sa->sa_encr, NULL, 0);	/* XXX ivlen */
    cipher_init_encrypt(sa->sa_encr);

    if ((dst = ibuf_dup(sa->sa_encr->encr_iv)) == NULL)
        goto done;

    if ((out = ibuf_new(NULL,
                        cipher_outlength(sa->sa_encr, encrlen))) == NULL)
        goto done;

    outlen = ibuf_size(out);
    cipher_update(sa->sa_encr,
                  ibuf_data(src), encrlen, ibuf_data(out), &outlen);

    if (outlen && ibuf_add(dst, ibuf_data(out), outlen) != 0)
        goto done;

    if ((ptr = ibuf_advance(dst, integrlen)) == NULL)
        goto done;
    explicit_bzero(ptr, integrlen);

    log_debug("%s: length %zu, padding %d, output length %zu",
              __func__, len + sizeof(pad), pad, ibuf_size(dst));
    print_hex(ibuf_data(dst), 0, ibuf_size(dst));

    ibuf_release(src);
    ibuf_release(out);
    return (dst);
done:
    ibuf_release(src);
    ibuf_release(out);
    ibuf_release(dst);
    return (NULL);
}