253 lines
8.0 KiB
Java
253 lines
8.0 KiB
Java
|
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.SkippingStreamCipher;
|
||
|
import org.bouncycastle.crypto.StreamBlockCipher;
|
||
|
import org.bouncycastle.crypto.params.ParametersWithIV;
|
||
|
import org.bouncycastle.util.Arrays;
|
||
|
import org.bouncycastle.util.Pack;
|
||
|
|
||
|
/* loaded from: classes6.dex */
|
||
|
public class SICBlockCipher extends StreamBlockCipher implements SkippingStreamCipher {
|
||
|
private byte[] IV;
|
||
|
private final int blockSize;
|
||
|
private int byteCount;
|
||
|
private final BlockCipher cipher;
|
||
|
private byte[] counter;
|
||
|
private byte[] counterOut;
|
||
|
|
||
|
@Override // org.bouncycastle.crypto.SkippingCipher
|
||
|
public long skip(long j) {
|
||
|
adjustCounter(j);
|
||
|
checkCounter();
|
||
|
this.cipher.processBlock(this.counter, 0, this.counterOut, 0);
|
||
|
return j;
|
||
|
}
|
||
|
|
||
|
@Override // org.bouncycastle.crypto.SkippingCipher
|
||
|
public long seekTo(long j) {
|
||
|
reset();
|
||
|
return skip(j);
|
||
|
}
|
||
|
|
||
|
@Override // org.bouncycastle.crypto.BlockCipher
|
||
|
public void reset() {
|
||
|
Arrays.fill(this.counter, (byte) 0);
|
||
|
byte[] bArr = this.IV;
|
||
|
System.arraycopy(bArr, 0, this.counter, 0, bArr.length);
|
||
|
this.cipher.reset();
|
||
|
this.byteCount = 0;
|
||
|
}
|
||
|
|
||
|
@Override // org.bouncycastle.crypto.BlockCipher
|
||
|
public int processBlock(byte[] bArr, int i, byte[] bArr2, int i2) throws DataLengthException, IllegalStateException {
|
||
|
processBytes(bArr, i, this.blockSize, bArr2, i2);
|
||
|
return this.blockSize;
|
||
|
}
|
||
|
|
||
|
@Override // org.bouncycastle.crypto.BlockCipher
|
||
|
public void init(boolean z, CipherParameters cipherParameters) throws IllegalArgumentException {
|
||
|
if (!(cipherParameters instanceof ParametersWithIV)) {
|
||
|
throw new IllegalArgumentException("CTR/SIC mode requires ParametersWithIV");
|
||
|
}
|
||
|
ParametersWithIV parametersWithIV = (ParametersWithIV) cipherParameters;
|
||
|
byte[] clone = Arrays.clone(parametersWithIV.getIV());
|
||
|
this.IV = clone;
|
||
|
int i = this.blockSize;
|
||
|
if (i < clone.length) {
|
||
|
StringBuilder sb = new StringBuilder("CTR/SIC mode requires IV no greater than: ");
|
||
|
sb.append(this.blockSize);
|
||
|
sb.append(" bytes.");
|
||
|
throw new IllegalArgumentException(sb.toString());
|
||
|
}
|
||
|
int i2 = i / 2;
|
||
|
if (8 <= i2) {
|
||
|
i2 = 8;
|
||
|
}
|
||
|
if (i - clone.length <= i2) {
|
||
|
if (parametersWithIV.getParameters() != null) {
|
||
|
this.cipher.init(true, parametersWithIV.getParameters());
|
||
|
}
|
||
|
reset();
|
||
|
} else {
|
||
|
StringBuilder sb2 = new StringBuilder("CTR/SIC mode requires IV of at least: ");
|
||
|
sb2.append(this.blockSize - i2);
|
||
|
sb2.append(" bytes.");
|
||
|
throw new IllegalArgumentException(sb2.toString());
|
||
|
}
|
||
|
}
|
||
|
|
||
|
@Override // org.bouncycastle.crypto.SkippingCipher
|
||
|
public long getPosition() {
|
||
|
byte[] bArr = this.counter;
|
||
|
int length = bArr.length;
|
||
|
byte[] bArr2 = new byte[length];
|
||
|
System.arraycopy(bArr, 0, bArr2, 0, length);
|
||
|
int i = length - 1;
|
||
|
while (i > 0) {
|
||
|
byte[] bArr3 = this.IV;
|
||
|
int i2 = i < bArr3.length ? (bArr2[i] & UnsignedBytes.MAX_VALUE) - (bArr3[i] & UnsignedBytes.MAX_VALUE) : bArr2[i] & UnsignedBytes.MAX_VALUE;
|
||
|
if (i2 < 0) {
|
||
|
bArr2[i - 1] = (byte) (bArr2[r3] - 1);
|
||
|
i2 += 256;
|
||
|
}
|
||
|
bArr2[i] = (byte) i2;
|
||
|
i--;
|
||
|
}
|
||
|
return (Pack.bigEndianToLong(bArr2, length - 8) * this.blockSize) + this.byteCount;
|
||
|
}
|
||
|
|
||
|
@Override // org.bouncycastle.crypto.BlockCipher
|
||
|
public int getBlockSize() {
|
||
|
return this.cipher.getBlockSize();
|
||
|
}
|
||
|
|
||
|
@Override // org.bouncycastle.crypto.BlockCipher
|
||
|
public String getAlgorithmName() {
|
||
|
StringBuilder sb = new StringBuilder();
|
||
|
sb.append(this.cipher.getAlgorithmName());
|
||
|
sb.append("/SIC");
|
||
|
return sb.toString();
|
||
|
}
|
||
|
|
||
|
@Override // org.bouncycastle.crypto.StreamBlockCipher
|
||
|
public byte calculateByte(byte b) throws DataLengthException, IllegalStateException {
|
||
|
int i = this.byteCount;
|
||
|
if (i == 0) {
|
||
|
this.cipher.processBlock(this.counter, 0, this.counterOut, 0);
|
||
|
byte[] bArr = this.counterOut;
|
||
|
int i2 = this.byteCount;
|
||
|
this.byteCount = i2 + 1;
|
||
|
return (byte) (b ^ bArr[i2]);
|
||
|
}
|
||
|
byte[] bArr2 = this.counterOut;
|
||
|
int i3 = i + 1;
|
||
|
this.byteCount = i3;
|
||
|
byte b2 = (byte) (b ^ bArr2[i]);
|
||
|
if (i3 == this.counter.length) {
|
||
|
this.byteCount = 0;
|
||
|
incrementCounterAt(0);
|
||
|
checkCounter();
|
||
|
}
|
||
|
return b2;
|
||
|
}
|
||
|
|
||
|
private void incrementCounterAt(int i) {
|
||
|
byte b;
|
||
|
int length = this.counter.length - i;
|
||
|
do {
|
||
|
length--;
|
||
|
if (length < 0) {
|
||
|
return;
|
||
|
}
|
||
|
byte[] bArr = this.counter;
|
||
|
b = (byte) (bArr[length] + 1);
|
||
|
bArr[length] = b;
|
||
|
} while (b == 0);
|
||
|
}
|
||
|
|
||
|
private void incrementCounter(int i) {
|
||
|
byte[] bArr = this.counter;
|
||
|
byte b = bArr[bArr.length - 1];
|
||
|
int length = bArr.length - 1;
|
||
|
bArr[length] = (byte) (bArr[length] + i);
|
||
|
if (b == 0 || bArr[bArr.length - 1] >= b) {
|
||
|
return;
|
||
|
}
|
||
|
incrementCounterAt(1);
|
||
|
}
|
||
|
|
||
|
private void decrementCounterAt(int i) {
|
||
|
byte b;
|
||
|
int length = this.counter.length - i;
|
||
|
do {
|
||
|
length--;
|
||
|
if (length < 0) {
|
||
|
return;
|
||
|
}
|
||
|
b = (byte) (r1[length] - 1);
|
||
|
this.counter[length] = b;
|
||
|
} while (b == -1);
|
||
|
}
|
||
|
|
||
|
private void checkCounter() {
|
||
|
if (this.IV.length >= this.blockSize) {
|
||
|
return;
|
||
|
}
|
||
|
int i = 0;
|
||
|
while (true) {
|
||
|
byte[] bArr = this.IV;
|
||
|
if (i == bArr.length) {
|
||
|
return;
|
||
|
}
|
||
|
if (this.counter[i] != bArr[i]) {
|
||
|
throw new IllegalStateException("Counter in CTR/SIC mode out of range.");
|
||
|
}
|
||
|
i++;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
private void adjustCounter(long j) {
|
||
|
long j2;
|
||
|
long j3;
|
||
|
int i = 5;
|
||
|
if (j >= 0) {
|
||
|
long j4 = (this.byteCount + j) / this.blockSize;
|
||
|
if (j4 > 255) {
|
||
|
j3 = j4;
|
||
|
while (i > 0) {
|
||
|
long j5 = 1 << (i << 3);
|
||
|
while (j3 >= j5) {
|
||
|
incrementCounterAt(i);
|
||
|
j3 -= j5;
|
||
|
}
|
||
|
i--;
|
||
|
}
|
||
|
} else {
|
||
|
j3 = j4;
|
||
|
}
|
||
|
incrementCounter((int) j3);
|
||
|
this.byteCount = (int) ((j + this.byteCount) - (this.blockSize * j4));
|
||
|
return;
|
||
|
}
|
||
|
long j6 = ((-j) - this.byteCount) / this.blockSize;
|
||
|
if (j6 > 255) {
|
||
|
j2 = j6;
|
||
|
while (i > 0) {
|
||
|
long j7 = 1 << (i << 3);
|
||
|
while (j2 > j7) {
|
||
|
decrementCounterAt(i);
|
||
|
j2 -= j7;
|
||
|
}
|
||
|
i--;
|
||
|
}
|
||
|
} else {
|
||
|
j2 = j6;
|
||
|
}
|
||
|
for (long j8 = 0; j8 != j2; j8++) {
|
||
|
decrementCounterAt(0);
|
||
|
}
|
||
|
int i2 = (int) (this.byteCount + j + (this.blockSize * j6));
|
||
|
if (i2 >= 0) {
|
||
|
this.byteCount = 0;
|
||
|
} else {
|
||
|
decrementCounterAt(0);
|
||
|
this.byteCount = this.blockSize + i2;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
public SICBlockCipher(BlockCipher blockCipher) {
|
||
|
super(blockCipher);
|
||
|
this.cipher = blockCipher;
|
||
|
int blockSize = blockCipher.getBlockSize();
|
||
|
this.blockSize = blockSize;
|
||
|
this.IV = new byte[blockSize];
|
||
|
this.counter = new byte[blockSize];
|
||
|
this.counterOut = new byte[blockSize];
|
||
|
this.byteCount = 0;
|
||
|
}
|
||
|
}
|