148 lines
7.7 KiB
Java
148 lines
7.7 KiB
Java
|
package org.jmrtd.protocol;
|
||
|
|
||
|
import java.math.BigInteger;
|
||
|
import java.security.GeneralSecurityException;
|
||
|
import java.security.InvalidKeyException;
|
||
|
import java.security.KeyPair;
|
||
|
import java.security.KeyPairGenerator;
|
||
|
import java.security.MessageDigest;
|
||
|
import java.security.NoSuchAlgorithmException;
|
||
|
import java.security.PrivateKey;
|
||
|
import java.security.PublicKey;
|
||
|
import java.security.interfaces.ECPublicKey;
|
||
|
import java.security.spec.AlgorithmParameterSpec;
|
||
|
import java.util.logging.Logger;
|
||
|
import javax.crypto.KeyAgreement;
|
||
|
import javax.crypto.SecretKey;
|
||
|
import javax.crypto.interfaces.DHPublicKey;
|
||
|
import net.sf.scuba.smartcards.CardServiceException;
|
||
|
import org.bouncycastle.pqc.jcajce.spec.McElieceCCA2KeyGenParameterSpec;
|
||
|
import org.jmrtd.PassportService;
|
||
|
import org.jmrtd.Util;
|
||
|
import org.jmrtd.lds.ChipAuthenticationInfo;
|
||
|
import org.jmrtd.lds.ChipAuthenticationPublicKeyInfo;
|
||
|
|
||
|
/* loaded from: classes6.dex */
|
||
|
public class CAProtocol {
|
||
|
private static final Logger LOGGER = Logger.getLogger("org.jmrtd");
|
||
|
private PassportService service;
|
||
|
private SecureMessagingWrapper wrapper;
|
||
|
|
||
|
public CAProtocol(PassportService passportService, SecureMessagingWrapper secureMessagingWrapper) {
|
||
|
this.service = passportService;
|
||
|
this.wrapper = secureMessagingWrapper;
|
||
|
}
|
||
|
|
||
|
public CAResult doCA(BigInteger bigInteger, String str, String str2, PublicKey publicKey) throws CardServiceException {
|
||
|
AlgorithmParameterSpec params;
|
||
|
if (publicKey == null) {
|
||
|
throw new IllegalArgumentException("PICC public key is null");
|
||
|
}
|
||
|
String keyAgreementAlgorithm = ChipAuthenticationInfo.toKeyAgreementAlgorithm(str);
|
||
|
if (keyAgreementAlgorithm == null) {
|
||
|
throw new IllegalArgumentException("Unknown agreement algorithm");
|
||
|
}
|
||
|
if (!"ECDH".equals(keyAgreementAlgorithm) && !"DH".equals(keyAgreementAlgorithm)) {
|
||
|
throw new IllegalArgumentException("Unsupported agreement algorithm, expected ECDH or DH, found ".concat(String.valueOf(keyAgreementAlgorithm)));
|
||
|
}
|
||
|
if (str == null) {
|
||
|
str = inferChipAuthenticationOIDfromPublicKeyOID(str2);
|
||
|
}
|
||
|
try {
|
||
|
if ("DH".equals(keyAgreementAlgorithm)) {
|
||
|
params = ((DHPublicKey) publicKey).getParams();
|
||
|
} else {
|
||
|
params = "ECDH".equals(keyAgreementAlgorithm) ? ((ECPublicKey) publicKey).getParams() : null;
|
||
|
}
|
||
|
KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance(keyAgreementAlgorithm);
|
||
|
keyPairGenerator.initialize(params);
|
||
|
KeyPair generateKeyPair = keyPairGenerator.generateKeyPair();
|
||
|
PublicKey publicKey2 = generateKeyPair.getPublic();
|
||
|
PrivateKey privateKey = generateKeyPair.getPrivate();
|
||
|
sendPublicKey(this.service, this.wrapper, str, bigInteger, publicKey2);
|
||
|
byte[] keyHash = getKeyHash(keyAgreementAlgorithm, publicKey2);
|
||
|
SecureMessagingWrapper restartSecureMessaging = restartSecureMessaging(str, computeSharedSecret(keyAgreementAlgorithm, publicKey, privateKey));
|
||
|
this.wrapper = restartSecureMessaging;
|
||
|
return new CAResult(bigInteger, publicKey, keyHash, publicKey2, privateKey, restartSecureMessaging);
|
||
|
} catch (GeneralSecurityException e) {
|
||
|
throw new CardServiceException(e.toString());
|
||
|
}
|
||
|
}
|
||
|
|
||
|
public static void sendPublicKey(PassportService passportService, SecureMessagingWrapper secureMessagingWrapper, String str, BigInteger bigInteger, PublicKey publicKey) throws CardServiceException {
|
||
|
String keyAgreementAlgorithm = ChipAuthenticationInfo.toKeyAgreementAlgorithm(str);
|
||
|
String cipherAlgorithm = ChipAuthenticationInfo.toCipherAlgorithm(str);
|
||
|
byte[] keyData = getKeyData(keyAgreementAlgorithm, publicKey);
|
||
|
if (cipherAlgorithm.startsWith("DESede")) {
|
||
|
passportService.sendMSEKAT(secureMessagingWrapper, Util.wrapDO((byte) -111, keyData), bigInteger != null ? Util.wrapDO((byte) -124, bigInteger.toByteArray()) : null);
|
||
|
} else {
|
||
|
if (cipherAlgorithm.startsWith("AES")) {
|
||
|
passportService.sendMSESetATIntAuth(secureMessagingWrapper, str, bigInteger);
|
||
|
passportService.sendGeneralAuthenticate(secureMessagingWrapper, Util.wrapDO(Byte.MIN_VALUE, keyData), true);
|
||
|
return;
|
||
|
}
|
||
|
throw new IllegalStateException("Cannot set up secure channel with cipher ".concat(String.valueOf(cipherAlgorithm)));
|
||
|
}
|
||
|
}
|
||
|
|
||
|
public static byte[] computeSharedSecret(String str, PublicKey publicKey, PrivateKey privateKey) throws NoSuchAlgorithmException, InvalidKeyException {
|
||
|
KeyAgreement keyAgreement = KeyAgreement.getInstance(str);
|
||
|
keyAgreement.init(privateKey);
|
||
|
keyAgreement.doPhase(publicKey, true);
|
||
|
return keyAgreement.generateSecret();
|
||
|
}
|
||
|
|
||
|
public static SecureMessagingWrapper restartSecureMessaging(String str, byte[] bArr) throws GeneralSecurityException {
|
||
|
String cipherAlgorithm = ChipAuthenticationInfo.toCipherAlgorithm(str);
|
||
|
int keyLength = ChipAuthenticationInfo.toKeyLength(str);
|
||
|
SecretKey deriveKey = Util.deriveKey(bArr, cipherAlgorithm, keyLength, 1);
|
||
|
SecretKey deriveKey2 = Util.deriveKey(bArr, cipherAlgorithm, keyLength, 2);
|
||
|
if (cipherAlgorithm.startsWith("DESede")) {
|
||
|
return new DESedeSecureMessagingWrapper(deriveKey, deriveKey2, 0L);
|
||
|
}
|
||
|
if (cipherAlgorithm.startsWith("AES")) {
|
||
|
return new AESSecureMessagingWrapper(deriveKey, deriveKey2, 0L);
|
||
|
}
|
||
|
throw new IllegalStateException("Unsupported cipher algorithm ".concat(String.valueOf(cipherAlgorithm)));
|
||
|
}
|
||
|
|
||
|
private static byte[] getKeyHash(String str, PublicKey publicKey) throws NoSuchAlgorithmException {
|
||
|
if ("DH".equals(str)) {
|
||
|
MessageDigest.getInstance(McElieceCCA2KeyGenParameterSpec.SHA1);
|
||
|
return MessageDigest.getInstance(McElieceCCA2KeyGenParameterSpec.SHA1).digest(getKeyData(str, publicKey));
|
||
|
}
|
||
|
if ("ECDH".equals(str)) {
|
||
|
org.bouncycastle.jce.interfaces.ECPublicKey eCPublicKey = (org.bouncycastle.jce.interfaces.ECPublicKey) publicKey;
|
||
|
return Util.alignKeyDataToSize(Util.i2os(eCPublicKey.getQ().getX().toBigInteger()), eCPublicKey.getParameters().getCurve().getFieldSize() / 8);
|
||
|
}
|
||
|
throw new IllegalArgumentException("Unsupported agreement algorithm ".concat(String.valueOf(str)));
|
||
|
}
|
||
|
|
||
|
private static byte[] getKeyData(String str, PublicKey publicKey) {
|
||
|
if ("DH".equals(str)) {
|
||
|
return ((DHPublicKey) publicKey).getY().toByteArray();
|
||
|
}
|
||
|
if ("ECDH".equals(str)) {
|
||
|
return ((org.bouncycastle.jce.interfaces.ECPublicKey) publicKey).getQ().getEncoded();
|
||
|
}
|
||
|
throw new IllegalArgumentException("Unsupported agreement algorithm ".concat(String.valueOf(str)));
|
||
|
}
|
||
|
|
||
|
private static String inferChipAuthenticationOIDfromPublicKeyOID(String str) {
|
||
|
if (ChipAuthenticationPublicKeyInfo.ID_PK_ECDH.equals(str)) {
|
||
|
LOGGER.warning("Could not determine ChipAuthentication algorithm, defaulting to id-CA-ECDH-3DES-CBC-CBC");
|
||
|
return ChipAuthenticationInfo.ID_CA_ECDH_3DES_CBC_CBC;
|
||
|
}
|
||
|
if (ChipAuthenticationPublicKeyInfo.ID_PK_DH.equals(str)) {
|
||
|
LOGGER.warning("Could not determine ChipAuthentication algorithm, defaulting to id-CA-DH-3DES-CBC-CBC");
|
||
|
return ChipAuthenticationInfo.ID_CA_DH_3DES_CBC_CBC;
|
||
|
}
|
||
|
LOGGER.severe("No ChipAuthenticationInfo and unsupported ChipAuthenticationPublicKeyInfo public key OID ".concat(String.valueOf(str)));
|
||
|
return null;
|
||
|
}
|
||
|
|
||
|
public SecureMessagingWrapper getWrapper() {
|
||
|
return this.wrapper;
|
||
|
}
|
||
|
}
|