protected byte[] engineUpdate(byte[] input, int inputOffset, int inputLen) {
    int length = cipher.getUpdateOutputSize(inputLen);

    if (length > 0) {
      byte[] out = new byte[length];

      cipher.processBytes(input, inputOffset, inputLen, out, 0);
      return out;
    }

    cipher.processBytes(input, inputOffset, inputLen, null, 0);

    return null;
  }
  protected void engineSetPadding(String padding) throws NoSuchPaddingException {
    String paddingName = Strings.toUpperCase(padding);

    if (paddingName.equals("NOPADDING")) {
      cipher = new BufferedBlockCipher(cipher.getUnderlyingCipher());
    } else if (paddingName.equals("PKCS5PADDING")
        || paddingName.equals("PKCS7PADDING")
        || paddingName.equals("ISO10126PADDING")) {
      cipher = new PaddedBufferedBlockCipher(cipher.getUnderlyingCipher());
    } else if (paddingName.equals("WITHCTS")) {
      cipher = new CTSBlockCipher(cipher.getUnderlyingCipher());
    } else {
      throw new NoSuchPaddingException("Padding " + padding + " unknown.");
    }
  }
  protected int engineDoFinal(
      byte[] input, int inputOffset, int inputLen, byte[] output, int outputOffset)
      throws IllegalBlockSizeException, BadPaddingException {
    int len = 0;

    if (inputLen != 0) {
      len = cipher.processBytes(input, inputOffset, inputLen, output, outputOffset);
    }

    try {
      return len + cipher.doFinal(output, outputOffset + len);
    } catch (DataLengthException e) {
      throw new IllegalBlockSizeException(e.getMessage());
    } catch (InvalidCipherTextException e) {
      throw new BadPaddingException(e.getMessage());
    }
  }
  protected byte[] engineDoFinal(byte[] input, int inputOffset, int inputLen)
      throws IllegalBlockSizeException, BadPaddingException {
    int len = 0;
    byte[] tmp = new byte[engineGetOutputSize(inputLen)];

    if (inputLen != 0) {
      len = cipher.processBytes(input, inputOffset, inputLen, tmp, 0);
    }

    try {
      len += cipher.doFinal(tmp, len);
    } catch (DataLengthException e) {
      throw new IllegalBlockSizeException(e.getMessage());
    } catch (InvalidCipherTextException e) {
      throw new BadPaddingException(e.getMessage());
    }

    byte[] out = new byte[len];

    System.arraycopy(tmp, 0, out, 0, len);

    return out;
  }
  protected AlgorithmParameters engineGetParameters() {
    if (engineParams == null) {
      if (ivParam != null) {
        String name = cipher.getUnderlyingCipher().getAlgorithmName();

        if (name.indexOf('/') >= 0) {
          name = name.substring(0, name.indexOf('/'));
        }

        try {
          engineParams = AlgorithmParameters.getInstance(name, BouncyCastleProvider.PROVIDER_NAME);
          engineParams.init(ivParam.getIV());
        } catch (Exception e) {
          throw new RuntimeException(e.toString());
        }
      }
    }

    return engineParams;
  }
 protected int engineGetOutputSize(int inputLen) {
   return cipher.getOutputSize(inputLen);
 }
 protected int engineGetBlockSize() {
   return cipher.getBlockSize();
 }
 protected int engineUpdate(
     byte[] input, int inputOffset, int inputLen, byte[] output, int outputOffset) {
   return cipher.processBytes(input, inputOffset, inputLen, output, outputOffset);
 }
  protected void engineInit(int opmode, Key key, AlgorithmParameterSpec params, SecureRandom random)
      throws InvalidKeyException, InvalidAlgorithmParameterException {
    CipherParameters param;

    //
    // a note on iv's - if ivLength is zero the IV gets ignored (we don't use it).
    //
    if (key instanceof JCEPBEKey) {
      param =
          Util.makePBEParameters(
              (JCEPBEKey) key,
              params,
              pbeType,
              pbeHash,
              cipher.getUnderlyingCipher().getAlgorithmName(),
              pbeKeySize,
              pbeIvSize);

      if (pbeIvSize != 0) {
        ivParam = (ParametersWithIV) param;
      }
    } else if (params == null) {
      param = new KeyParameter(key.getEncoded());
    } else if (params instanceof IvParameterSpec) {
      if (ivLength != 0) {
        param =
            new ParametersWithIV(
                new KeyParameter(key.getEncoded()), ((IvParameterSpec) params).getIV());
        ivParam = (ParametersWithIV) param;
      } else {
        param = new KeyParameter(key.getEncoded());
      }
    } else if (params instanceof RC2ParameterSpec) {
      RC2ParameterSpec rc2Param = (RC2ParameterSpec) params;

      param =
          new RC2Parameters(key.getEncoded(), ((RC2ParameterSpec) params).getEffectiveKeyBits());

      if (rc2Param.getIV() != null && ivLength != 0) {
        param = new ParametersWithIV(param, rc2Param.getIV());
        ivParam = (ParametersWithIV) param;
      }
    } else if (params instanceof RC5ParameterSpec) {
      RC5ParameterSpec rc5Param = (RC5ParameterSpec) params;

      param = new RC5Parameters(key.getEncoded(), ((RC5ParameterSpec) params).getRounds());
      if (rc5Param.getWordSize() != 32) {
        throw new IllegalArgumentException("can only accept RC5 word size 32 (at the moment...)");
      }
      if ((rc5Param.getIV() != null) && (ivLength != 0)) {
        param = new ParametersWithIV(param, rc5Param.getIV());
        ivParam = (ParametersWithIV) param;
      }
    } else {
      throw new InvalidAlgorithmParameterException("unknown parameter type.");
    }

    if ((ivLength != 0) && !(param instanceof ParametersWithIV)) {
      if (random == null) {
        random = new SecureRandom();
      }

      if ((opmode == Cipher.ENCRYPT_MODE) || (opmode == Cipher.WRAP_MODE)) {
        byte[] iv = new byte[ivLength];

        random.nextBytes(iv);
        param = new ParametersWithIV(param, iv);
        ivParam = (ParametersWithIV) param;
      } else {
        throw new InvalidAlgorithmParameterException("no IV set when one expected");
      }
    }

    switch (opmode) {
      case Cipher.ENCRYPT_MODE:
      case Cipher.WRAP_MODE:
        cipher.init(true, param);
        break;
      case Cipher.DECRYPT_MODE:
      case Cipher.UNWRAP_MODE:
        cipher.init(false, param);
        break;
      default:
        System.out.println("eeek!");
    }
  }
  protected void engineSetMode(String mode) {
    String modeName = Strings.toUpperCase(mode);

    if (modeName.equals("ECB")) {
      ivLength = 0;
      cipher = new PaddedBufferedBlockCipher(cipher.getUnderlyingCipher());
    } else if (modeName.equals("CBC")) {
      ivLength = cipher.getUnderlyingCipher().getBlockSize();
      cipher = new PaddedBufferedBlockCipher(new CBCBlockCipher(cipher.getUnderlyingCipher()));
    } else if (modeName.startsWith("OFB")) {
      ivLength = cipher.getUnderlyingCipher().getBlockSize();
      if (modeName.length() != 3) {
        int wordSize = Integer.parseInt(modeName.substring(3));

        cipher =
            new PaddedBufferedBlockCipher(
                new OFBBlockCipher(cipher.getUnderlyingCipher(), wordSize));
      } else {
        cipher =
            new PaddedBufferedBlockCipher(
                new OFBBlockCipher(cipher.getUnderlyingCipher(), 8 * cipher.getBlockSize()));
      }
    } else if (modeName.startsWith("CFB")) {
      ivLength = cipher.getUnderlyingCipher().getBlockSize();
      if (modeName.length() != 3) {
        int wordSize = Integer.parseInt(modeName.substring(3));

        cipher =
            new PaddedBufferedBlockCipher(
                new CFBBlockCipher(cipher.getUnderlyingCipher(), wordSize));
      } else {
        cipher =
            new PaddedBufferedBlockCipher(
                new CFBBlockCipher(cipher.getUnderlyingCipher(), 8 * cipher.getBlockSize()));
      }
    } else {
      throw new IllegalArgumentException("can't support mode " + mode);
    }
  }