290 lines
9.9 KiB
Java
290 lines
9.9 KiB
Java
package org.bouncycastle.crypto.modes;
|
|
|
|
import org.bouncycastle.crypto.BlockCipher;
|
|
import org.bouncycastle.crypto.CipherParameters;
|
|
import org.bouncycastle.crypto.DataLengthException;
|
|
import org.bouncycastle.crypto.InvalidCipherTextException;
|
|
import org.bouncycastle.crypto.Mac;
|
|
import org.bouncycastle.crypto.OutputLengthException;
|
|
import org.bouncycastle.crypto.macs.CMac;
|
|
import org.bouncycastle.crypto.params.AEADParameters;
|
|
import org.bouncycastle.crypto.params.ParametersWithIV;
|
|
import org.bouncycastle.util.Arrays;
|
|
|
|
/* loaded from: classes6.dex */
|
|
public class EAXBlockCipher implements AEADBlockCipher {
|
|
private static final byte cTAG = 2;
|
|
private static final byte hTAG = 1;
|
|
private static final byte nTAG = 0;
|
|
private byte[] associatedTextMac;
|
|
private int blockSize;
|
|
private byte[] bufBlock;
|
|
private int bufOff;
|
|
private SICBlockCipher cipher;
|
|
private boolean cipherInitialized;
|
|
private boolean forEncryption;
|
|
private byte[] initialAssociatedText;
|
|
private Mac mac;
|
|
private byte[] macBlock;
|
|
private int macSize;
|
|
private byte[] nonceMac;
|
|
|
|
@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 {
|
|
initCipher();
|
|
if (bArr.length < i + i2) {
|
|
throw new DataLengthException("Input buffer too short");
|
|
}
|
|
int i4 = 0;
|
|
for (int i5 = 0; i5 != i2; i5++) {
|
|
i4 += process(bArr[i + i5], bArr2, i3 + i4);
|
|
}
|
|
return i4;
|
|
}
|
|
|
|
@Override // org.bouncycastle.crypto.modes.AEADBlockCipher
|
|
public int processByte(byte b, byte[] bArr, int i) throws DataLengthException {
|
|
initCipher();
|
|
return process(b, bArr, i);
|
|
}
|
|
|
|
@Override // org.bouncycastle.crypto.modes.AEADBlockCipher
|
|
public void processAADBytes(byte[] bArr, int i, int i2) {
|
|
if (this.cipherInitialized) {
|
|
throw new IllegalStateException("AAD data cannot be added after encryption/decryption processing has begun.");
|
|
}
|
|
this.mac.update(bArr, i, i2);
|
|
}
|
|
|
|
@Override // org.bouncycastle.crypto.modes.AEADBlockCipher
|
|
public void processAADByte(byte b) {
|
|
if (this.cipherInitialized) {
|
|
throw new IllegalStateException("AAD data cannot be added after encryption/decryption processing has begun.");
|
|
}
|
|
this.mac.update(b);
|
|
}
|
|
|
|
@Override // org.bouncycastle.crypto.modes.AEADBlockCipher
|
|
public void init(boolean z, CipherParameters cipherParameters) throws IllegalArgumentException {
|
|
byte[] iv;
|
|
CipherParameters parameters;
|
|
this.forEncryption = z;
|
|
if (cipherParameters instanceof AEADParameters) {
|
|
AEADParameters aEADParameters = (AEADParameters) cipherParameters;
|
|
iv = aEADParameters.getNonce();
|
|
this.initialAssociatedText = aEADParameters.getAssociatedText();
|
|
this.macSize = aEADParameters.getMacSize() / 8;
|
|
parameters = aEADParameters.getKey();
|
|
} else {
|
|
if (!(cipherParameters instanceof ParametersWithIV)) {
|
|
throw new IllegalArgumentException("invalid parameters passed to EAX");
|
|
}
|
|
ParametersWithIV parametersWithIV = (ParametersWithIV) cipherParameters;
|
|
iv = parametersWithIV.getIV();
|
|
this.initialAssociatedText = null;
|
|
this.macSize = this.mac.getMacSize() / 2;
|
|
parameters = parametersWithIV.getParameters();
|
|
}
|
|
this.bufBlock = new byte[z ? this.blockSize : this.blockSize + this.macSize];
|
|
byte[] bArr = new byte[this.blockSize];
|
|
this.mac.init(parameters);
|
|
int i = this.blockSize;
|
|
bArr[i - 1] = 0;
|
|
this.mac.update(bArr, 0, i);
|
|
this.mac.update(iv, 0, iv.length);
|
|
this.mac.doFinal(this.nonceMac, 0);
|
|
this.cipher.init(true, new ParametersWithIV(null, this.nonceMac));
|
|
reset();
|
|
}
|
|
|
|
@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 % this.blockSize);
|
|
}
|
|
|
|
@Override // org.bouncycastle.crypto.modes.AEADBlockCipher
|
|
public BlockCipher getUnderlyingCipher() {
|
|
return this.cipher.getUnderlyingCipher();
|
|
}
|
|
|
|
@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() {
|
|
int i = this.macSize;
|
|
byte[] bArr = new byte[i];
|
|
System.arraycopy(this.macBlock, 0, bArr, 0, i);
|
|
return bArr;
|
|
}
|
|
|
|
public int getBlockSize() {
|
|
return this.cipher.getBlockSize();
|
|
}
|
|
|
|
@Override // org.bouncycastle.crypto.modes.AEADBlockCipher
|
|
public String getAlgorithmName() {
|
|
StringBuilder sb = new StringBuilder();
|
|
sb.append(this.cipher.getUnderlyingCipher().getAlgorithmName());
|
|
sb.append("/EAX");
|
|
return sb.toString();
|
|
}
|
|
|
|
@Override // org.bouncycastle.crypto.modes.AEADBlockCipher
|
|
public int doFinal(byte[] bArr, int i) throws IllegalStateException, InvalidCipherTextException {
|
|
initCipher();
|
|
int i2 = this.bufOff;
|
|
byte[] bArr2 = this.bufBlock;
|
|
byte[] bArr3 = new byte[bArr2.length];
|
|
this.bufOff = 0;
|
|
if (this.forEncryption) {
|
|
int i3 = i + i2;
|
|
if (bArr.length < this.macSize + i3) {
|
|
throw new OutputLengthException("Output buffer too short");
|
|
}
|
|
this.cipher.processBlock(bArr2, 0, bArr3, 0);
|
|
System.arraycopy(bArr3, 0, bArr, i, i2);
|
|
this.mac.update(bArr3, 0, i2);
|
|
calculateMac();
|
|
System.arraycopy(this.macBlock, 0, bArr, i3, this.macSize);
|
|
reset(false);
|
|
return i2 + this.macSize;
|
|
}
|
|
int i4 = this.macSize;
|
|
if (i2 < i4) {
|
|
throw new InvalidCipherTextException("data too short");
|
|
}
|
|
if (bArr.length < (i + i2) - i4) {
|
|
throw new OutputLengthException("Output buffer too short");
|
|
}
|
|
if (i2 > i4) {
|
|
this.mac.update(bArr2, 0, i2 - i4);
|
|
this.cipher.processBlock(this.bufBlock, 0, bArr3, 0);
|
|
System.arraycopy(bArr3, 0, bArr, i, i2 - this.macSize);
|
|
}
|
|
calculateMac();
|
|
if (!verifyMac(this.bufBlock, i2 - this.macSize)) {
|
|
throw new InvalidCipherTextException("mac check in EAX failed");
|
|
}
|
|
reset(false);
|
|
return i2 - this.macSize;
|
|
}
|
|
|
|
private boolean verifyMac(byte[] bArr, int i) {
|
|
int i2 = 0;
|
|
for (int i3 = 0; i3 < this.macSize; i3++) {
|
|
i2 |= this.macBlock[i3] ^ bArr[i + i3];
|
|
}
|
|
return i2 == 0;
|
|
}
|
|
|
|
private void reset(boolean z) {
|
|
this.cipher.reset();
|
|
this.mac.reset();
|
|
this.bufOff = 0;
|
|
Arrays.fill(this.bufBlock, (byte) 0);
|
|
if (z) {
|
|
Arrays.fill(this.macBlock, (byte) 0);
|
|
}
|
|
int i = this.blockSize;
|
|
byte[] bArr = new byte[i];
|
|
bArr[i - 1] = 1;
|
|
this.mac.update(bArr, 0, i);
|
|
this.cipherInitialized = false;
|
|
byte[] bArr2 = this.initialAssociatedText;
|
|
if (bArr2 != null) {
|
|
processAADBytes(bArr2, 0, bArr2.length);
|
|
}
|
|
}
|
|
|
|
private int process(byte b, byte[] bArr, int i) {
|
|
int processBlock;
|
|
byte[] bArr2 = this.bufBlock;
|
|
int i2 = this.bufOff;
|
|
int i3 = i2 + 1;
|
|
this.bufOff = i3;
|
|
bArr2[i2] = b;
|
|
if (i3 != bArr2.length) {
|
|
return 0;
|
|
}
|
|
int length = bArr.length;
|
|
int i4 = this.blockSize;
|
|
if (length < i + i4) {
|
|
throw new OutputLengthException("Output buffer is too short");
|
|
}
|
|
if (this.forEncryption) {
|
|
processBlock = this.cipher.processBlock(bArr2, 0, bArr, i);
|
|
this.mac.update(bArr, i, this.blockSize);
|
|
} else {
|
|
this.mac.update(bArr2, 0, i4);
|
|
processBlock = this.cipher.processBlock(this.bufBlock, 0, bArr, i);
|
|
}
|
|
this.bufOff = 0;
|
|
if (!this.forEncryption) {
|
|
byte[] bArr3 = this.bufBlock;
|
|
System.arraycopy(bArr3, this.blockSize, bArr3, 0, this.macSize);
|
|
this.bufOff = this.macSize;
|
|
}
|
|
return processBlock;
|
|
}
|
|
|
|
private void initCipher() {
|
|
if (this.cipherInitialized) {
|
|
return;
|
|
}
|
|
this.cipherInitialized = true;
|
|
this.mac.doFinal(this.associatedTextMac, 0);
|
|
int i = this.blockSize;
|
|
byte[] bArr = new byte[i];
|
|
bArr[i - 1] = 2;
|
|
this.mac.update(bArr, 0, i);
|
|
}
|
|
|
|
private void calculateMac() {
|
|
byte[] bArr = new byte[this.blockSize];
|
|
int i = 0;
|
|
this.mac.doFinal(bArr, 0);
|
|
while (true) {
|
|
byte[] bArr2 = this.macBlock;
|
|
if (i >= bArr2.length) {
|
|
return;
|
|
}
|
|
bArr2[i] = (byte) ((this.nonceMac[i] ^ this.associatedTextMac[i]) ^ bArr[i]);
|
|
i++;
|
|
}
|
|
}
|
|
|
|
public EAXBlockCipher(BlockCipher blockCipher) {
|
|
this.blockSize = blockCipher.getBlockSize();
|
|
CMac cMac = new CMac(blockCipher);
|
|
this.mac = cMac;
|
|
this.macBlock = new byte[this.blockSize];
|
|
this.associatedTextMac = new byte[cMac.getMacSize()];
|
|
this.nonceMac = new byte[this.mac.getMacSize()];
|
|
this.cipher = new SICBlockCipher(blockCipher);
|
|
}
|
|
}
|