GordianDigestInputStream.java
/*
* GordianKnot: Security Suite
* Copyright 2012-2026. Tony Washer
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy
* of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations under
* the License.
*/
package io.github.tonywasher.joceanus.gordianknot.impl.core.stream;
import io.github.tonywasher.joceanus.gordianknot.api.base.GordianException;
import io.github.tonywasher.joceanus.gordianknot.api.digest.GordianDigest;
import io.github.tonywasher.joceanus.gordianknot.impl.core.exc.GordianDataException;
import org.bouncycastle.util.Arrays;
import java.io.InputStream;
/**
* Input stream Digest implementation.
*/
class GordianDigestInputStream
extends GordianInputStream {
/**
* The digest.
*/
private final GordianDigest theDigest;
/**
* The expected result.
*/
private final byte[] theExpected;
/**
* The MacStream.
*/
private final GordianMacInputStream theMacStream;
/**
* Constructor.
*
* @param pDigest the digest
* @param pExpected the expected result
* @param pInput the underlying input stream
* @param pMacStream the MacStream
* @throws GordianException on error
*/
GordianDigestInputStream(final GordianDigest pDigest,
final byte[] pExpected,
final InputStream pInput,
final GordianMacInputStream pMacStream) throws GordianException {
/* Initialise underlying class */
super(pInput);
/* Store parameters */
theDigest = pDigest;
theExpected = Arrays.copyOf(pExpected, pExpected.length);
theMacStream = pMacStream;
/* Create processed buffer */
setProcessedBuffer(new GordianDigestBuffer(this));
/* Report the expected Digest to the Mac */
theMacStream.setExpectedDigest(theExpected);
}
/**
* Obtain the Digest.
*
* @return the digest
*/
public GordianDigest getDigest() {
return theDigest;
}
/**
* Check result.
*
* @throws GordianException on error
*/
void checkResult() throws GordianException {
/* Calculate digest */
final byte[] myResult = theDigest.finish();
/* Check valid digest */
if (!Arrays.areEqual(myResult, theExpected)) {
throw new GordianDataException("Invalid Digest");
}
}
/**
* Buffer to hold the processed data prior to returning it to the caller.
*/
private static final class GordianDigestBuffer
extends GordianProcessedBuffer {
/**
* The InputStream.
*/
private final GordianDigestInputStream theStream;
/**
* The digest.
*/
private final GordianDigest theDigest;
/**
* Constructor.
*
* @param pStream the input stream
*/
GordianDigestBuffer(final GordianDigestInputStream pStream) {
theStream = pStream;
theDigest = theStream.getDigest();
}
@Override
public int processBytes(final byte[] pBuffer,
final int pLength) throws GordianException {
/* Initialise variables */
final int iLength = pLength;
/* If we have EOF from the input stream */
if (iLength == -1) {
/* Record the fact and reset the read length to zero */
setEOFSeen();
theStream.checkResult();
return -1;
}
/* Update the digest */
theDigest.update(pBuffer, 0, iLength);
/* Set up buffer variables */
setBuffer(pBuffer, iLength);
return iLength;
}
}
}