On Wed, 31 Jul 2024 19:28:33 GMT, Weijun Wang <wei...@openjdk.org> wrote:
>> Kevin Driver has updated the pull request with a new target base due to a >> merge or a rebase. The incremental webrev excludes the unrelated changes >> brought in by the merge/rebase. The pull request contains 16 additional >> commits since the last revision: >> >> - update test to include Spi updates >> - Update with latest from master >> >> Merge remote-tracking branch 'origin/master' into kdf-jep-wip >> # Please enter a commit message to explain why this merge is necessary, >> # especially if it merges an updated upstream into a topic branch. >> # >> # Lines starting with '#' will be ignored, and an empty message aborts >> # the commit. >> - add engineGetKDFParameters to the KDFSpi >> - code review comment fix for javadoc specification >> - change course on null return values from derive methods >> - code review comments >> - threading refactor + code review comments >> - review comments >> - review comments >> - update code snippet type in KDF >> - ... and 6 more: https://git.openjdk.org/jdk/compare/d5bcb5a2...dd2ee48f > > Comments for `HKDFParameterSpec`. @wangweij: Commit https://github.com/openjdk/jdk/pull/20301/commits/30dd26e2382486b6aaec6fd0798aa77c934fcb7a contains the `synchronized` block refactor as well as changes to address your other code review comments, except where I replied or asked a follow-up. > src/java.base/share/classes/javax/crypto/KDF.java line 51: > >> 49: * <p> >> 50: * {@code KDF} objects are instantiated with the {@code getInstance} >> family of >> 51: * methods. KDF algorithm names follow a naming convention of > > I'm not sure KDF algorithms always follow this name. For example, kdf3, > scrypt, and argon2. The existing sentence seems to cover this scenario. Let me know if you disagree. `In some cases the WithPRF portion of the algorithm field may be omitted if the KDF algorithm has a fixed or default PRF.` However, if Argon2 (or another relevant example) were to require a PRF specifier at some point in the future, we would still want it to follow that form, right? `<em>Algorithm</em>With<em>PRF</em>` > src/java.base/share/classes/javax/crypto/KDF.java line 183: > >> 181: * if no additional parameters were provided >> 182: */ >> 183: public KDFParameters getKDFParameters() { > > I still want to know if this method always returns null if only > getInstance(alg) is called without params. Or, when there are default params, > they will be returned. Will discuss "offline" with the other `KDFParameters` & DPS discussion. > src/java.base/share/classes/javax/crypto/KDF.java line 274: > >> 272: * the specified algorithm >> 273: * @throws InvalidAlgorithmParameterException >> 274: * if the {@code KDFParameters} is an invalid value > > Be careful here. Do you really want to throw both `NoSuchAlgorithmException` > and `InvalidAlgorithmParameterException` here? Suppose there is an impl that > is for the algorithm name but does not accept the parameters. Which exception > do you want to throw? Is your rule always reliable? In that case, it should be an `InvalidAlgorithmParameterException` because the parameters provided were invalid. > src/java.base/share/classes/javax/crypto/KDF.java line 304: > >> 302: * if no {@code Provider} supports a {@code KDFSpi} >> implementation for >> 303: * the specified algorithm >> 304: * @throws InvalidAlgorithmParameterException > > In your current implementation, parameters are never checked. IIUC, it will > only be used (i.e. passed into the constructor of implementations) in > deriveXyz calls. > > This brings out another issue. When deriveXyz is called and and > InvalidAlgorithmParameterException is thrown, do we need if it's because the > constructor fails or the engineDeriveXyz call fails? This is a bigger problem. ~`KDFParameters` is an empty interface **and** optional. There is nothing to validate, yet. The parameters need only be passed to the implementation. The HKDF implementation does not require them.~ After discussion, I understand the first concern better. It is not related to the HKDF implementation. We will discuss this further "offline". Your second concern is relevant if `getInstance` and `deriveX` happen in the same try/catch but not otherwise. In that case, the exception message can do the work of informing the user what occurred. An implementation could also create a subclass of `InvalidAlgorithmParameterException` to indicate by type instead of message. > src/java.base/share/classes/javax/crypto/KDF.java line 404: > >> 402: * <p> >> 403: * The {@code deriveKey} method may be called multiple times on a >> particular >> 404: * {@code KDF} instance. > > Similar comment as in `KDFSpi`. If we don't want to talk about thread-safety, > I'd rather not mention anything. Same as above: I was trying to convey that deriveKey|Data are not like doFinal in that they can be called more than once on a single instance. Is there a different way to word this? Or is it not important to mention here? > src/java.base/share/classes/javax/crypto/KDFSpi.java line 38: > >> 36: * This class defines the <i>Service Provider Interface</i> (<b>SPI</b>) >> for the >> 37: * {@code KDF} class. >> 38: * <p> > > Unfortunately I cannot unresolve a resolved conversation. For my comment > above, thanks for adding the requirement on constructors. What about my other > 2 suggestions? 1) An example of a KDF implementation within the class header seems a bit excessive to me. 2) I felt that changes to the wording describing `KDFParameters` elsewhere accomplished this goal. > src/java.base/share/classes/javax/crypto/KDFSpi.java line 72: > >> 70: * <p> >> 71: * The {@code engineDeriveKey} method may be called multiple times >> on a particular >> 72: * {@code KDFSpi} instance. > > This sentence invites people asking about thread safety, but we don't want to > guarantee anything here. I was trying to convey that deriveKey|Data are not like doFinal in that they can be called more than once on a single instance. Is there a different way to word this? Or is it not important to mention here? > src/java.base/share/classes/javax/crypto/KDFSpi.java line 80: > >> 78: * >> 79: * @return a {@code SecretKey} object corresponding to a key built >> from the >> 80: * KDF output and according to the derivation parameters > > Do we need to specify that if the result is extractable then the encoding > should be the same as the output of `deriveData`? I'm really not sure about > this. Can you add some more detail here? > src/java.base/share/classes/javax/crypto/KDFSpi.java line 89: > >> 87: * KDF output and according to the derivation parameters or >> {@code null} >> 88: * in cases where an exception is not thrown but a value cannot >> be >> 89: * returned > > Do you really need to say "corresponding to" and "according to"? What else > can it be? > > It's not clear when the return value is null. This also requires users to > check for multiple invalid cases. I looked at `Cipher` and `Mac`. They do not specify in `doFinal` whether or not the result may be `null`. I think this specification is sufficient for implementations (more precise than the above mentioned classes) and allows the implementors of `KDFSpi` to return `null` in cases which we may not yet have anticipated. > src/java.base/share/classes/javax/crypto/KDFSpi.java line 93: > >> 91: >> 92: /** >> 93: * Obtains raw data from a key derivation function. > > `Obtains` or `Derives`? I think "obtains ... derivation ..." reads better than "derives ... derivation ...". Personal opinion maybe. > src/java.base/share/classes/javax/crypto/KDFSpi.java line 94: > >> 92: * if the information contained within the {@code >> kdfParameterSpec} is >> 93: * invalid or incorrect for the type of key to be derived or if >> 94: * {@code alg} is invalid or unsupported by the KDF >> implementation > > The current spec says this is bad or that is bad. Is it necessary to include > the case where the combination is invalid? > > BTW, I still don't see why it's worth mentioning "invalid" and "incorrect". > After all, the exception name only mentions invalid. Do you think it's not > precise? I am open to changing this wording, but here is my logic on the above: `or if {@code alg} is invalid or unsupported by the KDF implementation` Since the kdfParameterSpec (the `AlgorithmParameterSpec`) determines the KDF implementation, my feeling is that **if** the implementation cannot return a key of the desired algorithm, this could be because it is: `unsupported by the KDF implementation`. To me, this covers the combination case. > src/java.base/share/classes/javax/crypto/KDFSpi.java line 107: > >> 105: * @throws InvalidAlgorithmParameterException >> 106: * if the information contained within the {@code >> KDFParameterSpec} is >> 107: * invalid or incorrect for the type of key to be derived > > Do we need both `invalid` and `incorrect`? IMO they mean different things. Invalid may suggest input that is out of a particular range, for example. Incorrect input may suggest input that passes "sanitation" checks but may not make sense in a particular scenario. > src/java.base/share/classes/javax/crypto/spec/HKDFParameterSpec.java line 81: > >> 79: */ >> 80: @PreviewFeature(feature = PreviewFeature.Feature.KEY_DERIVATION) >> 81: public interface HKDFParameterSpec extends AlgorithmParameterSpec { > > Does this class need to extend `AlgorithmParameterSpec`? It's more like a > factory. Each of the inner classes extend `HKDFParameterSpec` and therefore `AlgorithmParameterSpec`. I like the inheritance model here. > src/java.base/share/classes/javax/crypto/spec/HKDFParameterSpec.java line 297: > >> 295: * @param length >> 296: * the length of the output key material (must be > 0 and >> < 255 * >> 297: * HMAC length) > > The maximum length can only be checked in the implementation and not here. > Maybe do not mention it. I disagree. I think this is a helpful bit of info for the developer who may be surprised later by an `Exception`. ------------- PR Comment: https://git.openjdk.org/jdk/pull/20301#issuecomment-2263878241 PR Review Comment: https://git.openjdk.org/jdk/pull/20301#discussion_r1699108651 PR Review Comment: https://git.openjdk.org/jdk/pull/20301#discussion_r1702170605 PR Review Comment: https://git.openjdk.org/jdk/pull/20301#discussion_r1700429103 PR Review Comment: https://git.openjdk.org/jdk/pull/20301#discussion_r1700971254 PR Review Comment: https://git.openjdk.org/jdk/pull/20301#discussion_r1699087939 PR Review Comment: https://git.openjdk.org/jdk/pull/20301#discussion_r1700878089 PR Review Comment: https://git.openjdk.org/jdk/pull/20301#discussion_r1698680917 PR Review Comment: https://git.openjdk.org/jdk/pull/20301#discussion_r1700779973 PR Review Comment: https://git.openjdk.org/jdk/pull/20301#discussion_r1700875137 PR Review Comment: https://git.openjdk.org/jdk/pull/20301#discussion_r1699086646 PR Review Comment: https://git.openjdk.org/jdk/pull/20301#discussion_r1700886443 PR Review Comment: https://git.openjdk.org/jdk/pull/20301#discussion_r1699084170 PR Review Comment: https://git.openjdk.org/jdk/pull/20301#discussion_r1700726226 PR Review Comment: https://git.openjdk.org/jdk/pull/20301#discussion_r1700733297