447 lines
14 KiB
Java
447 lines
14 KiB
Java
package org.bouncycastle.crypto.digests;
|
|
|
|
import org.bouncycastle.asn1.x509.DisplayText;
|
|
import org.bouncycastle.crypto.ExtendedDigest;
|
|
import org.bouncycastle.util.Arrays;
|
|
|
|
/* loaded from: classes6.dex */
|
|
public class KeccakDigest implements ExtendedDigest {
|
|
long[] C;
|
|
protected int bitsAvailableForSqueezing;
|
|
protected int bitsInQueue;
|
|
long[] chiC;
|
|
protected byte[] chunk;
|
|
protected byte[] dataQueue;
|
|
protected int fixedOutputLength;
|
|
protected byte[] oneByte;
|
|
protected int rate;
|
|
protected boolean squeezing;
|
|
protected byte[] state;
|
|
long[] tempA;
|
|
private static long[] KeccakRoundConstants = keccakInitializeRoundConstants();
|
|
private static int[] KeccakRhoOffsets = keccakInitializeRhoOffsets();
|
|
|
|
@Override // org.bouncycastle.crypto.Digest
|
|
public void update(byte[] bArr, int i, int i2) {
|
|
absorb(bArr, i, i2 << 3);
|
|
}
|
|
|
|
@Override // org.bouncycastle.crypto.Digest
|
|
public void update(byte b) {
|
|
byte[] bArr = this.oneByte;
|
|
bArr[0] = b;
|
|
absorb(bArr, 0, 8L);
|
|
}
|
|
|
|
/* JADX INFO: Access modifiers changed from: protected */
|
|
public void squeeze(byte[] bArr, int i, long j) {
|
|
if (!this.squeezing) {
|
|
padAndSwitchToSqueezingPhase();
|
|
}
|
|
long j2 = 0;
|
|
if (j % 8 != 0) {
|
|
throw new IllegalStateException("outputLength not a multiple of 8");
|
|
}
|
|
while (j2 < j) {
|
|
if (this.bitsAvailableForSqueezing == 0) {
|
|
keccakPermutation(this.state);
|
|
int i2 = this.rate;
|
|
if (i2 == 1024) {
|
|
KeccakExtract1024bits(this.state, this.dataQueue);
|
|
this.bitsAvailableForSqueezing = 1024;
|
|
} else {
|
|
KeccakExtract(this.state, this.dataQueue, i2 / 64);
|
|
this.bitsAvailableForSqueezing = this.rate;
|
|
}
|
|
}
|
|
int i3 = this.bitsAvailableForSqueezing;
|
|
long j3 = j - j2;
|
|
int i4 = ((long) i3) > j3 ? (int) j3 : i3;
|
|
System.arraycopy(this.dataQueue, (this.rate - i3) / 8, bArr, ((int) (j2 / 8)) + i, i4 / 8);
|
|
this.bitsAvailableForSqueezing -= i4;
|
|
j2 += i4;
|
|
}
|
|
}
|
|
|
|
@Override // org.bouncycastle.crypto.Digest
|
|
public void reset() {
|
|
init(this.fixedOutputLength);
|
|
}
|
|
|
|
@Override // org.bouncycastle.crypto.Digest
|
|
public int getDigestSize() {
|
|
return this.fixedOutputLength / 8;
|
|
}
|
|
|
|
@Override // org.bouncycastle.crypto.ExtendedDigest
|
|
public int getByteLength() {
|
|
return this.rate / 8;
|
|
}
|
|
|
|
@Override // org.bouncycastle.crypto.Digest
|
|
public String getAlgorithmName() {
|
|
StringBuilder sb = new StringBuilder("Keccak-");
|
|
sb.append(this.fixedOutputLength);
|
|
return sb.toString();
|
|
}
|
|
|
|
/* JADX INFO: Access modifiers changed from: protected */
|
|
public int doFinal(byte[] bArr, int i, byte b, int i2) {
|
|
if (i2 > 0) {
|
|
byte[] bArr2 = this.oneByte;
|
|
bArr2[0] = b;
|
|
absorb(bArr2, 0, i2);
|
|
}
|
|
squeeze(bArr, i, this.fixedOutputLength);
|
|
reset();
|
|
return getDigestSize();
|
|
}
|
|
|
|
@Override // org.bouncycastle.crypto.Digest
|
|
public int doFinal(byte[] bArr, int i) {
|
|
squeeze(bArr, i, this.fixedOutputLength);
|
|
reset();
|
|
return getDigestSize();
|
|
}
|
|
|
|
/* JADX INFO: Access modifiers changed from: protected */
|
|
public void absorb(byte[] bArr, int i, long j) {
|
|
if (this.bitsInQueue % 8 != 0) {
|
|
throw new IllegalStateException("attempt to absorb with odd length queue");
|
|
}
|
|
if (this.squeezing) {
|
|
throw new IllegalStateException("attempt to absorb while squeezing");
|
|
}
|
|
long j2 = 0;
|
|
while (j2 < j) {
|
|
int i2 = this.bitsInQueue;
|
|
if (i2 == 0) {
|
|
long j3 = this.rate;
|
|
if (j >= j3 && j2 <= j - j3) {
|
|
long j4 = (j - j2) / j3;
|
|
for (long j5 = 0; j5 < j4; j5++) {
|
|
byte[] bArr2 = this.chunk;
|
|
System.arraycopy(bArr, (int) (i + (j2 / 8) + (bArr2.length * j5)), bArr2, 0, bArr2.length);
|
|
byte[] bArr3 = this.state;
|
|
byte[] bArr4 = this.chunk;
|
|
KeccakAbsorb(bArr3, bArr4, bArr4.length);
|
|
}
|
|
j2 += j4 * this.rate;
|
|
}
|
|
}
|
|
int i3 = (int) (j - j2);
|
|
int i4 = this.rate;
|
|
if (i3 + i2 > i4) {
|
|
i3 = i4 - i2;
|
|
}
|
|
int i5 = i3 % 8;
|
|
int i6 = i3 - i5;
|
|
System.arraycopy(bArr, ((int) (j2 / 8)) + i, this.dataQueue, i2 / 8, i6 / 8);
|
|
int i7 = this.bitsInQueue + i6;
|
|
this.bitsInQueue = i7;
|
|
j2 += i6;
|
|
if (i7 == this.rate) {
|
|
absorbQueue();
|
|
}
|
|
if (i5 > 0) {
|
|
byte[] bArr5 = this.dataQueue;
|
|
int i8 = this.bitsInQueue;
|
|
bArr5[i8 / 8] = (byte) (bArr[((int) (j2 / 8)) + i] & ((1 << i5) - 1));
|
|
this.bitsInQueue = i8 + i5;
|
|
j2 += i5;
|
|
}
|
|
}
|
|
}
|
|
|
|
private void theta(long[] jArr) {
|
|
for (int i = 0; i < 5; i++) {
|
|
this.C[i] = 0;
|
|
for (int i2 = 0; i2 < 5; i2++) {
|
|
long[] jArr2 = this.C;
|
|
jArr2[i] = jArr2[i] ^ jArr[(i2 * 5) + i];
|
|
}
|
|
}
|
|
int i3 = 0;
|
|
while (i3 < 5) {
|
|
long[] jArr3 = this.C;
|
|
int i4 = i3 + 1;
|
|
long j = jArr3[i4 % 5];
|
|
long j2 = jArr3[(i3 + 4) % 5];
|
|
for (int i5 = 0; i5 < 5; i5++) {
|
|
int i6 = (i5 * 5) + i3;
|
|
jArr[i6] = jArr[i6] ^ (((j >>> 63) ^ (j << 1)) ^ j2);
|
|
}
|
|
i3 = i4;
|
|
}
|
|
}
|
|
|
|
private void rho(long[] jArr) {
|
|
long j;
|
|
for (int i = 0; i < 5; i++) {
|
|
for (int i2 = 0; i2 < 5; i2++) {
|
|
int i3 = (i2 * 5) + i;
|
|
int i4 = KeccakRhoOffsets[i3];
|
|
if (i4 != 0) {
|
|
long j2 = jArr[i3];
|
|
j = (j2 << i4) ^ (j2 >>> (64 - i4));
|
|
} else {
|
|
j = jArr[i3];
|
|
}
|
|
jArr[i3] = j;
|
|
}
|
|
}
|
|
}
|
|
|
|
private void pi(long[] jArr) {
|
|
long[] jArr2 = this.tempA;
|
|
System.arraycopy(jArr, 0, jArr2, 0, jArr2.length);
|
|
for (int i = 0; i < 5; i++) {
|
|
for (int i2 = 0; i2 < 5; i2++) {
|
|
jArr[((((i << 1) + (i2 * 3)) % 5) * 5) + i2] = this.tempA[(i2 * 5) + i];
|
|
}
|
|
}
|
|
}
|
|
|
|
private void padAndSwitchToSqueezingPhase() {
|
|
int i = this.bitsInQueue;
|
|
int i2 = this.rate;
|
|
if (i + 1 == i2) {
|
|
byte[] bArr = this.dataQueue;
|
|
int i3 = i / 8;
|
|
bArr[i3] = (byte) ((1 << (i % 8)) | bArr[i3]);
|
|
absorbQueue();
|
|
clearDataQueueSection(0, this.rate / 8);
|
|
} else {
|
|
int i4 = (i + 7) / 8;
|
|
clearDataQueueSection(i4, (i2 / 8) - i4);
|
|
byte[] bArr2 = this.dataQueue;
|
|
int i5 = this.bitsInQueue;
|
|
int i6 = i5 / 8;
|
|
bArr2[i6] = (byte) ((1 << (i5 % 8)) | bArr2[i6]);
|
|
}
|
|
byte[] bArr3 = this.dataQueue;
|
|
int i7 = this.rate - 1;
|
|
int i8 = i7 / 8;
|
|
bArr3[i8] = (byte) ((1 << (i7 % 8)) | bArr3[i8]);
|
|
absorbQueue();
|
|
int i9 = this.rate;
|
|
if (i9 == 1024) {
|
|
KeccakExtract1024bits(this.state, this.dataQueue);
|
|
this.bitsAvailableForSqueezing = 1024;
|
|
} else {
|
|
KeccakExtract(this.state, this.dataQueue, i9 / 64);
|
|
this.bitsAvailableForSqueezing = this.rate;
|
|
}
|
|
this.squeezing = true;
|
|
}
|
|
|
|
private void keccakPermutationOnWords(long[] jArr) {
|
|
for (int i = 0; i < 24; i++) {
|
|
theta(jArr);
|
|
rho(jArr);
|
|
pi(jArr);
|
|
chi(jArr);
|
|
iota(jArr, i);
|
|
}
|
|
}
|
|
|
|
private void keccakPermutationAfterXor(byte[] bArr, byte[] bArr2, int i) {
|
|
for (int i2 = 0; i2 < i; i2++) {
|
|
bArr[i2] = (byte) (bArr[i2] ^ bArr2[i2]);
|
|
}
|
|
keccakPermutation(bArr);
|
|
}
|
|
|
|
private void keccakPermutation(byte[] bArr) {
|
|
long[] jArr = new long[bArr.length / 8];
|
|
fromBytesToWords(jArr, bArr);
|
|
keccakPermutationOnWords(jArr);
|
|
fromWordsToBytes(bArr, jArr);
|
|
}
|
|
|
|
private static long[] keccakInitializeRoundConstants() {
|
|
long[] jArr = new long[24];
|
|
byte[] bArr = {1};
|
|
for (int i = 0; i < 24; i++) {
|
|
jArr[i] = 0;
|
|
for (int i2 = 0; i2 < 7; i2++) {
|
|
if (LFSR86540(bArr)) {
|
|
jArr[i] = jArr[i] ^ (1 << ((1 << i2) - 1));
|
|
}
|
|
}
|
|
}
|
|
return jArr;
|
|
}
|
|
|
|
private static int[] keccakInitializeRhoOffsets() {
|
|
int[] iArr = new int[25];
|
|
int i = 0;
|
|
iArr[0] = 0;
|
|
int i2 = 0;
|
|
int i3 = 1;
|
|
while (i2 < 24) {
|
|
int i4 = i2 + 1;
|
|
int i5 = i % 5;
|
|
iArr[(i3 % 5) + (i5 * 5)] = (((i2 + 2) * i4) / 2) % 64;
|
|
i = ((i3 << 1) + (i * 3)) % 5;
|
|
i2 = i4;
|
|
i3 = i5;
|
|
}
|
|
return iArr;
|
|
}
|
|
|
|
private void iota(long[] jArr, int i) {
|
|
jArr[0] = jArr[0] ^ KeccakRoundConstants[i];
|
|
}
|
|
|
|
private void initSponge(int i, int i2) {
|
|
if (i + i2 != 1600) {
|
|
throw new IllegalStateException("rate + capacity != 1600");
|
|
}
|
|
if (i <= 0 || i >= 1600 || i % 64 != 0) {
|
|
throw new IllegalStateException("invalid rate value");
|
|
}
|
|
this.rate = i;
|
|
Arrays.fill(this.state, (byte) 0);
|
|
Arrays.fill(this.dataQueue, (byte) 0);
|
|
this.bitsInQueue = 0;
|
|
this.squeezing = false;
|
|
this.bitsAvailableForSqueezing = 0;
|
|
this.fixedOutputLength = i2 / 2;
|
|
this.chunk = new byte[i / 8];
|
|
this.oneByte = new byte[1];
|
|
}
|
|
|
|
private void init(int i) {
|
|
int i2;
|
|
int i3;
|
|
if (i == 128) {
|
|
initSponge(1344, 256);
|
|
return;
|
|
}
|
|
if (i != 224) {
|
|
i3 = 512;
|
|
if (i == 256) {
|
|
i2 = 1088;
|
|
} else if (i == 288) {
|
|
initSponge(1024, 576);
|
|
return;
|
|
} else {
|
|
if (i != 384) {
|
|
if (i != 512) {
|
|
throw new IllegalArgumentException("bitLength must be one of 128, 224, 256, 288, 384, or 512.");
|
|
}
|
|
initSponge(576, 1024);
|
|
return;
|
|
}
|
|
i2 = 832;
|
|
i3 = 768;
|
|
}
|
|
} else {
|
|
i2 = 1152;
|
|
i3 = 448;
|
|
}
|
|
initSponge(i2, i3);
|
|
}
|
|
|
|
private void fromWordsToBytes(byte[] bArr, long[] jArr) {
|
|
for (int i = 0; i < 25; i++) {
|
|
for (int i2 = 0; i2 < 8; i2++) {
|
|
bArr[(i << 3) + i2] = (byte) ((jArr[i] >>> (i2 << 3)) & 255);
|
|
}
|
|
}
|
|
}
|
|
|
|
private void fromBytesToWords(long[] jArr, byte[] bArr) {
|
|
for (int i = 0; i < 25; i++) {
|
|
jArr[i] = 0;
|
|
for (int i2 = 0; i2 < 8; i2++) {
|
|
jArr[i] = jArr[i] | ((bArr[(i << 3) + i2] & 255) << (i2 << 3));
|
|
}
|
|
}
|
|
}
|
|
|
|
private void clearDataQueueSection(int i, int i2) {
|
|
for (int i3 = i; i3 != i + i2; i3++) {
|
|
this.dataQueue[i3] = 0;
|
|
}
|
|
}
|
|
|
|
private void chi(long[] jArr) {
|
|
for (int i = 0; i < 5; i++) {
|
|
int i2 = 0;
|
|
while (i2 < 5) {
|
|
int i3 = i * 5;
|
|
int i4 = i2 + 1;
|
|
this.chiC[i2] = jArr[i2 + i3] ^ ((~jArr[(i4 % 5) + i3]) & jArr[((i2 + 2) % 5) + i3]);
|
|
i2 = i4;
|
|
}
|
|
for (int i5 = 0; i5 < 5; i5++) {
|
|
jArr[(i * 5) + i5] = this.chiC[i5];
|
|
}
|
|
}
|
|
}
|
|
|
|
private void absorbQueue() {
|
|
KeccakAbsorb(this.state, this.dataQueue, this.rate / 8);
|
|
this.bitsInQueue = 0;
|
|
}
|
|
|
|
private static boolean LFSR86540(byte[] bArr) {
|
|
byte b = bArr[0];
|
|
boolean z = (b & 1) != 0;
|
|
int i = b << 1;
|
|
if ((b & 128) != 0) {
|
|
bArr[0] = (byte) (i ^ 113);
|
|
} else {
|
|
bArr[0] = (byte) i;
|
|
}
|
|
return z;
|
|
}
|
|
|
|
private void KeccakExtract1024bits(byte[] bArr, byte[] bArr2) {
|
|
System.arraycopy(bArr, 0, bArr2, 0, 128);
|
|
}
|
|
|
|
private void KeccakExtract(byte[] bArr, byte[] bArr2, int i) {
|
|
System.arraycopy(bArr, 0, bArr2, 0, i << 3);
|
|
}
|
|
|
|
private void KeccakAbsorb(byte[] bArr, byte[] bArr2, int i) {
|
|
keccakPermutationAfterXor(bArr, bArr2, i);
|
|
}
|
|
|
|
public KeccakDigest(KeccakDigest keccakDigest) {
|
|
byte[] bArr = new byte[DisplayText.DISPLAY_TEXT_MAXIMUM_SIZE];
|
|
this.state = bArr;
|
|
this.dataQueue = new byte[192];
|
|
this.C = new long[5];
|
|
this.tempA = new long[25];
|
|
this.chiC = new long[5];
|
|
byte[] bArr2 = keccakDigest.state;
|
|
System.arraycopy(bArr2, 0, bArr, 0, bArr2.length);
|
|
byte[] bArr3 = keccakDigest.dataQueue;
|
|
System.arraycopy(bArr3, 0, this.dataQueue, 0, bArr3.length);
|
|
this.rate = keccakDigest.rate;
|
|
this.bitsInQueue = keccakDigest.bitsInQueue;
|
|
this.fixedOutputLength = keccakDigest.fixedOutputLength;
|
|
this.squeezing = keccakDigest.squeezing;
|
|
this.bitsAvailableForSqueezing = keccakDigest.bitsAvailableForSqueezing;
|
|
this.chunk = Arrays.clone(keccakDigest.chunk);
|
|
this.oneByte = Arrays.clone(keccakDigest.oneByte);
|
|
}
|
|
|
|
public KeccakDigest(int i) {
|
|
this.state = new byte[DisplayText.DISPLAY_TEXT_MAXIMUM_SIZE];
|
|
this.dataQueue = new byte[192];
|
|
this.C = new long[5];
|
|
this.tempA = new long[25];
|
|
this.chiC = new long[5];
|
|
init(i);
|
|
}
|
|
|
|
public KeccakDigest() {
|
|
this(288);
|
|
}
|
|
}
|