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

nl.open.jwtdependency.org.bouncycastle.crypto.digests.KeccakDigest Maven / Gradle / Ivy

Go to download

This is a drop in replacement for the auth0 java-jwt library (see https://github.com/auth0/java-jwt). This jar makes sure there are no external dependencies (e.g. fasterXml, Apacha Commons) needed. This is useful when deploying to an application server (e.g. tomcat with Alfreso or Pega).

The newest version!
package org.bouncycastle.crypto.digests;

import org.bouncycastle.crypto.ExtendedDigest;
import org.bouncycastle.util.Arrays;

/**
 * implementation of Keccak based on following KeccakNISTInterface.c from http://keccak.noekeon.org/
 * 

* Following the naming conventions used in the C source code to enable easy review of the implementation. */ public class KeccakDigest implements ExtendedDigest { private static long[] KeccakRoundConstants = keccakInitializeRoundConstants(); private static int[] KeccakRhoOffsets = keccakInitializeRhoOffsets(); private static long[] keccakInitializeRoundConstants() { long[] keccakRoundConstants = new long[24]; byte[] LFSRstate = new byte[1]; LFSRstate[0] = 0x01; int i, j, bitPosition; for (i = 0; i < 24; i++) { keccakRoundConstants[i] = 0; for (j = 0; j < 7; j++) { bitPosition = (1 << j) - 1; if (LFSR86540(LFSRstate)) { keccakRoundConstants[i] ^= 1L << bitPosition; } } } return keccakRoundConstants; } private static boolean LFSR86540(byte[] LFSR) { boolean result = (((LFSR[0]) & 0x01) != 0); if (((LFSR[0]) & 0x80) != 0) { LFSR[0] = (byte)(((LFSR[0]) << 1) ^ 0x71); } else { LFSR[0] <<= 1; } return result; } private static int[] keccakInitializeRhoOffsets() { int[] keccakRhoOffsets = new int[25]; int x, y, t, newX, newY; keccakRhoOffsets[(((0) % 5) + 5 * ((0) % 5))] = 0; x = 1; y = 0; for (t = 0; t < 24; t++) { keccakRhoOffsets[(((x) % 5) + 5 * ((y) % 5))] = ((t + 1) * (t + 2) / 2) % 64; newX = (0 * x + 1 * y) % 5; newY = (2 * x + 3 * y) % 5; x = newX; y = newY; } return keccakRhoOffsets; } protected byte[] state = new byte[(1600 / 8)]; protected byte[] dataQueue = new byte[(1536 / 8)]; protected int rate; protected int bitsInQueue; protected int fixedOutputLength; protected boolean squeezing; protected int bitsAvailableForSqueezing; protected byte[] chunk; protected byte[] oneByte; private void clearDataQueueSection(int off, int len) { for (int i = off; i != off + len; i++) { dataQueue[i] = 0; } } public KeccakDigest() { this(288); } public KeccakDigest(int bitLength) { init(bitLength); } public KeccakDigest(KeccakDigest source) { System.arraycopy(source.state, 0, this.state, 0, source.state.length); System.arraycopy(source.dataQueue, 0, this.dataQueue, 0, source.dataQueue.length); this.rate = source.rate; this.bitsInQueue = source.bitsInQueue; this.fixedOutputLength = source.fixedOutputLength; this.squeezing = source.squeezing; this.bitsAvailableForSqueezing = source.bitsAvailableForSqueezing; this.chunk = Arrays.clone(source.chunk); this.oneByte = Arrays.clone(source.oneByte); } public String getAlgorithmName() { return "Keccak-" + fixedOutputLength; } public int getDigestSize() { return fixedOutputLength / 8; } public void update(byte in) { oneByte[0] = in; absorb(oneByte, 0, 8L); } public void update(byte[] in, int inOff, int len) { absorb(in, inOff, len * 8L); } public int doFinal(byte[] out, int outOff) { squeeze(out, outOff, fixedOutputLength); reset(); return getDigestSize(); } /* * TODO Possible API change to support partial-byte suffixes. */ protected int doFinal(byte[] out, int outOff, byte partialByte, int partialBits) { if (partialBits > 0) { oneByte[0] = partialByte; absorb(oneByte, 0, partialBits); } squeeze(out, outOff, fixedOutputLength); reset(); return getDigestSize(); } public void reset() { init(fixedOutputLength); } /** * Return the size of block that the compression function is applied to in bytes. * * @return internal byte length of a block. */ public int getByteLength() { return rate / 8; } private void init(int bitLength) { switch (bitLength) { case 288: initSponge(1024, 576); break; case 128: initSponge(1344, 256); break; case 224: initSponge(1152, 448); break; case 256: initSponge(1088, 512); break; case 384: initSponge(832, 768); break; case 512: initSponge(576, 1024); break; default: throw new IllegalArgumentException("bitLength must be one of 128, 224, 256, 288, 384, or 512."); } } private void initSponge(int rate, int capacity) { if (rate + capacity != 1600) { throw new IllegalStateException("rate + capacity != 1600"); } if ((rate <= 0) || (rate >= 1600) || ((rate % 64) != 0)) { throw new IllegalStateException("invalid rate value"); } this.rate = rate; // this is never read, need to check to see why we want to save it // this.capacity = capacity; Arrays.fill(this.state, (byte)0); Arrays.fill(this.dataQueue, (byte)0); this.bitsInQueue = 0; this.squeezing = false; this.bitsAvailableForSqueezing = 0; this.fixedOutputLength = capacity / 2; this.chunk = new byte[rate / 8]; this.oneByte = new byte[1]; } private void absorbQueue() { KeccakAbsorb(state, dataQueue, rate / 8); bitsInQueue = 0; } protected void absorb(byte[] data, int off, long databitlen) { long i, j, wholeBlocks; if ((bitsInQueue % 8) != 0) { throw new IllegalStateException("attempt to absorb with odd length queue"); } if (squeezing) { throw new IllegalStateException("attempt to absorb while squeezing"); } i = 0; while (i < databitlen) { if ((bitsInQueue == 0) && (databitlen >= rate) && (i <= (databitlen - rate))) { wholeBlocks = (databitlen - i) / rate; for (j = 0; j < wholeBlocks; j++) { System.arraycopy(data, (int)(off + (i / 8) + (j * chunk.length)), chunk, 0, chunk.length); // displayIntermediateValues.displayBytes(1, "Block to be absorbed", curData, rate / 8); KeccakAbsorb(state, chunk, chunk.length); } i += wholeBlocks * rate; } else { int partialBlock = (int)(databitlen - i); if (partialBlock + bitsInQueue > rate) { partialBlock = rate - bitsInQueue; } int partialByte = partialBlock % 8; partialBlock -= partialByte; System.arraycopy(data, off + (int)(i / 8), dataQueue, bitsInQueue / 8, partialBlock / 8); bitsInQueue += partialBlock; i += partialBlock; if (bitsInQueue == rate) { absorbQueue(); } if (partialByte > 0) { int mask = (1 << partialByte) - 1; dataQueue[bitsInQueue / 8] = (byte)(data[off + ((int)(i / 8))] & mask); bitsInQueue += partialByte; i += partialByte; } } } } private void padAndSwitchToSqueezingPhase() { if (bitsInQueue + 1 == rate) { dataQueue[bitsInQueue / 8] |= 1 << (bitsInQueue % 8); absorbQueue(); clearDataQueueSection(0, rate / 8); } else { clearDataQueueSection((bitsInQueue + 7) / 8, rate / 8 - (bitsInQueue + 7) / 8); dataQueue[bitsInQueue / 8] |= 1 << (bitsInQueue % 8); } dataQueue[(rate - 1) / 8] |= 1 << ((rate - 1) % 8); absorbQueue(); // displayIntermediateValues.displayText(1, "--- Switching to squeezing phase ---"); if (rate == 1024) { KeccakExtract1024bits(state, dataQueue); bitsAvailableForSqueezing = 1024; } else { KeccakExtract(state, dataQueue, rate / 64); bitsAvailableForSqueezing = rate; } // displayIntermediateValues.displayBytes(1, "Block available for squeezing", dataQueue, bitsAvailableForSqueezing / 8); squeezing = true; } protected void squeeze(byte[] output, int offset, long outputLength) { long i; int partialBlock; if (!squeezing) { padAndSwitchToSqueezingPhase(); } if ((outputLength % 8) != 0) { throw new IllegalStateException("outputLength not a multiple of 8"); } i = 0; while (i < outputLength) { if (bitsAvailableForSqueezing == 0) { keccakPermutation(state); if (rate == 1024) { KeccakExtract1024bits(state, dataQueue); bitsAvailableForSqueezing = 1024; } else { KeccakExtract(state, dataQueue, rate / 64); bitsAvailableForSqueezing = rate; } // displayIntermediateValues.displayBytes(1, "Block available for squeezing", dataQueue, bitsAvailableForSqueezing / 8); } partialBlock = bitsAvailableForSqueezing; if ((long)partialBlock > outputLength - i) { partialBlock = (int)(outputLength - i); } System.arraycopy(dataQueue, (rate - bitsAvailableForSqueezing) / 8, output, offset + (int)(i / 8), partialBlock / 8); bitsAvailableForSqueezing -= partialBlock; i += partialBlock; } } private void fromBytesToWords(long[] stateAsWords, byte[] state) { for (int i = 0; i < (1600 / 64); i++) { stateAsWords[i] = 0; int index = i * (64 / 8); for (int j = 0; j < (64 / 8); j++) { stateAsWords[i] |= ((long)state[index + j] & 0xff) << ((8 * j)); } } } private void fromWordsToBytes(byte[] state, long[] stateAsWords) { for (int i = 0; i < (1600 / 64); i++) { int index = i * (64 / 8); for (int j = 0; j < (64 / 8); j++) { state[index + j] = (byte)((stateAsWords[i] >>> ((8 * j))) & 0xFF); } } } private void keccakPermutation(byte[] state) { long[] longState = new long[state.length / 8]; fromBytesToWords(longState, state); // displayIntermediateValues.displayStateAsBytes(1, "Input of permutation", longState); keccakPermutationOnWords(longState); // displayIntermediateValues.displayStateAsBytes(1, "State after permutation", longState); fromWordsToBytes(state, longState); } private void keccakPermutationAfterXor(byte[] state, byte[] data, int dataLengthInBytes) { int i; for (i = 0; i < dataLengthInBytes; i++) { state[i] ^= data[i]; } keccakPermutation(state); } private void keccakPermutationOnWords(long[] state) { int i; // displayIntermediateValues.displayStateAs64bitWords(3, "Same, with lanes as 64-bit words", state); for (i = 0; i < 24; i++) { // displayIntermediateValues.displayRoundNumber(3, i); theta(state); // displayIntermediateValues.displayStateAs64bitWords(3, "After theta", state); rho(state); // displayIntermediateValues.displayStateAs64bitWords(3, "After rho", state); pi(state); // displayIntermediateValues.displayStateAs64bitWords(3, "After pi", state); chi(state); // displayIntermediateValues.displayStateAs64bitWords(3, "After chi", state); iota(state, i); // displayIntermediateValues.displayStateAs64bitWords(3, "After iota", state); } } long[] C = new long[5]; private void theta(long[] A) { for (int x = 0; x < 5; x++) { C[x] = 0; for (int y = 0; y < 5; y++) { C[x] ^= A[x + 5 * y]; } } for (int x = 0; x < 5; x++) { long dX = ((((C[(x + 1) % 5]) << 1) ^ ((C[(x + 1) % 5]) >>> (64 - 1)))) ^ C[(x + 4) % 5]; for (int y = 0; y < 5; y++) { A[x + 5 * y] ^= dX; } } } private void rho(long[] A) { for (int x = 0; x < 5; x++) { for (int y = 0; y < 5; y++) { int index = x + 5 * y; A[index] = ((KeccakRhoOffsets[index] != 0) ? (((A[index]) << KeccakRhoOffsets[index]) ^ ((A[index]) >>> (64 - KeccakRhoOffsets[index]))) : A[index]); } } } long[] tempA = new long[25]; private void pi(long[] A) { System.arraycopy(A, 0, tempA, 0, tempA.length); for (int x = 0; x < 5; x++) { for (int y = 0; y < 5; y++) { A[y + 5 * ((2 * x + 3 * y) % 5)] = tempA[x + 5 * y]; } } } long[] chiC = new long[5]; private void chi(long[] A) { for (int y = 0; y < 5; y++) { for (int x = 0; x < 5; x++) { chiC[x] = A[x + 5 * y] ^ ((~A[(((x + 1) % 5) + 5 * y)]) & A[(((x + 2) % 5) + 5 * y)]); } for (int x = 0; x < 5; x++) { A[x + 5 * y] = chiC[x]; } } } private void iota(long[] A, int indexRound) { A[(((0) % 5) + 5 * ((0) % 5))] ^= KeccakRoundConstants[indexRound]; } private void KeccakAbsorb(byte[] byteState, byte[] data, int dataInBytes) { keccakPermutationAfterXor(byteState, data, dataInBytes); } private void KeccakExtract1024bits(byte[] byteState, byte[] data) { System.arraycopy(byteState, 0, data, 0, 128); } private void KeccakExtract(byte[] byteState, byte[] data, int laneCount) { System.arraycopy(byteState, 0, data, 0, laneCount * 8); } }





© 2015 - 2025 Weber Informatics LLC | Privacy Policy