// Path: src/main/java/com/healthmarketscience/jackcess/crypt/InvalidCredentialsException.java
// public class InvalidCredentialsException extends IllegalStateException
// {
//   private static final long serialVersionUID = 20170130L;
// 
//   public InvalidCredentialsException(String msg) {
//     super(msg);
//   }
// 
// }
// 
// Path: src/main/java/com/healthmarketscience/jackcess/crypt/util/StreamCipherCompat.java
// public interface StreamCipherCompat 
// {
//   public String getAlgorithmName();
// 
//   public void init(boolean forEncryption, CipherParameters params);
// 
//   public byte returnByte(byte in);
// 
//   public int processStreamBytes(byte[] in, int inOff,
//                                 int len, byte[] out, int outOff);
// 
//   public void reset();
// }


import org.bouncycastle.crypto.Digest;
import org.bouncycastle.crypto.digests.MD5Digest;
import org.bouncycastle.crypto.digests.SHA1Digest;
import org.bouncycastle.crypto.params.KeyParameter;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.charset.Charset;
import java.util.Arrays;
import java.util.function.Supplier;
import com.healthmarketscience.jackcess.crypt.InvalidCredentialsException;
import com.healthmarketscience.jackcess.crypt.util.StreamCipherCompat;
import com.healthmarketscience.jackcess.impl.ByteUtil;
import com.healthmarketscience.jackcess.impl.CodecHandler;
import com.healthmarketscience.jackcess.impl.ColumnImpl;
import com.healthmarketscience.jackcess.impl.DatabaseImpl;
import com.healthmarketscience.jackcess.impl.JetFormat;
import com.healthmarketscience.jackcess.impl.PageChannel;
    ByteBuffer buffer = readHeaderPage(channel);

    if ((buffer.get(ENCRYPTION_FLAGS_OFFSET) & NEW_ENCRYPTION) != 0) {
      return new MSISAMCryptCodecHandler(channel, callback.get(), charset, buffer);
    }

    // old MSISAM dbs use jet-style encryption w/ a different key
    return new JetCryptCodecHandler(channel,
        getOldDecryptionKey(buffer, channel.getFormat())) {
        @Override
        protected int getMaxEncodedPage() {
          return MSISAM_MAX_ENCRYPTED_PAGE;
        }
      };
  }

  @Override
  protected KeyParameter computeCipherParams(int pageNumber) {
    return new KeyParameter(
        applyPageNumber(_baseHash, PASSWORD_DIGEST_LENGTH, pageNumber));
  }

  @Override
  protected int getMaxEncodedPage() {
    return MSISAM_MAX_ENCRYPTED_PAGE;
  }

  private void verifyPassword(ByteBuffer buffer, byte[] testEncodingKey,
                              byte[] testBytes)
  {
// Path: src/main/java/com/healthmarketscience/jackcess/crypt/InvalidCredentialsException.java
// public class InvalidCredentialsException extends IllegalStateException
// {
//   private static final long serialVersionUID = 20170130L;
// 
//   public InvalidCredentialsException(String msg) {
//     super(msg);
//   }
// 
// }
// 
// Path: src/main/java/com/healthmarketscience/jackcess/crypt/util/StreamCipherCompat.java
// public interface StreamCipherCompat 
// {
//   public String getAlgorithmName();
// 
//   public void init(boolean forEncryption, CipherParameters params);
// 
//   public byte returnByte(byte in);
// 
//   public int processStreamBytes(byte[] in, int inOff,
//                                 int len, byte[] out, int outOff);
// 
//   public void reset();
// }


// Path: src/main/java/com/healthmarketscience/jackcess/crypt/impl/MSISAMCryptCodecHandler.java
import org.bouncycastle.crypto.Digest;
import org.bouncycastle.crypto.digests.MD5Digest;
import org.bouncycastle.crypto.digests.SHA1Digest;
import org.bouncycastle.crypto.params.KeyParameter;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.charset.Charset;
import java.util.Arrays;
import java.util.function.Supplier;
import com.healthmarketscience.jackcess.crypt.InvalidCredentialsException;
import com.healthmarketscience.jackcess.crypt.util.StreamCipherCompat;
import com.healthmarketscience.jackcess.impl.ByteUtil;
import com.healthmarketscience.jackcess.impl.CodecHandler;
import com.healthmarketscience.jackcess.impl.ColumnImpl;
import com.healthmarketscience.jackcess.impl.DatabaseImpl;
import com.healthmarketscience.jackcess.impl.JetFormat;
import com.healthmarketscience.jackcess.impl.PageChannel;

    ByteBuffer buffer = readHeaderPage(channel);

    if ((buffer.get(ENCRYPTION_FLAGS_OFFSET) & NEW_ENCRYPTION) != 0) {
      return new MSISAMCryptCodecHandler(channel, callback.get(), charset, buffer);
    }

    // old MSISAM dbs use jet-style encryption w/ a different key
    return new JetCryptCodecHandler(channel,
        getOldDecryptionKey(buffer, channel.getFormat())) {
        @Override
        protected int getMaxEncodedPage() {
          return MSISAM_MAX_ENCRYPTED_PAGE;
        }
      };
  }

  @Override
  protected KeyParameter computeCipherParams(int pageNumber) {
    return new KeyParameter(
        applyPageNumber(_baseHash, PASSWORD_DIGEST_LENGTH, pageNumber));
  }

  @Override
  protected int getMaxEncodedPage() {
    return MSISAM_MAX_ENCRYPTED_PAGE;
  }

  private void verifyPassword(ByteBuffer buffer, byte[] testEncodingKey,
                              byte[] testBytes)
  {
    StreamCipherCompat engine = decryptInit(getStreamCipher(),