Changeset View
Standalone View
sys/opencrypto/cryptosoft.c
Show First 20 Lines • Show All 99 Lines • ▼ Show 20 Lines | |||||
static int | static int | ||||
swcr_encdec(const struct swcr_session *ses, struct cryptop *crp) | swcr_encdec(const struct swcr_session *ses, struct cryptop *crp) | ||||
{ | { | ||||
unsigned char blk[EALG_MAX_BLOCK_LEN]; | unsigned char blk[EALG_MAX_BLOCK_LEN]; | ||||
const struct crypto_session_params *csp; | const struct crypto_session_params *csp; | ||||
const struct enc_xform *exf; | const struct enc_xform *exf; | ||||
const struct swcr_encdec *sw; | const struct swcr_encdec *sw; | ||||
void *ctx; | void *ctx; | ||||
size_t inlen, outlen; | size_t inlen, outlen, todo; | ||||
int blks, resid; | int blks, resid; | ||||
struct crypto_buffer_cursor cc_in, cc_out; | struct crypto_buffer_cursor cc_in, cc_out; | ||||
const unsigned char *inblk; | const unsigned char *inblk; | ||||
unsigned char *outblk; | unsigned char *outblk; | ||||
int error; | int error; | ||||
bool encrypting; | bool encrypting; | ||||
error = 0; | error = 0; | ||||
Show All 32 Lines | swcr_encdec(const struct swcr_session *ses, struct cryptop *crp) | ||||
inblk = crypto_cursor_segment(&cc_in, &inlen); | inblk = crypto_cursor_segment(&cc_in, &inlen); | ||||
if (CRYPTO_HAS_OUTPUT_BUFFER(crp)) { | if (CRYPTO_HAS_OUTPUT_BUFFER(crp)) { | ||||
crypto_cursor_init(&cc_out, &crp->crp_obuf); | crypto_cursor_init(&cc_out, &crp->crp_obuf); | ||||
crypto_cursor_advance(&cc_out, crp->crp_payload_output_start); | crypto_cursor_advance(&cc_out, crp->crp_payload_output_start); | ||||
} else | } else | ||||
cc_out = cc_in; | cc_out = cc_in; | ||||
outblk = crypto_cursor_segment(&cc_out, &outlen); | outblk = crypto_cursor_segment(&cc_out, &outlen); | ||||
resid = crp->crp_payload_length; | |||||
encrypting = CRYPTO_OP_IS_ENCRYPT(crp->crp_op); | encrypting = CRYPTO_OP_IS_ENCRYPT(crp->crp_op); | ||||
/* | /* | ||||
* Loop through encrypting blocks. 'inlen' is the remaining | * Loop through encrypting blocks. 'inlen' is the remaining | ||||
* length of the current segment in the input buffer. | * length of the current segment in the input buffer. | ||||
* 'outlen' is the remaining length of current segment in the | * 'outlen' is the remaining length of current segment in the | ||||
* output buffer. | * output buffer. | ||||
*/ | */ | ||||
while (resid >= blks) { | for (resid = crp->crp_payload_length; resid >= blks; resid -= todo) { | ||||
markj: I wish `blks` was called `blksz`. | |||||
Done Inline ActionsI think I even spelled it as 'block_size' in ossl(4) to be more readable. :-/ But the extra 'z' alone would help, yes. jhb: I think I even spelled it as 'block_size' in ossl(4) to be more readable. :-/ But the extra… | |||||
/* | /* | ||||
* If the current block is not contained within the | * If the current block is not contained within the | ||||
* current input/output segment, use 'blk' as a local | * current input/output segment, use 'blk' as a local | ||||
* buffer. | * buffer. | ||||
*/ | */ | ||||
if (inlen < blks) { | if (inlen < blks) { | ||||
crypto_cursor_copydata(&cc_in, blks, blk); | crypto_cursor_copydata(&cc_in, blks, blk); | ||||
inblk = blk; | inblk = blk; | ||||
inlen = blks; | |||||
} | } | ||||
if (outlen < blks) | if (outlen < blks) { | ||||
outblk = blk; | outblk = blk; | ||||
outlen = blks; | |||||
} | |||||
todo = rounddown2(MIN(resid, MIN(inlen, outlen)), blks); | |||||
if (encrypting) | if (encrypting) | ||||
exf->encrypt(ctx, inblk, outblk); | exf->encrypt_multi(ctx, inblk, outblk, todo); | ||||
else | else | ||||
exf->decrypt(ctx, inblk, outblk); | exf->decrypt_multi(ctx, inblk, outblk, todo); | ||||
if (inlen < blks) { | if (inblk == blk) { | ||||
inblk = crypto_cursor_segment(&cc_in, &inlen); | inblk = crypto_cursor_segment(&cc_in, &inlen); | ||||
} else { | } else { | ||||
crypto_cursor_advance(&cc_in, blks); | crypto_cursor_advance(&cc_in, todo); | ||||
inlen -= blks; | inlen -= todo; | ||||
inblk += blks; | inblk += todo; | ||||
if (inlen == 0) | |||||
inblk = crypto_cursor_segment(&cc_in, &inlen); | |||||
} | } | ||||
if (outlen < blks) { | if (outblk == blk) { | ||||
crypto_cursor_copyback(&cc_out, blks, blk); | crypto_cursor_copyback(&cc_out, blks, blk); | ||||
outblk = crypto_cursor_segment(&cc_out, &outlen); | outblk = crypto_cursor_segment(&cc_out, &outlen); | ||||
} else { | } else { | ||||
crypto_cursor_advance(&cc_out, blks); | crypto_cursor_advance(&cc_out, todo); | ||||
outlen -= blks; | outlen -= todo; | ||||
Not Done Inline ActionsHow can resid be smaller than both inlen and outlen? markj: How can `resid` be smaller than both `inlen` and `outlen`? | |||||
Done Inline ActionsI ran into this with chacha20-poly1305 in ossl(4) actually. The problem is that the buffer might be larger than just the cipher text. For example when you are doing ETA such as AES-CBC + SHA256 HMAC for IPsec (or even TLS 1.1). In that case inline and outlen might include the space for the MAC if the MAC is contiguous, but you don't want to encrypt the space for the MAC, just the ciphertext itself. You can reproduce this fairly easily with /dev/crypto and ETA requests since they use a flat, contiguous buffer with the MAC just after the ciphertext. jhb: I ran into this with chacha20-poly1305 in ossl(4) actually. The problem is that the buffer… | |||||
Not Done Inline ActionsHmm, I know that this situation can arise in general, I was really wondering specifically how it can happen here, since swcr_encdec() only handles plain encryption/decryption. That is, ETA and AEAD modes are not handled here. markj: Hmm, I know that this situation can arise in general, I was really wondering specifically how… | |||||
Done Inline ActionsNo, ETA uses this. swcr_eta calls swcr_encdec for the encryption/decryption step. jhb: No, ETA uses this. swcr_eta calls swcr_encdec for the encryption/decryption step. | |||||
Not Done Inline ActionsOops, I see now. markj: Oops, I see now. | |||||
outblk += blks; | outblk += todo; | ||||
if (outlen == 0) | |||||
outblk = crypto_cursor_segment(&cc_out, | |||||
&outlen); | |||||
} | } | ||||
resid -= blks; | |||||
} | } | ||||
/* Handle trailing partial block for stream ciphers. */ | /* Handle trailing partial block for stream ciphers. */ | ||||
if (resid > 0) { | if (resid > 0) { | ||||
KASSERT(exf->native_blocksize != 0, | KASSERT(exf->native_blocksize != 0, | ||||
("%s: partial block of %d bytes for cipher %s", | ("%s: partial block of %d bytes for cipher %s", | ||||
__func__, resid, exf->name)); | __func__, resid, exf->name)); | ||||
KASSERT(resid < blks, ("%s: partial block too big", __func__)); | KASSERT(resid < blks, ("%s: partial block too big", __func__)); | ||||
▲ Show 20 Lines • Show All 1,391 Lines • Show Last 20 Lines |
I wish blks was called blksz.