diff --git a/sys/opencrypto/cryptosoft.c b/sys/opencrypto/cryptosoft.c index 822a862235d7..6974015200de 100644 --- a/sys/opencrypto/cryptosoft.c +++ b/sys/opencrypto/cryptosoft.c @@ -248,21 +248,29 @@ swcr_encdec(struct cryptodesc *crd, struct swcr_data *sw, caddr_t buf, break; } - /* - * Warning: idat may point to garbage here, but - * we only use it in the while() loop, only if - * there are indeed enough data. - */ - idat = (char *)uio->uio_iov[ind].iov_base + k; - while (uio->uio_iov[ind].iov_len >= k + blks && i > 0) { + size_t nb, rem; + + nb = blks; + rem = uio->uio_iov[ind].iov_len - k; + idat = (char *)uio->uio_iov[ind].iov_base + k; + if (exf->reinit) { - if (crd->crd_flags & CRD_F_ENCRYPT) { + if ((crd->crd_flags & CRD_F_ENCRYPT) != 0 && + exf->encrypt_multi == NULL) exf->encrypt(sw->sw_kschedule, idat); - } else { + else if ((crd->crd_flags & CRD_F_ENCRYPT) != 0) { + nb = rounddown(rem, blks); + exf->encrypt_multi(sw->sw_kschedule, + idat, nb); + } else if (exf->decrypt_multi == NULL) exf->decrypt(sw->sw_kschedule, idat); + else { + nb = rounddown(rem, blks); + exf->decrypt_multi(sw->sw_kschedule, + idat, nb); } } else if (crd->crd_flags & CRD_F_ENCRYPT) { /* XOR with previous block/IV */ @@ -288,10 +296,10 @@ swcr_encdec(struct cryptodesc *crd, struct swcr_data *sw, caddr_t buf, ivp = nivp; } - idat += blks; - count += blks; - k += blks; - i -= blks; + idat += nb; + count += nb; + k += nb; + i -= nb; } /* @@ -566,14 +574,26 @@ swcr_authenc(struct cryptop *crp) exf->reinit(swe->sw_kschedule, iv); /* Do encryption/decryption with MAC */ - for (i = 0; i < crde->crd_len; i += blksz) { - len = MIN(crde->crd_len - i, blksz); + for (i = 0; i < crde->crd_len; i += len) { + if (exf->encrypt_multi != NULL) { + len = rounddown(crde->crd_len - i, blksz); + if (len == 0) + len = blksz; + else + len = MIN(len, sizeof(blkbuf)); + } else + len = blksz; + len = MIN(crde->crd_len - i, len); if (len < blksz) bzero(blk, blksz); crypto_copydata(crp->crp_flags, buf, crde->crd_skip + i, len, blk); if (crde->crd_flags & CRD_F_ENCRYPT) { - exf->encrypt(swe->sw_kschedule, blk); + if (exf->encrypt_multi != NULL) + exf->encrypt_multi(swe->sw_kschedule, blk, + len); + else + exf->encrypt(swe->sw_kschedule, blk); axf->Update(&ctx, blk, len); crypto_copyback(crp->crp_flags, buf, crde->crd_skip + i, len, blk); diff --git a/sys/opencrypto/xform_enc.h b/sys/opencrypto/xform_enc.h index 7bb6a9dd1a37..dc49c7f4c4ee 100644 --- a/sys/opencrypto/xform_enc.h +++ b/sys/opencrypto/xform_enc.h @@ -59,6 +59,14 @@ struct enc_xform { int (*setkey) (u_int8_t **, u_int8_t *, int len); void (*zerokey) (u_int8_t **); void (*reinit) (caddr_t, u_int8_t *); + /* + * Encrypt/decrypt 1+ blocks of input -- total size is 'len' bytes. + * Len is guaranteed to be a multiple of the defined 'blocksize'. + * Optional interface -- most useful for stream ciphers with a small + * blocksize (1). + */ + void (*encrypt_multi) (void *, uint8_t *, size_t len); + void (*decrypt_multi) (void *, uint8_t *, size_t len); };