372 lines
14 KiB
Java
372 lines
14 KiB
Java
package org.bouncycastle.crypto.signers;
|
|
|
|
import com.google.common.primitives.UnsignedBytes;
|
|
import net.sf.scuba.smartcards.ISO7816;
|
|
import org.bouncycastle.crypto.AsymmetricBlockCipher;
|
|
import org.bouncycastle.crypto.CipherParameters;
|
|
import org.bouncycastle.crypto.CryptoException;
|
|
import org.bouncycastle.crypto.Digest;
|
|
import org.bouncycastle.crypto.InvalidCipherTextException;
|
|
import org.bouncycastle.crypto.SignerWithRecovery;
|
|
import org.bouncycastle.crypto.params.RSAKeyParameters;
|
|
import org.bouncycastle.util.Arrays;
|
|
|
|
/* loaded from: classes6.dex */
|
|
public class ISO9796d2Signer implements SignerWithRecovery {
|
|
public static final int TRAILER_IMPLICIT = 188;
|
|
public static final int TRAILER_RIPEMD128 = 13004;
|
|
public static final int TRAILER_RIPEMD160 = 12748;
|
|
public static final int TRAILER_SHA1 = 13260;
|
|
public static final int TRAILER_SHA256 = 13516;
|
|
public static final int TRAILER_SHA384 = 14028;
|
|
public static final int TRAILER_SHA512 = 13772;
|
|
public static final int TRAILER_WHIRLPOOL = 14284;
|
|
private byte[] block;
|
|
private AsymmetricBlockCipher cipher;
|
|
private Digest digest;
|
|
private boolean fullMessage;
|
|
private int keyBits;
|
|
private byte[] mBuf;
|
|
private int messageLength;
|
|
private byte[] preBlock;
|
|
private byte[] preSig;
|
|
private byte[] recoveredMessage;
|
|
private int trailer;
|
|
|
|
@Override // org.bouncycastle.crypto.Signer
|
|
public boolean verifySignature(byte[] bArr) {
|
|
byte[] processBlock;
|
|
int i;
|
|
byte[] bArr2 = this.preSig;
|
|
if (bArr2 == null) {
|
|
try {
|
|
processBlock = this.cipher.processBlock(bArr, 0, bArr.length);
|
|
} catch (Exception unused) {
|
|
return false;
|
|
}
|
|
} else {
|
|
if (!Arrays.areEqual(bArr2, bArr)) {
|
|
throw new IllegalStateException("updateWithRecoveredMessage called on different signature");
|
|
}
|
|
processBlock = this.preBlock;
|
|
this.preSig = null;
|
|
this.preBlock = null;
|
|
}
|
|
if (((processBlock[0] & ISO7816.INS_GET_RESPONSE) ^ 64) == 0 && ((processBlock[processBlock.length - 1] & 15) ^ 12) == 0) {
|
|
if (((processBlock[processBlock.length - 1] & UnsignedBytes.MAX_VALUE) ^ 188) == 0) {
|
|
i = 1;
|
|
} else {
|
|
i = 2;
|
|
int i2 = ((processBlock[processBlock.length - 2] & UnsignedBytes.MAX_VALUE) << 8) | (processBlock[processBlock.length - 1] & UnsignedBytes.MAX_VALUE);
|
|
Integer trailer = ISOTrailers.getTrailer(this.digest);
|
|
if (trailer == null) {
|
|
throw new IllegalArgumentException("unrecognised hash in signature");
|
|
}
|
|
if (i2 != trailer.intValue()) {
|
|
throw new IllegalStateException("signer initialised with wrong digest for trailer ".concat(String.valueOf(i2)));
|
|
}
|
|
}
|
|
int i3 = 0;
|
|
while (i3 != processBlock.length && ((processBlock[i3] & 15) ^ 10) != 0) {
|
|
i3++;
|
|
}
|
|
int i4 = i3 + 1;
|
|
int digestSize = this.digest.getDigestSize();
|
|
byte[] bArr3 = new byte[digestSize];
|
|
int length = (processBlock.length - i) - digestSize;
|
|
int i5 = length - i4;
|
|
if (i5 <= 0) {
|
|
return returnFalse(processBlock);
|
|
}
|
|
if ((processBlock[0] & 32) == 0) {
|
|
this.fullMessage = true;
|
|
if (this.messageLength > i5) {
|
|
return returnFalse(processBlock);
|
|
}
|
|
this.digest.reset();
|
|
this.digest.update(processBlock, i4, i5);
|
|
this.digest.doFinal(bArr3, 0);
|
|
boolean z = true;
|
|
for (int i6 = 0; i6 != digestSize; i6++) {
|
|
int i7 = length + i6;
|
|
byte b = (byte) (processBlock[i7] ^ bArr3[i6]);
|
|
processBlock[i7] = b;
|
|
if (b != 0) {
|
|
z = false;
|
|
}
|
|
}
|
|
if (!z) {
|
|
return returnFalse(processBlock);
|
|
}
|
|
byte[] bArr4 = new byte[i5];
|
|
this.recoveredMessage = bArr4;
|
|
System.arraycopy(processBlock, i4, bArr4, 0, i5);
|
|
} else {
|
|
this.fullMessage = false;
|
|
this.digest.doFinal(bArr3, 0);
|
|
boolean z2 = true;
|
|
for (int i8 = 0; i8 != digestSize; i8++) {
|
|
int i9 = length + i8;
|
|
byte b2 = (byte) (processBlock[i9] ^ bArr3[i8]);
|
|
processBlock[i9] = b2;
|
|
if (b2 != 0) {
|
|
z2 = false;
|
|
}
|
|
}
|
|
if (!z2) {
|
|
return returnFalse(processBlock);
|
|
}
|
|
byte[] bArr5 = new byte[i5];
|
|
this.recoveredMessage = bArr5;
|
|
System.arraycopy(processBlock, i4, bArr5, 0, i5);
|
|
}
|
|
if (this.messageLength != 0 && !isSameAs(this.mBuf, this.recoveredMessage)) {
|
|
return returnFalse(processBlock);
|
|
}
|
|
clearBlock(this.mBuf);
|
|
clearBlock(processBlock);
|
|
return true;
|
|
}
|
|
return returnFalse(processBlock);
|
|
}
|
|
|
|
@Override // org.bouncycastle.crypto.SignerWithRecovery
|
|
public void updateWithRecoveredMessage(byte[] bArr) throws InvalidCipherTextException {
|
|
int i;
|
|
byte[] processBlock = this.cipher.processBlock(bArr, 0, bArr.length);
|
|
if (((processBlock[0] & ISO7816.INS_GET_RESPONSE) ^ 64) != 0) {
|
|
throw new InvalidCipherTextException("malformed signature");
|
|
}
|
|
if (((processBlock[processBlock.length - 1] & 15) ^ 12) != 0) {
|
|
throw new InvalidCipherTextException("malformed signature");
|
|
}
|
|
if (((processBlock[processBlock.length - 1] & UnsignedBytes.MAX_VALUE) ^ 188) == 0) {
|
|
i = 1;
|
|
} else {
|
|
i = 2;
|
|
int i2 = ((processBlock[processBlock.length - 2] & UnsignedBytes.MAX_VALUE) << 8) | (processBlock[processBlock.length - 1] & UnsignedBytes.MAX_VALUE);
|
|
Integer trailer = ISOTrailers.getTrailer(this.digest);
|
|
if (trailer == null) {
|
|
throw new IllegalArgumentException("unrecognised hash in signature");
|
|
}
|
|
if (i2 != trailer.intValue()) {
|
|
throw new IllegalStateException("signer initialised with wrong digest for trailer ".concat(String.valueOf(i2)));
|
|
}
|
|
}
|
|
int i3 = 0;
|
|
while (i3 != processBlock.length && ((processBlock[i3] & 15) ^ 10) != 0) {
|
|
i3++;
|
|
}
|
|
int i4 = i3 + 1;
|
|
int length = ((processBlock.length - i) - this.digest.getDigestSize()) - i4;
|
|
if (length <= 0) {
|
|
throw new InvalidCipherTextException("malformed block");
|
|
}
|
|
if ((processBlock[0] & 32) == 0) {
|
|
this.fullMessage = true;
|
|
byte[] bArr2 = new byte[length];
|
|
this.recoveredMessage = bArr2;
|
|
System.arraycopy(processBlock, i4, bArr2, 0, length);
|
|
} else {
|
|
this.fullMessage = false;
|
|
byte[] bArr3 = new byte[length];
|
|
this.recoveredMessage = bArr3;
|
|
System.arraycopy(processBlock, i4, bArr3, 0, length);
|
|
}
|
|
this.preSig = bArr;
|
|
this.preBlock = processBlock;
|
|
Digest digest = this.digest;
|
|
byte[] bArr4 = this.recoveredMessage;
|
|
digest.update(bArr4, 0, bArr4.length);
|
|
byte[] bArr5 = this.recoveredMessage;
|
|
this.messageLength = bArr5.length;
|
|
System.arraycopy(bArr5, 0, this.mBuf, 0, bArr5.length);
|
|
}
|
|
|
|
@Override // org.bouncycastle.crypto.Signer
|
|
public void update(byte[] bArr, int i, int i2) {
|
|
while (i2 > 0 && this.messageLength < this.mBuf.length) {
|
|
update(bArr[i]);
|
|
i++;
|
|
i2--;
|
|
}
|
|
this.digest.update(bArr, i, i2);
|
|
this.messageLength += i2;
|
|
}
|
|
|
|
@Override // org.bouncycastle.crypto.Signer
|
|
public void update(byte b) {
|
|
this.digest.update(b);
|
|
int i = this.messageLength;
|
|
byte[] bArr = this.mBuf;
|
|
if (i < bArr.length) {
|
|
bArr[i] = b;
|
|
}
|
|
this.messageLength = i + 1;
|
|
}
|
|
|
|
@Override // org.bouncycastle.crypto.Signer
|
|
public void reset() {
|
|
this.digest.reset();
|
|
this.messageLength = 0;
|
|
clearBlock(this.mBuf);
|
|
byte[] bArr = this.recoveredMessage;
|
|
if (bArr != null) {
|
|
clearBlock(bArr);
|
|
}
|
|
this.recoveredMessage = null;
|
|
this.fullMessage = false;
|
|
if (this.preSig != null) {
|
|
this.preSig = null;
|
|
clearBlock(this.preBlock);
|
|
this.preBlock = null;
|
|
}
|
|
}
|
|
|
|
@Override // org.bouncycastle.crypto.Signer
|
|
public void init(boolean z, CipherParameters cipherParameters) {
|
|
RSAKeyParameters rSAKeyParameters = (RSAKeyParameters) cipherParameters;
|
|
this.cipher.init(z, rSAKeyParameters);
|
|
int bitLength = rSAKeyParameters.getModulus().bitLength();
|
|
this.keyBits = bitLength;
|
|
this.block = new byte[(bitLength + 7) / 8];
|
|
if (this.trailer == 188) {
|
|
this.mBuf = new byte[(r2 - this.digest.getDigestSize()) - 2];
|
|
} else {
|
|
this.mBuf = new byte[(r2 - this.digest.getDigestSize()) - 3];
|
|
}
|
|
reset();
|
|
}
|
|
|
|
@Override // org.bouncycastle.crypto.SignerWithRecovery
|
|
public boolean hasFullMessage() {
|
|
return this.fullMessage;
|
|
}
|
|
|
|
@Override // org.bouncycastle.crypto.SignerWithRecovery
|
|
public byte[] getRecoveredMessage() {
|
|
return this.recoveredMessage;
|
|
}
|
|
|
|
@Override // org.bouncycastle.crypto.Signer
|
|
public byte[] generateSignature() throws CryptoException {
|
|
int length;
|
|
int i;
|
|
int i2;
|
|
int i3;
|
|
int digestSize = this.digest.getDigestSize();
|
|
if (this.trailer == 188) {
|
|
byte[] bArr = this.block;
|
|
length = (bArr.length - digestSize) - 1;
|
|
this.digest.doFinal(bArr, length);
|
|
byte[] bArr2 = this.block;
|
|
bArr2[bArr2.length - 1] = PSSSigner.TRAILER_IMPLICIT;
|
|
i = 8;
|
|
} else {
|
|
byte[] bArr3 = this.block;
|
|
length = (bArr3.length - digestSize) - 2;
|
|
this.digest.doFinal(bArr3, length);
|
|
byte[] bArr4 = this.block;
|
|
int length2 = bArr4.length;
|
|
int i4 = this.trailer;
|
|
bArr4[length2 - 2] = (byte) (i4 >>> 8);
|
|
bArr4[bArr4.length - 1] = (byte) i4;
|
|
i = 16;
|
|
}
|
|
int i5 = this.messageLength;
|
|
int i6 = ((((digestSize + i5) << 3) + i) + 4) - this.keyBits;
|
|
if (i6 > 0) {
|
|
int i7 = i5 - ((i6 + 7) / 8);
|
|
i2 = length - i7;
|
|
System.arraycopy(this.mBuf, 0, this.block, i2, i7);
|
|
this.recoveredMessage = new byte[i7];
|
|
i3 = 96;
|
|
} else {
|
|
i2 = length - i5;
|
|
System.arraycopy(this.mBuf, 0, this.block, i2, i5);
|
|
this.recoveredMessage = new byte[this.messageLength];
|
|
i3 = 64;
|
|
}
|
|
int i8 = i2 - 1;
|
|
if (i8 > 0) {
|
|
for (int i9 = i8; i9 != 0; i9--) {
|
|
this.block[i9] = -69;
|
|
}
|
|
byte[] bArr5 = this.block;
|
|
bArr5[i8] = (byte) (bArr5[i8] ^ 1);
|
|
bArr5[0] = 11;
|
|
bArr5[0] = (byte) (i3 | 11);
|
|
} else {
|
|
byte[] bArr6 = this.block;
|
|
bArr6[0] = 10;
|
|
bArr6[0] = (byte) (i3 | 10);
|
|
}
|
|
AsymmetricBlockCipher asymmetricBlockCipher = this.cipher;
|
|
byte[] bArr7 = this.block;
|
|
byte[] processBlock = asymmetricBlockCipher.processBlock(bArr7, 0, bArr7.length);
|
|
this.fullMessage = (i3 & 32) == 0;
|
|
byte[] bArr8 = this.mBuf;
|
|
byte[] bArr9 = this.recoveredMessage;
|
|
System.arraycopy(bArr8, 0, bArr9, 0, bArr9.length);
|
|
clearBlock(this.mBuf);
|
|
clearBlock(this.block);
|
|
return processBlock;
|
|
}
|
|
|
|
private boolean returnFalse(byte[] bArr) {
|
|
clearBlock(this.mBuf);
|
|
clearBlock(bArr);
|
|
return false;
|
|
}
|
|
|
|
private boolean isSameAs(byte[] bArr, byte[] bArr2) {
|
|
boolean z;
|
|
int i = this.messageLength;
|
|
byte[] bArr3 = this.mBuf;
|
|
if (i > bArr3.length) {
|
|
z = bArr3.length <= bArr2.length;
|
|
for (int i2 = 0; i2 != this.mBuf.length; i2++) {
|
|
if (bArr[i2] != bArr2[i2]) {
|
|
z = false;
|
|
}
|
|
}
|
|
} else {
|
|
z = i == bArr2.length;
|
|
for (int i3 = 0; i3 != bArr2.length; i3++) {
|
|
if (bArr[i3] != bArr2[i3]) {
|
|
z = false;
|
|
}
|
|
}
|
|
}
|
|
return z;
|
|
}
|
|
|
|
private void clearBlock(byte[] bArr) {
|
|
for (int i = 0; i != bArr.length; i++) {
|
|
bArr[i] = 0;
|
|
}
|
|
}
|
|
|
|
public ISO9796d2Signer(AsymmetricBlockCipher asymmetricBlockCipher, Digest digest, boolean z) {
|
|
int intValue;
|
|
this.cipher = asymmetricBlockCipher;
|
|
this.digest = digest;
|
|
if (z) {
|
|
intValue = 188;
|
|
} else {
|
|
Integer trailer = ISOTrailers.getTrailer(digest);
|
|
if (trailer == null) {
|
|
StringBuilder sb = new StringBuilder("no valid trailer for digest: ");
|
|
sb.append(digest.getAlgorithmName());
|
|
throw new IllegalArgumentException(sb.toString());
|
|
}
|
|
intValue = trailer.intValue();
|
|
}
|
|
this.trailer = intValue;
|
|
}
|
|
|
|
public ISO9796d2Signer(AsymmetricBlockCipher asymmetricBlockCipher, Digest digest) {
|
|
this(asymmetricBlockCipher, digest, false);
|
|
}
|
|
}
|