/*
 * 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 "Recommendation for Block Cipher Modes of Operation: Methods for Key Wrapping" and represents AES cipher in KW mode.
/** * 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 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.
Returns:the string KW
/** * 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.
/** * 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.
/** * 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.
Params:
  • decrypting – flag indicating encryption or decryption
  • algorithm – the algorithm name
  • key – the key
  • iv – the iv
Throws:
/** * 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).
/** * 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.

The input pt, starting at 0 and ending at ptLen-1, is encrypted. The result is stored in place into pt, starting at 0.

The subclass that implements Cipher should ensure that init has been called before this method is called.

Params:
  • pt – the input buffer with the data to be encrypted
  • dummy1 – the offset in pt which is always 0
  • ptLen – the length of the input data
  • dummy2 – the output buffer for the encryption which is always pt
  • dummy3 – the offset in the output buffer which is always 0
Returns:the number of bytes placed into pt
/** * 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.

The input ct, starting at 0 and ending at ctLen-1, is decrypted. The result is stored in place into ct, starting at 0.

NOTE: Purpose of this special impl is for minimizing array copying, those unused arguments are named as dummyN.

The subclass that implements Cipher should ensure that init has been called before this method is called.

Params:
  • ct – the input buffer with the data to be decrypted
  • dummy1 – the offset in ct which is always 0
  • ctLen – the length of the input data
  • dummy2 – the output buffer for the decryption which is always ct
  • dummy3 – the offset in the output buffer which is always 0
Returns:the number of bytes placed into ct
/** * 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; } }