--- old/src/jdk.crypto.ucrypto/solaris/classes/com/oracle/security/ucrypto/NativeCipher.java 2020-05-20 18:10:43.634431854 -0700 +++ /dev/null 2020-03-09 18:57:19.455001459 -0700 @@ -1,569 +0,0 @@ -/* - * Copyright (c) 2014, 2015, 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.oracle.security.ucrypto; - -import java.nio.ByteBuffer; -import java.util.Set; -import java.util.Arrays; -import java.util.concurrent.ConcurrentSkipListSet; -import java.lang.ref.*; - -import java.security.*; -import java.security.spec.*; -import javax.crypto.*; - -import javax.crypto.spec.SecretKeySpec; -import javax.crypto.spec.IvParameterSpec; - -import sun.security.jca.JCAUtil; - -/** - * Cipher wrapper class utilizing ucrypto APIs. This class currently supports - * - AES/ECB/NOPADDING - * - AES/CBC/NOPADDING - * - AES/CTR/NOPADDING - * - AES/CFB128/NOPADDING - * (Support for GCM mode is inside the child class NativeGCMCipher) - * - * @since 9 - */ -class NativeCipher extends CipherSpi { - - // public implementation classes - public static final class AesEcbNoPadding extends NativeCipher { - public AesEcbNoPadding() throws NoSuchAlgorithmException { - super(UcryptoMech.CRYPTO_AES_ECB); - } - public AesEcbNoPadding(int keySize) throws NoSuchAlgorithmException { - super(UcryptoMech.CRYPTO_AES_ECB, keySize); - } - } - public static final class AesCbcNoPadding extends NativeCipher { - public AesCbcNoPadding() throws NoSuchAlgorithmException { - super(UcryptoMech.CRYPTO_AES_CBC); - } - public AesCbcNoPadding(int keySize) throws NoSuchAlgorithmException { - super(UcryptoMech.CRYPTO_AES_CBC, keySize); - } - } - public static final class AesCtrNoPadding extends NativeCipher { - public AesCtrNoPadding() throws NoSuchAlgorithmException { - super(UcryptoMech.CRYPTO_AES_CTR); - } - } - public static final class AesCfb128NoPadding extends NativeCipher { - public AesCfb128NoPadding() throws NoSuchAlgorithmException { - super(UcryptoMech.CRYPTO_AES_CFB128); - } - } - - // ok as constants since AES is all we support - public static final int AES_BLOCK_SIZE = 16; - public static final String AES_KEY_ALGO = "AES"; - - // fields set in constructor - protected final UcryptoMech mech; - protected String keyAlgo; - protected int blockSize; - protected int fixedKeySize; - - // - // fields (re)set in every init() - // - protected CipherContextRef pCtxt = null; - protected byte[] keyValue = null; - protected byte[] iv = null; - protected boolean initialized = false; - protected boolean encrypt = true; - protected int bytesBuffered = 0; - - // private utility methods for key re-construction - private static final PublicKey constructPublicKey(byte[] encodedKey, - String encodedKeyAlgorithm) - throws InvalidKeyException, NoSuchAlgorithmException { - - PublicKey key = null; - try { - KeyFactory keyFactory = - KeyFactory.getInstance(encodedKeyAlgorithm); - X509EncodedKeySpec keySpec = new X509EncodedKeySpec(encodedKey); - key = keyFactory.generatePublic(keySpec); - } catch (NoSuchAlgorithmException nsae) { - throw new NoSuchAlgorithmException("No provider found for " + - encodedKeyAlgorithm + - " KeyFactory"); - } catch (InvalidKeySpecException ikse) { - // Should never happen - throw new InvalidKeyException("Cannot construct public key", ikse); - } - return key; - } - - private static final PrivateKey constructPrivateKey(byte[] encodedKey, - String encodedKeyAlgorithm) - throws InvalidKeyException, NoSuchAlgorithmException { - - PrivateKey key = null; - try { - KeyFactory keyFactory = - KeyFactory.getInstance(encodedKeyAlgorithm); - PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(encodedKey); - key = keyFactory.generatePrivate(keySpec); - } catch (NoSuchAlgorithmException nsae) { - throw new NoSuchAlgorithmException("No provider found for " + - encodedKeyAlgorithm + - " KeyFactory"); - } catch (InvalidKeySpecException ikse) { - // Should never happen - throw new InvalidKeyException("Cannot construct private key", ikse); - } - return key; - } - - private static final SecretKey constructSecretKey(byte[] encodedKey, - String encodedKeyAlgorithm) { - return new SecretKeySpec(encodedKey, encodedKeyAlgorithm); - } - - // package-private utility method for general key re-construction - static final Key constructKey(int keyType, byte[] encodedKey, - String encodedKeyAlgorithm) - throws InvalidKeyException, NoSuchAlgorithmException { - Key result = null; - switch (keyType) { - case Cipher.SECRET_KEY: - result = constructSecretKey(encodedKey, - encodedKeyAlgorithm); - break; - case Cipher.PRIVATE_KEY: - result = constructPrivateKey(encodedKey, - encodedKeyAlgorithm); - break; - case Cipher.PUBLIC_KEY: - result = constructPublicKey(encodedKey, - encodedKeyAlgorithm); - break; - } - return result; - } - - NativeCipher(UcryptoMech mech, int fixedKeySize) throws NoSuchAlgorithmException { - this.mech = mech; - // defaults to AES - the only supported symmetric cipher algo - this.blockSize = AES_BLOCK_SIZE; - this.keyAlgo = AES_KEY_ALGO; - this.fixedKeySize = fixedKeySize; - } - - NativeCipher(UcryptoMech mech) throws NoSuchAlgorithmException { - this(mech, -1); - } - - @Override - protected void engineSetMode(String mode) throws NoSuchAlgorithmException { - // Disallow change of mode for now since currently it's explicitly - // defined in transformation strings - throw new NoSuchAlgorithmException("Unsupported mode " + mode); - } - - // see JCE spec - @Override - protected void engineSetPadding(String padding) - throws NoSuchPaddingException { - // Disallow change of padding for now since currently it's explicitly - // defined in transformation strings - throw new NoSuchPaddingException("Unsupported padding " + padding); - } - - // see JCE spec - @Override - protected int engineGetBlockSize() { - return blockSize; - } - - // see JCE spec - @Override - protected synchronized int engineGetOutputSize(int inputLen) { - return getOutputSizeByOperation(inputLen, true); - } - - // see JCE spec - @Override - protected synchronized byte[] engineGetIV() { - return (iv != null? iv.clone() : null); - } - - // see JCE spec - @Override - protected synchronized AlgorithmParameters engineGetParameters() { - AlgorithmParameters params = null; - try { - if (iv != null) { - IvParameterSpec ivSpec = new IvParameterSpec(iv.clone()); - params = AlgorithmParameters.getInstance(keyAlgo); - params.init(ivSpec); - } - } catch (GeneralSecurityException e) { - // NoSuchAlgorithmException, NoSuchProviderException - // InvalidParameterSpecException - throw new UcryptoException("Could not encode parameters", e); - } - return params; - } - - @Override - protected int engineGetKeySize(Key key) throws InvalidKeyException { - return checkKey(key) * 8; - } - - // see JCE spec - @Override - protected synchronized void engineInit(int opmode, Key key, - SecureRandom random) throws InvalidKeyException { - try { - engineInit(opmode, key, (AlgorithmParameterSpec)null, random); - } catch (InvalidAlgorithmParameterException e) { - throw new InvalidKeyException("init() failed", e); - } - } - - // see JCE spec - @Override - protected synchronized void engineInit(int opmode, Key key, - AlgorithmParameterSpec params, SecureRandom random) - throws InvalidKeyException, InvalidAlgorithmParameterException { - checkKey(key); - if (opmode != Cipher.ENCRYPT_MODE && - opmode != Cipher.DECRYPT_MODE && - opmode != Cipher.WRAP_MODE && - opmode != Cipher.UNWRAP_MODE) { - throw new InvalidAlgorithmParameterException - ("Unsupported mode: " + opmode); - } - boolean doEncrypt = - (opmode == Cipher.ENCRYPT_MODE || opmode == Cipher.WRAP_MODE); - - byte[] ivBytes = null; - if (mech == UcryptoMech.CRYPTO_AES_ECB) { - if (params != null) { - throw new InvalidAlgorithmParameterException - ("No Parameters for ECB mode"); - } - } else { - if (params != null) { - if (!(params instanceof IvParameterSpec)) { - throw new InvalidAlgorithmParameterException - ("IvParameterSpec required. Received: " + - params.getClass().getName()); - } else { - ivBytes = ((IvParameterSpec) params).getIV(); - if (ivBytes.length != blockSize) { - throw new InvalidAlgorithmParameterException - ("Wrong IV length: must be " + blockSize + - " bytes long. Received length:" + ivBytes.length); - } - } - } else { - if (encrypt) { - // generate IV if none supplied for encryption - ivBytes = new byte[blockSize]; - if (random == null) { - random = JCAUtil.getSecureRandom(); - } - random.nextBytes(ivBytes); - } else { - throw new InvalidAlgorithmParameterException - ("Parameters required for decryption"); - } - } - } - init(doEncrypt, key.getEncoded().clone(), ivBytes); - } - - // see JCE spec - @Override - protected synchronized void engineInit(int opmode, Key key, - AlgorithmParameters params, SecureRandom random) - throws InvalidKeyException, InvalidAlgorithmParameterException { - AlgorithmParameterSpec spec = null; - if (params != null) { - try { - spec = params.getParameterSpec(IvParameterSpec.class); - } catch (InvalidParameterSpecException iaps) { - throw new InvalidAlgorithmParameterException(iaps); - } - } - engineInit(opmode, key, spec, random); - } - - // see JCE spec - @Override - protected synchronized byte[] engineUpdate(byte[] in, int ofs, int len) { - byte[] out = new byte[getOutputSizeByOperation(len, false)]; - int n = update(in, ofs, len, out, 0); - if (n == 0) { - return null; - } else if (out.length != n) { - out = Arrays.copyOf(out, n); - } - return out; - } - - // see JCE spec - @Override - protected synchronized int engineUpdate(byte[] in, int inOfs, int inLen, - byte[] out, int outOfs) throws ShortBufferException { - int min = getOutputSizeByOperation(inLen, false); - if (out.length - outOfs < min) { - throw new ShortBufferException("min " + min + "-byte buffer needed"); - } - return update(in, inOfs, inLen, out, outOfs); - } - - // see JCE spec - @Override - protected synchronized void engineUpdateAAD(byte[] src, int ofs, int len) - throws IllegalStateException { - throw new IllegalStateException("No AAD can be supplied"); - } - - // see JCE spec - @Override - protected void engineUpdateAAD(ByteBuffer src) - throws IllegalStateException { - throw new IllegalStateException("No AAD can be supplied"); - } - - // see JCE spec - @Override - protected synchronized byte[] engineDoFinal(byte[] in, int ofs, int len) - throws IllegalBlockSizeException, BadPaddingException { - byte[] out = new byte[getOutputSizeByOperation(len, true)]; - try { - // delegate to the other engineDoFinal(...) method - int k = engineDoFinal(in, ofs, len, out, 0); - if (out.length != k) { - out = Arrays.copyOf(out, k); - } - return out; - } catch (ShortBufferException e) { - throw new UcryptoException("Internal Error", e); - } - } - - // see JCE spec - @Override - protected synchronized int engineDoFinal(byte[] in, int inOfs, int inLen, - byte[] out, int outOfs) - throws ShortBufferException, IllegalBlockSizeException, - BadPaddingException { - int k = 0; - int min = getOutputSizeByOperation(inLen, true); - if (out.length - outOfs < min) { - throw new ShortBufferException("min " + min + "-byte buffer needed"); - } - if (inLen > 0) { - k = update(in, inOfs, inLen, out, outOfs); - outOfs += k; - } - k += doFinal(out, outOfs); - return k; - } - - - // see JCE spec - @Override - protected synchronized byte[] engineWrap(Key key) - throws IllegalBlockSizeException, InvalidKeyException { - byte[] result = null; - try { - byte[] encodedKey = key.getEncoded(); - if ((encodedKey == null) || (encodedKey.length == 0)) { - throw new InvalidKeyException("Cannot get an encoding of " + - "the key to be wrapped"); - } - result = engineDoFinal(encodedKey, 0, encodedKey.length); - } catch (BadPaddingException e) { - // Should never happen for key wrapping - throw new UcryptoException("Internal Error" , e); - } - return result; - } - - // see JCE spec - @Override - protected synchronized Key engineUnwrap(byte[] wrappedKey, - String wrappedKeyAlgorithm, int wrappedKeyType) - throws InvalidKeyException, NoSuchAlgorithmException { - - byte[] encodedKey; - Key result = null; - try { - encodedKey = engineDoFinal(wrappedKey, 0, - wrappedKey.length); - } catch (Exception e) { - throw (InvalidKeyException) - (new InvalidKeyException()).initCause(e); - } - - return constructKey(wrappedKeyType, encodedKey, wrappedKeyAlgorithm); - } - - final int checkKey(Key key) throws InvalidKeyException { - if (key == null || key.getEncoded() == null) { - throw new InvalidKeyException("Key cannot be null"); - } else { - // check key algorithm and format - if (!keyAlgo.equalsIgnoreCase(key.getAlgorithm())) { - throw new InvalidKeyException("Key algorithm must be " + - keyAlgo); - } - if (!"RAW".equalsIgnoreCase(key.getFormat())) { - throw new InvalidKeyException("Key format must be RAW"); - } - int keyLen = key.getEncoded().length; - if (fixedKeySize == -1) { - // all 3 AES key lengths are allowed - if (keyLen != 16 && keyLen != 24 && keyLen != 32) { - throw new InvalidKeyException("Key size is not valid." + - " Got key length of: " + keyLen); - } - } else { - if (keyLen != fixedKeySize) { - throw new InvalidKeyException("Only " + fixedKeySize + - "-byte keys are accepted. Got: " + keyLen); - } - } - // return the validated key length in bytes - return keyLen; - } - } - - protected void reset(boolean doCancel) { - initialized = false; - bytesBuffered = 0; - if (pCtxt != null) { - pCtxt.dispose(doCancel); - pCtxt = null; - } - } - - /** - * calls ucrypto_encrypt_init(...) or ucrypto_decrypt_init(...) - * @return pointer to the context - */ - protected native static long nativeInit(int mech, boolean encrypt, - byte[] key, byte[] iv, - int tagLen, byte[] aad); - - /** - * calls ucrypto_encrypt_update(...) or ucrypto_decrypt_update(...) - * @return the length of output or if negative, an error status code - */ - private native static int nativeUpdate(long pContext, boolean encrypt, - byte[] in, int inOfs, int inLen, - byte[] out, int outOfs); - - /** - * calls ucrypto_encrypt_final(...) or ucrypto_decrypt_final(...) - * @return the length of output or if negative, an error status code - */ - native static int nativeFinal(long pContext, boolean encrypt, - byte[] out, int outOfs); - - protected void ensureInitialized() { - if (!initialized) { - init(encrypt, keyValue, iv); - if (!initialized) { - throw new UcryptoException("Cannot initialize Cipher"); - } - } - } - - protected int getOutputSizeByOperation(int inLen, boolean isDoFinal) { - if (inLen <= 0) { - inLen = 0; - } - if (!isDoFinal && (inLen == 0)) { - return 0; - } - return inLen + bytesBuffered; - } - - // actual init() implementation - caller should clone key and iv if needed - protected void init(boolean encrypt, byte[] keyVal, byte[] ivVal) { - reset(true); - this.encrypt = encrypt; - this.keyValue = keyVal; - this.iv = ivVal; - long pCtxtVal = nativeInit(mech.value(), encrypt, keyValue, iv, 0, null); - initialized = (pCtxtVal != 0L); - if (initialized) { - pCtxt = new CipherContextRef(this, pCtxtVal, encrypt); - } else { - throw new UcryptoException("Cannot initialize Cipher"); - } - } - - // Caller MUST check and ensure output buffer has enough capacity - private int update(byte[] in, int inOfs, int inLen, byte[] out, int outOfs) { - ensureInitialized(); - if (inLen <= 0) { return 0; } - - int k = nativeUpdate(pCtxt.id, encrypt, in, inOfs, inLen, out, outOfs); - if (k < 0) { - reset(false); - // cannot throw ShortBufferException here since it's too late - // native context is invalid upon any failure - throw new UcryptoException(-k); - } - bytesBuffered += (inLen - k); - return k; - } - - // Caller MUST check and ensure output buffer has enough capacity - private int doFinal(byte[] out, int outOfs) throws IllegalBlockSizeException, - BadPaddingException { - try { - ensureInitialized(); - - int k = nativeFinal(pCtxt.id, encrypt, out, outOfs); - if (k < 0) { - String cause = UcryptoException.getErrorMessage(-k); - if (cause.endsWith("_LEN_RANGE")) { - throw new IllegalBlockSizeException(cause); - } else if (cause.endsWith("_DATA_INVALID")) { - throw new BadPaddingException(cause); - } else { - throw new UcryptoException(-k); - } - } - return k; - } finally { - reset(false); - } - } -}