I am currently working on a project where I need to translate a C# script method to code compatible with Android Studio. Unfortunately, I am facing some difficulties and would like to know if anyone is familiar with translating code between these two languages/environments.
Here is the method in question:
<code>public PaceKeys initiatePaceGenMapping()
{
this.sendSelectApplet();
PaceKeys paceKeys = new PaceKeys();
// Paramètres du domaine pour la courbe ECC-NIST 256
X9ECParameters curve = SecNamedCurves.GetByName("secp256r1");
// Utilisation des paramètres déjà connus
Org.BouncyCastle.Math.BigInteger prime = new Org.BouncyCastle.Math.BigInteger("FFFFFFFF00000001000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFF", 16);
Org.BouncyCastle.Math.BigInteger a = new Org.BouncyCastle.Math.BigInteger("FFFFFFFF00000001000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFC", 16);
Org.BouncyCastle.Math.BigInteger order = new Org.BouncyCastle.Math.BigInteger("FFFFFFFF00000000FFFFFFFFFFFFFFFFBCE6FAADA7179E84F3B9CAC2FC632551", 16);
Org.BouncyCastle.Math.BigInteger b = new Org.BouncyCastle.Math.BigInteger("5AC635D8AA3A93E7B3EBBD55769886BC651D06B0CC53B0F63BCE3C3E27D2604B", 16);
Org.BouncyCastle.Math.BigInteger G_X = new Org.BouncyCastle.Math.BigInteger("6B17D1F2E12C4247F8BCE6E563A440F277037D812DEB33A0F4A13945D898C296", 16);
Org.BouncyCastle.Math.BigInteger G_Y = new Org.BouncyCastle.Math.BigInteger("4FE342E2FE1A7F9B8EE7EB4A7C0F9E162BCE33576B315ECECBB6406837BF51F5", 16);
Org.BouncyCastle.Math.EC.ECPoint basePoint = curve.Curve.CreatePoint(G_X, G_Y);
ECDomainParameters domainParams = new ECDomainParameters(curve.Curve, basePoint, order, curve.H, curve.GetSeed());
// • Read EF.DIR and EF.CardAccess (applet capabilities)
string selectEF_F000 = executeCommandeSec("00A40000023F00");
if (string.Equals(selectEF_F000, "9000"))
{
string selectEF_CardAccess = executeCommandeSec("00a4020c02011c");
if (string.Equals(selectEF_CardAccess, "9000"))
{
string readBinaryCardAccess1 = executeCommandeSec("00b0000005");
string readBinaryCardAccess2 = executeCommandeSec("00b000055b");
// • Select algorithm (INS 22)
string setMSE = executeCommandeSec("0022c1a412800a04007f0007020204020283010384010c");
if (string.Equals(setMSE, "9000"))
{
// • The host requests PACE for authentication, possibly giving a preference :
string paceAuthenticationREQUEST = executeCommandeSec("10860000027c0000");
// • The card responds with a 128-bit (16 byte) random number (nonce) encrypted with PACE_nonce_AES128key : 7C 12 80 10 <encrypted_nonce>
int startIndex = paceAuthenticationREQUEST.IndexOf("7C128010") + "7C128010".Length;
// Trouver l'index de fin de la sous-chaîne
int endIndex = paceAuthenticationREQUEST.IndexOf("9000", startIndex);
// Extraire la sous-chaîne : representant Key: z - encrypted nonce (z [PACE])
string encryptedNonce = paceAuthenticationREQUEST.Substring(startIndex, endIndex - startIndex);
// the host decrypts the 128-bit nonce with PACE_nonce_AES128key derived from user input as described above
byte[] bytesEncryptedNonce = StringUtils.ToByteArray(encryptedNonce);
// Key: K - derived key from shared secret : trouver la clé dérivée du PIN
string derivedKeySH = calculerSHA1("3132333400000003");
byte[] bytesDerivedKeySH = StringUtils.ToByteArray(derivedKeySH);
// • [decrypt nonce nonce]
byte[] bytesDecryptedNonce = decryptAES(bytesEncryptedNonce, bytesDerivedKeySH);
string decryptedNonce = byteToHexStr(bytesDecryptedNonce);
Org.BouncyCastle.Math.BigInteger nonce = new Org.BouncyCastle.Math.BigInteger(decryptedNonce, 16);
// • [generate random number as private key SKPCD for DHKA]
SecureRandom random = new SecureRandom();
int randomNumber = random.NextInt();
Console.WriteLine("Nombre aléatoire : " + randomNumber);
Org.BouncyCastle.Math.BigInteger SKPCD = new Org.BouncyCastle.Math.BigInteger(domainParams.Curve.Order.BitLength, random).Mod(domainParams.Curve.Order);
Console.WriteLine("Secrete Key SKPCD : " + SKPCD);
// • [calculate ephermeral PKPCD = BasePoint G * SKPCD]
Org.BouncyCastle.Math.EC.ECPoint PKPCD = domainParams.G.Multiply(SKPCD).Normalize();
Console.WriteLine("Public Key PKPCD du terminal: " + PKPCD);
// Convertir les coordonnées X et Y en hexadécimal
/* string PKPCDXHex = PKPCD.XCoord.ToBigInteger().ToString(16);
string PKPCDYHex = PKPCD.YCoord.ToBigInteger().ToString(16);*/
// Convertir les coordonnées X et Y en hexadécimal
byte[] PKPCDXBytes = PKPCD.XCoord.ToBigInteger().ToByteArrayUnsigned();
byte[] PKPCDYBytes = PKPCD.YCoord.ToBigInteger().ToByteArrayUnsigned();
string PKPCDXHex = BitConverter.ToString(PKPCDXBytes).Replace("-", "");
string PKPCDYHex = BitConverter.ToString(PKPCDYBytes).Replace("-", "");
// • Send PKPCD and Receive PKPICC from card
string requestPKicc = "10860000457C43814104" + PKPCDXHex + PKPCDYHex + "00";
string reponsePKicc = executeCommandeSec(requestPKicc);
// Définir les positions de début et de fin de la sous-chaîne
int entete = 10; // Après les 4 premiers octets
int sw = reponsePKicc.Length - 4; // Avant les 4 derniers octets
// Extraire la sous-chaîne
reponsePKicc = reponsePKicc.Substring(entete, sw - entete);
string PKICCXHex = reponsePKicc.Substring(0, reponsePKicc.Length / 2);
string PKICCYHex = reponsePKicc.Substring(reponsePKicc.Length / 2);
Org.BouncyCastle.Math.EC.ECPoint PKPICC = curve.Curve.CreatePoint(new Org.BouncyCastle.Math.BigInteger(PKICCXHex, 16), new Org.BouncyCastle.Math.BigInteger(PKICCYHex, 16));
Console.WriteLine("Public Key PKICC de la carte: " + PKPICC);
// • [build shared secret: H = PKPICC * SKPCD = G * SKPICC * SKPCD]
Org.BouncyCastle.Math.EC.ECPoint H = PKPICC.Multiply(SKPCD).Normalize();
Console.WriteLine("Secret Partagé H : " + H);
// • [build new base point:] : Gmap = G * s + H = G * s + G * SKPICC * SKPCD = G * (s + SKPICC * SKPCD)
Org.BouncyCastle.Math.EC.ECPoint Gmap = basePoint.Multiply(nonce); Gmap = Gmap.Add(H).Normalize();
Console.WriteLine("Nouveau Point de base Gmap : " + Gmap);
// • [generate random number as private key SKPCD,map for DHKA]
Org.BouncyCastle.Math.BigInteger SKPCDMap = new Org.BouncyCastle.Math.BigInteger(Gmap.Curve.Order.BitLength, random).Mod(Gmap.Curve.Order);
Console.WriteLine("Nouvel clé secrete SKPCDMap : " + SKPCDMap);
// • [calculate ephermeral PKPCD,map = BasePoint Gmap * SKPCD,map]
Org.BouncyCastle.Math.EC.ECPoint PKPCDMap = Gmap.Multiply(SKPCDMap).Normalize();
Console.WriteLine("Nouvelle clé publique éphémère PKPCDMap du terminal : " + PKPCDMap);
// Convertir les coordonnées X et Y en hexadécimal
string PKPCDMapXHex = PKPCDMap.XCoord.ToBigInteger().ToString(16);
string PKPCDMapYHex = PKPCDMap.YCoord.ToBigInteger().ToString(16);
// • Send PKPCD,map and Receive PKPICC,map from card
string requestPKpcdmap = "10860000457c43834104" + PKPCDMapXHex + PKPCDMapYHex + "00";
string responsePKpcdmap = executeCommandeSec(requestPKpcdmap);
sw = responsePKpcdmap.Length - 4;
// Extraire la sous-chaîne
if (responsePKpcdmap.Length > 4)
{
responsePKpcdmap = responsePKpcdmap.Substring(entete, sw - entete);
string PKICCMapXHex = responsePKpcdmap.Substring(0, responsePKpcdmap.Length / 2);
string PKICCMapYHex = responsePKpcdmap.Substring(responsePKpcdmap.Length / 2);
Org.BouncyCastle.Math.EC.ECPoint PKPICCMap = curve.Curve.CreatePoint(new Org.BouncyCastle.Math.BigInteger(PKICCMapXHex, 16), new Org.BouncyCastle.Math.BigInteger(PKICCMapYHex, 16));
Console.WriteLine("Nouvelle clé publique éphémère de la puce PKPICCMap : " + PKPICCMap);
// • [build Hmap = PKPICC,map * SKPCD,map = Gmap * SKPICC,map * SKPCD,map]
Org.BouncyCastle.Math.EC.ECPoint Hmap = PKPICCMap.Multiply(SKPCDMap).Normalize();
byte[] HmapBytes = StringUtils.ToByteArray(Hmap.XCoord.ToBigInteger().ToString(16));
// • Derive session keys Kenc and Kmac from Hmap
string Kenc = calculerSHA1(Hmap.XCoord.ToBigInteger().ToString(16) + "00000001");
string Kmac = calculerSHA1(Hmap.XCoord.ToBigInteger().ToString(16) + "00000002");
Console.WriteLine("Clé encryption Kenc : " + Kenc);
Console.WriteLine("Clé mac Kmac : " + Kmac);
// • Calculate token: TPICC = MAC(Kmac , PKPCD,map), TPCD = MAC(Kmac, PKPICC,map)
string PKICCMap = "04" + PKICCMapXHex + PKICCMapYHex;
string auth_token_host = calculateCMAC(Kmac, PKICCMap);
Console.WriteLine("Token d'authentification : " + auth_token_host);
string tpicc = executeCommandeSec("008600000c7c0a8508" + auth_token_host);
Console.WriteLine("Réponse tpicc : " + tpicc);
if (tpicc != null && tpicc.Length > 4)
{
sw = tpicc.Length - 4;
string auth_token_tpicc = tpicc.Substring(8, sw - 8);
paceKeys.keyMac = Kmac;
paceKeys.keyEnc = Kenc;
Console.WriteLine("Pace object : keyMac et keyEnc " + paceKeys.keyMac + " " + paceKeys.keyEnc);
if (paceKeys.keyMac != null || paceKeys.keyEnc != null)
{
sm = new SecureMessaging(StringUtils.ToByteArray(Kmac), StringUtils.ToByteArray(Kenc));
return paceKeys;
}
else
{
String VerifyPUK = executeCommande("00200089083132333435363738");
Console.WriteLine("Verify PUK : " +VerifyPUK);
this.sendSelectApplet();
this.initiatePaceGenMapping();
}
}
else
{
String VerifyPUK = executeCommande("00200089083132333435363738");
Console.WriteLine("Verify PUK : " + VerifyPUK);
this.sendSelectApplet();
this.initiatePaceGenMapping();
}
}
else
{
String VerifyPUK = executeCommande("00200089083132333435363738");
Console.WriteLine("Verify PUK : " + VerifyPUK);
this.sendSelectApplet();
this.initiatePaceGenMapping();
}
}
}
}
return paceKeys;
}
</code>
<code>public PaceKeys initiatePaceGenMapping()
{
this.sendSelectApplet();
PaceKeys paceKeys = new PaceKeys();
// Paramètres du domaine pour la courbe ECC-NIST 256
X9ECParameters curve = SecNamedCurves.GetByName("secp256r1");
// Utilisation des paramètres déjà connus
Org.BouncyCastle.Math.BigInteger prime = new Org.BouncyCastle.Math.BigInteger("FFFFFFFF00000001000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFF", 16);
Org.BouncyCastle.Math.BigInteger a = new Org.BouncyCastle.Math.BigInteger("FFFFFFFF00000001000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFC", 16);
Org.BouncyCastle.Math.BigInteger order = new Org.BouncyCastle.Math.BigInteger("FFFFFFFF00000000FFFFFFFFFFFFFFFFBCE6FAADA7179E84F3B9CAC2FC632551", 16);
Org.BouncyCastle.Math.BigInteger b = new Org.BouncyCastle.Math.BigInteger("5AC635D8AA3A93E7B3EBBD55769886BC651D06B0CC53B0F63BCE3C3E27D2604B", 16);
Org.BouncyCastle.Math.BigInteger G_X = new Org.BouncyCastle.Math.BigInteger("6B17D1F2E12C4247F8BCE6E563A440F277037D812DEB33A0F4A13945D898C296", 16);
Org.BouncyCastle.Math.BigInteger G_Y = new Org.BouncyCastle.Math.BigInteger("4FE342E2FE1A7F9B8EE7EB4A7C0F9E162BCE33576B315ECECBB6406837BF51F5", 16);
Org.BouncyCastle.Math.EC.ECPoint basePoint = curve.Curve.CreatePoint(G_X, G_Y);
ECDomainParameters domainParams = new ECDomainParameters(curve.Curve, basePoint, order, curve.H, curve.GetSeed());
// • Read EF.DIR and EF.CardAccess (applet capabilities)
string selectEF_F000 = executeCommandeSec("00A40000023F00");
if (string.Equals(selectEF_F000, "9000"))
{
string selectEF_CardAccess = executeCommandeSec("00a4020c02011c");
if (string.Equals(selectEF_CardAccess, "9000"))
{
string readBinaryCardAccess1 = executeCommandeSec("00b0000005");
string readBinaryCardAccess2 = executeCommandeSec("00b000055b");
// • Select algorithm (INS 22)
string setMSE = executeCommandeSec("0022c1a412800a04007f0007020204020283010384010c");
if (string.Equals(setMSE, "9000"))
{
// • The host requests PACE for authentication, possibly giving a preference :
string paceAuthenticationREQUEST = executeCommandeSec("10860000027c0000");
// • The card responds with a 128-bit (16 byte) random number (nonce) encrypted with PACE_nonce_AES128key : 7C 12 80 10 <encrypted_nonce>
int startIndex = paceAuthenticationREQUEST.IndexOf("7C128010") + "7C128010".Length;
// Trouver l'index de fin de la sous-chaîne
int endIndex = paceAuthenticationREQUEST.IndexOf("9000", startIndex);
// Extraire la sous-chaîne : representant Key: z - encrypted nonce (z [PACE])
string encryptedNonce = paceAuthenticationREQUEST.Substring(startIndex, endIndex - startIndex);
// the host decrypts the 128-bit nonce with PACE_nonce_AES128key derived from user input as described above
byte[] bytesEncryptedNonce = StringUtils.ToByteArray(encryptedNonce);
// Key: K - derived key from shared secret : trouver la clé dérivée du PIN
string derivedKeySH = calculerSHA1("3132333400000003");
byte[] bytesDerivedKeySH = StringUtils.ToByteArray(derivedKeySH);
// • [decrypt nonce nonce]
byte[] bytesDecryptedNonce = decryptAES(bytesEncryptedNonce, bytesDerivedKeySH);
string decryptedNonce = byteToHexStr(bytesDecryptedNonce);
Org.BouncyCastle.Math.BigInteger nonce = new Org.BouncyCastle.Math.BigInteger(decryptedNonce, 16);
// • [generate random number as private key SKPCD for DHKA]
SecureRandom random = new SecureRandom();
int randomNumber = random.NextInt();
Console.WriteLine("Nombre aléatoire : " + randomNumber);
Org.BouncyCastle.Math.BigInteger SKPCD = new Org.BouncyCastle.Math.BigInteger(domainParams.Curve.Order.BitLength, random).Mod(domainParams.Curve.Order);
Console.WriteLine("Secrete Key SKPCD : " + SKPCD);
// • [calculate ephermeral PKPCD = BasePoint G * SKPCD]
Org.BouncyCastle.Math.EC.ECPoint PKPCD = domainParams.G.Multiply(SKPCD).Normalize();
Console.WriteLine("Public Key PKPCD du terminal: " + PKPCD);
// Convertir les coordonnées X et Y en hexadécimal
/* string PKPCDXHex = PKPCD.XCoord.ToBigInteger().ToString(16);
string PKPCDYHex = PKPCD.YCoord.ToBigInteger().ToString(16);*/
// Convertir les coordonnées X et Y en hexadécimal
byte[] PKPCDXBytes = PKPCD.XCoord.ToBigInteger().ToByteArrayUnsigned();
byte[] PKPCDYBytes = PKPCD.YCoord.ToBigInteger().ToByteArrayUnsigned();
string PKPCDXHex = BitConverter.ToString(PKPCDXBytes).Replace("-", "");
string PKPCDYHex = BitConverter.ToString(PKPCDYBytes).Replace("-", "");
// • Send PKPCD and Receive PKPICC from card
string requestPKicc = "10860000457C43814104" + PKPCDXHex + PKPCDYHex + "00";
string reponsePKicc = executeCommandeSec(requestPKicc);
// Définir les positions de début et de fin de la sous-chaîne
int entete = 10; // Après les 4 premiers octets
int sw = reponsePKicc.Length - 4; // Avant les 4 derniers octets
// Extraire la sous-chaîne
reponsePKicc = reponsePKicc.Substring(entete, sw - entete);
string PKICCXHex = reponsePKicc.Substring(0, reponsePKicc.Length / 2);
string PKICCYHex = reponsePKicc.Substring(reponsePKicc.Length / 2);
Org.BouncyCastle.Math.EC.ECPoint PKPICC = curve.Curve.CreatePoint(new Org.BouncyCastle.Math.BigInteger(PKICCXHex, 16), new Org.BouncyCastle.Math.BigInteger(PKICCYHex, 16));
Console.WriteLine("Public Key PKICC de la carte: " + PKPICC);
// • [build shared secret: H = PKPICC * SKPCD = G * SKPICC * SKPCD]
Org.BouncyCastle.Math.EC.ECPoint H = PKPICC.Multiply(SKPCD).Normalize();
Console.WriteLine("Secret Partagé H : " + H);
// • [build new base point:] : Gmap = G * s + H = G * s + G * SKPICC * SKPCD = G * (s + SKPICC * SKPCD)
Org.BouncyCastle.Math.EC.ECPoint Gmap = basePoint.Multiply(nonce); Gmap = Gmap.Add(H).Normalize();
Console.WriteLine("Nouveau Point de base Gmap : " + Gmap);
// • [generate random number as private key SKPCD,map for DHKA]
Org.BouncyCastle.Math.BigInteger SKPCDMap = new Org.BouncyCastle.Math.BigInteger(Gmap.Curve.Order.BitLength, random).Mod(Gmap.Curve.Order);
Console.WriteLine("Nouvel clé secrete SKPCDMap : " + SKPCDMap);
// • [calculate ephermeral PKPCD,map = BasePoint Gmap * SKPCD,map]
Org.BouncyCastle.Math.EC.ECPoint PKPCDMap = Gmap.Multiply(SKPCDMap).Normalize();
Console.WriteLine("Nouvelle clé publique éphémère PKPCDMap du terminal : " + PKPCDMap);
// Convertir les coordonnées X et Y en hexadécimal
string PKPCDMapXHex = PKPCDMap.XCoord.ToBigInteger().ToString(16);
string PKPCDMapYHex = PKPCDMap.YCoord.ToBigInteger().ToString(16);
// • Send PKPCD,map and Receive PKPICC,map from card
string requestPKpcdmap = "10860000457c43834104" + PKPCDMapXHex + PKPCDMapYHex + "00";
string responsePKpcdmap = executeCommandeSec(requestPKpcdmap);
sw = responsePKpcdmap.Length - 4;
// Extraire la sous-chaîne
if (responsePKpcdmap.Length > 4)
{
responsePKpcdmap = responsePKpcdmap.Substring(entete, sw - entete);
string PKICCMapXHex = responsePKpcdmap.Substring(0, responsePKpcdmap.Length / 2);
string PKICCMapYHex = responsePKpcdmap.Substring(responsePKpcdmap.Length / 2);
Org.BouncyCastle.Math.EC.ECPoint PKPICCMap = curve.Curve.CreatePoint(new Org.BouncyCastle.Math.BigInteger(PKICCMapXHex, 16), new Org.BouncyCastle.Math.BigInteger(PKICCMapYHex, 16));
Console.WriteLine("Nouvelle clé publique éphémère de la puce PKPICCMap : " + PKPICCMap);
// • [build Hmap = PKPICC,map * SKPCD,map = Gmap * SKPICC,map * SKPCD,map]
Org.BouncyCastle.Math.EC.ECPoint Hmap = PKPICCMap.Multiply(SKPCDMap).Normalize();
byte[] HmapBytes = StringUtils.ToByteArray(Hmap.XCoord.ToBigInteger().ToString(16));
// • Derive session keys Kenc and Kmac from Hmap
string Kenc = calculerSHA1(Hmap.XCoord.ToBigInteger().ToString(16) + "00000001");
string Kmac = calculerSHA1(Hmap.XCoord.ToBigInteger().ToString(16) + "00000002");
Console.WriteLine("Clé encryption Kenc : " + Kenc);
Console.WriteLine("Clé mac Kmac : " + Kmac);
// • Calculate token: TPICC = MAC(Kmac , PKPCD,map), TPCD = MAC(Kmac, PKPICC,map)
string PKICCMap = "04" + PKICCMapXHex + PKICCMapYHex;
string auth_token_host = calculateCMAC(Kmac, PKICCMap);
Console.WriteLine("Token d'authentification : " + auth_token_host);
string tpicc = executeCommandeSec("008600000c7c0a8508" + auth_token_host);
Console.WriteLine("Réponse tpicc : " + tpicc);
if (tpicc != null && tpicc.Length > 4)
{
sw = tpicc.Length - 4;
string auth_token_tpicc = tpicc.Substring(8, sw - 8);
paceKeys.keyMac = Kmac;
paceKeys.keyEnc = Kenc;
Console.WriteLine("Pace object : keyMac et keyEnc " + paceKeys.keyMac + " " + paceKeys.keyEnc);
if (paceKeys.keyMac != null || paceKeys.keyEnc != null)
{
sm = new SecureMessaging(StringUtils.ToByteArray(Kmac), StringUtils.ToByteArray(Kenc));
return paceKeys;
}
else
{
String VerifyPUK = executeCommande("00200089083132333435363738");
Console.WriteLine("Verify PUK : " +VerifyPUK);
this.sendSelectApplet();
this.initiatePaceGenMapping();
}
}
else
{
String VerifyPUK = executeCommande("00200089083132333435363738");
Console.WriteLine("Verify PUK : " + VerifyPUK);
this.sendSelectApplet();
this.initiatePaceGenMapping();
}
}
else
{
String VerifyPUK = executeCommande("00200089083132333435363738");
Console.WriteLine("Verify PUK : " + VerifyPUK);
this.sendSelectApplet();
this.initiatePaceGenMapping();
}
}
}
}
return paceKeys;
}
</code>
public PaceKeys initiatePaceGenMapping()
{
this.sendSelectApplet();
PaceKeys paceKeys = new PaceKeys();
// Paramètres du domaine pour la courbe ECC-NIST 256
X9ECParameters curve = SecNamedCurves.GetByName("secp256r1");
// Utilisation des paramètres déjà connus
Org.BouncyCastle.Math.BigInteger prime = new Org.BouncyCastle.Math.BigInteger("FFFFFFFF00000001000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFF", 16);
Org.BouncyCastle.Math.BigInteger a = new Org.BouncyCastle.Math.BigInteger("FFFFFFFF00000001000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFC", 16);
Org.BouncyCastle.Math.BigInteger order = new Org.BouncyCastle.Math.BigInteger("FFFFFFFF00000000FFFFFFFFFFFFFFFFBCE6FAADA7179E84F3B9CAC2FC632551", 16);
Org.BouncyCastle.Math.BigInteger b = new Org.BouncyCastle.Math.BigInteger("5AC635D8AA3A93E7B3EBBD55769886BC651D06B0CC53B0F63BCE3C3E27D2604B", 16);
Org.BouncyCastle.Math.BigInteger G_X = new Org.BouncyCastle.Math.BigInteger("6B17D1F2E12C4247F8BCE6E563A440F277037D812DEB33A0F4A13945D898C296", 16);
Org.BouncyCastle.Math.BigInteger G_Y = new Org.BouncyCastle.Math.BigInteger("4FE342E2FE1A7F9B8EE7EB4A7C0F9E162BCE33576B315ECECBB6406837BF51F5", 16);
Org.BouncyCastle.Math.EC.ECPoint basePoint = curve.Curve.CreatePoint(G_X, G_Y);
ECDomainParameters domainParams = new ECDomainParameters(curve.Curve, basePoint, order, curve.H, curve.GetSeed());
// • Read EF.DIR and EF.CardAccess (applet capabilities)
string selectEF_F000 = executeCommandeSec("00A40000023F00");
if (string.Equals(selectEF_F000, "9000"))
{
string selectEF_CardAccess = executeCommandeSec("00a4020c02011c");
if (string.Equals(selectEF_CardAccess, "9000"))
{
string readBinaryCardAccess1 = executeCommandeSec("00b0000005");
string readBinaryCardAccess2 = executeCommandeSec("00b000055b");
// • Select algorithm (INS 22)
string setMSE = executeCommandeSec("0022c1a412800a04007f0007020204020283010384010c");
if (string.Equals(setMSE, "9000"))
{
// • The host requests PACE for authentication, possibly giving a preference :
string paceAuthenticationREQUEST = executeCommandeSec("10860000027c0000");
// • The card responds with a 128-bit (16 byte) random number (nonce) encrypted with PACE_nonce_AES128key : 7C 12 80 10 <encrypted_nonce>
int startIndex = paceAuthenticationREQUEST.IndexOf("7C128010") + "7C128010".Length;
// Trouver l'index de fin de la sous-chaîne
int endIndex = paceAuthenticationREQUEST.IndexOf("9000", startIndex);
// Extraire la sous-chaîne : representant Key: z - encrypted nonce (z [PACE])
string encryptedNonce = paceAuthenticationREQUEST.Substring(startIndex, endIndex - startIndex);
// the host decrypts the 128-bit nonce with PACE_nonce_AES128key derived from user input as described above
byte[] bytesEncryptedNonce = StringUtils.ToByteArray(encryptedNonce);
// Key: K - derived key from shared secret : trouver la clé dérivée du PIN
string derivedKeySH = calculerSHA1("3132333400000003");
byte[] bytesDerivedKeySH = StringUtils.ToByteArray(derivedKeySH);
// • [decrypt nonce nonce]
byte[] bytesDecryptedNonce = decryptAES(bytesEncryptedNonce, bytesDerivedKeySH);
string decryptedNonce = byteToHexStr(bytesDecryptedNonce);
Org.BouncyCastle.Math.BigInteger nonce = new Org.BouncyCastle.Math.BigInteger(decryptedNonce, 16);
// • [generate random number as private key SKPCD for DHKA]
SecureRandom random = new SecureRandom();
int randomNumber = random.NextInt();
Console.WriteLine("Nombre aléatoire : " + randomNumber);
Org.BouncyCastle.Math.BigInteger SKPCD = new Org.BouncyCastle.Math.BigInteger(domainParams.Curve.Order.BitLength, random).Mod(domainParams.Curve.Order);
Console.WriteLine("Secrete Key SKPCD : " + SKPCD);
// • [calculate ephermeral PKPCD = BasePoint G * SKPCD]
Org.BouncyCastle.Math.EC.ECPoint PKPCD = domainParams.G.Multiply(SKPCD).Normalize();
Console.WriteLine("Public Key PKPCD du terminal: " + PKPCD);
// Convertir les coordonnées X et Y en hexadécimal
/* string PKPCDXHex = PKPCD.XCoord.ToBigInteger().ToString(16);
string PKPCDYHex = PKPCD.YCoord.ToBigInteger().ToString(16);*/
// Convertir les coordonnées X et Y en hexadécimal
byte[] PKPCDXBytes = PKPCD.XCoord.ToBigInteger().ToByteArrayUnsigned();
byte[] PKPCDYBytes = PKPCD.YCoord.ToBigInteger().ToByteArrayUnsigned();
string PKPCDXHex = BitConverter.ToString(PKPCDXBytes).Replace("-", "");
string PKPCDYHex = BitConverter.ToString(PKPCDYBytes).Replace("-", "");
// • Send PKPCD and Receive PKPICC from card
string requestPKicc = "10860000457C43814104" + PKPCDXHex + PKPCDYHex + "00";
string reponsePKicc = executeCommandeSec(requestPKicc);
// Définir les positions de début et de fin de la sous-chaîne
int entete = 10; // Après les 4 premiers octets
int sw = reponsePKicc.Length - 4; // Avant les 4 derniers octets
// Extraire la sous-chaîne
reponsePKicc = reponsePKicc.Substring(entete, sw - entete);
string PKICCXHex = reponsePKicc.Substring(0, reponsePKicc.Length / 2);
string PKICCYHex = reponsePKicc.Substring(reponsePKicc.Length / 2);
Org.BouncyCastle.Math.EC.ECPoint PKPICC = curve.Curve.CreatePoint(new Org.BouncyCastle.Math.BigInteger(PKICCXHex, 16), new Org.BouncyCastle.Math.BigInteger(PKICCYHex, 16));
Console.WriteLine("Public Key PKICC de la carte: " + PKPICC);
// • [build shared secret: H = PKPICC * SKPCD = G * SKPICC * SKPCD]
Org.BouncyCastle.Math.EC.ECPoint H = PKPICC.Multiply(SKPCD).Normalize();
Console.WriteLine("Secret Partagé H : " + H);
// • [build new base point:] : Gmap = G * s + H = G * s + G * SKPICC * SKPCD = G * (s + SKPICC * SKPCD)
Org.BouncyCastle.Math.EC.ECPoint Gmap = basePoint.Multiply(nonce); Gmap = Gmap.Add(H).Normalize();
Console.WriteLine("Nouveau Point de base Gmap : " + Gmap);
// • [generate random number as private key SKPCD,map for DHKA]
Org.BouncyCastle.Math.BigInteger SKPCDMap = new Org.BouncyCastle.Math.BigInteger(Gmap.Curve.Order.BitLength, random).Mod(Gmap.Curve.Order);
Console.WriteLine("Nouvel clé secrete SKPCDMap : " + SKPCDMap);
// • [calculate ephermeral PKPCD,map = BasePoint Gmap * SKPCD,map]
Org.BouncyCastle.Math.EC.ECPoint PKPCDMap = Gmap.Multiply(SKPCDMap).Normalize();
Console.WriteLine("Nouvelle clé publique éphémère PKPCDMap du terminal : " + PKPCDMap);
// Convertir les coordonnées X et Y en hexadécimal
string PKPCDMapXHex = PKPCDMap.XCoord.ToBigInteger().ToString(16);
string PKPCDMapYHex = PKPCDMap.YCoord.ToBigInteger().ToString(16);
// • Send PKPCD,map and Receive PKPICC,map from card
string requestPKpcdmap = "10860000457c43834104" + PKPCDMapXHex + PKPCDMapYHex + "00";
string responsePKpcdmap = executeCommandeSec(requestPKpcdmap);
sw = responsePKpcdmap.Length - 4;
// Extraire la sous-chaîne
if (responsePKpcdmap.Length > 4)
{
responsePKpcdmap = responsePKpcdmap.Substring(entete, sw - entete);
string PKICCMapXHex = responsePKpcdmap.Substring(0, responsePKpcdmap.Length / 2);
string PKICCMapYHex = responsePKpcdmap.Substring(responsePKpcdmap.Length / 2);
Org.BouncyCastle.Math.EC.ECPoint PKPICCMap = curve.Curve.CreatePoint(new Org.BouncyCastle.Math.BigInteger(PKICCMapXHex, 16), new Org.BouncyCastle.Math.BigInteger(PKICCMapYHex, 16));
Console.WriteLine("Nouvelle clé publique éphémère de la puce PKPICCMap : " + PKPICCMap);
// • [build Hmap = PKPICC,map * SKPCD,map = Gmap * SKPICC,map * SKPCD,map]
Org.BouncyCastle.Math.EC.ECPoint Hmap = PKPICCMap.Multiply(SKPCDMap).Normalize();
byte[] HmapBytes = StringUtils.ToByteArray(Hmap.XCoord.ToBigInteger().ToString(16));
// • Derive session keys Kenc and Kmac from Hmap
string Kenc = calculerSHA1(Hmap.XCoord.ToBigInteger().ToString(16) + "00000001");
string Kmac = calculerSHA1(Hmap.XCoord.ToBigInteger().ToString(16) + "00000002");
Console.WriteLine("Clé encryption Kenc : " + Kenc);
Console.WriteLine("Clé mac Kmac : " + Kmac);
// • Calculate token: TPICC = MAC(Kmac , PKPCD,map), TPCD = MAC(Kmac, PKPICC,map)
string PKICCMap = "04" + PKICCMapXHex + PKICCMapYHex;
string auth_token_host = calculateCMAC(Kmac, PKICCMap);
Console.WriteLine("Token d'authentification : " + auth_token_host);
string tpicc = executeCommandeSec("008600000c7c0a8508" + auth_token_host);
Console.WriteLine("Réponse tpicc : " + tpicc);
if (tpicc != null && tpicc.Length > 4)
{
sw = tpicc.Length - 4;
string auth_token_tpicc = tpicc.Substring(8, sw - 8);
paceKeys.keyMac = Kmac;
paceKeys.keyEnc = Kenc;
Console.WriteLine("Pace object : keyMac et keyEnc " + paceKeys.keyMac + " " + paceKeys.keyEnc);
if (paceKeys.keyMac != null || paceKeys.keyEnc != null)
{
sm = new SecureMessaging(StringUtils.ToByteArray(Kmac), StringUtils.ToByteArray(Kenc));
return paceKeys;
}
else
{
String VerifyPUK = executeCommande("00200089083132333435363738");
Console.WriteLine("Verify PUK : " +VerifyPUK);
this.sendSelectApplet();
this.initiatePaceGenMapping();
}
}
else
{
String VerifyPUK = executeCommande("00200089083132333435363738");
Console.WriteLine("Verify PUK : " + VerifyPUK);
this.sendSelectApplet();
this.initiatePaceGenMapping();
}
}
else
{
String VerifyPUK = executeCommande("00200089083132333435363738");
Console.WriteLine("Verify PUK : " + VerifyPUK);
this.sendSelectApplet();
this.initiatePaceGenMapping();
}
}
}
}
return paceKeys;
}
This method works correctly on C#, it consists of exchanging keys between a terminal and a smart card.
I can read secure smart cards with PACE GENERIC MAPPING.