All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.bouncycastle.crypto.digests.ParallelHash Maven / Gradle / Ivy

Go to download

The Bouncy Castle Crypto package is a Java implementation of cryptographic algorithms. This jar contains JCE provider and lightweight API for the Bouncy Castle Cryptography APIs for JDK 1.4.

There is a newer version: 1.79
Show newest version
package org.bouncycastle.crypto.digests;

import org.bouncycastle.crypto.CryptoServicePurpose;
import org.bouncycastle.crypto.CryptoServicesRegistrar;
import org.bouncycastle.crypto.DataLengthException;
import org.bouncycastle.crypto.Digest;
import org.bouncycastle.crypto.Xof;
import org.bouncycastle.util.Arrays;
import org.bouncycastle.util.Strings;

/**
 * ParallelHash - a hash designed  to  support the efficient hashing of very long strings, by taking advantage
 * of the parallelism available in modern processors with an optional XOF mode.
 * 

* From NIST Special Publication 800-185 - SHA-3 Derived Functions:cSHAKE, KMAC, TupleHash and ParallelHash *

*/ public class ParallelHash implements Xof, Digest { private static final byte[] N_PARALLEL_HASH = Strings.toByteArray("ParallelHash"); private final CSHAKEDigest cshake; private final CSHAKEDigest compressor; private final int bitLength; private final int outputLength; private final int B; private final byte[] buffer; private final byte[] compressorBuffer; private boolean firstOutput; private int nCount; private int bufOff; private final CryptoServicePurpose purpose; /** * Base constructor. * * @param bitLength security strength (bits) of the underlying SHAKE function, 128 or 256. * @param S the customization string - available for local use. * @param B the blocksize (in bytes) for hashing. */ public ParallelHash(int bitLength, byte[] S, int B) { this(bitLength, S, B, bitLength * 2, CryptoServicePurpose.ANY); } public ParallelHash(int bitLength, byte[] S, int B, int outputSize) { this(bitLength, S, B, outputSize, CryptoServicePurpose.ANY); } public ParallelHash(int bitLength, byte[] S, int B, int outputSize, CryptoServicePurpose purpose) { this.cshake = new CSHAKEDigest(bitLength, N_PARALLEL_HASH, S); this.compressor = new CSHAKEDigest(bitLength, new byte[0], new byte[0]); this.bitLength = bitLength; this.B = B; this.outputLength = (outputSize + 7) / 8; this.buffer = new byte[B]; this.compressorBuffer = new byte[bitLength * 2 / 8]; this.purpose = purpose; CryptoServicesRegistrar.checkConstraints(Utils.getDefaultProperties(this, bitLength, purpose)); reset(); } public ParallelHash(ParallelHash source) { this.cshake = new CSHAKEDigest(source.cshake); this.compressor = new CSHAKEDigest(source.compressor); this.bitLength = source.bitLength; this.B = source.B; this.outputLength = source.outputLength; this.buffer = Arrays.clone(source.buffer); this.compressorBuffer = Arrays.clone(source.compressorBuffer); this.purpose = source.purpose; this.firstOutput = source.firstOutput; this.nCount = source.nCount; this.bufOff = source.bufOff; CryptoServicesRegistrar.checkConstraints(Utils.getDefaultProperties(this, bitLength, purpose)); } public String getAlgorithmName() { return "ParallelHash" + cshake.getAlgorithmName().substring(6); } public int getByteLength() { return cshake.getByteLength(); } public int getDigestSize() { return outputLength; } public void update(byte in) throws IllegalStateException { buffer[bufOff++] = in; if (bufOff == buffer.length) { compress(); } } public void update(byte[] in, int inOff, int len) throws DataLengthException, IllegalStateException { len = Math.max(0, len); // // fill the current word // int i = 0; if (bufOff != 0) { while (i < len && bufOff != buffer.length) { buffer[bufOff++] = in[inOff + i++]; } if (bufOff == buffer.length) { compress(); } } if (i < len) { while (len - i >= B) { compress(in, inOff + i, B); i += B; } } while (i < len) { update(in[inOff + i++]); } } private void compress() { compress(buffer, 0, bufOff); bufOff = 0; } private void compress(byte[] buf, int offSet, int len) { compressor.update(buf, offSet, len); compressor.doFinal(compressorBuffer, 0, compressorBuffer.length); cshake.update(compressorBuffer, 0, compressorBuffer.length); nCount++; } private void wrapUp(int outputSize) { if (bufOff != 0) { compress(); } byte[] nOut = XofUtils.rightEncode(nCount); byte[] encOut = XofUtils.rightEncode(outputSize * 8); cshake.update(nOut, 0, nOut.length); cshake.update(encOut, 0, encOut.length); firstOutput = false; } public int doFinal(byte[] out, int outOff) throws DataLengthException, IllegalStateException { if (firstOutput) { wrapUp(outputLength); } int rv = cshake.doFinal(out, outOff, getDigestSize()); reset(); return rv; } public int doFinal(byte[] out, int outOff, int outLen) { if (firstOutput) { wrapUp(outputLength); } int rv = cshake.doFinal(out, outOff, outLen); reset(); return rv; } public int doOutput(byte[] out, int outOff, int outLen) { if (firstOutput) { wrapUp(0); } return cshake.doOutput(out, outOff, outLen); } public void reset() { cshake.reset(); Arrays.clear(buffer); byte[] hdr = XofUtils.leftEncode(B); cshake.update(hdr, 0, hdr.length); nCount = 0; bufOff = 0; firstOutput = true; } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy