Path: blob/master/src/java.base/share/classes/com/sun/crypto/provider/AESKeyWrapPadded.java
41161 views
/*1* Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation. Oracle designates this7* particular file as subject to the "Classpath" exception as provided8* by Oracle in the LICENSE file that accompanied this code.9*10* This code is distributed in the hope that it will be useful, but WITHOUT11* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or12* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License13* version 2 for more details (a copy is included in the LICENSE file that14* accompanied this code).15*16* You should have received a copy of the GNU General Public License version17* 2 along with this work; if not, write to the Free Software Foundation,18* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.19*20* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA21* or visit www.oracle.com if you need additional information or have any22* questions.23*/2425package com.sun.crypto.provider;2627import java.util.Arrays;28import java.security.*;29import java.security.spec.*;30import javax.crypto.*;31import javax.crypto.spec.*;32import static com.sun.crypto.provider.KWUtil.*;3334/**35* This class implement the AES KeyWrap With Padding mode of operation as36* defined in37* <a href=https://nvlpubs.nist.gov/nistpubs/SpecialPublications/NIST.SP.800-38F.pdf>38* "Recommendation for Block Cipher Modes of Operation: Methods for Key Wrapping"</a>39* and represents AES cipher in KWP mode.40*/41class AESKeyWrapPadded extends FeedbackCipher {4243// default integrity check value (icv) if iv is not supplied44private static final byte[] ICV2 = { // SEMI_BLKSIZE/2 long45(byte) 0xA6, (byte) 0x59, (byte) 0x59, (byte) 0xA6,46};4748private static final byte[] PAD_BLK = new byte[SEMI_BLKSIZE - 1];4950// set the first semiblock of dest with iv and inLen51private static void setIvAndLen(byte[] dest, byte[] iv, int inLen) {52assert(dest.length >= SEMI_BLKSIZE) : "buffer needs at least 8 bytes";5354System.arraycopy(iv, 0, dest, 0, iv.length);55dest[4] = (byte) ((inLen >>> 24) & 0xFF);56dest[5] = (byte) ((inLen >>> 16) & 0xFF);57dest[6] = (byte) ((inLen >>> 8) & 0xFF);58dest[7] = (byte) (inLen & 0xFF);59}6061// validate the recovered internal ivAndLen semiblock against iv and62// return the recovered input length63private static int validateIV(byte[] ivAndLen, byte[] iv)64throws IllegalBlockSizeException {65// check against iv and fail if not match66int match = 0;67for (int i = 0; i < ICV2.length; i++) {68match |= (ivAndLen[i] ^ iv[i]);69}70if (match != 0) {71throw new IllegalBlockSizeException("Integrity check failed");72}73int outLen = ivAndLen[4];7475for (int k = 5; k < SEMI_BLKSIZE; k++) {76if (outLen != 0) {77outLen <<= 8;78}79outLen |= ivAndLen[k] & 0xFF;80}81return outLen;82}8384AESKeyWrapPadded() {85super(new AESCrypt());86}8788/**89* Gets the name of this feedback mode.90*91* @return the string <code>KW</code>92*/93@Override94String getFeedback() {95return "KWP";96}9798/**99* Save the current content of this cipher.100*/101@Override102void save() {103throw new UnsupportedOperationException("save not supported");104};105106/**107* Restores the content of this cipher to the previous saved one.108*/109@Override110void restore() {111throw new UnsupportedOperationException("restore not supported");112};113114/**115* Initializes the cipher in the specified mode with the given key116* and iv.117*118* @param decrypting flag indicating encryption or decryption119* @param algorithm the algorithm name120* @param key the key121* @param iv the iv122*123* @exception InvalidKeyException if the given key is inappropriate for124* initializing this cipher125* @exception InvalidAlgorithmParameterException if the given iv is126* non-null and not the right length127*/128@Override129void init(boolean decrypting, String algorithm, byte[] key, byte[] iv)130throws InvalidKeyException, InvalidAlgorithmParameterException {131if (key == null) {132throw new InvalidKeyException("Invalid null key");133}134if (iv != null && iv.length != ICV2.length) {135throw new InvalidAlgorithmParameterException("Invalid IV length");136}137embeddedCipher.init(decrypting, algorithm, key);138// iv is retrieved from IvParameterSpec.getIV() which is already cloned139this.iv = (iv == null? ICV2 : iv);140}141142/**143* Resets the iv to its original value.144* This is used when doFinal is called in the Cipher class, so that the145* cipher can be reused (with its original iv).146*/147@Override148void reset() {149throw new UnsupportedOperationException("reset not supported");150};151152// no support for multi-part encryption153@Override154int encrypt(byte[] pt, int ptOfs, int ptLen, byte[] ct, int ctOfs) {155throw new UnsupportedOperationException("multi-part not supported");156};157158// no support for multi-part decryption159@Override160int decrypt(byte[] ct, int ctOfs, int ctLen, byte[] pt, int ptOfs) {161throw new UnsupportedOperationException("multi-part not supported");162};163164/**165* Performs single-part encryption operation.166*167* <p>The input <code>pt</code>, starting at <code>0</code>168* and ending at <code>ptLen-1</code>, is encrypted.169* The result is stored in place into <code>pt</code>, starting at170* <code>0</code>.171*172* <p>The subclass that implements Cipher should ensure that173* <code>init</code> has been called before this method is called.174*175* @param pt the input buffer with the data to be encrypted176* @param dummy1 the offset in <code>pt</code> which is always 0177* @param ptLen the length of the input data178* @param dummy2 the output buffer for the encryption which is always pt179* @param dummy3 the offset in the output buffer which is always 0180* @return the number of bytes placed into <code>pt</code>181*/182@Override183int encryptFinal(byte[] pt, int dummy1, int ptLen, byte[] dummy2,184int dummy3) throws IllegalBlockSizeException {185int actualLen = ptLen - SEMI_BLKSIZE;186if (actualLen < 1) {187throw new IllegalBlockSizeException188("data should have at least 1 byte");189}190191if (ptLen % SEMI_BLKSIZE != 0) {192int rem = SEMI_BLKSIZE - (ptLen % SEMI_BLKSIZE);193System.arraycopy(PAD_BLK, 0, pt, ptLen, rem);194ptLen += rem;195}196197if (ptLen <= BLKSIZE) {198// overwrite the first semiblock with iv and input length199setIvAndLen(pt, iv, actualLen);200embeddedCipher.encryptBlock(pt, 0, pt, 0);201} else {202byte[] ivAndLen = new byte[SEMI_BLKSIZE];203setIvAndLen(ivAndLen, iv, actualLen);204ptLen = W(ivAndLen, pt, ptLen, embeddedCipher);205}206return ptLen;207}208209/**210* Performs single-part decryption operation.211*212* <p>The input <code>ct</code>, starting at <code>0</code>213* and ending at <code>ctLen-1</code>, is decrypted.214* The result is stored in place into <code>ct</code>, starting at215* <code>0</code>.216*217* <p>The subclass that implements Cipher should ensure that218* <code>init</code> has been called before this method is called.219*220* @param ct the input buffer with the data to be decrypted221* @param dummy1 the offset in <code>ct</code> which is always 0222* @param ctLen the length of the input data223* @param dummy2 the output buffer for the decryption which is always ct224* @param dummy3 the offset in the output buffer which is always 0225* @return the number of bytes placed into <code>ct</code>226*/227@Override228int decryptFinal(byte[] ct, int dummy1, int ctLen, byte[] dummy2,229int dummy3) throws IllegalBlockSizeException {230if (ctLen < BLKSIZE || ctLen % SEMI_BLKSIZE != 0) {231throw new IllegalBlockSizeException232("data should be at least 16 bytes and multiples of 8");233}234235byte[] ivAndLen = new byte[SEMI_BLKSIZE];236if (ctLen == BLKSIZE) {237embeddedCipher.decryptBlock(ct, 0, ct, 0);238System.arraycopy(ct, 0, ivAndLen, 0, SEMI_BLKSIZE);239System.arraycopy(ct, SEMI_BLKSIZE, ct, 0, SEMI_BLKSIZE);240ctLen -= SEMI_BLKSIZE;241} else {242ctLen = W_INV(ct, ctLen, ivAndLen, embeddedCipher);243}244245int outLen = validateIV(ivAndLen, this.iv);246// check padding bytes247int padLen = ctLen - outLen;248if (padLen < 0 || padLen >= SEMI_BLKSIZE) {249throw new IllegalBlockSizeException("Invalid KWP pad length " +250padLen);251}252for (int k = padLen; k > 0; k--) {253if (ct[ctLen - k] != 0) {254throw new IllegalBlockSizeException("Invalid KWP pad value");255}256}257return outLen;258}259}260261262