Hi,

I would like to propose an implementation to support AES CBC with Ciphertext 
Stealing (CTS) in SunPKCS11, according to what has been specified in 
[JDK-8330843 CSR](https://bugs.openjdk.org/browse/JDK-8330843).

What follows are implementation notes that describe the most relevant aspects 
of the proposed change.

### Buffering

A buffering mechanism was implemented so PKCS #​11 tokens only receive 
multipart input updates (`C_EncryptUpdate` or `C_DecryptUpdate`) in multiples 
of the block size. This mechanism protects against tokens —such as NSS— that 
assume an update with data not multiple of the block size is final and do 
variant ordering between the last 2 blocks, returning an incorrect partial 
output and resetting state. For example, when encrypting, a token may receive 
an update with an input not multiple of the block size and prematurely finalize 
the operation returning the last two blocks of ciphertext according to its 
ordering. By buffering on the Java side, the token is not aware of the end of 
the stream during updates and SunPKCS11 retains full control to do the last two 
blocks at `C_EncryptFinal` or `C_DecryptFinal`. A bug in NSS (see 
[1823875](https://bugzilla.mozilla.org/show_bug.cgi?id=1823875#c2)) requires 
buffering three blocks instead of two. If this bug gets fixed, the three block 
buff
 ering will still work and allow it to support old versions of the NSS library.

### `implUpdate` implementation

The code added to `P11Cipher::implUpdate` follows the existing three-stage 
strategy: 1) Process data in the `padBuffer`, 2) Process data in the input and 
3) Buffer to `padBuffer`. Stage #​1 for CTS has some additional complexity that 
is worth describing in this section.

The stage begins by calculating the total data available (what is already 
buffered in `padBuffer` + the new input) and assigning this value to the 
variable `totalInLen`. `newPadBufferLen` is the number of bytes that must be 
buffered at the end of the update operation, irrespective of where they come 
from (`padBuffer` or input). This number of bytes is determined out of 
`totalInLen` and based on the fact that each operation must retain bytes from 
the last two —or three, for NSS— blocks in `padBuffer`, or retain whatever is 
available if less than that. `dataForP11Update` is the number of bytes to be 
passed to the token during the operation (`C_EncryptUpdate` or 
`C_DecryptUpdate` calls), irrespective of the stage in which they are passed 
and of the data source (`padBuffer` or input). This value is always a multiple 
of the block size. The relationship between the variables described so far is 
the following: `totalInLen = dataForP11Update + newPadBufferLen`.

The next step is to determine how many bytes from `dataForP11Update` must be 
passed to the token during the stage #​1 —the rest, if any, will be passed 
during the second stage—. For this calculation, we first determine how many 
bytes are needed to fill `padBuffer` up to a multiple of the block size and 
store this value in the variable `fillLen`. If plenty of bytes are available in 
the input for the token (`dataForP11Update >= padBufferLen + fillLen`), we 
complete `padBuffer` up to a multiple of the block size by taking bytes from 
the input and flush `padBuffer` entirely. Otherwise (`dataForP11Update < 
padBufferLen + fillLen`), we flush `dataForP11Update` bytes from `padBuffer`. 
Notice that in this case stage #​2 will be skipped, as there is nothing else 
available in the input for the token. Any remaining bytes in `padBuffer` are 
shifted to the beginning of the array. Stage #​3 may still buffer input to 
`padBuffer`.

### Testing

Two tests were extended for AES CBC-CTS (`TestSymmCiphersNoPad` and 
`TestSymmCiphers`) and a new one introduced 
(`TestCipherTextStealingMultipart`). Test `TestCipherTextStealingMultipart` 
cross-checks encryption and decryption operations against SunJCE's 
implementation, splitting the input into multipart operations of different 
sizes. This test covers all execution paths in `P11Cipher::implUpdate`.

In addition, no regressions have been observed in the following test categories:

* `jdk:tier1`
* `test/jdk/com/sun/crypto/provider/Cipher`
* `test/jdk/javax/crypto/Cipher`
* `test/jdk/sun/security/pkcs11/Cipher`

This work is in collaboration with @martinuy.

Thanks.-

-------------

Commit messages:
 - 8330842: Add AES CBC with Ciphertext Stealing (CTS) SunPKCS11 tests
 - 8330842: Support AES CBC with Ciphertext Stealing (CTS) in SunPKCS11
 - Fix cipher tests logging
 - Implement integer constants as enum
 - Arrange parameters of native methods evenly

Changes: https://git.openjdk.org/jdk/pull/18898/files
  Webrev: https://webrevs.openjdk.org/?repo=jdk&pr=18898&range=00
  Issue: https://bugs.openjdk.org/browse/JDK-8330842
  Stats: 604 lines in 6 files changed: 491 ins; 27 del; 86 mod
  Patch: https://git.openjdk.org/jdk/pull/18898.diff
  Fetch: git fetch https://git.openjdk.org/jdk.git pull/18898/head:pull/18898

PR: https://git.openjdk.org/jdk/pull/18898

Reply via email to