Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Browse files
Browse the repository at this point in the history
8248268: Support KWP in addition to KW
Reviewed-by: xuelei
- Loading branch information
Valerie Peng
committed
Jun 2, 2021
1 parent
3482cb8
commit 136badb
Showing
18 changed files
with
2,223 additions
and
675 deletions.
There are no files selected for viewing
196 changes: 196 additions & 0 deletions
196
src/java.base/share/classes/com/sun/crypto/provider/AESKeyWrap.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,196 @@ | ||
/* | ||
* Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved. | ||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. | ||
* | ||
* This code is free software; you can redistribute it and/or modify it | ||
* under the terms of the GNU General Public License version 2 only, as | ||
* published by the Free Software Foundation. Oracle designates this | ||
* particular file as subject to the "Classpath" exception as provided | ||
* by Oracle in the LICENSE file that accompanied this code. | ||
* | ||
* This code is distributed in the hope that it will be useful, but WITHOUT | ||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License | ||
* version 2 for more details (a copy is included in the LICENSE file that | ||
* accompanied this code). | ||
* | ||
* You should have received a copy of the GNU General Public License version | ||
* 2 along with this work; if not, write to the Free Software Foundation, | ||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. | ||
* | ||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA | ||
* or visit www.oracle.com if you need additional information or have any | ||
* questions. | ||
*/ | ||
|
||
package com.sun.crypto.provider; | ||
|
||
import java.util.Arrays; | ||
import java.security.*; | ||
import java.security.spec.*; | ||
import javax.crypto.*; | ||
import javax.crypto.spec.*; | ||
import static com.sun.crypto.provider.KWUtil.*; | ||
|
||
/** | ||
* This class implement the AES KeyWrap mode of operation as defined in | ||
* <a href=https://nvlpubs.nist.gov/nistpubs/SpecialPublications/NIST.SP.800-38F.pdf> | ||
* "Recommendation for Block Cipher Modes of Operation: Methods for Key Wrapping"</a> | ||
* and represents AES cipher in KW mode. | ||
*/ | ||
class AESKeyWrap extends FeedbackCipher { | ||
|
||
// default integrity check value (icv) if iv is not supplied | ||
private static final byte[] ICV1 = { // SEMI_BLKSIZE long | ||
(byte) 0xA6, (byte) 0xA6, (byte) 0xA6, (byte) 0xA6, | ||
(byte) 0xA6, (byte) 0xA6, (byte) 0xA6, (byte) 0xA6 | ||
}; | ||
|
||
AESKeyWrap() { | ||
super(new AESCrypt()); | ||
} | ||
|
||
/** | ||
* Gets the name of this feedback mode. | ||
* | ||
* @return the string <code>KW</code> | ||
*/ | ||
@Override | ||
String getFeedback() { | ||
return "KW"; | ||
} | ||
|
||
/** | ||
* Save the current content of this cipher. | ||
*/ | ||
@Override | ||
void save() { | ||
throw new UnsupportedOperationException("save not supported"); | ||
}; | ||
|
||
/** | ||
* Restores the content of this cipher to the previous saved one. | ||
*/ | ||
@Override | ||
void restore() { | ||
throw new UnsupportedOperationException("restore not supported"); | ||
}; | ||
|
||
/** | ||
* Initializes the cipher in the specified mode with the given key | ||
* and iv. | ||
* | ||
* @param decrypting flag indicating encryption or decryption | ||
* @param algorithm the algorithm name | ||
* @param key the key | ||
* @param iv the iv | ||
* | ||
* @exception InvalidKeyException if the given key is inappropriate for | ||
* initializing this cipher | ||
* @exception InvalidAlgorithmParameterException if the given iv is | ||
* non-null and not the right length | ||
*/ | ||
@Override | ||
void init(boolean decrypting, String algorithm, byte[] key, byte[] iv) | ||
throws InvalidKeyException, InvalidAlgorithmParameterException { | ||
if (key == null) { | ||
throw new InvalidKeyException("Invalid null key"); | ||
} | ||
if (iv != null && iv.length != SEMI_BLKSIZE) { | ||
throw new InvalidAlgorithmParameterException("Invalid IV"); | ||
} | ||
embeddedCipher.init(decrypting, algorithm, key); | ||
// iv is retrieved from IvParameterSpec.getIV() which is already cloned | ||
this.iv = (iv == null? ICV1 : iv); | ||
} | ||
|
||
/** | ||
* Resets the iv to its original value. | ||
* This is used when doFinal is called in the Cipher class, so that the | ||
* cipher can be reused (with its original iv). | ||
*/ | ||
@Override | ||
void reset() { | ||
throw new UnsupportedOperationException("reset not supported"); | ||
}; | ||
|
||
|
||
// no support for multi-part encryption | ||
@Override | ||
int encrypt(byte[] pt, int ptOfs, int ptLen, byte[] ct, int ctOfs) { | ||
throw new UnsupportedOperationException("multi-part not supported"); | ||
}; | ||
|
||
// no support for multi-part decryption | ||
@Override | ||
int decrypt(byte[] ct, int ctOfs, int ctLen, byte[] pt, int ptOfs) { | ||
throw new UnsupportedOperationException("multi-part not supported"); | ||
}; | ||
|
||
/** | ||
* Performs single-part encryption operation. | ||
* | ||
* <p>The input <code>pt</code>, starting at <code>0</code> | ||
* and ending at <code>ptLen-1</code>, is encrypted. | ||
* The result is stored in place into <code>pt</code>, starting at | ||
* <code>0</code>. | ||
* | ||
* <p>The subclass that implements Cipher should ensure that | ||
* <code>init</code> has been called before this method is called. | ||
* | ||
* @param pt the input buffer with the data to be encrypted | ||
* @param dummy1 the offset in <code>pt</code> which is always 0 | ||
* @param ptLen the length of the input data | ||
* @param dummy2 the output buffer for the encryption which is always pt | ||
* @param dummy3 the offset in the output buffer which is always 0 | ||
* @return the number of bytes placed into <code>pt</code> | ||
*/ | ||
@Override | ||
int encryptFinal(byte[] pt, int dummy1, int ptLen, byte[] dummy2, | ||
int dummy3) throws IllegalBlockSizeException { | ||
// adjust the min value since pt contains the first semi-block | ||
if (ptLen < MIN_INPUTLEN || (ptLen % SEMI_BLKSIZE) != 0) { | ||
throw new IllegalBlockSizeException("data should" + | ||
" be at least 16 bytes and multiples of 8"); | ||
} | ||
return W(iv, pt, ptLen, embeddedCipher); | ||
} | ||
|
||
/** | ||
* Performs single-part decryption operation. | ||
* | ||
* <p>The input <code>ct</code>, starting at <code>0</code> | ||
* and ending at <code>ctLen-1</code>, is decrypted. | ||
* The result is stored in place into <code>ct</code>, starting at | ||
* <code>0</code>. | ||
* | ||
* <p>NOTE: Purpose of this special impl is for minimizing array | ||
* copying, those unused arguments are named as dummyN. | ||
* | ||
* <p>The subclass that implements Cipher should ensure that | ||
* <code>init</code> has been called before this method is called. | ||
* | ||
* @param ct the input buffer with the data to be decrypted | ||
* @param dummy1 the offset in <code>ct</code> which is always 0 | ||
* @param ctLen the length of the input data | ||
* @param dummy2 the output buffer for the decryption which is always ct | ||
* @param dummy3 the offset in the output buffer which is always 0 | ||
* @return the number of bytes placed into <code>ct</code> | ||
*/ | ||
@Override | ||
int decryptFinal(byte[] ct, int dummy1, int ctLen, byte[] dummy2, | ||
int dummy3) throws IllegalBlockSizeException { | ||
if (ctLen < MIN_INPUTLEN || (ctLen % SEMI_BLKSIZE) != 0) { | ||
throw new IllegalBlockSizeException | ||
("data should be at least 24 bytes and multiples of 8"); | ||
} | ||
byte[] ivOut = new byte[SEMI_BLKSIZE]; | ||
ctLen = W_INV(ct, ctLen, ivOut, embeddedCipher); | ||
|
||
// check against icv and fail if not match | ||
if (!MessageDigest.isEqual(ivOut, this.iv)) { | ||
throw new IllegalBlockSizeException("Integrity check failed"); | ||
} | ||
return ctLen; | ||
} | ||
} |
Oops, something went wrong.
136badb
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Review
Issues