Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

8248268: Support KWP in addition to KW #2404

Closed
wants to merge 10 commits into from

Conversation

valeriepeng
Copy link

@valeriepeng valeriepeng commented Feb 4, 2021

This change updates SunJCE provider as below:

  • updated existing AESWrap support with AES/KW/NoPadding cipher transformation.
  • added support for AES/KWP/NoPadding and AES/KW/PKCS5Padding.

Existing AESWrap impl, i.e. AESWrapCipher class, is re-factored and renamed to KeyWrapCipher class. The W and W_inverse functions are moved to KWUtil class. The KW and KWP support are in the new AESKeyWrap and AESKeyWrapPadded classes which extend FeedbackCipher and used in KeyWrapCipher class. To minimize data copying, AESKeyWrap and AESKeyWrapPadded will do the crypto operation over the same input buffer which is allocated and managed by KeyWrapCipher class.

Also note that existing AESWrap impl does not take IV. However, the corresponding PKCS#11 mechanisms do, so I added support for accepting IVs to both KW and KWP.

Thanks,
Valerie


Progress

  • Change must not contain extraneous whitespace
  • Commit message must refer to an issue
  • Change must be properly reviewed

Issue

Reviewers

Reviewing

Using git

Checkout this PR locally:
$ git fetch https://git.openjdk.java.net/jdk pull/2404/head:pull/2404
$ git checkout pull/2404

Update a local copy of the PR:
$ git checkout pull/2404
$ git pull https://git.openjdk.java.net/jdk pull/2404/head

Using Skara CLI tools

Checkout this PR locally:
$ git pr checkout 2404

View PR using the GUI difftool:
$ git pr show -t 2404

Using diff file

Download this PR as a diff file:
https://git.openjdk.java.net/jdk/pull/2404.diff

Updated existing AESWrap support with AES/KW/NoPadding cipher
transformation. Added support for AES/KWP/NoPadding and
AES/KW/PKCS5Padding support to SunJCE provider.
@bridgekeeper
Copy link

bridgekeeper bot commented Feb 4, 2021

👋 Welcome back valeriep! A progress list of the required criteria for merging this PR into master will be added to the body of your pull request. There are additional pull request commands available for use with this pull request.

@openjdk openjdk bot added the rfr Pull request is ready for review label Feb 4, 2021
@valeriepeng
Copy link
Author

/csr

@openjdk
Copy link

openjdk bot commented Feb 4, 2021

@valeriepeng The following label will be automatically applied to this pull request:

  • security

When this pull request is ready to be reviewed, an "RFR" email will be sent to the corresponding mailing list. If you would like to change these labels, use the /label pull request command.

@openjdk openjdk bot added security security-dev@openjdk.org csr Pull request needs approved CSR before integration labels Feb 4, 2021
@openjdk
Copy link

openjdk bot commented Feb 4, 2021

@valeriepeng has indicated that a compatibility and specification (CSR) request is needed for this pull request.
@valeriepeng please create a CSR request and add link to it in JDK-8248268. This pull request cannot be integrated until the CSR request is approved.

@mlbridge
Copy link

mlbridge bot commented Feb 4, 2021

@bridgekeeper
Copy link

bridgekeeper bot commented Mar 4, 2021

@valeriepeng This pull request has been inactive for more than 4 weeks and will be automatically closed if another 4 weeks passes without any activity. To avoid this, simply add a new comment to the pull request. Feel free to ask for assistance if you need help with progressing this pull request towards integration!

@valeriepeng
Copy link
Author

Ping, anyone has time to review this?

throw new IllegalBlockSizeException("data should" +
" be at least 16 bytes and multiples of 8");
}
// assert ptOfs == 0; ct == pt; ctOfs == 0;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this a missing code assertion?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm, there are some inconsistencies in how the variables are named. I will remove this comment and update the method javadoc accordingly, i.e. ptOfs, ct, ctOfs have all been renamed to dummyN.

Comment on lines 186 to 193
byte[] ivOut = new byte[ICV1.length];
W_INV(ct, ctLen, ivOut, embeddedCipher);
ctLen -= SEMI_BLKSIZE;

// check against icv and fail if not match
if (!Arrays.equals(ivOut, 0, ICV1.length, this.iv, 0, ICV1.length)) {
throw new IllegalBlockSizeException("Integrity check failed");
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It feels like an odd asymmetry that we validate the IV upon decryption in AESKeyWrap but the IV is prepended in KeyWrapCipher.writeIvSemiBlock. I'm worried that by separating this logic like this it is easier for us to get it wrong (or break it in the future).

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm, another alternative is to move this logic to the underlying key wrap impl, i.e. AESKeyWrap and AESKeyWrapPadded, and start saving data after the first 8-byte in KeyWrapCipher class.

Comment on lines 67 to 69
if (!Arrays.equals(ivAndLen, 0, ICV2.length, icv, 0, ICV2.length)) {
throw new IllegalBlockSizeException("Integrity check failed");
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

While I cannot find any public discussion of this, I'm always uncomfortable checking the plaintext (prior to authentication) against a known value in non-constant time. I'm worried that this (and the equivalent in the unpadded version) might be a problem in the future.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is just IV and length, not plaintext. So, I didn't use the constant time array check. I can switch to the constant time version, it's trivial.

Comment on lines 469 to 507
if (!decrypting && dataIdx == 0) {
writeIvSemiBlock(dataBuf);
}

if (inLen > 0) {
store(in, inOfs, inLen);
}

// if enc, add padding
if (!decrypting) {
int actualLen = dataIdx - SEMI_BLKSIZE;
if (padding != null) {
int paddingLen = padding.padLength(actualLen);
// check and re-size dataBuf if needed
store(null, 0, paddingLen);
try {
padding.padWithLen(dataBuf, dataIdx, paddingLen);
dataIdx += paddingLen;
} catch (ShortBufferException sbe) {
// should never happen
throw new AssertionError();
}
}
}
try {
int outLen;
if (decrypting) {
outLen = cipher.decryptFinal(dataBuf, 0, dataIdx, null, -1);
// unpad if padding is used
if (padding != null) {
int padIdx = padding.unpad(dataBuf, 0, outLen);
if (padIdx <= 0) {
throw new BadPaddingException("Bad Padding: " + padIdx);
}
outLen = padIdx;
}
} else {
outLen = cipher.encryptFinal(dataBuf, 0, dataIdx, null, -1);
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we extract this shared logic (among the different versions of engineDoFinal) into a separate helper method so that the different engineDoFinal methods just need to handle their specific differences (such as returning Arrays.copyOf(dataBuf, outLen) or calling System.arraycopy(dataBuf, 0, out, outOfs, outLen); return outLen;).

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Right, I agree. Will look into it.

@mlbridge
Copy link

mlbridge bot commented Mar 23, 2021

Mailing list message from Michael StJohns on security-dev:

On 3/23/2021 4:15 PM, Greg Rubin wrote:

177: System.out.println("Testing " + ALGO);
178: c = Cipher.getInstance(ALGO, "SunJCE");
179: for (int i = 0; i < MAX_KWP_PAD_LEN; i++) {
I see that here (and earlier) we do test all padding lengths. I'd still like some KATs generated by a known good implementation to ensure that we are not just compatible with ourselves.

http://csrc.nist.gov/groups/STM/cavp/documents/mac/kwtestvectors.zip has
the NIST test vectors.? See
https://csrc.nist.gov/CSRC/media/Projects/Cryptographic-Algorithm-Validation-Program/documents/mac/KWVS.pdf
for details.

Mike

-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://mail.openjdk.java.net/pipermail/security-dev/attachments/20210323/e1a400db/attachment.htm>

@mlbridge
Copy link

mlbridge bot commented Mar 23, 2021

Mailing list message from Michael StJohns on security-dev:

On 3/22/2021 5:43 PM, Valerie Peng wrote:

This change updates SunJCE provider as below:
- updated existing AESWrap support with AES/KW/NoPadding cipher transformation.
- added support for AES/KWP/NoPadding and AES/KW/PKCS5Padding.

Existing AESWrap impl, i.e. AESWrapCipher class, is re-factored and renamed to KeyWrapCipher class. The W and W_inverse functions are moved to KWUtil class. The KW and KWP support are in the new AESKeyWrap and AESKeyWrapPadded classes which extend FeedbackCipher and used in KeyWrapCipher class. To minimize data copying, AESKeyWrap and AESKeyWrapPadded will do the crypto operation over the same input buffer which is allocated and managed by KeyWrapCipher class.

Also note that existing AESWrap impl does not take IV. However, the corresponding PKCS#11 mechanisms do, so I added support for accepting IVs to both KW and KWP.

Thanks,
Valerie

KeyWrapCipher.java:

  \/\*\*

212 * Sets the padding mechanism of this cipher. Currently, only
213 * "NoPadding" scheme is accepted for this cipher.
214 *
215 * @param padding the padding mechanism
216 *
217 * @exception NoSuchPaddingException if the requested padding mechanism
218 * does not match the supported padding scheme
219 */
220 @Override
221 protected void engineSetPadding(String padding)
222 throws NoSuchPaddingException {
223 if ((this.padding == null && !"NoPadding".equalsIgnoreCase(padding)) ||
224 this.padding instanceof PKCS5Padding &&
225 "PKCS5Padding".equalsIgnoreCase(padding)) {
226 throw new NoSuchPaddingException();
227 }
228 }

Shouldn't this be rejecting PKCS5Padding?

Actually, I keep wondering why this isn't? AES/KW/NoPadding,
AES/KW/KWPPadding and AES/KW/AutoPadding where the latter doesn't take a
user provided IV, but figures out which of the two default IV values to
use based on whether the input is a multiple of the blocksize or not?

Decrypting is similar - do the decryption, and check which IV you get to
figure out padded or not padded.

Mike

-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://mail.openjdk.java.net/pipermail/security-dev/attachments/20210323/0372393b/attachment-0001.htm>

@valeriepeng
Copy link
Author

Mailing list message from Michael StJohns on security-dev:

On 3/23/2021 4:15 PM, Greg Rubin wrote:

177: System.out.println("Testing " + ALGO);
178: c = Cipher.getInstance(ALGO, "SunJCE");
179: for (int i = 0; i < MAX_KWP_PAD_LEN; i++) {
I see that here (and earlier) we do test all padding lengths. I'd still like some KATs generated by a known good implementation to ensure that we are not just compatible with ourselves.

http://csrc.nist.gov/groups/STM/cavp/documents/mac/kwtestvectors.zip has
the NIST test vectors.? See
https://csrc.nist.gov/CSRC/media/Projects/Cryptographic-Algorithm-Validation-Program/documents/mac/KWVS.pdf
for details.

Mike

-------------- next part --------------
An HTML attachment was scrubbed...
URL: https://mail.openjdk.java.net/pipermail/security-dev/attachments/20210323/e1a400db/attachment.htm

Sure, I will add some, thanks Mike for the pointers.

@valeriepeng
Copy link
Author

Hi Mike,

Please find comments in line below.

KeyWrapCipher.java:

212 * Sets the padding mechanism of this cipher. Currently, only
213 * "NoPadding" scheme is accepted for this cipher.
214 *
215 * @param padding the padding mechanism
216 *
217 * @exception NoSuchPaddingException if the requested padding mechanism
218 * does not match the supported padding scheme
219 */
220 @OverRide
221 protected void engineSetPadding(String padding)
222 throws NoSuchPaddingException {
223 if ((this.padding == null && !"NoPadding".equalsIgnoreCase(padding)) ||
224 this.padding instanceof PKCS5Padding &&
225 "PKCS5Padding".equalsIgnoreCase(padding)) {
226 throw new NoSuchPaddingException();
227 }
228 }

Shouldn't this be rejecting PKCS5Padding?

Right, will fix this and update the javadoc above as well.

Actually, I keep wondering why this isn't? AES/KW/NoPadding,
AES/KW/KWPPadding and AES/KW/AutoPadding where the latter doesn't take a
user provided IV, but figures out which of the two default IV values to
use based on whether the input is a multiple of the blocksize or not?

Decrypting is similar - do the decryption, and check which IV you get to
figure out padded or not padded.

The way I view it, both KW and KWP are modes. For interoperability, I referenced the corresponding mechanism definition from PKCS#11 v3.0 and base the java transformation on the corresponding PKCS#11 mechanisms. As for AES/KW/AutoPadding, it's an interesting idea, is there any other provider or library support it? To encrypt data of any size, we can just use AES/KWP/NoPadding. Is there additional benefit for this AutoPadding scheme?

Thanks,
Valerie

Mike

-------------- next part --------------
An HTML attachment was scrubbed...
URL: https://mail.openjdk.java.net/pipermail/security-dev/attachments/20210323/0372393b/attachment-0001.htm

Address review comments
Add more test vectors
Copy link
Contributor

@SalusaSecondus SalusaSecondus left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd advise against the AutoPadding scheme without more careful analysis and discussion. Have we seen either KW or KWP specifications which recommend that behavior?

My concern is that we've seen cases before where two different cryptographic algorithms could be selected transparently upon decryption and it lowers the security of the overall system. (A variant of in-band signalling.) The general consensus that I've been seeing in the (applied) cryptographic community is strongly away from in-band signalling and towards the decryptor fully specifying the algorithms and behavior prior to attempting decryption.

Comment on lines 67 to 71
boolean match = true;
for (int i = 0; i < ICV2.length; i++) {
match &= (ivAndLen[i] == iv[i]);
}
if (!match) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

True nitpick (thus ignorable): I believe that using bitwise math is slightly more resistant to compiler and/or CPU optimization to defend against timing-attacks. (Since I haven't even seen an attack against KW or KWP, this is simply a note in general rather than something which needs to be fixed.)

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sure, I can change to below:

Suggested change
boolean match = true;
for (int i = 0; i < ICV2.length; i++) {
match &= (ivAndLen[i] == iv[i]);
}
if (!match) {
int match = 0;
for (int i = 0; i < ICV2.length; i++) {
match |= (ivAndLen[i] ^ iv[i]);
}
if (match != 0) {
throw new IllegalBlockSizeException("Integrity check failed");
}

Is this what you have in mind?

@mlbridge
Copy link

mlbridge bot commented Apr 3, 2021

Mailing list message from Michael StJohns on security-dev:

On 4/3/2021 11:35 AM, Greg Rubin wrote:

I'd advise against the AutoPadding scheme without more careful analysis and discussion. Have we seen either KW or KWP specifications which recommend that behavior?

My concern is that we've seen cases before where two different cryptographic algorithms could be selected transparently upon decryption and it lowers the security of the overall system. (A variant of in-band signalling.) The general consensus that I've been seeing in the (applied) cryptographic community is strongly away from in-band signalling and towards the decryptor fully specifying the algorithms and behavior prior to attempting decryption.

I think this is in response to my comment?

The wrap function can take a Key as an input and can have the unwrap
method produce a Key as an output - indeed it should be used primarily
for this rather than the more general encrypt/decrypt functions.? The
problem is that the encoding of the key may not be known prior to the
attempt to wrap it - hence it's not known whether or not padding need be
applied.? This is especially problematic with HSMs.? Providing an
AutoPadding mode would allow the wrapping algorithm to decide whether to
use either of the RFC 3394 (AKA KW) Integrity Check Value (ICV) or the
RFC5649 (aka KWP) value and padding length.

The key thing to remember here is that the IV (initial value - RFC
language) /ICV (integrity check value - NIST language)actually isn't an
IV(initialization vector) in the ordinary meaning, it's a flag, padding
and integrity indicator and will be fixed for all keys of the same
length that use the specified values.?? E.g. unlike other modes that
require an initialization vector, you don't need to know the ICV to
decrypt the underlying key stream, but you can? (and for that matter
MUST) easily test the recovered first block against the expected ICV to
determine whether the output needs padding removed or not.

FWIW, the actual cryptographic operations between padded data and
non-padded data (of the right multiple length) are identical. It's only
the pre or post processing that's looking for different data.

Obviously, this doesn't work if someone provides their own IV - but
that's fairly unlikely.? CF CCM and its non-normative example formatting
function appendix A -? each and every implementation I've seen uses that
formatting function, even though it isn't actually required by the
standard.? I'd be surprised if anyone decided to use a different set of
non-standard IV values.

If an AutoPadding mode were implemented, I'd throw exceptions if someone
tried to set the IV.

Later, Mike

@mlbridge
Copy link

mlbridge bot commented Apr 7, 2021

Mailing list message from Greg Rubin on security-dev:

Mike,

Yes, this was in response to your comment.

I'm aware that the IV really serves more as an integrity check and mode
signalling mechanism than anything else. My concern is that in the past few
years I've seen various issues related to "in band signalling" where
something about the ciphertext (or directly associated metadata) changes
how the data is decrypted and authenticated. This has reached the level
where several cryptographic forums I participate in are starting to
consider it a full anti-pattern.

The proposed "AutoPadding" mode is an example of in-band signalling in
which an externally provided ciphertext changes how it is interpreted.
While I cannot personally think of a specific risk in this case, I would be
inclined not to include this mode unless there is a strong driving need
from our users. While I have definitely seen people not knowing if their
data was encrypted with KW or KW+PKCS5/7, I haven't personally seen
uncertainty between KW and KWP. (I also haven't worked with all possible
HSMs, just a few of them.) So, from a position of caution, I'd avoid
"AutoPadding", but this is a preference based on current best-practice
rather than a strong objection based on specific concerns or risks.

Thank you,
Greg

On Sat, Apr 3, 2021 at 4:38 PM Michael StJohns <mstjohns at comcast.net> wrote:

On 4/3/2021 11:35 AM, Greg Rubin wrote:

I'd advise against the AutoPadding scheme without more careful analysis
and discussion. Have we seen either KW or KWP specifications which
recommend that behavior?

My concern is that we've seen cases before where two different
cryptographic algorithms could be selected transparently upon decryption
and it lowers the security of the overall system. (A variant of in-band
signalling.) The general consensus that I've been seeing in the (applied)
cryptographic community is strongly away from in-band signalling and
towards the decryptor fully specifying the algorithms and behavior prior to
attempting decryption.

I think this is in response to my comment?

The wrap function can take a Key as an input and can have the unwrap
method produce a Key as an output - indeed it should be used primarily
for this rather than the more general encrypt/decrypt functions. The
problem is that the encoding of the key may not be known prior to the
attempt to wrap it - hence it's not known whether or not padding need be
applied. This is especially problematic with HSMs. Providing an
AutoPadding mode would allow the wrapping algorithm to decide whether to
use either of the RFC 3394 (AKA KW) Integrity Check Value (ICV) or the
RFC5649 (aka KWP) value and padding length.

The key thing to remember here is that the IV (initial value - RFC
language) /ICV (integrity check value - NIST language)actually isn't an
IV(initialization vector) in the ordinary meaning, it's a flag, padding
and integrity indicator and will be fixed for all keys of the same
length that use the specified values. E.g. unlike other modes that
require an initialization vector, you don't need to know the ICV to
decrypt the underlying key stream, but you can (and for that matter
MUST) easily test the recovered first block against the expected ICV to
determine whether the output needs padding removed or not.

FWIW, the actual cryptographic operations between padded data and
non-padded data (of the right multiple length) are identical. It's only
the pre or post processing that's looking for different data.

Obviously, this doesn't work if someone provides their own IV - but
that's fairly unlikely. CF CCM and its non-normative example formatting
function appendix A - each and every implementation I've seen uses that
formatting function, even though it isn't actually required by the
standard. I'd be surprised if anyone decided to use a different set of
non-standard IV values.

If an AutoPadding mode were implemented, I'd throw exceptions if someone
tried to set the IV.

Later, Mike

-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://mail.openjdk.java.net/pipermail/security-dev/attachments/20210407/f47a485a/attachment-0001.htm>

@mlbridge
Copy link

mlbridge bot commented Apr 7, 2021

Mailing list message from Michael StJohns on security-dev:

On 4/7/2021 1:28 PM, Greg Rubin wrote:

Mike,

Yes, this was in response to your comment.

I'm aware that the IV really serves more as an integrity check and
mode signalling mechanism than anything else. My concern is that in
the past few years I've seen various issues related to "in band
signalling" where something about the ciphertext (or directly
associated metadata) changes how the data is decrypted and
authenticated. This has reached the level where several cryptographic
forums I participate in are starting to consider it a full anti-pattern.

The proposed "AutoPadding" mode is an example of in-band signalling in
which an externally provided ciphertext? changes how it is
interpreted. While I cannot personally think of a specific risk in
this case, I would be inclined not to include this mode unless there
is a strong driving need from our users. While I have definitely seen
people not knowing if their data was encrypted with KW or KW+PKCS5/7,
I haven't personally?seen uncertainty between KW and KWP. (I also
haven't worked with all possible HSMs, just a few of them.) So, from a
position of caution, I'd avoid "AutoPadding", but this is a preference
based on current best-practice rather than a strong objection based on
specific concerns or risks.

I sent a note off to the original mode inventor - Russ Housley:

Can you think of any reason why there might be an issue with providing
an autopadding mode for KW/KWP (e.g. select which to use based on the
input data for encrypt and determine which was used after running the
unwrap function but before removing the initial block and any padding)?

I got back:

As long as every party supports both modes, you could use KW id [sic -
I think he meant "is"] the inout is a multiple of 64 bits, otherwise
use KWP. ?Of course, the algorithm identifier needs to be set
appropriately.

Which sort of confirms what I thought, but added a question:? Are there
algorithm OIDs for KW with PKCS5 padding or do people just use the KW
OID( 2.16.840.1.101.3.4.1.{5,25,45}?? As far as I can tell, there are no
OIDs for KW with PKCS5.

Does there need to be an autopad OID?

If it were me, I'd be avoiding implementing the PKCS5 padding mode
here.? I can't actually find a specification that includes it and it
looks like a hack that was fixed by the specification of KWP.? I'd
prefer not to extend the hack's lifetime, given that RFC5649 is 10+
years old.

WRT to HSM uncertainty, I ran into problems especially trying to wrap
RSA private keys.? Turned out that some encoded as 8 byte multiples and
some did not.? In any event, I mentioned HSMs, but I really care about
the general model for the JCE.? I'd *really* like to avoid having to
have to first figure out the private key encoding length (which may be
difficult as a provider may not choose to export an unwrapped private
key even if its a software provider) before choosing the wrapping
algorithm.?? Doing it that way just fits the JCE model better.

At some point, there needs to be an RFC written that specifies the
default encodings for keys wrapped by this algorithm.

Later, Mike

Thank you,
Greg

On Sat, Apr 3, 2021 at 4:38 PM Michael StJohns <mstjohns at comcast.net
<mailto:mstjohns at comcast.net>> wrote:

On 4\/3\/2021 11\:35 AM\, Greg Rubin wrote\:
> I\'d advise against the AutoPadding scheme without more careful
analysis and discussion\. Have we seen either KW or KWP
specifications which recommend that behavior\?
>
> My concern is that we\'ve seen cases before where two different
cryptographic algorithms could be selected transparently upon
decryption and it lowers the security of the overall system\. \(A
variant of in\-band signalling\.\) The general consensus that I\'ve
been seeing in the \(applied\) cryptographic community is strongly
away from in\-band signalling and towards the decryptor fully
specifying the algorithms and behavior prior to attempting decryption\.

I think this is in response to my comment\?

The wrap function can take a Key as an input and can have the unwrap
method produce a Key as an output \- indeed it should be used
primarily
for this rather than the more general encrypt\/decrypt functions\.\? The
problem is that the encoding of the key may not be known prior to the
attempt to wrap it \- hence it\'s not known whether or not padding
need be
applied\.\? This is especially problematic with HSMs\.\? Providing an
AutoPadding mode would allow the wrapping algorithm to decide
whether to
use either of the RFC 3394 \(AKA KW\) Integrity Check Value \(ICV\) or
the
RFC5649 \(aka KWP\) value and padding length\.

The key thing to remember here is that the IV \(initial value \- RFC
language\) \/ICV \(integrity check value \- NIST language\)actually
isn\'t an
IV\(initialization vector\) in the ordinary meaning\, it\'s a flag\,
padding
and integrity indicator and will be fixed for all keys of the same
length that use the specified values\.\?\? E\.g\. unlike other modes that
require an initialization vector\, you don\'t need to know the ICV to
decrypt the underlying key stream\, but you can\? \(and for that matter
MUST\) easily test the recovered first block against the expected
ICV to
determine whether the output needs padding removed or not\.

FWIW\, the actual cryptographic operations between padded data and
non\-padded data \(of the right multiple length\) are identical\. It\'s
only
the pre or post processing that\'s looking for different data\.

Obviously\, this doesn\'t work if someone provides their own IV \- but
that\'s fairly unlikely\.\? CF CCM and its non\-normative example
formatting
function appendix A \-\? each and every implementation I\'ve seen
uses that
formatting function\, even though it isn\'t actually required by the
standard\.\? I\'d be surprised if anyone decided to use a different
set of
non\-standard IV values\.

If an AutoPadding mode were implemented\, I\'d throw exceptions if
someone
tried to set the IV\.

Later\, Mike

-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://mail.openjdk.java.net/pipermail/security-dev/attachments/20210407/b498eacf/attachment.htm>

@mlbridge
Copy link

mlbridge bot commented Apr 7, 2021

Mailing list message from Michael StJohns on security-dev:

*sigh* Minor correction in line.

On 4/7/2021 2:49 PM, Michael StJohns wrote:

On 4/7/2021 1:28 PM, Greg Rubin wrote:

Mike,

Yes, this was in response to your comment.

I'm aware that the IV really serves more as an integrity check and
mode signalling mechanism than anything else. My concern is that in
the past few years I've seen various issues related to "in band
signalling" where something about the ciphertext (or directly
associated metadata) changes how the data is decrypted and
authenticated. This has reached the level where several cryptographic
forums I participate in are starting to consider it a full anti-pattern.

The proposed "AutoPadding" mode is an example of in-band signalling
in which an externally provided ciphertext changes how it is
interpreted. While I cannot personally think of a specific risk in
this case, I would be inclined not to include this mode unless there
is a strong driving need from our users. While I have definitely seen
people not knowing if their data was encrypted with KW or KW+PKCS5/7,
I haven't personally?seen uncertainty between KW and KWP. (I also
haven't worked with all possible HSMs, just a few of them.)? So, from
a position of caution, I'd avoid "AutoPadding", but this is a
preference based on current best-practice rather than a strong
objection based on specific concerns or risks.

I sent a note off to the original mode inventor - Russ Housley:

Can you think of any reason why there might be an issue with
providing an autopadding mode for KW/KWP (e.g. select which to use
based on the input data for encrypt and determine which was used
after running the unwrap function but before removing the initial
block and any padding)?

I got back:

As long as every party supports both modes, you could use KW id [sic
- I think he meant "is"]

"if" not "is"

the inout is a multiple of 64 bits, otherwise use KWP. ?Of course,
the algorithm identifier needs to be set appropriately.

Which sort of confirms what I thought, but added a question: Are there
algorithm OIDs for KW with PKCS5 padding or do people just use the KW
OID( 2.16.840.1.101.3.4.1.{5,25,45}?? As far as I can tell, there are
no OIDs for KW with PKCS5.

Does there need to be an autopad OID?

If it were me, I'd be avoiding implementing the PKCS5 padding mode
here.? I can't actually find a specification that includes it and it
looks like a hack that was fixed by the specification of KWP.? I'd
prefer not to extend the hack's lifetime, given that? RFC5649 is 10+
years old.

WRT to HSM uncertainty, I ran into problems especially trying to wrap
RSA private keys.? Turned out that some encoded as 8 byte multiples
and some did not.? In any event, I mentioned HSMs, but I really care
about the general model for the JCE. I'd *really* like to avoid having
to have to first figure out the private key encoding length (which may
be difficult as a provider may not choose to export an unwrapped
private key even if its a software provider) before choosing the
wrapping algorithm.?? Doing it that way just fits the JCE model better.

At some point, there needs to be an RFC written that specifies the
default encodings for keys wrapped by this algorithm.

Later, Mike

Thank you,
Greg

On Sat, Apr 3, 2021 at 4:38 PM Michael StJohns <mstjohns at comcast.net
<mailto:mstjohns at comcast.net>> wrote:

On 4\/3\/2021 11\:35 AM\, Greg Rubin wrote\:
> I\'d advise against the AutoPadding scheme without more careful
analysis and discussion\. Have we seen either KW or KWP
specifications which recommend that behavior\?
>
> My concern is that we\'ve seen cases before where two different
cryptographic algorithms could be selected transparently upon
decryption and it lowers the security of the overall system\. \(A
variant of in\-band signalling\.\) The general consensus that I\'ve
been seeing in the \(applied\) cryptographic community is strongly
away from in\-band signalling and towards the decryptor fully
specifying the algorithms and behavior prior to attempting
decryption\.

I think this is in response to my comment\?

The wrap function can take a Key as an input and can have the unwrap
method produce a Key as an output \- indeed it should be used
primarily
for this rather than the more general encrypt\/decrypt functions\.\?
The
problem is that the encoding of the key may not be known prior to
the
attempt to wrap it \- hence it\'s not known whether or not padding
need be
applied\.\? This is especially problematic with HSMs\. Providing an
AutoPadding mode would allow the wrapping algorithm to decide
whether to
use either of the RFC 3394 \(AKA KW\) Integrity Check Value \(ICV\)
or the
RFC5649 \(aka KWP\) value and padding length\.

The key thing to remember here is that the IV \(initial value \- RFC
language\) \/ICV \(integrity check value \- NIST language\)actually
isn\'t an
IV\(initialization vector\) in the ordinary meaning\, it\'s a flag\,
padding
and integrity indicator and will be fixed for all keys of the same
length that use the specified values\.\?\? E\.g\. unlike other modes that
require an initialization vector\, you don\'t need to know the ICV to
decrypt the underlying key stream\, but you can\? \(and for that matter
MUST\) easily test the recovered first block against the expected
ICV to
determine whether the output needs padding removed or not\.

FWIW\, the actual cryptographic operations between padded data and
non\-padded data \(of the right multiple length\) are identical\.
It\'s only
the pre or post processing that\'s looking for different data\.

Obviously\, this doesn\'t work if someone provides their own IV \- but
that\'s fairly unlikely\.\? CF CCM and its non\-normative example
formatting
function appendix A \-\? each and every implementation I\'ve seen
uses that
formatting function\, even though it isn\'t actually required by the
standard\.\? I\'d be surprised if anyone decided to use a different
set of
non\-standard IV values\.

If an AutoPadding mode were implemented\, I\'d throw exceptions if
someone
tried to set the IV\.

Later\, Mike

-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://mail.openjdk.java.net/pipermail/security-dev/attachments/20210407/4a0fa3fe/attachment-0001.htm>

@mlbridge
Copy link

mlbridge bot commented Apr 7, 2021

Mailing list message from Greg Rubin on security-dev:

I agree that the response from Housley certainly supports that
"AutoPadding" is likely a safe mode to use. I still would prefer not to see
it (keeping things simple) but don't really have any objections to it.

For KW+PKCS5, I have (unfortunately) seen this deployed in the real world
and had to assist Java developers in manually removing PKCS5 padding from
the result of KW decryption. (No OIDs were used in any parts of these
designs, so I cannot say what would have been used.) So, since I had to
help multiple people write this code already, I really cannot object to
adding support for it. The JCA supports many algorithms which shouldn't be
used but exist for compatibility and interactions with other systems (DES,
RC4, etc.). This would be yet another algorithm of that type. (Arguably,
both KW and KWP should probably be replaced by AES-GCM for modern systems,
but that is an entirely different discussion.)

As for OIDs, that seems somewhat unrelated and I don't think we need
something new. I've rarely needed to use the OIDs for KW or KWP and
suspect that we could simply choose the one that corresponds to the
algorithm we actually used.

I've also encountered HSMs which added PKCS5 padding prior to KW so that
all output was 8-byte aligned. That was very frustrating to deal with as it
was not clearly documented at the time.

Finally, I believe that the encoding question is separate from the wrapping
question. Each key type should (and generally does) define how to encode it
as an octet string. Then you apply the relevant wrapping/unwrapping
algorithm to that encoding. KW/KWP should not define how to encode keys any
more than RSA should define how to wrap a serialized RSA key. (However, I
may have misunderstood your comment "... RFC written that specifies the
default encodings for keys wrapped by this algorithm.")

Greg

On Wed, Apr 7, 2021 at 11:51 AM Michael StJohns <mstjohns at comcast.net>
wrote:

*sigh* Minor correction in line.

On 4/7/2021 2:49 PM, Michael StJohns wrote:

On 4/7/2021 1:28 PM, Greg Rubin wrote:

Mike,

Yes, this was in response to your comment.

I'm aware that the IV really serves more as an integrity check and mode
signalling mechanism than anything else. My concern is that in the past few
years I've seen various issues related to "in band signalling" where
something about the ciphertext (or directly associated metadata) changes
how the data is decrypted and authenticated. This has reached the level
where several cryptographic forums I participate in are starting to
consider it a full anti-pattern.

The proposed "AutoPadding" mode is an example of in-band signalling in
which an externally provided ciphertext changes how it is interpreted.
While I cannot personally think of a specific risk in this case, I would be
inclined not to include this mode unless there is a strong driving need
from our users. While I have definitely seen people not knowing if their
data was encrypted with KW or KW+PKCS5/7, I haven't personally seen
uncertainty between KW and KWP. (I also haven't worked with all possible
HSMs, just a few of them.) So, from a position of caution, I'd avoid
"AutoPadding", but this is a preference based on current best-practice
rather than a strong objection based on specific concerns or risks.

I sent a note off to the original mode inventor - Russ Housley:

Can you think of any reason why there might be an issue with providing an
autopadding mode for KW/KWP (e.g. select which to use based on the input
data for encrypt and determine which was used after running the unwrap
function but before removing the initial block and any padding)?

I got back:

As long as every party supports both modes, you could use KW id [sic - I
think he meant "is"]

"if" not "is"

the inout is a multiple of 64 bits, otherwise use KWP. Of course, the
algorithm identifier needs to be set appropriately.

Which sort of confirms what I thought, but added a question: Are there
algorithm OIDs for KW with PKCS5 padding or do people just use the KW OID(
2.16.840.1.101.3.4.1.{5,25,45}? As far as I can tell, there are no OIDs
for KW with PKCS5.

Does there need to be an autopad OID?

If it were me, I'd be avoiding implementing the PKCS5 padding mode here.
I can't actually find a specification that includes it and it looks like a
hack that was fixed by the specification of KWP. I'd prefer not to extend
the hack's lifetime, given that RFC5649 is 10+ years old.

WRT to HSM uncertainty, I ran into problems especially trying to wrap RSA
private keys. Turned out that some encoded as 8 byte multiples and some
did not. In any event, I mentioned HSMs, but I really care about the
general model for the JCE. I'd *really* like to avoid having to have to
first figure out the private key encoding length (which may be difficult as
a provider may not choose to export an unwrapped private key even if its a
software provider) before choosing the wrapping algorithm. Doing it that
way just fits the JCE model better.

At some point, there needs to be an RFC written that specifies the default
encodings for keys wrapped by this algorithm.

Later, Mike

Thank you,
Greg

On Sat, Apr 3, 2021 at 4:38 PM Michael StJohns <mstjohns at comcast.net>
wrote:

On 4/3/2021 11:35 AM, Greg Rubin wrote:

I'd advise against the AutoPadding scheme without more careful analysis
and discussion. Have we seen either KW or KWP specifications which
recommend that behavior?

My concern is that we've seen cases before where two different
cryptographic algorithms could be selected transparently upon decryption
and it lowers the security of the overall system. (A variant of in-band
signalling.) The general consensus that I've been seeing in the (applied)
cryptographic community is strongly away from in-band signalling and
towards the decryptor fully specifying the algorithms and behavior prior to
attempting decryption.

I think this is in response to my comment?

The wrap function can take a Key as an input and can have the unwrap
method produce a Key as an output - indeed it should be used primarily
for this rather than the more general encrypt/decrypt functions. The
problem is that the encoding of the key may not be known prior to the
attempt to wrap it - hence it's not known whether or not padding need be
applied. This is especially problematic with HSMs. Providing an
AutoPadding mode would allow the wrapping algorithm to decide whether to
use either of the RFC 3394 (AKA KW) Integrity Check Value (ICV) or the
RFC5649 (aka KWP) value and padding length.

The key thing to remember here is that the IV (initial value - RFC
language) /ICV (integrity check value - NIST language)actually isn't an
IV(initialization vector) in the ordinary meaning, it's a flag, padding
and integrity indicator and will be fixed for all keys of the same
length that use the specified values. E.g. unlike other modes that
require an initialization vector, you don't need to know the ICV to
decrypt the underlying key stream, but you can (and for that matter
MUST) easily test the recovered first block against the expected ICV to
determine whether the output needs padding removed or not.

FWIW, the actual cryptographic operations between padded data and
non-padded data (of the right multiple length) are identical. It's only
the pre or post processing that's looking for different data.

Obviously, this doesn't work if someone provides their own IV - but
that's fairly unlikely. CF CCM and its non-normative example formatting
function appendix A - each and every implementation I've seen uses that
formatting function, even though it isn't actually required by the
standard. I'd be surprised if anyone decided to use a different set of
non-standard IV values.

If an AutoPadding mode were implemented, I'd throw exceptions if someone
tried to set the IV.

Later, Mike

-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://mail.openjdk.java.net/pipermail/security-dev/attachments/20210407/07f8e86a/attachment.htm>

@bridgekeeper
Copy link

bridgekeeper bot commented May 11, 2021

@valeriepeng This pull request has been inactive for more than 4 weeks and will be automatically closed if another 4 weeks passes without any activity. To avoid this, simply add a new comment to the pull request. Feel free to ask for assistance if you need help with progressing this pull request towards integration!

@openjdk
Copy link

openjdk bot commented May 13, 2021

@valeriepeng this pull request can not be integrated into master due to one or more merge conflicts. To resolve these merge conflicts and update this pull request you can run the following commands in the local repository for your personal fork:

git checkout JDK-8248268
git fetch https://git.openjdk.java.net/jdk master
git merge FETCH_HEAD
# resolve conflicts and follow the instructions given by git merge
git commit -m "Merge master"
git push

@openjdk openjdk bot added the merge-conflict Pull request has merge conflict with target branch label May 13, 2021
@openjdk openjdk bot added rfr Pull request is ready for review and removed merge-conflict Pull request has merge conflict with target branch labels May 14, 2021
Comment on lines -49 to +50
core = new BlockCipherParamsCore(AESConstants.AES_BLOCK_SIZE);
core = new BlockCipherParamsCore(AESConstants.AES_BLOCK_SIZE, 4, 8);
Copy link
Member

@XueleiFan XueleiFan May 21, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A cipher object may not take different IV sizes at the same time. I was just wondering how it could be used in practice. Maybe something like:

AlgorithmParameters algParams = AlgorithmParameters.getInstance("AES");
algParams.init(ivParameterSpec);

The IV parameter is given with the init() method. Then, it may be not necessary to construct the BlockCipherParamsCore object will all potential IV sizes. See the comments in BlockCipherParamsCore.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cipher objects normally takes just one iv size. BlockCipherParamsCore is used by various impls of AlgorithmParametersSpi class which may be used with different block cipher algorithms. The iv parameter is given with the AlgorithmParametersSpi.init() method and invalid iv will lead to exceptions. Since there are iv size checks built in BlockCipherParamsCore already, it seems safer to relax the check a bit for AES (4 and 8 for KWP and KW). The other choice is to just remove the size check from BlockCipherParamsCore for AES algorithm, but then we'd not be able to reject invalid iv lengths as before.

@@ -48,8 +49,11 @@
private int block_size = 0;
private byte[] iv = null;

BlockCipherParamsCore(int blksize) {
private int[] moreSizes = null;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The moreSizes is not used other than the init() method field. It may be not easy to check the specific size if we cache all supported sized in the object. For example, if the required IV size if 8 bytes, it may be a problem about how to make sure the iv size is 8 bytes exactly for a specific algorithm.

Maybe, we could just have a ivSize filed. The default value is block_size, which coupe be set with the init(ivParameterSpec) method.

    ....
    private int ivSize;
    ...
   BlockCipherParamsCore(int blkSize) {
       block_size = blkSize;
       ivSize = blkSize;
    }
    ...
   void init(AlgorithmParameterSpec paramSpec) {
        ivSize = ...;  // reset IV size.
    }

    // use ivSize while encoding and decoding.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The problem with this is that this assumes that the specified paramSpec argument of the init() method is always valid.

@mlbridge
Copy link

mlbridge bot commented May 22, 2021

Mailing list message from Michael StJohns on security-dev:

In line

On 5/21/2021 5:01 PM, Xue-Lei Andrew Fan wrote:

On Fri, 14 May 2021 00:33:12 GMT, Valerie Peng <valeriep at openjdk.org> wrote:

This change updates SunJCE provider as below:
- updated existing AESWrap support with AES/KW/NoPadding cipher transformation.
- added support for AES/KWP/NoPadding and AES/KW/PKCS5Padding.

Existing AESWrap impl, i.e. AESWrapCipher class, is re-factored and renamed to KeyWrapCipher class. The W and W_inverse functions are moved to KWUtil class. The KW and KWP support are in the new AESKeyWrap and AESKeyWrapPadded classes which extend FeedbackCipher and used in KeyWrapCipher class. To minimize data copying, AESKeyWrap and AESKeyWrapPadded will do the crypto operation over the same input buffer which is allocated and managed by KeyWrapCipher class.

Also note that existing AESWrap impl does not take IV. However, the corresponding PKCS#11 mechanisms do, so I added support for accepting IVs to both KW and KWP.

Thanks,
Valerie
Valerie Peng has updated the pull request with a new target base due to a merge or a rebase. The pull request now contains seven commits:

- Merge master into JDK-8248268
- Minor update to address review comments.
- Changed AESParameters to allow 4-byte, 8-byte IVs and removed
KWParameters and KWPParameters.
- Refactor code to reduce code duplication
Address review comments
Add more test vectors
- Changed AlgorithmParameters impls to register under AES/KW/NoPadding and
AES/KWP/NoPadding
- Restored Iv algorithm parameters impl.
- 8248268: Support KWP in addition to KW

Updated existing AESWrap support with AES\/KW\/NoPadding cipher
transformation\. Added support for AES\/KWP\/NoPadding and
AES\/KW\/PKCS5Padding support to SunJCE provider\.

src/java.base/share/classes/com/sun/crypto/provider/AESParameters.java line 50:

48:
49: public AESParameters() {
50: core = new BlockCipherParamsCore(AESConstants.AES_BLOCK_SIZE, 4, 8);
A cipher object may not take different IV sizes at the same time. I was just wondering how it could be used in practice. Maybe something like:

The mode is KW - it has a fixed length 8 byte non-iv integrity tag.???
KWP is a special case of KW where there's still an 8 byte tag, but part
of it is interpreted by KWP to figure out how much padding was
included.?? KW (AKA RFC3394) permits user (actually specification
specified) IV values.? KWP (aka RFC5649) does not.

I'd treat KWP as a final (in the Java final sense) extension to KW with
a fixed AIV flag value and a defined interpretation for the 8 byte AIV
tag.? E.g. if you try to specify an IV for KWP, it should fail.?? If
someone else wants to do something like KWP or even twiddle with the 4
byte AIV, let them do their own KW wrap around - which they should be
able to do that via the KW/NoPadding model by specifying their own AIV.?
That should improve interoperability by preventing some monkey see
monkey do errors.

This is sort of one reason I was arguing for AES/KW/KWPPadding rather
than AES/KWP/NoPadding.

Mike

1 similar comment
@mlbridge
Copy link

mlbridge bot commented May 22, 2021

Mailing list message from Michael StJohns on security-dev:

In line

On 5/21/2021 5:01 PM, Xue-Lei Andrew Fan wrote:

On Fri, 14 May 2021 00:33:12 GMT, Valerie Peng <valeriep at openjdk.org> wrote:

This change updates SunJCE provider as below:
- updated existing AESWrap support with AES/KW/NoPadding cipher transformation.
- added support for AES/KWP/NoPadding and AES/KW/PKCS5Padding.

Existing AESWrap impl, i.e. AESWrapCipher class, is re-factored and renamed to KeyWrapCipher class. The W and W_inverse functions are moved to KWUtil class. The KW and KWP support are in the new AESKeyWrap and AESKeyWrapPadded classes which extend FeedbackCipher and used in KeyWrapCipher class. To minimize data copying, AESKeyWrap and AESKeyWrapPadded will do the crypto operation over the same input buffer which is allocated and managed by KeyWrapCipher class.

Also note that existing AESWrap impl does not take IV. However, the corresponding PKCS#11 mechanisms do, so I added support for accepting IVs to both KW and KWP.

Thanks,
Valerie
Valerie Peng has updated the pull request with a new target base due to a merge or a rebase. The pull request now contains seven commits:

- Merge master into JDK-8248268
- Minor update to address review comments.
- Changed AESParameters to allow 4-byte, 8-byte IVs and removed
KWParameters and KWPParameters.
- Refactor code to reduce code duplication
Address review comments
Add more test vectors
- Changed AlgorithmParameters impls to register under AES/KW/NoPadding and
AES/KWP/NoPadding
- Restored Iv algorithm parameters impl.
- 8248268: Support KWP in addition to KW

Updated existing AESWrap support with AES\/KW\/NoPadding cipher
transformation\. Added support for AES\/KWP\/NoPadding and
AES\/KW\/PKCS5Padding support to SunJCE provider\.

src/java.base/share/classes/com/sun/crypto/provider/AESParameters.java line 50:

48:
49: public AESParameters() {
50: core = new BlockCipherParamsCore(AESConstants.AES_BLOCK_SIZE, 4, 8);
A cipher object may not take different IV sizes at the same time. I was just wondering how it could be used in practice. Maybe something like:

The mode is KW - it has a fixed length 8 byte non-iv integrity tag.???
KWP is a special case of KW where there's still an 8 byte tag, but part
of it is interpreted by KWP to figure out how much padding was
included.?? KW (AKA RFC3394) permits user (actually specification
specified) IV values.? KWP (aka RFC5649) does not.

I'd treat KWP as a final (in the Java final sense) extension to KW with
a fixed AIV flag value and a defined interpretation for the 8 byte AIV
tag.? E.g. if you try to specify an IV for KWP, it should fail.?? If
someone else wants to do something like KWP or even twiddle with the 4
byte AIV, let them do their own KW wrap around - which they should be
able to do that via the KW/NoPadding model by specifying their own AIV.?
That should improve interoperability by preventing some monkey see
monkey do errors.

This is sort of one reason I was arguing for AES/KW/KWPPadding rather
than AES/KWP/NoPadding.

Mike

@XueleiFan
Copy link
Member

Good points, Mike! Thank you!

Mailing list message from Michael StJohns on security-dev:

src/java.base/share/classes/com/sun/crypto/provider/AESParameters.java line 50:

48:
49: public AESParameters() {
50: core = new BlockCipherParamsCore(AESConstants.AES_BLOCK_SIZE, 4, 8);
A cipher object may not take different IV sizes at the same time. I was just wondering how it could be used in practice. Maybe something like:

The mode is KW - it has a fixed length 8 byte non-iv integrity tag.???
KWP is a special case of KW where there's still an 8 byte tag, but part
of it is interpreted by KWP to figure out how much padding was
included.?? KW (AKA RFC3394) permits user (actually specification
specified) IV values.? KWP (aka RFC5649) does not.

Hm, I missed this point. KW (RFC 3394) supports Alternative IV (AIV), while KWP is just a case about how to construct the alternative IV for KWP operations.

I'd treat KWP as a final (in the Java final sense) extension to KW with
a fixed AIV flag value and a defined interpretation for the 8 byte AIV
tag.? E.g. if you try to specify an IV for KWP, it should fail.?? If
someone else wants to do something like KWP or even twiddle with the 4
byte AIV, let them do their own KW wrap around - which they should be
able to do that via the KW/NoPadding model by specifying their own AIV.?
That should improve interoperability by preventing some monkey see
monkey do errors.

I agreed. Maybe, we could do:

  1. Support Alternative IV for KW, for the flexibility as described in section 2.2.3.2 of RFC 3394.
  2. Use default IV if no AIV specified for KW, as described in section 2.2.3.1 of RFC 3394.
  3. Use a fixed IV for KWP, as described in section 3of RFC 5649.

This is sort of one reason I was arguing for AES/KW/KWPPadding rather
than AES/KWP/NoPadding.

I thought of the "AES/KW/KWPPadding" style as well. The "AES/KWP/NoPadding" looks a little bit weird to me because there is padding while we call it with "NoPadding".

KWP is not exactly like the traditional AES/CBC/PKCS5Padding, where the components could be treated separately. The padding scheme of KWP impact the IV as well. So it was arguable to me.

Finally I feel better of the "AES/KWP/NoPadding" when I read the NIST SP title again, "Recommendation for Block Cipher Modes of Operation: Methods for Key Wrapping". Maybe, it is an industry accepted notation to treat KWP as a block cipher mode.

@mlbridge
Copy link

mlbridge bot commented May 22, 2021

Mailing list message from Michael StJohns on security-dev:

On 5/22/2021 1:57 PM, Xue-Lei Andrew Fan wrote:

On Fri, 14 May 2021 00:33:12 GMT, Valerie Peng <valeriep at openjdk.org> wrote:

This change updates SunJCE provider as below:
- updated existing AESWrap support with AES/KW/NoPadding cipher transformation.
- added support for AES/KWP/NoPadding and AES/KW/PKCS5Padding.

Existing AESWrap impl, i.e. AESWrapCipher class, is re-factored and renamed to KeyWrapCipher class. The W and W_inverse functions are moved to KWUtil class. The KW and KWP support are in the new AESKeyWrap and AESKeyWrapPadded classes which extend FeedbackCipher and used in KeyWrapCipher class. To minimize data copying, AESKeyWrap and AESKeyWrapPadded will do the crypto operation over the same input buffer which is allocated and managed by KeyWrapCipher class.

Also note that existing AESWrap impl does not take IV. However, the corresponding PKCS#11 mechanisms do, so I added support for accepting IVs to both KW and KWP.

Thanks,
Valerie
Valerie Peng has updated the pull request with a new target base due to a merge or a rebase. The pull request now contains seven commits:

- Merge master into JDK-8248268
- Minor update to address review comments.
- Changed AESParameters to allow 4-byte, 8-byte IVs and removed
KWParameters and KWPParameters.
- Refactor code to reduce code duplication
Address review comments
Add more test vectors
- Changed AlgorithmParameters impls to register under AES/KW/NoPadding and
AES/KWP/NoPadding
- Restored Iv algorithm parameters impl.
- 8248268: Support KWP in addition to KW

Updated existing AESWrap support with AES\/KW\/NoPadding cipher
transformation\. Added support for AES\/KWP\/NoPadding and
AES\/KW\/PKCS5Padding support to SunJCE provider\.

Good points, Mike! Thank you!

_Mailing list message from [Michael StJohns](mailto:mstjohns at comcast.net) on [security-dev](mailto:security-dev at mail.openjdk.java.net):_

src/java.base/share/classes/com/sun/crypto/provider/AESParameters.java line 50:

48:
49: public AESParameters() {
50: core = new BlockCipherParamsCore(AESConstants.AES_BLOCK_SIZE, 4, 8);
A cipher object may not take different IV sizes at the same time. I was just wondering how it could be used in practice. Maybe something like:
The mode is KW - it has a fixed length 8 byte non-iv integrity tag.???
KWP is a special case of KW where there's still an 8 byte tag, but part
of it is interpreted by KWP to figure out how much padding was
included.?? KW (AKA RFC3394) permits user (actually specification
specified) IV values.? KWP (aka RFC5649) does not.

Hm, I missed this point. KW (RFC 3394) supports Alternative IV (AIV), while KWP is just a case about how to construct the alternative IV for KWP operations.

Yes.? Sorry if I wasn't clearer in earlier emails.

I'd treat KWP as a final (in the Java final sense) extension to KW with
a fixed AIV flag value and a defined interpretation for the 8 byte AIV
tag.? E.g. if you try to specify an IV for KWP, it should fail.?? If
someone else wants to do something like KWP or even twiddle with the 4
byte AIV, let them do their own KW wrap around - which they should be
able to do that via the KW/NoPadding model by specifying their own AIV.?
That should improve interoperability by preventing some monkey see
monkey do errors.

I agreed. Maybe, we could do:
1. Support Alternative IV for KW, for the flexibility as described in section 2.2.3.2 of RFC 3394.

I think that's acceptable.? Hmm... is it possible to make the set ICV
call protected rather than public??? Generally, the defined ICVs match
up with specific algorithm OIDS.? You shouldn't see a third one unless
someone defines a brand new variant.? But you want to make it possible
for someone to do an extension.

2. Use default IV if no AIV specified for KW, as described in section 2.2.3.1 of RFC 3394.

Works.? Or see the above.

3. Use a fixed IV for KWP, as described in section 3of RFC 5649.

Yes.

This is sort of one reason I was arguing for AES/KW/KWPPadding rather
than AES/KWP/NoPadding.

I thought of the "AES/KW/KWPPadding" style as well. The "AES/KWP/NoPadding" looks a little bit weird to me because there is padding while we call it with "NoPadding".

KWP is not exactly like the traditional AES/CBC/PKCS5Padding, where the components could be treated separately. The padding scheme of KWP impact the IV as well. So it was arguable to me.

We keep referring to it as an IV? - but it isn't - it's an Integrity
Check Value.? Unlike an IV, it doesn't inform the decryption stage, it's
only checked after the decryption is complete.? (E.g. in a mode with an
IV, you need to know the IV before you encrypt and before you decrypt).?
Then there's this from Section 6.3 of SP800-38F.

Let S = ICV2|| [len(P)/8]32 || P|| PAD

Step 5 of the KWP-AE algorithm basically passes the A65959A6 value
pre-prepended to the pad length both pre-pended to the padded data
through to W().

The equivalent for KW-AE is step 2 which passes the ICV1 value in
pre-pended to the plaintext.? (e.g. these are the inputs to W()).

The underlying function W() is doing what it does without any reference
to the actual value of the ICV both on encrypt and decrypt.

So the differences between KWP and KW are actually in how the plain text
data is marshalled? and unmarshalled and the checking they do on the
decrypted ICVs, not in the actual cryptography.

Think of it this way:? W() and W'() are the actual cryptographic actions
that implement key wrapping - the mode if you will.? KW-AE and KWP-AE
are the NoPadding and KWPPadding instantiations of that mode.

Another way of looking at that - KW-AE can't use a variant ICV. (Or at
least I can't find a place where it's permitted - I was mistaken in
including it above as the same as RFC3394).? If you're going to call it
KWP/NoPadding and KW/NoPadding, then maybe you shouldn't support the
provision of a different ICV as this isn't supported by SP800-38F.

*shrug*

I don't think that Java nomenclature and NIST nomenclature have to match
up.? But ideally, Java nomenclature should try to be consistent amongst
itself.? AES/KWP/NoPadding just sounds less right than AES/KW/KWPPadding.

Mike

-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://mail.openjdk.java.net/pipermail/security-dev/attachments/20210522/583ff57a/attachment.htm>

1 similar comment
@mlbridge
Copy link

mlbridge bot commented May 22, 2021

Mailing list message from Michael StJohns on security-dev:

On 5/22/2021 1:57 PM, Xue-Lei Andrew Fan wrote:

On Fri, 14 May 2021 00:33:12 GMT, Valerie Peng <valeriep at openjdk.org> wrote:

This change updates SunJCE provider as below:
- updated existing AESWrap support with AES/KW/NoPadding cipher transformation.
- added support for AES/KWP/NoPadding and AES/KW/PKCS5Padding.

Existing AESWrap impl, i.e. AESWrapCipher class, is re-factored and renamed to KeyWrapCipher class. The W and W_inverse functions are moved to KWUtil class. The KW and KWP support are in the new AESKeyWrap and AESKeyWrapPadded classes which extend FeedbackCipher and used in KeyWrapCipher class. To minimize data copying, AESKeyWrap and AESKeyWrapPadded will do the crypto operation over the same input buffer which is allocated and managed by KeyWrapCipher class.

Also note that existing AESWrap impl does not take IV. However, the corresponding PKCS#11 mechanisms do, so I added support for accepting IVs to both KW and KWP.

Thanks,
Valerie
Valerie Peng has updated the pull request with a new target base due to a merge or a rebase. The pull request now contains seven commits:

- Merge master into JDK-8248268
- Minor update to address review comments.
- Changed AESParameters to allow 4-byte, 8-byte IVs and removed
KWParameters and KWPParameters.
- Refactor code to reduce code duplication
Address review comments
Add more test vectors
- Changed AlgorithmParameters impls to register under AES/KW/NoPadding and
AES/KWP/NoPadding
- Restored Iv algorithm parameters impl.
- 8248268: Support KWP in addition to KW

Updated existing AESWrap support with AES\/KW\/NoPadding cipher
transformation\. Added support for AES\/KWP\/NoPadding and
AES\/KW\/PKCS5Padding support to SunJCE provider\.

Good points, Mike! Thank you!

_Mailing list message from [Michael StJohns](mailto:mstjohns at comcast.net) on [security-dev](mailto:security-dev at mail.openjdk.java.net):_

src/java.base/share/classes/com/sun/crypto/provider/AESParameters.java line 50:

48:
49: public AESParameters() {
50: core = new BlockCipherParamsCore(AESConstants.AES_BLOCK_SIZE, 4, 8);
A cipher object may not take different IV sizes at the same time. I was just wondering how it could be used in practice. Maybe something like:
The mode is KW - it has a fixed length 8 byte non-iv integrity tag.???
KWP is a special case of KW where there's still an 8 byte tag, but part
of it is interpreted by KWP to figure out how much padding was
included.?? KW (AKA RFC3394) permits user (actually specification
specified) IV values.? KWP (aka RFC5649) does not.

Hm, I missed this point. KW (RFC 3394) supports Alternative IV (AIV), while KWP is just a case about how to construct the alternative IV for KWP operations.

Yes.? Sorry if I wasn't clearer in earlier emails.

I'd treat KWP as a final (in the Java final sense) extension to KW with
a fixed AIV flag value and a defined interpretation for the 8 byte AIV
tag.? E.g. if you try to specify an IV for KWP, it should fail.?? If
someone else wants to do something like KWP or even twiddle with the 4
byte AIV, let them do their own KW wrap around - which they should be
able to do that via the KW/NoPadding model by specifying their own AIV.?
That should improve interoperability by preventing some monkey see
monkey do errors.

I agreed. Maybe, we could do:
1. Support Alternative IV for KW, for the flexibility as described in section 2.2.3.2 of RFC 3394.

I think that's acceptable.? Hmm... is it possible to make the set ICV
call protected rather than public??? Generally, the defined ICVs match
up with specific algorithm OIDS.? You shouldn't see a third one unless
someone defines a brand new variant.? But you want to make it possible
for someone to do an extension.

2. Use default IV if no AIV specified for KW, as described in section 2.2.3.1 of RFC 3394.

Works.? Or see the above.

3. Use a fixed IV for KWP, as described in section 3of RFC 5649.

Yes.

This is sort of one reason I was arguing for AES/KW/KWPPadding rather
than AES/KWP/NoPadding.

I thought of the "AES/KW/KWPPadding" style as well. The "AES/KWP/NoPadding" looks a little bit weird to me because there is padding while we call it with "NoPadding".

KWP is not exactly like the traditional AES/CBC/PKCS5Padding, where the components could be treated separately. The padding scheme of KWP impact the IV as well. So it was arguable to me.

We keep referring to it as an IV? - but it isn't - it's an Integrity
Check Value.? Unlike an IV, it doesn't inform the decryption stage, it's
only checked after the decryption is complete.? (E.g. in a mode with an
IV, you need to know the IV before you encrypt and before you decrypt).?
Then there's this from Section 6.3 of SP800-38F.

Let S = ICV2|| [len(P)/8]32 || P|| PAD

Step 5 of the KWP-AE algorithm basically passes the A65959A6 value
pre-prepended to the pad length both pre-pended to the padded data
through to W().

The equivalent for KW-AE is step 2 which passes the ICV1 value in
pre-pended to the plaintext.? (e.g. these are the inputs to W()).

The underlying function W() is doing what it does without any reference
to the actual value of the ICV both on encrypt and decrypt.

So the differences between KWP and KW are actually in how the plain text
data is marshalled? and unmarshalled and the checking they do on the
decrypted ICVs, not in the actual cryptography.

Think of it this way:? W() and W'() are the actual cryptographic actions
that implement key wrapping - the mode if you will.? KW-AE and KWP-AE
are the NoPadding and KWPPadding instantiations of that mode.

Another way of looking at that - KW-AE can't use a variant ICV. (Or at
least I can't find a place where it's permitted - I was mistaken in
including it above as the same as RFC3394).? If you're going to call it
KWP/NoPadding and KW/NoPadding, then maybe you shouldn't support the
provision of a different ICV as this isn't supported by SP800-38F.

*shrug*

I don't think that Java nomenclature and NIST nomenclature have to match
up.? But ideally, Java nomenclature should try to be consistent amongst
itself.? AES/KWP/NoPadding just sounds less right than AES/KW/KWPPadding.

Mike

-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://mail.openjdk.java.net/pipermail/security-dev/attachments/20210522/583ff57a/attachment.htm>

@mlbridge
Copy link

mlbridge bot commented May 25, 2021

Mailing list message from Michael StJohns on security-dev:

Some more general comments - related to the restructuring.

In AESKeyWrap at 152-155 - that check probably should be moved to W().??
KWP should do the formatting prior to passing the data to W().? Also at
185-187 - move that to W_INV().

AESKeyWrap at 158 - shouldn't you be returning the cipher text length??
That's what the comment in FeedbackCipher says.? W() should probably be
returning the final length.

The length of the final ciphertext data should be 8 bytes longer than
the plaintext. decryptFinal() seems to do the right thing by decreasing
the length returned.?? But again - shouldn't that be the purview of W_INV()?

The call in KeyWrapCipher.engineGetOutputSize() should probably also be
passed into KWUtil rather than being? done in KeyWrapCipher.? And the
more I look at this, the more I think that all of the engineUpdate
operations should throw UnsupportedOperationException - it would
certainly simplify the logic.? That would make the call return either?
inputLength + 8 or inputLength - 8 depending on mode.

KWUtil.W() - should probably check that in.length >= inLen + 8 and throw
a ShortBufferException if not.

Would it be useful to add a comment in KeyWrapCipher that? warns
maintainers that? AESKeyWrap(Padded).encryptFinal() and decryptFinal()
uses the input buffer as the output buffer? That's a reasonable approach
for decryption, but I'm wondering if you might want to support in-place
encryption as there's no spec prohibition requiring data to be held
until the encryption is complete.

Mike

On 5/24/2021 7:01 PM, Valerie Peng wrote:

1 similar comment
@mlbridge
Copy link

mlbridge bot commented May 25, 2021

Mailing list message from Michael StJohns on security-dev:

Some more general comments - related to the restructuring.

In AESKeyWrap at 152-155 - that check probably should be moved to W().??
KWP should do the formatting prior to passing the data to W().? Also at
185-187 - move that to W_INV().

AESKeyWrap at 158 - shouldn't you be returning the cipher text length??
That's what the comment in FeedbackCipher says.? W() should probably be
returning the final length.

The length of the final ciphertext data should be 8 bytes longer than
the plaintext. decryptFinal() seems to do the right thing by decreasing
the length returned.?? But again - shouldn't that be the purview of W_INV()?

The call in KeyWrapCipher.engineGetOutputSize() should probably also be
passed into KWUtil rather than being? done in KeyWrapCipher.? And the
more I look at this, the more I think that all of the engineUpdate
operations should throw UnsupportedOperationException - it would
certainly simplify the logic.? That would make the call return either?
inputLength + 8 or inputLength - 8 depending on mode.

KWUtil.W() - should probably check that in.length >= inLen + 8 and throw
a ShortBufferException if not.

Would it be useful to add a comment in KeyWrapCipher that? warns
maintainers that? AESKeyWrap(Padded).encryptFinal() and decryptFinal()
uses the input buffer as the output buffer? That's a reasonable approach
for decryption, but I'm wondering if you might want to support in-place
encryption as there's no spec prohibition requiring data to be held
until the encryption is complete.

Mike

On 5/24/2021 7:01 PM, Valerie Peng wrote:

@valeriepeng
Copy link
Author

Current impl takes account into RFC 3394 (Sept 2002), RFC 5649 (Aug 2009), NIST 800-38F (Dec 2012) and PKCS#11 v3.0 Current Mech Spec (June 2020) and tries to support them all. If solely basing on RFC 3394/5649, then AES KW and KWP cipher should just supports key wrap/unwrap but not enc/dec. The main reason that I added the support for alternative iv and enc/dec is more for NIST 800-38F which states that KW/KWP can be used for general data protection as well and PKCS#11 v3.0 which lists 3 mechanisms mapping to java's AES using KW, AES using KW and PKCS5Padding and AES using KWP. These 3 mechanisms supports all 4, i.e. enc/dec/wrap/unwrap, as well custom IVs (8-byte for KW and 4-byte for KWP). Naming can be a very subjective matter and putting it aside, I don't see why KW and KWP should not allow custom IVs? Isn't hardcoded values less secure or fragile in general?

@valeriepeng
Copy link
Author

Mailing list message from Michael StJohns on security-dev:

Some more general comments - related to the restructuring.

In AESKeyWrap at 152-155 - that check probably should be moved to W().??
KWP should do the formatting prior to passing the data to W().? Also at
185-187 - move that to W_INV().

AESKeyWrap at 158 - shouldn't you be returning the cipher text length??
That's what the comment in FeedbackCipher says.? W() should probably be
returning the final length.

The length of the final ciphertext data should be 8 bytes longer than
the plaintext. decryptFinal() seems to do the right thing by decreasing
the length returned.?? But again - shouldn't that be the purview of W_INV()?

The call in KeyWrapCipher.engineGetOutputSize() should probably also be
passed into KWUtil rather than being? done in KeyWrapCipher.? And the
more I look at this, the more I think that all of the engineUpdate
operations should throw UnsupportedOperationException - it would
certainly simplify the logic.? That would make the call return either?
inputLength + 8 or inputLength - 8 depending on mode.

KWUtil.W() - should probably check that in.length >= inLen + 8 and throw
a ShortBufferException if not.

Would it be useful to add a comment in KeyWrapCipher that? warns
maintainers that? AESKeyWrap(Padded).encryptFinal() and decryptFinal()
uses the input buffer as the output buffer? That's a reasonable approach
for decryption, but I'm wondering if you might want to support in-place
encryption as there's no spec prohibition requiring data to be held
until the encryption is complete.

Mike

On 5/24/2021 7:01 PM, Valerie Peng wrote:

Hi Mike,

Thanks for chiming in and review. Please find my comments below:

  1. regarding the data length checks in AESKeyWrap/AESKeyWrapPadded class, it's better to check them before formatting the data and passing them to W(). This way, the error message can be clear and fail fast. I added assert statement to W()/W_INV() so the assumption on data sizes are clear.
  2. regarding the returned text length of encryptFinal()/decryptFinal() calls, the returned value is correct in that 'ptLen' is the length of the formatted input to W() which contains both the first semiblock and user-supplied data. The name of the variable probably caused the confusion. For better readability, I changed W()/W_INV() to return an int. The javadoc explains what the returned int means. Hope this is clearer now.
  3. regarding KWUtil, it's just a state-less class holding utility methods which are used by both AESKeyWrap (KW impl) and AESKeyWrapPadded (KWP impl). So I don't see why it should handle engineGetOutputSize() calls.
  4. as for engineUpdate(...) throwing UnsupportedOperationException, I see the point that you are trying to make. Currently we are bound by the Cipher/CipherSpi javadoc spec. Another concern is that existing apps which are using multi-part enc/dec, may be caught off guard with this. So, that's how it is.

I need to do a system update and will get to your other comments once it's finished.
Thanks,
Valerie

@valeriepeng
Copy link
Author

In the latest commit, I have made some minor optimizations regrading the in-place encryption as suggested in Mike's earlier comments. However, the optimizations are limited to when the output offset == 0 case.

@openjdk openjdk bot removed the csr Pull request needs approved CSR before integration label Jun 1, 2021
@openjdk
Copy link

openjdk bot commented Jun 1, 2021

@valeriepeng This change now passes all automated pre-integration checks.

ℹ️ This project also has non-automated pre-integration requirements. Please see the file CONTRIBUTING.md for details.

After integration, the commit message for the final commit will be:

8248268: Support KWP in addition to KW

Reviewed-by: xuelei

You can use pull request commands such as /summary, /contributor and /issue to adjust it as needed.

At the time when this comment was updated there had been 269 new commits pushed to the master branch:

  • 1ae934e: 8263332: JFR: Dump recording from a recording stream
  • b7ac705: 8263642: javac emits duplicate checkcast for first bound of intersection type in cast
  • e1462e7: 8267176: StandardDoclet should provide access to Reporter and Locale
  • 56b65e4: 8267569: java.io.File.equals contains misleading Javadoc
  • 508cec7: 8267521: Post JEP 411 refactoring: maximum covering > 50K
  • 40d23a0: 8267543: Post JEP 411 refactoring: security
  • 4767758: 8267920: Create separate Events buffer for VMOperations
  • dc19bac: 8268094: Some vmTestbase/nsk tests fail after ACC_STRICT/strictfp changes
  • 2963c9e: 8268103: JNI functions incorrectly return a double after JDK-8265836
  • 6765f90: 8266459: Implement JEP 411: Deprecate the Security Manager for Removal
  • ... and 259 more: https://git.openjdk.java.net/jdk/compare/853ffdb25c76637555fa732f5e05024243747a70...master

As there are no conflicts, your changes will automatically be rebased on top of these commits when integrating. If you prefer to avoid this automatic rebasing, please check the documentation for the /integrate command for further details.

➡️ To integrate this PR with the above commit message to the master branch, type /integrate in a new comment.

@openjdk openjdk bot added the ready Pull request is ready to be integrated label Jun 1, 2021
@valeriepeng
Copy link
Author

Hi Mike,
Lastly, regarding the naming, I am not too inclined toward the AES/KW/KWPPadding suggestion since the general concept of padding is that it's general, not mode-specific and are applied before data is processed by crypto operations. The mode can just process data without knowing whether padding is applied as long as the data has the right length. Thus, I'd keep KWP as a mode which does internal padding instead of a generic padding scheme. The AutoPadding suggestion is interesting and can be easily built on top of KW and KWP modes if desired.

Thanks for the feedbacks,
Valerie

@valeriepeng
Copy link
Author

/integrate

@openjdk openjdk bot closed this Jun 2, 2021
@openjdk openjdk bot added integrated Pull request has been integrated and removed ready Pull request is ready to be integrated rfr Pull request is ready for review labels Jun 2, 2021
@openjdk
Copy link

openjdk bot commented Jun 2, 2021

@valeriepeng Since your change was applied there have been 273 commits pushed to the master branch:

Your commit was automatically rebased without conflicts.

Pushed as commit 136badb.

💡 You may see a message that your pull request was closed with unmerged commits. This can be safely ignored.

@valeriepeng valeriepeng deleted the JDK-8248268 branch June 2, 2021 21:54
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
integrated Pull request has been integrated security security-dev@openjdk.org
3 participants