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

469 lines
16 KiB
Java

package org.bouncycastle.crypto.modes;
import com.google.common.primitives.UnsignedBytes;
import java.util.Vector;
import net.sf.scuba.smartcards.ISO7816;
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.params.AEADParameters;
import org.bouncycastle.crypto.params.KeyParameter;
import org.bouncycastle.crypto.params.ParametersWithIV;
import org.bouncycastle.util.Arrays;
/* loaded from: classes6.dex */
public class OCBBlockCipher implements AEADBlockCipher {
private static final int BLOCK_SIZE = 16;
private byte[] Checksum;
private Vector L;
private byte[] L_Asterisk;
private byte[] L_Dollar;
private byte[] OffsetHASH;
private byte[] Sum;
private boolean forEncryption;
private byte[] hashBlock;
private long hashBlockCount;
private int hashBlockPos;
private BlockCipher hashCipher;
private byte[] initialAssociatedText;
private byte[] macBlock;
private int macSize;
private byte[] mainBlock;
private long mainBlockCount;
private int mainBlockPos;
private BlockCipher mainCipher;
private byte[] KtopInput = null;
private byte[] Stretch = new byte[24];
private byte[] OffsetMAIN_0 = new byte[16];
private byte[] OffsetMAIN = new byte[16];
protected static int OCB_ntz(long j) {
if (j == 0) {
return 64;
}
int i = 0;
while ((1 & j) == 0) {
i++;
j >>>= 1;
}
return i;
}
protected void updateHASH(byte[] bArr) {
xor(this.OffsetHASH, bArr);
xor(this.hashBlock, this.OffsetHASH);
BlockCipher blockCipher = this.hashCipher;
byte[] bArr2 = this.hashBlock;
blockCipher.processBlock(bArr2, 0, bArr2, 0);
xor(this.Sum, this.hashBlock);
}
protected void reset(boolean z) {
this.hashCipher.reset();
this.mainCipher.reset();
clear(this.hashBlock);
clear(this.mainBlock);
this.hashBlockPos = 0;
this.mainBlockPos = 0;
this.hashBlockCount = 0L;
this.mainBlockCount = 0L;
clear(this.OffsetHASH);
clear(this.Sum);
System.arraycopy(this.OffsetMAIN_0, 0, this.OffsetMAIN, 0, 16);
clear(this.Checksum);
if (z) {
this.macBlock = null;
}
byte[] bArr = this.initialAssociatedText;
if (bArr != null) {
processAADBytes(bArr, 0, bArr.length);
}
}
@Override // org.bouncycastle.crypto.modes.AEADBlockCipher
public void reset() {
reset(true);
}
protected int processNonce(byte[] bArr) {
byte[] bArr2 = new byte[16];
int i = 0;
System.arraycopy(bArr, 0, bArr2, 16 - bArr.length, bArr.length);
bArr2[0] = (byte) (this.macSize << 4);
int length = 15 - bArr.length;
bArr2[length] = (byte) (bArr2[length] | 1);
byte b = bArr2[15];
bArr2[15] = (byte) (b & ISO7816.INS_GET_RESPONSE);
byte[] bArr3 = this.KtopInput;
if (bArr3 == null || !Arrays.areEqual(bArr2, bArr3)) {
byte[] bArr4 = new byte[16];
this.KtopInput = bArr2;
this.hashCipher.processBlock(bArr2, 0, bArr4, 0);
System.arraycopy(bArr4, 0, this.Stretch, 0, 16);
while (i < 8) {
int i2 = i + 1;
this.Stretch[i + 16] = (byte) (bArr4[i] ^ bArr4[i2]);
i = i2;
}
}
return b & 63;
}
protected void processMainBlock(byte[] bArr, int i) {
if (bArr.length < i + 16) {
throw new OutputLengthException("Output buffer too short");
}
if (this.forEncryption) {
xor(this.Checksum, this.mainBlock);
this.mainBlockPos = 0;
}
byte[] bArr2 = this.OffsetMAIN;
long j = this.mainBlockCount + 1;
this.mainBlockCount = j;
xor(bArr2, getLSub(OCB_ntz(j)));
xor(this.mainBlock, this.OffsetMAIN);
BlockCipher blockCipher = this.mainCipher;
byte[] bArr3 = this.mainBlock;
blockCipher.processBlock(bArr3, 0, bArr3, 0);
xor(this.mainBlock, this.OffsetMAIN);
System.arraycopy(this.mainBlock, 0, bArr, i, 16);
if (this.forEncryption) {
return;
}
xor(this.Checksum, this.mainBlock);
byte[] bArr4 = this.mainBlock;
System.arraycopy(bArr4, 16, bArr4, 0, this.macSize);
this.mainBlockPos = this.macSize;
}
protected void processHashBlock() {
long j = this.hashBlockCount + 1;
this.hashBlockCount = j;
updateHASH(getLSub(OCB_ntz(j)));
this.hashBlockPos = 0;
}
@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.mainBlock;
int i6 = this.mainBlockPos;
bArr3[i6] = bArr[i + i5];
int i7 = i6 + 1;
this.mainBlockPos = i7;
if (i7 == bArr3.length) {
processMainBlock(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.mainBlock;
int i2 = this.mainBlockPos;
bArr2[i2] = b;
int i3 = i2 + 1;
this.mainBlockPos = i3;
if (i3 != bArr2.length) {
return 0;
}
processMainBlock(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.hashBlock;
int i4 = this.hashBlockPos;
bArr2[i4] = bArr[i + i3];
int i5 = i4 + 1;
this.hashBlockPos = i5;
if (i5 == bArr2.length) {
processHashBlock();
}
}
}
@Override // org.bouncycastle.crypto.modes.AEADBlockCipher
public void processAADByte(byte b) {
byte[] bArr = this.hashBlock;
int i = this.hashBlockPos;
bArr[i] = b;
int i2 = i + 1;
this.hashBlockPos = i2;
if (i2 == bArr.length) {
processHashBlock();
}
}
@Override // org.bouncycastle.crypto.modes.AEADBlockCipher
public void init(boolean z, CipherParameters cipherParameters) throws IllegalArgumentException {
byte[] iv;
KeyParameter keyParameter;
boolean z2 = this.forEncryption;
this.forEncryption = z;
this.macBlock = null;
if (cipherParameters instanceof AEADParameters) {
AEADParameters aEADParameters = (AEADParameters) cipherParameters;
iv = aEADParameters.getNonce();
this.initialAssociatedText = aEADParameters.getAssociatedText();
int macSize = aEADParameters.getMacSize();
if (macSize < 64 || 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 OCB");
}
ParametersWithIV parametersWithIV = (ParametersWithIV) cipherParameters;
iv = parametersWithIV.getIV();
this.initialAssociatedText = null;
this.macSize = 16;
keyParameter = (KeyParameter) parametersWithIV.getParameters();
}
this.hashBlock = new byte[16];
this.mainBlock = new byte[z ? 16 : this.macSize + 16];
if (iv == null) {
iv = new byte[0];
}
if (iv.length > 15) {
throw new IllegalArgumentException("IV must be no more than 15 bytes");
}
if (keyParameter != null) {
this.hashCipher.init(true, keyParameter);
this.mainCipher.init(z, keyParameter);
this.KtopInput = null;
} else if (z2 != z) {
throw new IllegalArgumentException("cannot change encrypting state without providing key.");
}
byte[] bArr = new byte[16];
this.L_Asterisk = bArr;
this.hashCipher.processBlock(bArr, 0, bArr, 0);
this.L_Dollar = OCB_double(this.L_Asterisk);
Vector vector = new Vector();
this.L = vector;
vector.addElement(OCB_double(this.L_Dollar));
int processNonce = processNonce(iv);
int i = processNonce % 8;
int i2 = processNonce / 8;
if (i == 0) {
System.arraycopy(this.Stretch, i2, this.OffsetMAIN_0, 0, 16);
} else {
for (int i3 = 0; i3 < 16; i3++) {
byte[] bArr2 = this.Stretch;
byte b = bArr2[i2];
i2++;
this.OffsetMAIN_0[i3] = (byte) (((bArr2[i2] & UnsignedBytes.MAX_VALUE) >>> (8 - i)) | ((b & UnsignedBytes.MAX_VALUE) << i));
}
}
this.hashBlockPos = 0;
this.mainBlockPos = 0;
this.hashBlockCount = 0L;
this.mainBlockCount = 0L;
this.OffsetHASH = new byte[16];
this.Sum = new byte[16];
System.arraycopy(this.OffsetMAIN_0, 0, this.OffsetMAIN, 0, 16);
this.Checksum = new byte[16];
byte[] bArr3 = this.initialAssociatedText;
if (bArr3 != null) {
processAADBytes(bArr3, 0, bArr3.length);
}
}
@Override // org.bouncycastle.crypto.modes.AEADBlockCipher
public int getUpdateOutputSize(int i) {
int i2 = i + this.mainBlockPos;
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.mainCipher;
}
@Override // org.bouncycastle.crypto.modes.AEADBlockCipher
public int getOutputSize(int i) {
int i2 = i + this.mainBlockPos;
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);
}
protected byte[] getLSub(int i) {
while (i >= this.L.size()) {
Vector vector = this.L;
vector.addElement(OCB_double((byte[]) vector.lastElement()));
}
return (byte[]) this.L.elementAt(i);
}
@Override // org.bouncycastle.crypto.modes.AEADBlockCipher
public String getAlgorithmName() {
StringBuilder sb = new StringBuilder();
sb.append(this.mainCipher.getAlgorithmName());
sb.append("/OCB");
return sb.toString();
}
@Override // org.bouncycastle.crypto.modes.AEADBlockCipher
public int doFinal(byte[] bArr, int i) throws IllegalStateException, InvalidCipherTextException {
byte[] bArr2;
if (this.forEncryption) {
bArr2 = null;
} else {
int i2 = this.mainBlockPos;
int i3 = this.macSize;
if (i2 < i3) {
throw new InvalidCipherTextException("data too short");
}
int i4 = i2 - i3;
this.mainBlockPos = i4;
bArr2 = new byte[i3];
System.arraycopy(this.mainBlock, i4, bArr2, 0, i3);
}
int i5 = this.hashBlockPos;
if (i5 > 0) {
OCB_extend(this.hashBlock, i5);
updateHASH(this.L_Asterisk);
}
int i6 = this.mainBlockPos;
if (i6 > 0) {
if (this.forEncryption) {
OCB_extend(this.mainBlock, i6);
xor(this.Checksum, this.mainBlock);
}
xor(this.OffsetMAIN, this.L_Asterisk);
byte[] bArr3 = new byte[16];
this.hashCipher.processBlock(this.OffsetMAIN, 0, bArr3, 0);
xor(this.mainBlock, bArr3);
int length = bArr.length;
int i7 = this.mainBlockPos;
if (length < i + i7) {
throw new OutputLengthException("Output buffer too short");
}
System.arraycopy(this.mainBlock, 0, bArr, i, i7);
if (!this.forEncryption) {
OCB_extend(this.mainBlock, this.mainBlockPos);
xor(this.Checksum, this.mainBlock);
}
}
xor(this.Checksum, this.OffsetMAIN);
xor(this.Checksum, this.L_Dollar);
BlockCipher blockCipher = this.hashCipher;
byte[] bArr4 = this.Checksum;
blockCipher.processBlock(bArr4, 0, bArr4, 0);
xor(this.Checksum, this.Sum);
int i8 = this.macSize;
byte[] bArr5 = new byte[i8];
this.macBlock = bArr5;
System.arraycopy(this.Checksum, 0, bArr5, 0, i8);
int i9 = this.mainBlockPos;
if (this.forEncryption) {
int length2 = bArr.length;
int i10 = i + i9;
int i11 = this.macSize;
if (length2 < i10 + i11) {
throw new OutputLengthException("Output buffer too short");
}
System.arraycopy(this.macBlock, 0, bArr, i10, i11);
i9 += this.macSize;
} else if (!Arrays.constantTimeAreEqual(this.macBlock, bArr2)) {
throw new InvalidCipherTextException("mac check in OCB failed");
}
reset(false);
return i9;
}
protected void clear(byte[] bArr) {
if (bArr != null) {
Arrays.fill(bArr, (byte) 0);
}
}
protected static void xor(byte[] bArr, byte[] bArr2) {
for (int i = 15; i >= 0; i--) {
bArr[i] = (byte) (bArr[i] ^ bArr2[i]);
}
}
protected static int shiftLeft(byte[] bArr, byte[] bArr2) {
int i = 16;
int i2 = 0;
while (true) {
i--;
if (i < 0) {
return i2;
}
int i3 = bArr[i] & UnsignedBytes.MAX_VALUE;
bArr2[i] = (byte) (i2 | (i3 << 1));
i2 = (i3 >>> 7) & 1;
}
}
protected static void OCB_extend(byte[] bArr, int i) {
bArr[i] = Byte.MIN_VALUE;
while (true) {
i++;
if (i >= 16) {
return;
} else {
bArr[i] = 0;
}
}
}
protected static byte[] OCB_double(byte[] bArr) {
byte[] bArr2 = new byte[16];
bArr2[15] = (byte) ((135 >>> ((1 - shiftLeft(bArr, bArr2)) << 3)) ^ bArr2[15]);
return bArr2;
}
public OCBBlockCipher(BlockCipher blockCipher, BlockCipher blockCipher2) {
if (blockCipher == null) {
throw new IllegalArgumentException("'hashCipher' cannot be null");
}
if (blockCipher.getBlockSize() != 16) {
throw new IllegalArgumentException("'hashCipher' must have a block size of 16");
}
if (blockCipher2 == null) {
throw new IllegalArgumentException("'mainCipher' cannot be null");
}
if (blockCipher2.getBlockSize() != 16) {
throw new IllegalArgumentException("'mainCipher' must have a block size of 16");
}
if (!blockCipher.getAlgorithmName().equals(blockCipher2.getAlgorithmName())) {
throw new IllegalArgumentException("'hashCipher' and 'mainCipher' must be the same algorithm");
}
this.hashCipher = blockCipher;
this.mainCipher = blockCipher2;
}
}