/* Provenance: openssl/openssl CRYPTO_ocb128_encrypt (fixed). * repo: openssl/openssl * commit: 52d23c86a54adab5ee9f80e48b242b52c4cc2347 * parent: 475c466ef2fbd8fc1df6fae1c3eed9c813fc8ff6 * commit_url: https://github.com/openssl/openssl/commit/52d23c86a54adab5ee9f80e48b242b52c4cc2347 * cve: CVE-2025-69418 * license: Apache-2.0 * function: CRYPTO_ocb128_encrypt * relpath: crypto/modes/ocb128.c */ int CRYPTO_ocb128_encrypt(OCB128_CONTEXT *ctx, const unsigned char *in, unsigned char *out, size_t len) { u64 i, all_num_blocks; size_t num_blocks, last_len; /* * Calculate the number of blocks of data to be encrypted provided now, and * so far */ num_blocks = len / 16; all_num_blocks = num_blocks + ctx->sess.blocks_processed; if (num_blocks && all_num_blocks == (size_t)all_num_blocks && ctx->stream != NULL) { size_t max_idx = 0, top = (size_t)all_num_blocks, processed_bytes = 0; /* * See how many L_{i} entries we need to process data at hand * and pre-compute missing entries in the table [if any]... */ while (top >>= 1) max_idx++; if (ocb_lookup_l(ctx, max_idx) == NULL) return 0; ctx->stream(in, out, num_blocks, ctx->keyenc, (size_t)ctx->sess.blocks_processed + 1, ctx->sess.offset.c, (const unsigned char (*)[16])ctx->l, ctx->sess.checksum.c); processed_bytes = num_blocks * 16; in += processed_bytes; out += processed_bytes; } else { /* Loop through all full blocks to be encrypted */ for (i = ctx->sess.blocks_processed + 1; i <= all_num_blocks; i++) { OCB_BLOCK *lookup; OCB_BLOCK tmp; /* Offset_i = Offset_{i-1} xor L_{ntz(i)} */ lookup = ocb_lookup_l(ctx, ocb_ntz(i)); if (lookup == NULL) return 0; ocb_block16_xor(&ctx->sess.offset, lookup, &ctx->sess.offset); memcpy(tmp.c, in, 16); in += 16; /* Checksum_i = Checksum_{i-1} xor P_i */ ocb_block16_xor(&tmp, &ctx->sess.checksum, &ctx->sess.checksum); /* C_i = Offset_i xor ENCIPHER(K, P_i xor Offset_i) */ ocb_block16_xor(&ctx->sess.offset, &tmp, &tmp); ctx->encrypt(tmp.c, tmp.c, ctx->keyenc); ocb_block16_xor(&ctx->sess.offset, &tmp, &tmp); memcpy(out, tmp.c, 16); out += 16; } } /* * Check if we have any partial blocks left over. This is only valid in the * last call to this function */ last_len = len % 16; if (last_len > 0) { OCB_BLOCK pad; /* Offset_* = Offset_m xor L_* */ ocb_block16_xor(&ctx->sess.offset, &ctx->l_star, &ctx->sess.offset); /* Pad = ENCIPHER(K, Offset_*) */ ctx->encrypt(ctx->sess.offset.c, pad.c, ctx->keyenc); /* C_* = P_* xor Pad[1..bitlen(P_*)] */ ocb_block_xor(in, pad.c, last_len, out); /* Checksum_* = Checksum_m xor (P_* || 1 || zeros(127-bitlen(P_*))) */ memset(pad.c, 0, 16); /* borrow pad */ memcpy(pad.c, in, last_len); pad.c[last_len] = 0x80; ocb_block16_xor(&pad, &ctx->sess.checksum, &ctx->sess.checksum); } ctx->sess.blocks_processed = all_num_blocks; return 1; }