Updated on 2026-08-14
This commit is contained in:
commit
73c73f12ae
49 changed files with 2047 additions and 74 deletions
|
|
@ -1,6 +1,7 @@
|
|||
package com.tangem.card_common.data;
|
||||
|
||||
import com.tangem.card_common.reader.CardCrypto;
|
||||
import com.tangem.card_common.util.PBKDF2;
|
||||
import com.tangem.card_common.util.Util;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
|
@ -15,11 +16,25 @@ public class Issuer {
|
|||
|
||||
static class KeyPair {
|
||||
String privateKey;
|
||||
String privateKeyEncrypted;
|
||||
String publicKey;
|
||||
|
||||
|
||||
byte[] getPrivateKey() throws Exception {
|
||||
if (privateKey != null) {
|
||||
return Util.hexToBytes(privateKey);
|
||||
} else if (privateKeyEncrypted != null) {
|
||||
byte[] A = PBKDF2.deriveKey(Util.calculateSHA256(Tangem().getPrivateTransactionKey()),Util.calculateSHA256(Tangem().getPrivateDataKey()), 100);
|
||||
//String B = Util.bytesToHex(CardCrypto.Encrypt(A, Util.hexToBytes(""), true));
|
||||
try {
|
||||
return CardCrypto.Decrypt(A, Util.hexToBytes(privateKeyEncrypted), true);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
e.printStackTrace();
|
||||
throw new Exception("No private key!");
|
||||
}
|
||||
|
||||
} else {
|
||||
throw new Exception("No private key!");
|
||||
}
|
||||
|
|
@ -57,8 +72,7 @@ public class Issuer {
|
|||
instances.add(unknown);
|
||||
}
|
||||
|
||||
public static void fillIssuers(List<Issuer> issuers)
|
||||
{
|
||||
public static void fillIssuers(List<Issuer> issuers) {
|
||||
instances.addAll(issuers);
|
||||
}
|
||||
|
||||
|
|
@ -119,4 +133,9 @@ public class Issuer {
|
|||
public static Issuer Unknown() {
|
||||
return instances.get(0);
|
||||
}
|
||||
|
||||
public static Issuer Tangem() {
|
||||
return instances.get(1);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -821,9 +821,9 @@ public class CardProtocol {
|
|||
* @throws Exception - if something went wrong
|
||||
*/
|
||||
public TLVList run_SignHashes(String PIN2, byte[][] hashes, byte[] issuerTransactionSignature, byte[] issuerData, byte[] issuerDataSignature) throws Exception {
|
||||
if (mCard.getSigningMethod() != TangemCard.SigningMethod.Sign_Hash_Validated_By_Issuer && mCard.getSigningMethod() != TangemCard.SigningMethod.Sign_Hash) {
|
||||
throw new TangemException("Card don't support signing hashes!");
|
||||
}
|
||||
// if (mCard.getSigningMethod() != TangemCard.SigningMethod.Sign_Hash_Validated_By_Issuer && mCard.getSigningMethod() != TangemCard.SigningMethod.Sign_Hash) {
|
||||
// throw new TangemException("Card don't support signing hashes!");
|
||||
// }
|
||||
|
||||
ByteArrayOutputStream bs = new ByteArrayOutputStream();
|
||||
if (hashes.length > 10) throw new TangemException("To much hashes in one transaction!");
|
||||
|
|
@ -837,7 +837,7 @@ public class CardProtocol {
|
|||
rqApdu.addTLV_U8(TLV.Tag.TAG_TrOut_HashSize, hashes[0].length);
|
||||
rqApdu.addTLV(TLV.Tag.TAG_TrOut_Hash, bs.toByteArray());
|
||||
if (issuerData != null) {
|
||||
if (mCard.getSigningMethod() != TangemCard.SigningMethod.Sign_Hash_Validated_By_Issuer_And_WriteIssuerData)
|
||||
if (!mCard.allowedSigningMethod.contains(TangemCard.SigningMethod.Sign_Hash_Validated_By_Issuer_And_WriteIssuerData))
|
||||
throw new TangemException("Card don't support simultaneous sign with write issuer data!");
|
||||
|
||||
if (issuerDataSignature == null)
|
||||
|
|
@ -849,7 +849,7 @@ public class CardProtocol {
|
|||
if (issuerTransactionSignature != null) {
|
||||
//byte[] issuerSignature = CardCrypto.Signature(issuer.getPrivateTransactionKey(), bs.toByteArray());
|
||||
rqApdu.addTLV(TLV.Tag.TAG_Issuer_Transaction_Signature, issuerTransactionSignature);
|
||||
} else if (mCard.getSigningMethod() == TangemCard.SigningMethod.Sign_Hash_Validated_By_Issuer) {
|
||||
} else if (!mCard.allowedSigningMethod.contains(TangemCard.SigningMethod.Sign_Hash)) {
|
||||
throw new TangemException("Card require issuer validation before sign the transaction!");
|
||||
}
|
||||
|
||||
|
|
@ -900,7 +900,7 @@ public class CardProtocol {
|
|||
bs.write(bTxOutData);
|
||||
|
||||
if (issuerData != null) {
|
||||
if (mCard.getSigningMethod() != TangemCard.SigningMethod.Sign_Hash_Validated_By_Issuer_And_WriteIssuerData)
|
||||
if (!mCard.allowedSigningMethod.contains(TangemCard.SigningMethod.Sign_Raw_Validated_By_Issuer_And_WriteIssuerData))
|
||||
throw new TangemException("Card don't support simultaneous sign with write issuer data!");
|
||||
|
||||
if (issuerDataSignature == null)
|
||||
|
|
@ -911,7 +911,7 @@ public class CardProtocol {
|
|||
}
|
||||
if (issuerTransactionSignature != null) {
|
||||
rqApdu.addTLV(TLV.Tag.TAG_Issuer_Transaction_Signature, issuerTransactionSignature);
|
||||
} else if (mCard.getSigningMethod() == TangemCard.SigningMethod.Sign_Hash_Validated_By_Issuer) {
|
||||
} else if (!mCard.allowedSigningMethod.contains(TangemCard.SigningMethod.Sign_Raw)) {
|
||||
throw new TangemException("Card require issuer validation before sign the transaction!");
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -38,7 +38,7 @@ public class CustomReadCardTask extends Thread {
|
|||
// this fields are static to optimize process when need enter pin and scan card again
|
||||
private static ArrayList<String> lastRead_UnsuccessfullPINs = new ArrayList<>();
|
||||
private static TangemCard.EncryptionMode lastRead_Encryption = null;
|
||||
private static String lastRead_UID;
|
||||
private static String lastRead_UID = "";
|
||||
|
||||
public static void resetLastReadInfo() {
|
||||
lastRead_UID = "";
|
||||
|
|
@ -419,6 +419,7 @@ public class CustomReadCardTask extends Thread {
|
|||
|
||||
} finally {
|
||||
Log.i(TAG, String.format("[-- Finish task -- %s --]", getClass().getSimpleName()));
|
||||
mNotifications.onReadWait(0);
|
||||
mNotifications.onReadFinish(protocol);
|
||||
}
|
||||
} finally {
|
||||
|
|
|
|||
|
|
@ -0,0 +1,100 @@
|
|||
package com.tangem.card_common.tasks;
|
||||
|
||||
import com.tangem.card_common.data.TangemCard;
|
||||
import com.tangem.card_common.data.external.CardDataSubstitutionProvider;
|
||||
import com.tangem.card_common.data.external.PINsProvider;
|
||||
import com.tangem.card_common.reader.CardProtocol;
|
||||
import com.tangem.card_common.reader.NfcReader;
|
||||
import com.tangem.card_common.reader.TLV;
|
||||
import com.tangem.card_common.reader.TLVList;
|
||||
import com.tangem.card_common.util.Log;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
|
||||
public class OneTouchSignTask extends ReadCardInfoTask {
|
||||
public static final String TAG = OneTouchSignTask.class.getSimpleName();
|
||||
|
||||
/**
|
||||
* Transaction Engine request/notifications during sign process
|
||||
*/
|
||||
public interface TransactionToSign {
|
||||
boolean isSigningOnCardSupported(TangemCard card);
|
||||
|
||||
boolean isIssuerCanSignData(TangemCard card);
|
||||
|
||||
boolean isIssuerCanSignTransaction(TangemCard card);
|
||||
|
||||
byte[][] getHashesToSign(TangemCard card) throws Exception;
|
||||
|
||||
byte[] getRawDataToSign(TangemCard card) throws Exception;
|
||||
|
||||
String getHashAlgToSign(TangemCard card) throws Exception;
|
||||
|
||||
byte[] getIssuerTransactionSignature(TangemCard card, byte[] dataToSignByIssuer) throws Exception;
|
||||
|
||||
void onSignCompleted(TangemCard card, byte[] signature) throws Exception;
|
||||
}
|
||||
|
||||
private TransactionToSign transactionToSign;
|
||||
|
||||
public OneTouchSignTask(NfcReader reader, CardDataSubstitutionProvider cardDataSubstitutionProvider, PINsProvider pinsProvider, CardProtocol.Notifications notifications, TransactionToSign transactionToSign) {
|
||||
super(reader, cardDataSubstitutionProvider, pinsProvider, notifications);
|
||||
this.transactionToSign = transactionToSign;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run_Task() throws Exception {
|
||||
super.run_Task();
|
||||
Log.i(TAG, "Manufacturer: " + protocol.getCard().getManufacturer().getOfficialName());
|
||||
|
||||
mNotifications.onReadProgress(protocol, 30);
|
||||
if (isCancelled) return;
|
||||
|
||||
if (!transactionToSign.isSigningOnCardSupported(mCard)) {
|
||||
throw new CardProtocol.TangemException("Signing method isn't supported!");
|
||||
}
|
||||
|
||||
TLVList signResult;
|
||||
|
||||
if (transactionToSign.isIssuerCanSignTransaction(mCard) &&
|
||||
(
|
||||
mCard.allowedSigningMethod.contains(TangemCard.SigningMethod.Sign_Hash_Validated_By_Issuer) ||
|
||||
(
|
||||
transactionToSign.isIssuerCanSignData(mCard) &&
|
||||
mCard.allowedSigningMethod.contains(TangemCard.SigningMethod.Sign_Hash_Validated_By_Issuer_And_WriteIssuerData)
|
||||
)
|
||||
)
|
||||
) {
|
||||
ByteArrayOutputStream bs = new ByteArrayOutputStream();
|
||||
byte[][] hashes = transactionToSign.getHashesToSign(mCard);
|
||||
if (hashes.length > 10) throw new CardProtocol.TangemException("To much hashes in one transaction!");
|
||||
for (int i = 0; i < hashes.length; i++) {
|
||||
if (i != 0 && hashes[0].length != hashes[i].length)
|
||||
throw new CardProtocol.TangemException("Hashes length must be identical!");
|
||||
bs.write(hashes[i]);
|
||||
}
|
||||
signResult = protocol.run_SignHashes(pinsProvider.getPIN2(), hashes, transactionToSign.getIssuerTransactionSignature(mCard, bs.toByteArray()), null, null);
|
||||
} else if (
|
||||
transactionToSign.isIssuerCanSignTransaction(mCard) &&
|
||||
(
|
||||
mCard.allowedSigningMethod.contains(TangemCard.SigningMethod.Sign_Raw_Validated_By_Issuer) ||
|
||||
(
|
||||
transactionToSign.isIssuerCanSignData(mCard) &&
|
||||
mCard.allowedSigningMethod.contains(TangemCard.SigningMethod.Sign_Raw_Validated_By_Issuer_And_WriteIssuerData)
|
||||
)
|
||||
)
|
||||
) {
|
||||
byte[] txOut = transactionToSign.getRawDataToSign(mCard);
|
||||
signResult = protocol.run_SignRaw(pinsProvider.getPIN2(), transactionToSign.getHashAlgToSign(mCard), txOut, transactionToSign.getIssuerTransactionSignature(mCard, txOut), null, null);
|
||||
} else if (mCard.allowedSigningMethod.contains(TangemCard.SigningMethod.Sign_Hash)) {
|
||||
signResult = protocol.run_SignHashes(pinsProvider.getPIN2(), transactionToSign.getHashesToSign(mCard), null, null, null);
|
||||
} else if (mCard.allowedSigningMethod.contains(TangemCard.SigningMethod.Sign_Raw)) {
|
||||
signResult = protocol.run_SignRaw(pinsProvider.getPIN2(), transactionToSign.getHashAlgToSign(mCard), transactionToSign.getRawDataToSign(mCard), null, null, null);
|
||||
} else {
|
||||
throw new CardProtocol.TangemException("Signing method isn't supported!");
|
||||
}
|
||||
|
||||
transactionToSign.onSignCompleted(mCard, signResult.getTLV(TLV.Tag.TAG_Signature).Value);
|
||||
mNotifications.onReadProgress(protocol, 100);
|
||||
}
|
||||
}
|
||||
|
|
@ -2,12 +2,18 @@ package com.tangem.card_common.util;
|
|||
|
||||
public class Log {
|
||||
public static void i(String logTag, String message) {
|
||||
|
||||
if( loggerInstance!=null ) loggerInstance.i(logTag,message);
|
||||
}
|
||||
public static void e(String logTag, String message) {
|
||||
|
||||
if( loggerInstance!=null ) loggerInstance.e(logTag,message);
|
||||
}
|
||||
public static void v(String logTag, String message) {
|
||||
if( loggerInstance!=null ) loggerInstance.v(logTag,message);
|
||||
}
|
||||
|
||||
private static LoggerInterface loggerInstance=null;
|
||||
public static void setLogger(LoggerInterface logger)
|
||||
{
|
||||
loggerInstance=logger;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,7 @@
|
|||
package com.tangem.card_common.util;
|
||||
|
||||
public interface LoggerInterface {
|
||||
void i(String logTag, String message);
|
||||
void e(String logTag, String message);
|
||||
void v(String logTag, String message);
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue