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); }
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); }