protected Key engineUnwrap(byte[] wrappedKey, String wrappedKeyAlgorithm, int wrappedKeyType)
      throws InvalidKeyException, NoSuchAlgorithmException {
    byte[] encoded;
    try {
      if (wrapEngine == null) {
        encoded = engineDoFinal(wrappedKey, 0, wrappedKey.length);
      } else {
        encoded = wrapEngine.unwrap(wrappedKey, 0, wrappedKey.length);
      }
    } catch (InvalidCipherTextException e) {
      throw new InvalidKeyException(e.getMessage());
    } catch (BadPaddingException e) {
      throw new InvalidKeyException(e.getMessage());
    } catch (IllegalBlockSizeException e2) {
      throw new InvalidKeyException(e2.getMessage());
    }

    if (wrappedKeyType == Cipher.SECRET_KEY) {
      return new SecretKeySpec(encoded, wrappedKeyAlgorithm);
    } else if (wrappedKeyAlgorithm.equals("") && wrappedKeyType == Cipher.PRIVATE_KEY) {
      /*
       * The caller doesn't know the algorithm as it is part of
       * the encrypted data.
       */
      try {
        PrivateKeyInfo in = PrivateKeyInfo.getInstance(encoded);

        PrivateKey privKey = BouncyCastleProvider.getPrivateKey(in);

        if (privKey != null) {
          return privKey;
        } else {
          throw new InvalidKeyException(
              "algorithm " + in.getPrivateKeyAlgorithm().getAlgorithm() + " not supported");
        }
      } catch (Exception e) {
        throw new InvalidKeyException("Invalid key encoding.");
      }
    } else {
      try {
        KeyFactory kf =
            KeyFactory.getInstance(wrappedKeyAlgorithm, BouncyCastleProvider.PROVIDER_NAME);

        if (wrappedKeyType == Cipher.PUBLIC_KEY) {
          return kf.generatePublic(new X509EncodedKeySpec(encoded));
        } else if (wrappedKeyType == Cipher.PRIVATE_KEY) {
          return kf.generatePrivate(new PKCS8EncodedKeySpec(encoded));
        }
      } catch (NoSuchProviderException e) {
        throw new InvalidKeyException("Unknown key type " + e.getMessage());
      } catch (InvalidKeySpecException e2) {
        throw new InvalidKeyException("Unknown key type " + e2.getMessage());
      }

      throw new InvalidKeyException("Unknown key type " + wrappedKeyType);
    }
  }
  protected void engineInit(int opmode, Key key, AlgorithmParameterSpec params, SecureRandom random)
      throws InvalidKeyException, InvalidAlgorithmParameterException {
    CipherParameters param;

    if (key instanceof BCPBEKey) {
      BCPBEKey k = (BCPBEKey) key;

      if (params instanceof PBEParameterSpec) {
        param = PBE.Util.makePBEParameters(k, params, wrapEngine.getAlgorithmName());
      } else if (k.getParam() != null) {
        param = k.getParam();
      } else {
        throw new InvalidAlgorithmParameterException("PBE requires PBE parameters to be set.");
      }
    } else {
      param = new KeyParameter(key.getEncoded());
    }

    if (params instanceof IvParameterSpec) {
      IvParameterSpec iv = (IvParameterSpec) params;
      param = new ParametersWithIV(param, iv.getIV());
    }

    if (param instanceof KeyParameter && ivSize != 0) {
      iv = new byte[ivSize];
      random.nextBytes(iv);
      param = new ParametersWithIV(param, iv);
    }

    switch (opmode) {
      case Cipher.WRAP_MODE:
        wrapEngine.init(true, param);
        break;
      case Cipher.UNWRAP_MODE:
        wrapEngine.init(false, param);
        break;
      case Cipher.ENCRYPT_MODE:
      case Cipher.DECRYPT_MODE:
        throw new IllegalArgumentException("engine only valid for wrapping");
      default:
        System.out.println("eeek!");
    }
  }
  protected byte[] engineWrap(Key key) throws IllegalBlockSizeException, InvalidKeyException {
    byte[] encoded = key.getEncoded();
    if (encoded == null) {
      throw new InvalidKeyException("Cannot wrap key, null encoding.");
    }

    try {
      if (wrapEngine == null) {
        return engineDoFinal(encoded, 0, encoded.length);
      } else {
        return wrapEngine.wrap(encoded, 0, encoded.length);
      }
    } catch (BadPaddingException e) {
      throw new IllegalBlockSizeException(e.getMessage());
    }
  }