/**
   * Return the symmetric key algorithm required to decrypt the data protected by this object.
   *
   * @param dataDecryptorFactory decryptor factory to use to recover the session data.
   * @return the integer encryption algorithm code.
   * @throws PGPException if the session data cannot be recovered.
   */
  public int getSymmetricAlgorithm(PBEDataDecryptorFactory dataDecryptorFactory)
      throws PGPException {
    byte[] key =
        dataDecryptorFactory.makeKeyFromPassPhrase(keyData.getEncAlgorithm(), keyData.getS2K());
    byte[] sessionData =
        dataDecryptorFactory.recoverSessionData(
            keyData.getEncAlgorithm(), key, keyData.getSecKeyData());

    return sessionData[0];
  }
  /**
   * Open an input stream which will provide the decrypted data protected by this object.
   *
   * @param dataDecryptorFactory decryptor factory to use to recover the session data and provide
   *     the stream.
   * @return the resulting input stream
   * @throws PGPException if the session data cannot be recovered or the stream cannot be created.
   */
  public InputStream getDataStream(PBEDataDecryptorFactory dataDecryptorFactory)
      throws PGPException {
    try {
      int keyAlgorithm = keyData.getEncAlgorithm();
      byte[] key = dataDecryptorFactory.makeKeyFromPassPhrase(keyAlgorithm, keyData.getS2K());
      boolean withIntegrityPacket = encData instanceof SymmetricEncIntegrityPacket;

      byte[] sessionData =
          dataDecryptorFactory.recoverSessionData(
              keyData.getEncAlgorithm(), key, keyData.getSecKeyData());
      byte[] sessionKey = new byte[sessionData.length - 1];

      System.arraycopy(sessionData, 1, sessionKey, 0, sessionKey.length);

      PGPDataDecryptor dataDecryptor =
          dataDecryptorFactory.createDataDecryptor(
              withIntegrityPacket, sessionData[0] & 0xff, sessionKey);

      encStream = new BCPGInputStream(dataDecryptor.getInputStream(encData.getInputStream()));

      if (withIntegrityPacket) {
        truncStream = new TruncatedStream(encStream);

        integrityCalculator = dataDecryptor.getIntegrityCalculator();

        encStream = new TeeInputStream(truncStream, integrityCalculator.getOutputStream());
      }

      byte[] iv = new byte[dataDecryptor.getBlockSize()];
      for (int i = 0; i != iv.length; i++) {
        int ch = encStream.read();

        if (ch < 0) {
          throw new EOFException("unexpected end of stream.");
        }

        iv[i] = (byte) ch;
      }

      int v1 = encStream.read();
      int v2 = encStream.read();

      if (v1 < 0 || v2 < 0) {
        throw new EOFException("unexpected end of stream.");
      }

      // Note: the oracle attack on "quick check" bytes is not deemed
      // a security risk for PBE (see PGPPublicKeyEncryptedData)

      boolean repeatCheckPassed = iv[iv.length - 2] == (byte) v1 && iv[iv.length - 1] == (byte) v2;

      // Note: some versions of PGP appear to produce 0 for the extra
      // bytes rather than repeating the two previous bytes
      boolean zeroesCheckPassed = v1 == 0 && v2 == 0;

      if (!repeatCheckPassed && !zeroesCheckPassed) {
        throw new PGPDataValidationException("data check failed.");
      }

      return encStream;
    } catch (PGPException e) {
      throw e;
    } catch (Exception e) {
      throw new PGPException("Exception creating cipher", e);
    }
  }