NativeCipher.java revision 13517:a043ca3a539c
1103285Sikob/* 2113584Ssimokawa * Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved. 3113584Ssimokawa * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4103285Sikob * 5103285Sikob * This code is free software; you can redistribute it and/or modify it 6103285Sikob * under the terms of the GNU General Public License version 2 only, as 7103285Sikob * published by the Free Software Foundation. Oracle designates this 8103285Sikob * particular file as subject to the "Classpath" exception as provided 9103285Sikob * by Oracle in the LICENSE file that accompanied this code. 10103285Sikob * 11103285Sikob * This code is distributed in the hope that it will be useful, but WITHOUT 12103285Sikob * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13103285Sikob * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14103285Sikob * version 2 for more details (a copy is included in the LICENSE file that 15103285Sikob * accompanied this code). 16103285Sikob * 17103285Sikob * You should have received a copy of the GNU General Public License version 18103285Sikob * 2 along with this work; if not, write to the Free Software Foundation, 19103285Sikob * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20103285Sikob * 21103285Sikob * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22103285Sikob * or visit www.oracle.com if you need additional information or have any 23103285Sikob * questions. 24103285Sikob */ 25103285Sikob 26103285Sikobpackage com.oracle.security.ucrypto; 27103285Sikob 28103285Sikobimport java.nio.ByteBuffer; 29103285Sikobimport java.util.Set; 30103285Sikobimport java.util.Arrays; 31103285Sikobimport java.util.concurrent.ConcurrentSkipListSet; 32103285Sikobimport java.lang.ref.*; 33103285Sikob 34103285Sikobimport java.security.*; 35103285Sikobimport java.security.spec.*; 36103285Sikobimport javax.crypto.*; 37103285Sikob 38103285Sikobimport javax.crypto.spec.SecretKeySpec; 39103285Sikobimport javax.crypto.spec.IvParameterSpec; 40103285Sikob 41103285Sikobimport sun.security.jca.JCAUtil; 42103285Sikob 43103285Sikob/** 44103285Sikob * Cipher wrapper class utilizing ucrypto APIs. This class currently supports 45103285Sikob * - AES/ECB/NOPADDING 46103285Sikob * - AES/CBC/NOPADDING 47112136Ssimokawa * - AES/CTR/NOPADDING 48112136Ssimokawa * - AES/CFB128/NOPADDING 49112136Ssimokawa * (Support for GCM mode is inside the child class NativeGCMCipher) 50103285Sikob * 51103285Sikob * @since 1.9 52103285Sikob */ 53103285Sikobclass NativeCipher extends CipherSpi { 54103285Sikob 55103285Sikob // public implementation classes 56103285Sikob public static final class AesEcbNoPadding extends NativeCipher { 57103285Sikob public AesEcbNoPadding() throws NoSuchAlgorithmException { 58103285Sikob super(UcryptoMech.CRYPTO_AES_ECB); 59103285Sikob } 60103285Sikob public AesEcbNoPadding(int keySize) throws NoSuchAlgorithmException { 61103285Sikob super(UcryptoMech.CRYPTO_AES_ECB, keySize); 62103285Sikob } 63103285Sikob } 64103285Sikob public static final class AesCbcNoPadding extends NativeCipher { 65103285Sikob public AesCbcNoPadding() throws NoSuchAlgorithmException { 66113584Ssimokawa super(UcryptoMech.CRYPTO_AES_CBC); 67103285Sikob } 68103285Sikob public AesCbcNoPadding(int keySize) throws NoSuchAlgorithmException { 69103285Sikob super(UcryptoMech.CRYPTO_AES_CBC, keySize); 70103285Sikob } 71103285Sikob } 72111615Ssimokawa public static final class AesCtrNoPadding extends NativeCipher { 73103285Sikob public AesCtrNoPadding() throws NoSuchAlgorithmException { 74113584Ssimokawa super(UcryptoMech.CRYPTO_AES_CTR); 75113584Ssimokawa } 76113584Ssimokawa } 77103285Sikob public static final class AesCfb128NoPadding extends NativeCipher { 78113584Ssimokawa public AesCfb128NoPadding() throws NoSuchAlgorithmException { 79103285Sikob super(UcryptoMech.CRYPTO_AES_CFB128); 80111615Ssimokawa } 81111615Ssimokawa } 82111615Ssimokawa 83111615Ssimokawa // ok as constants since AES is all we support 84111615Ssimokawa public static final int AES_BLOCK_SIZE = 16; 85111615Ssimokawa public static final String AES_KEY_ALGO = "AES"; 86111615Ssimokawa 87111615Ssimokawa // fields set in constructor 88111615Ssimokawa protected final UcryptoMech mech; 89111615Ssimokawa protected String keyAlgo; 90111615Ssimokawa protected int blockSize; 91111615Ssimokawa protected int fixedKeySize; 92111615Ssimokawa 93111615Ssimokawa // 94111615Ssimokawa // fields (re)set in every init() 95103285Sikob // 96111615Ssimokawa protected CipherContextRef pCtxt = null; 97103285Sikob protected byte[] keyValue = null; 98103285Sikob protected byte[] iv = null; 99103285Sikob protected boolean initialized = false; 100103285Sikob protected boolean encrypt = true; 101103285Sikob protected int bytesBuffered = 0; 102103285Sikob 103103285Sikob // private utility methods for key re-construction 104103285Sikob private static final PublicKey constructPublicKey(byte[] encodedKey, 105103285Sikob String encodedKeyAlgorithm) 106103285Sikob throws InvalidKeyException, NoSuchAlgorithmException { 107103285Sikob 108103285Sikob PublicKey key = null; 109103285Sikob try { 110103285Sikob KeyFactory keyFactory = 111103285Sikob KeyFactory.getInstance(encodedKeyAlgorithm); 112103285Sikob X509EncodedKeySpec keySpec = new X509EncodedKeySpec(encodedKey); 113103285Sikob key = keyFactory.generatePublic(keySpec); 114103285Sikob } catch (NoSuchAlgorithmException nsae) { 115103285Sikob throw new NoSuchAlgorithmException("No provider found for " + 116103285Sikob encodedKeyAlgorithm + 117103285Sikob " KeyFactory"); 118103285Sikob } catch (InvalidKeySpecException ikse) { 119103285Sikob // Should never happen 120103285Sikob throw new InvalidKeyException("Cannot construct public key", ikse); 121103285Sikob } 122103285Sikob return key; 123103285Sikob } 124103285Sikob 125111615Ssimokawa private static final PrivateKey constructPrivateKey(byte[] encodedKey, 126103285Sikob String encodedKeyAlgorithm) 127103285Sikob throws InvalidKeyException, NoSuchAlgorithmException { 128103285Sikob 129103285Sikob PrivateKey key = null; 130103285Sikob try { 131103285Sikob KeyFactory keyFactory = 132103285Sikob KeyFactory.getInstance(encodedKeyAlgorithm); 133103285Sikob PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(encodedKey); 134103285Sikob key = keyFactory.generatePrivate(keySpec); 135103285Sikob } catch (NoSuchAlgorithmException nsae) { 136103285Sikob throw new NoSuchAlgorithmException("No provider found for " + 137103285Sikob encodedKeyAlgorithm + 138103285Sikob " KeyFactory"); 139103285Sikob } catch (InvalidKeySpecException ikse) { 140103285Sikob // Should never happen 141103285Sikob throw new InvalidKeyException("Cannot construct private key", ikse); 142103285Sikob } 143103285Sikob return key; 144103285Sikob } 145103285Sikob 146103285Sikob private static final SecretKey constructSecretKey(byte[] encodedKey, 147103285Sikob String encodedKeyAlgorithm) { 148103285Sikob return new SecretKeySpec(encodedKey, encodedKeyAlgorithm); 149103285Sikob } 150103285Sikob 151111203Ssimokawa // package-private utility method for general key re-construction 152103285Sikob static final Key constructKey(int keyType, byte[] encodedKey, 153103285Sikob String encodedKeyAlgorithm) 154111199Ssimokawa throws InvalidKeyException, NoSuchAlgorithmException { 155103285Sikob Key result = null; 156103285Sikob switch (keyType) { 157103285Sikob case Cipher.SECRET_KEY: 158103285Sikob result = constructSecretKey(encodedKey, 159103285Sikob encodedKeyAlgorithm); 160103285Sikob break; 161103285Sikob case Cipher.PRIVATE_KEY: 162103285Sikob result = constructPrivateKey(encodedKey, 163103285Sikob encodedKeyAlgorithm); 164103285Sikob break; 165103285Sikob case Cipher.PUBLIC_KEY: 166103285Sikob result = constructPublicKey(encodedKey, 167103285Sikob encodedKeyAlgorithm); 168103285Sikob break; 169103285Sikob } 170103285Sikob return result; 171103285Sikob } 172103285Sikob 173113584Ssimokawa NativeCipher(UcryptoMech mech, int fixedKeySize) throws NoSuchAlgorithmException { 174113584Ssimokawa this.mech = mech; 175113584Ssimokawa // defaults to AES - the only supported symmetric cipher algo 176113584Ssimokawa this.blockSize = AES_BLOCK_SIZE; 177113584Ssimokawa this.keyAlgo = AES_KEY_ALGO; 178113584Ssimokawa this.fixedKeySize = fixedKeySize; 179103285Sikob } 180103285Sikob 181103285Sikob NativeCipher(UcryptoMech mech) throws NoSuchAlgorithmException { 182113584Ssimokawa this(mech, -1); 183103285Sikob } 184113584Ssimokawa 185103285Sikob @Override 186103285Sikob protected void engineSetMode(String mode) throws NoSuchAlgorithmException { 187113584Ssimokawa // Disallow change of mode for now since currently it's explicitly 188103285Sikob // defined in transformation strings 189103285Sikob throw new NoSuchAlgorithmException("Unsupported mode " + mode); 190113584Ssimokawa } 191103285Sikob 192103285Sikob // see JCE spec 193113584Ssimokawa @Override 194103285Sikob protected void engineSetPadding(String padding) 195113584Ssimokawa throws NoSuchPaddingException { 196103285Sikob // Disallow change of padding for now since currently it's explicitly 197103285Sikob // defined in transformation strings 198103285Sikob throw new NoSuchPaddingException("Unsupported padding " + padding); 199103285Sikob } 200103285Sikob 201103285Sikob // see JCE spec 202103285Sikob @Override 203103285Sikob protected int engineGetBlockSize() { 204103285Sikob return blockSize; 205103285Sikob } 206103285Sikob 207113584Ssimokawa // see JCE spec 208113584Ssimokawa @Override 209113584Ssimokawa protected synchronized int engineGetOutputSize(int inputLen) { 210113584Ssimokawa return getOutputSizeByOperation(inputLen, true); 211113584Ssimokawa } 212113584Ssimokawa 213103285Sikob // see JCE spec 214103285Sikob @Override 215103285Sikob protected synchronized byte[] engineGetIV() { 216103285Sikob return (iv != null? iv.clone() : null); 217113584Ssimokawa } 218113584Ssimokawa 219103285Sikob // see JCE spec 220103285Sikob @Override 221103285Sikob protected synchronized AlgorithmParameters engineGetParameters() { 222103285Sikob AlgorithmParameters params = null; 223103285Sikob try { 224103285Sikob if (iv != null) { 225103285Sikob IvParameterSpec ivSpec = new IvParameterSpec(iv.clone()); 226113584Ssimokawa params = AlgorithmParameters.getInstance(keyAlgo); 227113584Ssimokawa params.init(ivSpec); 228113584Ssimokawa } 229113584Ssimokawa } catch (GeneralSecurityException e) { 230113584Ssimokawa // NoSuchAlgorithmException, NoSuchProviderException 231113584Ssimokawa // InvalidParameterSpecException 232113584Ssimokawa throw new UcryptoException("Could not encode parameters", e); 233113584Ssimokawa } 234113584Ssimokawa return params; 235103285Sikob } 236103285Sikob 237103285Sikob @Override 238103285Sikob protected int engineGetKeySize(Key key) throws InvalidKeyException { 239103285Sikob return checkKey(key) * 8; 240103285Sikob } 241103285Sikob 242113584Ssimokawa // see JCE spec 243103285Sikob @Override 244103285Sikob protected synchronized void engineInit(int opmode, Key key, 245103285Sikob SecureRandom random) throws InvalidKeyException { 246103285Sikob try { 247113584Ssimokawa engineInit(opmode, key, (AlgorithmParameterSpec)null, random); 248113584Ssimokawa } catch (InvalidAlgorithmParameterException e) { 249113584Ssimokawa throw new InvalidKeyException("init() failed", e); 250113584Ssimokawa } 251113584Ssimokawa } 252103285Sikob 253103285Sikob // see JCE spec 254113584Ssimokawa @Override 255103285Sikob protected synchronized void engineInit(int opmode, Key key, 256113584Ssimokawa AlgorithmParameterSpec params, SecureRandom random) 257103285Sikob throws InvalidKeyException, InvalidAlgorithmParameterException { 258103285Sikob checkKey(key); 259103285Sikob if (opmode != Cipher.ENCRYPT_MODE && 260103285Sikob opmode != Cipher.DECRYPT_MODE && 261114732Ssimokawa opmode != Cipher.WRAP_MODE && 262110336Ssimokawa opmode != Cipher.UNWRAP_MODE) { 263103285Sikob throw new InvalidAlgorithmParameterException 264110336Ssimokawa ("Unsupported mode: " + opmode); 265103285Sikob } 266103285Sikob boolean doEncrypt = 267103285Sikob (opmode == Cipher.ENCRYPT_MODE || opmode == Cipher.WRAP_MODE); 268103285Sikob 269103285Sikob byte[] ivBytes = null; 270110336Ssimokawa if (mech == UcryptoMech.CRYPTO_AES_ECB) { 271114732Ssimokawa if (params != null) { 272108503Ssimokawa throw new InvalidAlgorithmParameterException 273108503Ssimokawa ("No Parameters for ECB mode"); 274111615Ssimokawa } 275103285Sikob } else { 276103285Sikob if (params != null) { 277113584Ssimokawa if (!(params instanceof IvParameterSpec)) { 278113584Ssimokawa throw new InvalidAlgorithmParameterException 279111615Ssimokawa ("IvParameterSpec required. Received: " + 280113584Ssimokawa params.getClass().getName()); 281103285Sikob } else { 282113584Ssimokawa ivBytes = ((IvParameterSpec) params).getIV(); 283103285Sikob if (ivBytes.length != blockSize) { 284103285Sikob throw new InvalidAlgorithmParameterException 285103285Sikob ("Wrong IV length: must be " + blockSize + 286103285Sikob " bytes long. Received length:" + ivBytes.length); 287103285Sikob } 288103285Sikob } 289103285Sikob } else { 290103285Sikob if (encrypt) { 291103285Sikob // generate IV if none supplied for encryption 292103285Sikob ivBytes = new byte[blockSize]; 293103285Sikob if (random == null) { 294103285Sikob random = JCAUtil.getSecureRandom(); 295111615Ssimokawa } 296111615Ssimokawa random.nextBytes(ivBytes); 297111615Ssimokawa } else { 298111615Ssimokawa throw new InvalidAlgorithmParameterException 299111615Ssimokawa ("Parameters required for decryption"); 300113584Ssimokawa } 301113584Ssimokawa } 302103285Sikob } 303103285Sikob init(doEncrypt, key.getEncoded().clone(), ivBytes); 304103285Sikob } 305103285Sikob 306103285Sikob // see JCE spec 307111615Ssimokawa @Override 308103285Sikob protected synchronized void engineInit(int opmode, Key key, 309103285Sikob AlgorithmParameters params, SecureRandom random) 310103285Sikob throws InvalidKeyException, InvalidAlgorithmParameterException { 311111615Ssimokawa AlgorithmParameterSpec spec = null; 312111615Ssimokawa if (params != null) { 313103285Sikob try { 314103285Sikob spec = params.getParameterSpec(IvParameterSpec.class); 315103285Sikob } catch (InvalidParameterSpecException iaps) { 316114732Ssimokawa throw new InvalidAlgorithmParameterException(iaps); 317103285Sikob } 318103285Sikob } 319103285Sikob engineInit(opmode, key, spec, random); 320113584Ssimokawa } 321103285Sikob 322103285Sikob // see JCE spec 323103285Sikob @Override 324113584Ssimokawa protected synchronized byte[] engineUpdate(byte[] in, int ofs, int len) { 325103285Sikob byte[] out = new byte[getOutputSizeByOperation(len, false)]; 326111615Ssimokawa int n = update(in, ofs, len, out, 0); 327110145Ssimokawa if (n == 0) { 328114732Ssimokawa return null; 329103285Sikob } else if (out.length != n) { 330111615Ssimokawa out = Arrays.copyOf(out, n); 331111615Ssimokawa } 332111615Ssimokawa return out; 333111615Ssimokawa } 334103285Sikob 335108281Ssimokawa // see JCE spec 336103285Sikob @Override 337103285Sikob protected synchronized int engineUpdate(byte[] in, int inOfs, int inLen, 338103285Sikob byte[] out, int outOfs) throws ShortBufferException { 339103285Sikob int min = getOutputSizeByOperation(inLen, false); 340111615Ssimokawa if (out.length - outOfs < min) { 341111615Ssimokawa throw new ShortBufferException("min " + min + "-byte buffer needed"); 342103285Sikob } 343103285Sikob return update(in, inOfs, inLen, out, outOfs); 344103285Sikob } 345103285Sikob 346103285Sikob // see JCE spec 347103285Sikob @Override 348103285Sikob protected synchronized void engineUpdateAAD(byte[] src, int ofs, int len) 349103285Sikob throws IllegalStateException { 350103285Sikob throw new IllegalStateException("No AAD can be supplied"); 351103285Sikob } 352103285Sikob 353103285Sikob // see JCE spec 354103285Sikob @Override 355103285Sikob protected void engineUpdateAAD(ByteBuffer src) 356103285Sikob throws IllegalStateException { 357103285Sikob throw new IllegalStateException("No AAD can be supplied"); 358103285Sikob } 359103285Sikob 360103285Sikob // see JCE spec 361103285Sikob @Override 362103285Sikob protected synchronized byte[] engineDoFinal(byte[] in, int ofs, int len) 363103285Sikob throws IllegalBlockSizeException, BadPaddingException { 364103285Sikob byte[] out = new byte[getOutputSizeByOperation(len, true)]; 365103285Sikob try { 366103285Sikob // delegate to the other engineDoFinal(...) method 367103285Sikob int k = engineDoFinal(in, ofs, len, out, 0); 368103285Sikob if (out.length != k) { 369103285Sikob out = Arrays.copyOf(out, k); 370103285Sikob } 371103285Sikob return out; 372103285Sikob } catch (ShortBufferException e) { 373103285Sikob throw new UcryptoException("Internal Error", e); 374103285Sikob } 375103285Sikob } 376103285Sikob 377103285Sikob // see JCE spec 378103285Sikob @Override 379103285Sikob protected synchronized int engineDoFinal(byte[] in, int inOfs, int inLen, 380103285Sikob byte[] out, int outOfs) 381103285Sikob throws ShortBufferException, IllegalBlockSizeException, 382103285Sikob BadPaddingException { 383103285Sikob int k = 0; 384103285Sikob int min = getOutputSizeByOperation(inLen, true); 385103285Sikob if (out.length - outOfs < min) { 386103285Sikob throw new ShortBufferException("min " + min + "-byte buffer needed"); 387103285Sikob } 388103285Sikob if (inLen > 0) { 389103285Sikob k = update(in, inOfs, inLen, out, outOfs); 390103285Sikob outOfs += k; 391103285Sikob } 392103285Sikob k += doFinal(out, outOfs); 393103285Sikob return k; 394103285Sikob } 395103285Sikob 396103285Sikob 397103285Sikob // see JCE spec 398103285Sikob @Override 399103285Sikob protected synchronized byte[] engineWrap(Key key) 400103285Sikob throws IllegalBlockSizeException, InvalidKeyException { 401103285Sikob byte[] result = null; 402103285Sikob try { 403103285Sikob byte[] encodedKey = key.getEncoded(); 404103285Sikob if ((encodedKey == null) || (encodedKey.length == 0)) { 405103285Sikob throw new InvalidKeyException("Cannot get an encoding of " + 406103285Sikob "the key to be wrapped"); 407103285Sikob } 408103285Sikob result = engineDoFinal(encodedKey, 0, encodedKey.length); 409103285Sikob } catch (BadPaddingException e) { 410103285Sikob // Should never happen for key wrapping 411103285Sikob throw new UcryptoException("Internal Error" , e); 412103285Sikob } 413103285Sikob return result; 414103285Sikob } 415103285Sikob 416111615Ssimokawa // see JCE spec 417111615Ssimokawa @Override 418111615Ssimokawa protected synchronized Key engineUnwrap(byte[] wrappedKey, 419103285Sikob String wrappedKeyAlgorithm, int wrappedKeyType) 420103285Sikob throws InvalidKeyException, NoSuchAlgorithmException { 421103285Sikob 422103285Sikob byte[] encodedKey; 423103285Sikob Key result = null; 424103285Sikob try { 425103285Sikob encodedKey = engineDoFinal(wrappedKey, 0, 426103285Sikob wrappedKey.length); 427103285Sikob } catch (Exception e) { 428103285Sikob throw (InvalidKeyException) 429103285Sikob (new InvalidKeyException()).initCause(e); 430103285Sikob } 431103285Sikob 432103285Sikob return constructKey(wrappedKeyType, encodedKey, wrappedKeyAlgorithm); 433103285Sikob } 434103285Sikob 435103285Sikob final int checkKey(Key key) throws InvalidKeyException { 436103285Sikob if (key == null || key.getEncoded() == null) { 437103285Sikob throw new InvalidKeyException("Key cannot be null"); 438108503Ssimokawa } else { 439108503Ssimokawa // check key algorithm and format 440103285Sikob if (!keyAlgo.equalsIgnoreCase(key.getAlgorithm())) { 441103285Sikob throw new InvalidKeyException("Key algorithm must be " + 442103285Sikob keyAlgo); 443103285Sikob } 444103285Sikob if (!"RAW".equalsIgnoreCase(key.getFormat())) { 445103285Sikob throw new InvalidKeyException("Key format must be RAW"); 446103285Sikob } 447103285Sikob int keyLen = key.getEncoded().length; 448103285Sikob if (fixedKeySize == -1) { 449103285Sikob // all 3 AES key lengths are allowed 450103285Sikob if (keyLen != 16 && keyLen != 24 && keyLen != 32) { 451103285Sikob throw new InvalidKeyException("Key size is not valid." + 452103285Sikob " Got key length of: " + keyLen); 453103285Sikob } 454110184Ssimokawa } else { 455110184Ssimokawa if (keyLen != fixedKeySize) { 456110184Ssimokawa throw new InvalidKeyException("Only " + fixedKeySize + 457110184Ssimokawa "-byte keys are accepted. Got: " + keyLen); 458110184Ssimokawa } 459110184Ssimokawa } 460110184Ssimokawa // return the validated key length in bytes 461110184Ssimokawa return keyLen; 462110184Ssimokawa } 463110184Ssimokawa } 464110184Ssimokawa 465110184Ssimokawa protected void reset(boolean doCancel) { 466110184Ssimokawa initialized = false; 467110184Ssimokawa bytesBuffered = 0; 468110184Ssimokawa if (pCtxt != null) { 469110184Ssimokawa pCtxt.dispose(doCancel); 470110184Ssimokawa pCtxt = null; 471110184Ssimokawa } 472110184Ssimokawa } 473110184Ssimokawa 474110184Ssimokawa /** 475110184Ssimokawa * calls ucrypto_encrypt_init(...) or ucrypto_decrypt_init(...) 476110184Ssimokawa * @return pointer to the context 477110184Ssimokawa */ 478110184Ssimokawa protected native static long nativeInit(int mech, boolean encrypt, 479110184Ssimokawa byte[] key, byte[] iv, 480110184Ssimokawa int tagLen, byte[] aad); 481110184Ssimokawa 482110184Ssimokawa /** 483110184Ssimokawa * calls ucrypto_encrypt_update(...) or ucrypto_decrypt_update(...) 484110184Ssimokawa * @return the length of output or if negative, an error status code 485110184Ssimokawa */ 486110184Ssimokawa private native static int nativeUpdate(long pContext, boolean encrypt, 487110184Ssimokawa byte[] in, int inOfs, int inLen, 488110184Ssimokawa byte[] out, int outOfs); 489110184Ssimokawa 490110184Ssimokawa /** 491110184Ssimokawa * calls ucrypto_encrypt_final(...) or ucrypto_decrypt_final(...) 492110184Ssimokawa * @return the length of output or if negative, an error status code 493110184Ssimokawa */ 494110184Ssimokawa native static int nativeFinal(long pContext, boolean encrypt, 495110184Ssimokawa byte[] out, int outOfs); 496110184Ssimokawa 497110184Ssimokawa protected void ensureInitialized() { 498110184Ssimokawa if (!initialized) { 499110184Ssimokawa init(encrypt, keyValue, iv); 500110184Ssimokawa if (!initialized) { 501110184Ssimokawa throw new UcryptoException("Cannot initialize Cipher"); 502110184Ssimokawa } 503110184Ssimokawa } 504110184Ssimokawa } 505110184Ssimokawa 506103285Sikob protected int getOutputSizeByOperation(int inLen, boolean isDoFinal) { 507103285Sikob if (inLen <= 0) { 508103285Sikob inLen = 0; 509108503Ssimokawa } 510103285Sikob if (!isDoFinal && (inLen == 0)) { 511103285Sikob return 0; 512108503Ssimokawa } 513108503Ssimokawa return inLen + bytesBuffered; 514103285Sikob } 515103285Sikob 516103285Sikob // actual init() implementation - caller should clone key and iv if needed 517103285Sikob protected void init(boolean encrypt, byte[] keyVal, byte[] ivVal) { 518110184Ssimokawa reset(true); 519110184Ssimokawa this.encrypt = encrypt; 520110184Ssimokawa this.keyValue = keyVal; 521103285Sikob this.iv = ivVal; 522103285Sikob long pCtxtVal = nativeInit(mech.value(), encrypt, keyValue, iv, 0, null); 523103285Sikob initialized = (pCtxtVal != 0L); 524103285Sikob if (initialized) { 525103285Sikob pCtxt = new CipherContextRef(this, pCtxtVal, encrypt); 526103285Sikob } else { 527103285Sikob throw new UcryptoException("Cannot initialize Cipher"); 528111704Ssimokawa } 529114069Ssimokawa } 530114069Ssimokawa 531114069Ssimokawa // Caller MUST check and ensure output buffer has enough capacity 532114069Ssimokawa private int update(byte[] in, int inOfs, int inLen, byte[] out, int outOfs) { 533103285Sikob ensureInitialized(); 534103285Sikob if (inLen <= 0) { return 0; } 535103285Sikob 536103285Sikob int k = nativeUpdate(pCtxt.id, encrypt, in, inOfs, inLen, out, outOfs); 537103285Sikob if (k < 0) { 538114069Ssimokawa reset(false); 539111615Ssimokawa // cannot throw ShortBufferException here since it's too late 540111704Ssimokawa // native context is invalid upon any failure 541111704Ssimokawa throw new UcryptoException(-k); 542111704Ssimokawa } 543113584Ssimokawa bytesBuffered += (inLen - k); 544113584Ssimokawa return k; 545111615Ssimokawa } 546111615Ssimokawa 547111615Ssimokawa // Caller MUST check and ensure output buffer has enough capacity 548111615Ssimokawa private int doFinal(byte[] out, int outOfs) throws IllegalBlockSizeException, 549103285Sikob BadPaddingException { 550108503Ssimokawa try { 551108503Ssimokawa ensureInitialized(); 552108503Ssimokawa 553108503Ssimokawa int k = nativeFinal(pCtxt.id, encrypt, out, outOfs); 554108503Ssimokawa if (k < 0) { 555108503Ssimokawa String cause = UcryptoException.getErrorMessage(-k); 556108503Ssimokawa if (cause.endsWith("_LEN_RANGE")) { 557110839Ssimokawa throw new IllegalBlockSizeException(cause); 558108642Ssimokawa } else if (cause.endsWith("_DATA_INVALID")) { 559108642Ssimokawa throw new BadPaddingException(cause); 560108642Ssimokawa } else { 561108503Ssimokawa throw new UcryptoException(-k); 562108503Ssimokawa } 563108503Ssimokawa } 564108503Ssimokawa return k; 565110839Ssimokawa } finally { 566110839Ssimokawa reset(false); 567110839Ssimokawa } 568110839Ssimokawa } 569108503Ssimokawa} 570103285Sikob