what-the-bank/sources/org/bouncycastle/crypto/modes/GCMBlockCipher.java

427 lines
15 KiB
Java
Raw Permalink Normal View History

2024-07-27 18:17:47 +07:00
package org.bouncycastle.crypto.modes;
import com.google.common.primitives.UnsignedBytes;
import org.bouncycastle.crypto.BlockCipher;
import org.bouncycastle.crypto.CipherParameters;
import org.bouncycastle.crypto.DataLengthException;
import org.bouncycastle.crypto.InvalidCipherTextException;
import org.bouncycastle.crypto.OutputLengthException;
import org.bouncycastle.crypto.modes.gcm.GCMExponentiator;
import org.bouncycastle.crypto.modes.gcm.GCMMultiplier;
import org.bouncycastle.crypto.modes.gcm.GCMUtil;
import org.bouncycastle.crypto.modes.gcm.Tables1kGCMExponentiator;
import org.bouncycastle.crypto.modes.gcm.Tables8kGCMMultiplier;
import org.bouncycastle.crypto.params.AEADParameters;
import org.bouncycastle.crypto.params.KeyParameter;
import org.bouncycastle.crypto.params.ParametersWithIV;
import org.bouncycastle.util.Arrays;
import org.bouncycastle.util.Pack;
/* loaded from: classes6.dex */
public class GCMBlockCipher implements AEADBlockCipher {
private static final int BLOCK_SIZE = 16;
private byte[] H;
private byte[] J0;
private byte[] S;
private byte[] S_at;
private byte[] S_atPre;
private byte[] atBlock;
private int atBlockPos;
private long atLength;
private long atLengthPre;
private int blocksRemaining;
private byte[] bufBlock;
private int bufOff;
private BlockCipher cipher;
private byte[] counter;
private GCMExponentiator exp;
private boolean forEncryption;
private byte[] initialAssociatedText;
private byte[] macBlock;
private int macSize;
private GCMMultiplier multiplier;
private byte[] nonce;
private long totalLength;
@Override // org.bouncycastle.crypto.modes.AEADBlockCipher
public void reset() {
reset(true);
}
@Override // org.bouncycastle.crypto.modes.AEADBlockCipher
public int processBytes(byte[] bArr, int i, int i2, byte[] bArr2, int i3) throws DataLengthException {
if (bArr.length < i + i2) {
throw new DataLengthException("Input buffer too short");
}
int i4 = 0;
for (int i5 = 0; i5 < i2; i5++) {
byte[] bArr3 = this.bufBlock;
int i6 = this.bufOff;
bArr3[i6] = bArr[i + i5];
int i7 = i6 + 1;
this.bufOff = i7;
if (i7 == bArr3.length) {
outputBlock(bArr2, i3 + i4);
i4 += 16;
}
}
return i4;
}
@Override // org.bouncycastle.crypto.modes.AEADBlockCipher
public int processByte(byte b, byte[] bArr, int i) throws DataLengthException {
byte[] bArr2 = this.bufBlock;
int i2 = this.bufOff;
bArr2[i2] = b;
int i3 = i2 + 1;
this.bufOff = i3;
if (i3 != bArr2.length) {
return 0;
}
outputBlock(bArr, i);
return 16;
}
@Override // org.bouncycastle.crypto.modes.AEADBlockCipher
public void processAADBytes(byte[] bArr, int i, int i2) {
for (int i3 = 0; i3 < i2; i3++) {
byte[] bArr2 = this.atBlock;
int i4 = this.atBlockPos;
bArr2[i4] = bArr[i + i3];
int i5 = i4 + 1;
this.atBlockPos = i5;
if (i5 == 16) {
gHASHBlock(this.S_at, bArr2);
this.atBlockPos = 0;
this.atLength += 16;
}
}
}
@Override // org.bouncycastle.crypto.modes.AEADBlockCipher
public void processAADByte(byte b) {
byte[] bArr = this.atBlock;
int i = this.atBlockPos;
bArr[i] = b;
int i2 = i + 1;
this.atBlockPos = i2;
if (i2 == 16) {
gHASHBlock(this.S_at, bArr);
this.atBlockPos = 0;
this.atLength += 16;
}
}
@Override // org.bouncycastle.crypto.modes.AEADBlockCipher
public void init(boolean z, CipherParameters cipherParameters) throws IllegalArgumentException {
KeyParameter keyParameter;
this.forEncryption = z;
this.macBlock = null;
if (cipherParameters instanceof AEADParameters) {
AEADParameters aEADParameters = (AEADParameters) cipherParameters;
this.nonce = aEADParameters.getNonce();
this.initialAssociatedText = aEADParameters.getAssociatedText();
int macSize = aEADParameters.getMacSize();
if (macSize < 32 || macSize > 128 || macSize % 8 != 0) {
throw new IllegalArgumentException("Invalid value for MAC size: ".concat(String.valueOf(macSize)));
}
this.macSize = macSize / 8;
keyParameter = aEADParameters.getKey();
} else {
if (!(cipherParameters instanceof ParametersWithIV)) {
throw new IllegalArgumentException("invalid parameters passed to GCM");
}
ParametersWithIV parametersWithIV = (ParametersWithIV) cipherParameters;
this.nonce = parametersWithIV.getIV();
this.initialAssociatedText = null;
this.macSize = 16;
keyParameter = (KeyParameter) parametersWithIV.getParameters();
}
this.bufBlock = new byte[z ? 16 : this.macSize + 16];
byte[] bArr = this.nonce;
if (bArr == null || bArr.length <= 0) {
throw new IllegalArgumentException("IV must be at least 1 byte");
}
if (keyParameter != null) {
this.cipher.init(true, keyParameter);
byte[] bArr2 = new byte[16];
this.H = bArr2;
this.cipher.processBlock(bArr2, 0, bArr2, 0);
this.multiplier.init(this.H);
this.exp = null;
} else if (this.H == null) {
throw new IllegalArgumentException("Key must be specified in initial init");
}
byte[] bArr3 = new byte[16];
this.J0 = bArr3;
byte[] bArr4 = this.nonce;
if (bArr4.length == 12) {
System.arraycopy(bArr4, 0, bArr3, 0, bArr4.length);
this.J0[15] = 1;
} else {
gHASH(bArr3, bArr4, bArr4.length);
byte[] bArr5 = new byte[16];
Pack.longToBigEndian(this.nonce.length << 3, bArr5, 8);
gHASHBlock(this.J0, bArr5);
}
this.S = new byte[16];
this.S_at = new byte[16];
this.S_atPre = new byte[16];
this.atBlock = new byte[16];
this.atBlockPos = 0;
this.atLength = 0L;
this.atLengthPre = 0L;
this.counter = Arrays.clone(this.J0);
this.blocksRemaining = -2;
this.bufOff = 0;
this.totalLength = 0L;
byte[] bArr6 = this.initialAssociatedText;
if (bArr6 != null) {
processAADBytes(bArr6, 0, bArr6.length);
}
}
@Override // org.bouncycastle.crypto.modes.AEADBlockCipher
public int getUpdateOutputSize(int i) {
int i2 = i + this.bufOff;
if (!this.forEncryption) {
int i3 = this.macSize;
if (i2 < i3) {
return 0;
}
i2 -= i3;
}
return i2 - (i2 % 16);
}
@Override // org.bouncycastle.crypto.modes.AEADBlockCipher
public BlockCipher getUnderlyingCipher() {
return this.cipher;
}
@Override // org.bouncycastle.crypto.modes.AEADBlockCipher
public int getOutputSize(int i) {
int i2 = i + this.bufOff;
if (this.forEncryption) {
return i2 + this.macSize;
}
int i3 = this.macSize;
if (i2 < i3) {
return 0;
}
return i2 - i3;
}
@Override // org.bouncycastle.crypto.modes.AEADBlockCipher
public byte[] getMac() {
return Arrays.clone(this.macBlock);
}
@Override // org.bouncycastle.crypto.modes.AEADBlockCipher
public String getAlgorithmName() {
StringBuilder sb = new StringBuilder();
sb.append(this.cipher.getAlgorithmName());
sb.append("/GCM");
return sb.toString();
}
@Override // org.bouncycastle.crypto.modes.AEADBlockCipher
public int doFinal(byte[] bArr, int i) throws IllegalStateException, InvalidCipherTextException {
if (this.totalLength == 0) {
initCipher();
}
int i2 = this.bufOff;
if (!this.forEncryption) {
int i3 = this.macSize;
if (i2 < i3) {
throw new InvalidCipherTextException("data too short");
}
i2 -= i3;
if (bArr.length < i + i2) {
throw new OutputLengthException("Output buffer too short");
}
} else if (bArr.length < i + i2 + this.macSize) {
throw new OutputLengthException("Output buffer too short");
}
if (i2 > 0) {
gCTRPartial(this.bufBlock, 0, i2, bArr, i);
}
long j = this.atLength;
int i4 = this.atBlockPos;
long j2 = j + i4;
this.atLength = j2;
if (j2 > this.atLengthPre) {
if (i4 > 0) {
gHASHPartial(this.S_at, this.atBlock, 0, i4);
}
if (this.atLengthPre > 0) {
GCMUtil.xor(this.S_at, this.S_atPre);
}
long j3 = this.totalLength;
byte[] bArr2 = new byte[16];
if (this.exp == null) {
Tables1kGCMExponentiator tables1kGCMExponentiator = new Tables1kGCMExponentiator();
this.exp = tables1kGCMExponentiator;
tables1kGCMExponentiator.init(this.H);
}
this.exp.exponentiateX(((j3 << 3) + 127) >>> 7, bArr2);
GCMUtil.multiply(this.S_at, bArr2);
GCMUtil.xor(this.S, this.S_at);
}
byte[] bArr3 = new byte[16];
Pack.longToBigEndian(this.atLength << 3, bArr3, 0);
Pack.longToBigEndian(this.totalLength << 3, bArr3, 8);
gHASHBlock(this.S, bArr3);
byte[] bArr4 = new byte[16];
this.cipher.processBlock(this.J0, 0, bArr4, 0);
GCMUtil.xor(bArr4, this.S);
int i5 = this.macSize;
byte[] bArr5 = new byte[i5];
this.macBlock = bArr5;
System.arraycopy(bArr4, 0, bArr5, 0, i5);
if (this.forEncryption) {
System.arraycopy(this.macBlock, 0, bArr, i + this.bufOff, this.macSize);
i2 += this.macSize;
} else {
int i6 = this.macSize;
byte[] bArr6 = new byte[i6];
System.arraycopy(this.bufBlock, i2, bArr6, 0, i6);
if (!Arrays.constantTimeAreEqual(this.macBlock, bArr6)) {
throw new InvalidCipherTextException("mac check in GCM failed");
}
}
reset(false);
return i2;
}
private void reset(boolean z) {
this.cipher.reset();
this.S = new byte[16];
this.S_at = new byte[16];
this.S_atPre = new byte[16];
this.atBlock = new byte[16];
this.atBlockPos = 0;
this.atLength = 0L;
this.atLengthPre = 0L;
this.counter = Arrays.clone(this.J0);
this.blocksRemaining = -2;
this.bufOff = 0;
this.totalLength = 0L;
byte[] bArr = this.bufBlock;
if (bArr != null) {
Arrays.fill(bArr, (byte) 0);
}
if (z) {
this.macBlock = null;
}
byte[] bArr2 = this.initialAssociatedText;
if (bArr2 != null) {
processAADBytes(bArr2, 0, bArr2.length);
}
}
private void outputBlock(byte[] bArr, int i) {
if (bArr.length < i + 16) {
throw new OutputLengthException("Output buffer too short");
}
if (this.totalLength == 0) {
initCipher();
}
gCTRBlock(this.bufBlock, bArr, i);
if (this.forEncryption) {
this.bufOff = 0;
return;
}
byte[] bArr2 = this.bufBlock;
System.arraycopy(bArr2, 16, bArr2, 0, this.macSize);
this.bufOff = this.macSize;
}
private void initCipher() {
if (this.atLength > 0) {
System.arraycopy(this.S_at, 0, this.S_atPre, 0, 16);
this.atLengthPre = this.atLength;
}
int i = this.atBlockPos;
if (i > 0) {
gHASHPartial(this.S_atPre, this.atBlock, 0, i);
this.atLengthPre += this.atBlockPos;
}
if (this.atLengthPre > 0) {
System.arraycopy(this.S_atPre, 0, this.S, 0, 16);
}
}
private byte[] getNextCounterBlock() {
int i = this.blocksRemaining;
if (i == 0) {
throw new IllegalStateException("Attempt to process too many blocks");
}
this.blocksRemaining = i - 1;
byte[] bArr = this.counter;
int i2 = (bArr[15] & UnsignedBytes.MAX_VALUE) + 1;
bArr[15] = (byte) i2;
int i3 = (i2 >>> 8) + (bArr[14] & UnsignedBytes.MAX_VALUE);
bArr[14] = (byte) i3;
int i4 = (i3 >>> 8) + (bArr[13] & UnsignedBytes.MAX_VALUE);
bArr[13] = (byte) i4;
bArr[12] = (byte) ((i4 >>> 8) + (bArr[12] & UnsignedBytes.MAX_VALUE));
byte[] bArr2 = new byte[16];
this.cipher.processBlock(bArr, 0, bArr2, 0);
return bArr2;
}
private void gHASHPartial(byte[] bArr, byte[] bArr2, int i, int i2) {
GCMUtil.xor(bArr, bArr2, i, i2);
this.multiplier.multiplyH(bArr);
}
private void gHASHBlock(byte[] bArr, byte[] bArr2) {
GCMUtil.xor(bArr, bArr2);
this.multiplier.multiplyH(bArr);
}
private void gHASH(byte[] bArr, byte[] bArr2, int i) {
for (int i2 = 0; i2 < i; i2 += 16) {
gHASHPartial(bArr, bArr2, i2, Math.min(i - i2, 16));
}
}
private void gCTRPartial(byte[] bArr, int i, int i2, byte[] bArr2, int i3) {
byte[] nextCounterBlock = getNextCounterBlock();
GCMUtil.xor(nextCounterBlock, bArr, i, i2);
System.arraycopy(nextCounterBlock, 0, bArr2, i3, i2);
byte[] bArr3 = this.S;
if (this.forEncryption) {
bArr = nextCounterBlock;
}
gHASHPartial(bArr3, bArr, 0, i2);
this.totalLength += i2;
}
private void gCTRBlock(byte[] bArr, byte[] bArr2, int i) {
byte[] nextCounterBlock = getNextCounterBlock();
GCMUtil.xor(nextCounterBlock, bArr);
System.arraycopy(nextCounterBlock, 0, bArr2, i, 16);
byte[] bArr3 = this.S;
if (this.forEncryption) {
bArr = nextCounterBlock;
}
gHASHBlock(bArr3, bArr);
this.totalLength += 16;
}
public GCMBlockCipher(BlockCipher blockCipher, GCMMultiplier gCMMultiplier) {
if (blockCipher.getBlockSize() != 16) {
throw new IllegalArgumentException("cipher required with a block size of 16.");
}
gCMMultiplier = gCMMultiplier == null ? new Tables8kGCMMultiplier() : gCMMultiplier;
this.cipher = blockCipher;
this.multiplier = gCMMultiplier;
}
public GCMBlockCipher(BlockCipher blockCipher) {
this(blockCipher, null);
}
}