Skip to content

Commit

Permalink
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
Show file tree
Hide file tree
Showing 18 changed files with 2,223 additions and 675 deletions.
196 changes: 196 additions & 0 deletions src/java.base/share/classes/com/sun/crypto/provider/AESKeyWrap.java
@@ -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;
}
}

1 comment on commit 136badb

@openjdk-notifier
Copy link

Choose a reason for hiding this comment

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

Please sign in to comment.