private ByteArray GenerateExAuthMAC(ByteArray command, ByteArray terminalCryptogram) { ByteArray input = command.Extract(0, 5) + terminalCryptogram + new ByteArray("80 00 00"); ByteArray result = input.EncodeAsData(_sessionKeys.SignKey, new ByteArray(8), PaddingMode.None, CipherMode.CBC); return(result.LSB(8)); }
private ByteArray GenerateExAuthMAC2(ByteArray command, ByteArray terminalCryptogram) { ByteArray input = command.Extract(0, 5) + terminalCryptogram + new ByteArray("80 00 00"); ByteArray mac_key_left = _sessionKeys.SignKey.MSB(8); //MSB mac key ByteArray mac_key_right = _sessionKeys.SignKey.LSB(8); ByteArray iv = new ByteArray(8, 0x00); //ByteArray result = input.EncodeAsData(SessionKeys.SignKey, new ByteArray(8), PaddingMode.None, CipherMode.CBC); //ByteArray result = input.EncodeAsData(mac_key_left + mac_key_right, iv, PaddingMode.None, CipherMode.CBC); //ByteArray result_comp = result.LSB(8); ByteArray apdu_left = input.MSB(8); ByteArray apdu_right = input.LSB(8); ByteArray result1 = apdu_left.SimpleEncodeAsData(mac_key_left, iv, PaddingMode.None, CipherMode.CBC); ByteArray result2 = result1.XOR(apdu_right); ByteArray result3 = result2.SimpleEncodeAsData(mac_key_left, iv, PaddingMode.None, CipherMode.CBC); ByteArray result4 = result3.SimpleDecodeAsData(mac_key_right, iv, PaddingMode.None, CipherMode.CBC); ByteArray result5 = result4.SimpleEncodeAsData(mac_key_left, iv, PaddingMode.None, CipherMode.CBC); Logger.Log("[JavaCard] Wyliczanie MAC dla APDU {0} (kolejne wyniki algorytmu DES)\n{1}\n{2}\n{3}\n{4}\n{5}", input, result1, result2, result3, result4, result5); return(result5); }
/// <summary> /// Dywersyfikuje klucze CM metodą GPIC_Serial /// </summary> /// <param name="motherKey">Klucz matka do dywersyfikacji</param> /// <param name="initUpdateResponse"> </param> /// <returns>Klucze Auth, Sign, KEK</returns> public JavaCardKeys GPICSerialDiversificate(ByteArray motherKey, ByteArray initUpdateResponse) { ByteArray diversificationData = initUpdateResponse.Extract(0, 2) + initUpdateResponse.Extract(4, 4); ByteArray[] keys = new ByteArray[3]; ByteArray authEncDivData = diversificationData + new ByteArray("f0 01") + diversificationData + new ByteArray("0f 01"); keys[0] = authEncDivData.EncodeAsData(motherKey, new ByteArray(8), PaddingMode.None, CipherMode.ECB); ByteArray sigDivData = diversificationData + new ByteArray("f0 02") + diversificationData + new ByteArray("0f 02"); keys[1] = sigDivData.EncodeAsData(motherKey, new ByteArray(8), PaddingMode.None, CipherMode.ECB); ByteArray kekDivData = diversificationData + new ByteArray("f0 03") + diversificationData + new ByteArray("0f 03"); keys[2] = kekDivData.EncodeAsData(motherKey, new ByteArray(8), PaddingMode.None, CipherMode.ECB); return(new JavaCardKeys(keys)); }
public static ByteArray Encrypt(ByteArray data, ByteArray key, ref ByteArray iv) { using (var memoryStream = new MemoryStream()) { using (var aes = new AesManaged { Key = key.ByteData, IV = iv.ByteData, Padding = PaddingMode.None, Mode = CipherMode.CBC }) { using (var cryptoStream = new CryptoStream(memoryStream, aes.CreateEncryptor(), CryptoStreamMode.Write)) { cryptoStream.Write(data.ByteData, 0, data.Length); } } ByteArray result = new ByteArray(memoryStream.ToArray()); iv = new ByteArray(result.Extract(result.Length - 16, 16).ByteData); return(result); } }
public static ByteArray Decrypt(ByteArray encrypted, ByteArray key, ref ByteArray iv) { using (var memoryStream = new MemoryStream(encrypted.ByteData)) { using (var aes = new AesManaged { Key = key.ByteData, IV = iv.ByteData, Padding = PaddingMode.None, Mode = CipherMode.CBC }) { using (var cryptoStream = new CryptoStream(memoryStream, aes.CreateDecryptor(), CryptoStreamMode.Read)) { byte[] decrypt = new byte[encrypted.Length]; cryptoStream.Read(decrypt, 0, decrypt.Length); ByteArray result = new ByteArray(decrypt); iv = new ByteArray(encrypted.Extract(encrypted.Length - 16, 16).ByteData); return(result); } } } }
public ByteArray ListApplications() { // p1 = 80, 40, 20, 10 // p2 = xxxxxxx0 - first or all, xxxxxxx1 - next, xxxxxx0x - less info, xxxxxx1x - more info try { ByteArray apdu = new ByteArray("80 F2 80 00 02 4F 00 00"); ByteArray response = SendSecuredCommand(apdu); //return response; apdu = new ByteArray("80 F2 40 00 02 4F 00 00"); response = SendSecuredCommand(apdu); //return response; apdu = new ByteArray("80 F2 20 00 02 4F 00 00"); response = SendSecuredCommand(apdu); apdu = new ByteArray("80 F2 20 01 02 4F 00 00"); response = response.Extract(0, response.Length - 2); response += SendSecuredCommand(apdu); return(response); apdu = new ByteArray("80 F2 10 00 02 4F 00 00"); response = SendSecuredCommand(apdu); return(response); } catch (APDUException exception) { return(null); } }
/// <summary> /// Uwierzytelnia do CM podanym kluczem /// </summary> public JavaCardKeys StartSecuredChannel(ByteArray motherKey, KeyDiversificationMethod diversification = KeyDiversificationMethod.None, SecurityControlMode securityMode = SecurityControlMode.NoSecurity, byte keyVersion = 0x00, byte referenceControlParameter2 = 0x00) { try { //losowanie danych terminala ByteArray terminalRandom = new ByteArray(8); terminalRandom.Randomize(random); //Initialize Update ByteArray response = InitializeUpdate(keyVersion, 00, terminalRandom); //z odpowiedzi wyciągamy dane byte scpId = response[11]; if (scpId == 0x01) { scp = SecureChannelProtocol.SCP01; } else if (scpId == 0x02) { scp = SecureChannelProtocol.SCP02; } ByteArray sn = response.Extract(4, 4); ByteArray aid = response.Extract(0, 2); ByteArray cardRandom = response.Extract(12, 8); ByteArray cardCryptogram = response.Extract(20, 8); Logger.Log("[JavaCard] \n{0}:\t{1}\n{2}:\t{3}\n{4}:\t{5}\n{6}:\t{7}\n{8}:\t{9}", "TerminalRandom", terminalRandom, "SN", sn, "AID", aid, "CardRandom", cardRandom, "CardCryptogram", cardCryptogram); //wyliczanie kluczy z matki switch (diversification) { case KeyDiversificationMethod.None: Keys = new JavaCardKeys(motherKey); break; case KeyDiversificationMethod.GPICSN: Keys = GPICSerialDiversificate(motherKey, response); break; case KeyDiversificationMethod.MPCOS3DES: throw new Exception("Wybrany algorytm dywersyfikacji nie jest na razie wspierany"); break; case KeyDiversificationMethod.TagCF: Keys = TagCFDiversificate(motherKey, response); break; } //wyliczamy klucze sesyjne AUTH/ENC i MAC if (scp == SecureChannelProtocol.SCP01) { ComputeSessionKeys(Keys, terminalRandom, cardRandom); } else if (scp == SecureChannelProtocol.SCP02) { ComputeSessionKeys2(Keys, terminalRandom, cardRandom); } else { throw new Exception("Nieobsługiwany protokół bezpiecznego kanału"); } //weryfikujemy kryptogram zwrócony przez InitializeUpdate if (!CheckCardCryptogram(cardCryptogram, terminalRandom, cardRandom)) { throw new JavaCardAuthenticationException("Kryptogram zwrócony przez komendę InitializeUpdate nie zgadza się."); } //ExternalAuthenticate ByteArray externalAuthenticateCommand = new ByteArray("84 82") + (byte)securityMode + new ByteArray("00 10"); ByteArray terminalCryptogram = GenerateTerminalCryptogram(terminalRandom, cardRandom); ByteArray MAC = new ByteArray(); if (scp == SecureChannelProtocol.SCP01) { MAC = GenerateExAuthMAC(externalAuthenticateCommand, terminalCryptogram); } else if (scp == SecureChannelProtocol.SCP02) { MAC = GenerateExAuthMAC2(externalAuthenticateCommand, terminalCryptogram); } ByteArray fullExternalAuthenticateCommand = externalAuthenticateCommand + terminalCryptogram + MAC; Encoder.SendCommand(fullExternalAuthenticateCommand); _securityMode = securityMode; _lastMAC = MAC; _authenticatedKeySetVersion = response[10]; } catch (APDUException exception) { _sessionKeys = null; _securityMode = SecurityControlMode.NoSecurity; throw new JavaCardAuthenticationException("Błąd ustanowienia bezpiecznego kanału.", exception); } catch (Exception exception) { _sessionKeys = null; _securityMode = SecurityControlMode.NoSecurity; throw new JavaCardAuthenticationException("Błąd ustanowienia bezpiecznego kanału.", exception); } return(_sessionKeys); }
/// <summary> /// Wysyła polecenie apdu bezpiecznym kanałem /// </summary> /// <param name="command">apdu</param> /// <returns></returns> public ByteArray SendSecuredCommand(ByteArray command) { byte CLA, INS, P1, P2, Lc, Le; Boolean hasLe = false; ByteArray data = new ByteArray(); Logger.Log("[JavaCard] +> " + command); //rozbijamy APDU na części składowe CLA = command[0]; INS = command[1]; P1 = command[2]; P2 = command[3]; Lc = 0x00; Le = 0x00; if (command.Length == 5) { Le = command[4]; hasLe = true; } else if (command.Length > 5) { Lc = command[4]; data = command.Extract(5, Lc); if (command.Length > Lc + 5) { Le = command[command.Length - 1]; hasLe = true; } } ByteArray commandToSend = new ByteArray(command.ByteData); if (_securityMode == SecurityControlMode.MAC) { ByteArray toMac = new ByteArray(new byte[] { (byte)(CLA | 0x04), INS, P1, P2, (byte)(Lc + 8) }) + data; //Lc zwiększamy o 8 - długość MACa commandToSend = new ByteArray(toMac.StringData); //macujemy ByteArray macData = MacData(toMac); _lastMAC = macData.LSB(8); commandToSend += _lastMAC; if (hasLe) { commandToSend += Le; } } else if (_securityMode == SecurityControlMode.MACAndEncryption) { //szyfrujemy ByteArray toEncrypt = data; ByteArray encryptedData = EncryptData(toEncrypt); //macujemy ByteArray toMac = new ByteArray(new byte[] { (byte)(CLA | 0x04), INS, P1, P2, (byte)(Lc + 8) }) + data; ByteArray macData = MacData(toMac); _lastMAC = macData.LSB(8); commandToSend = new ByteArray(new byte[] { (byte)(CLA | 0x04), INS, P1, P2, (byte)(encryptedData.Length + _lastMAC.Length) }) + encryptedData + _lastMAC; if (hasLe) { commandToSend += Le; } } return(Encoder.SendCommand(commandToSend)); }
/// <summary> /// Uwierzytelnia do CM podanymi kluczami /// </summary> /// <param name="keys">Klucze</param> /// <param name="keySet"></param> /// <param name="keyIndex"></param> /// <param name="securityMode"></param> public JavaCardKeys StartSecuredChannel(JavaCardKeys keys, SecurityControlMode securityMode, Byte keySet = 0, Byte keyIndex = 0) { try { //losowanie danych terminala ByteArray terminalRandom = new ByteArray(8); terminalRandom.Randomize(random); //terminalRandom = new ByteArray("00 00 00 00 00 00 00 00"); //Initialize Update ByteArray initializeUpdateCommand = new ByteArray("80 50 00 00 08") + terminalRandom + new ByteArray("00"); initializeUpdateCommand[2] = keySet; initializeUpdateCommand[3] = keyIndex; ByteArray response = Encoder.SendCommand(initializeUpdateCommand); //z odpowiedzi wyciągamy losowe dane karty i kryptogram ByteArray cardRandom = response.Extract(12, 8); ByteArray cardCryptogram = response.Extract(20, 8); byte scpId = response[11]; if (scpId == 0x01) { scp = SecureChannelProtocol.SCP01; } else if (scpId == 0x02) { scp = SecureChannelProtocol.SCP02; } //wyliczamy klucze sesyjne AUTH/ENC i MAC if (scp == SecureChannelProtocol.SCP01) { ComputeSessionKeys(Keys, terminalRandom, cardRandom); } else if (scp == SecureChannelProtocol.SCP02) { ComputeSessionKeys2(Keys, terminalRandom, cardRandom); } else { throw new Exception("Nieobsługiwany protokół bezpiecznego kanału"); } //weryfikujemy kryptogram zwrócony przez InitializeUpdate if (!CheckCardCryptogram(cardCryptogram, terminalRandom, cardRandom)) { throw new JavaCardAuthenticationException("Kryptogram zwrócony przez komendę InitializeUpdate nie zgadza się."); } //ExternalAuthenticate ByteArray externalAuthenticateCommand = new ByteArray("84 82") + (byte)securityMode + new ByteArray("00 10"); ByteArray terminalCryptogram = GenerateTerminalCryptogram(terminalRandom, cardRandom); ByteArray MAC = GenerateExAuthMAC(externalAuthenticateCommand, terminalCryptogram); ByteArray fullExternalAuthenticateCommand = externalAuthenticateCommand + terminalCryptogram + MAC; Encoder.SendCommand(fullExternalAuthenticateCommand); _securityMode = securityMode; _lastMAC = MAC; _authenticatedKeySetVersion = response[10]; } catch (APDUException exception) { _sessionKeys = null; _securityMode = SecurityControlMode.NoSecurity; throw new JavaCardAuthenticationException("Błąd ustanowienia bezpiecznego kanału.", exception); } catch (Exception exception) { _sessionKeys = null; _securityMode = SecurityControlMode.NoSecurity; throw new JavaCardAuthenticationException("Błąd ustanowienia bezpiecznego kanału.", exception); } return(_sessionKeys); }
/// <summary> /// Wysyła do karty polecenie APDU /// </summary> /// <param name="command">Polecenie APDU</param> /// <param name="checkSuccessful">Ma sprawdzać, czy odpowiedź jest poprawna (90 00)</param> /// <exception cref="APDUException"></exception> /// <returns>Odpowiedź na polecenie APDU</returns> public ByteArray SendCommand(ByteArray command, bool checkSuccessful = true) { ConnectCard(false); CardCommandAPDU apdu = null; if (command.Length == 4) { apdu = new CardCommandAPDU(command[0], command[1], command[2], command[3]); } else if (command.Length == 5) { apdu = new CardCommandAPDU(command[0], command[1], command[2], command[3], command[4]); } else if (command.Length > 5) { ByteArray data = command.Extract(5, command[4]); int length = 5 + command[4]; if (length == command.Length) { apdu = new CardCommandAPDU(command[0], command[1], command[2], command[3], data.ByteData); } else { apdu = new CardCommandAPDU(command[0], command[1], command[2], command[3], data.ByteData, command[command.Length - 1]); } } if (apdu == null) { throw new Exception("Nieprawidłowa komenda APDU: " + command); } int tryCounter = 5; CardResponseAPDU response = null; do { try { Logger.Log("[Encoder] -> " + command); response = CardHandle.SendCommand(apdu); break; } catch (System.Runtime.InteropServices.COMException comException) { tryCounter--; if (tryCounter == 0) { throw new Exception("Sprzętowy błąd wykonywania komendy APDU (Message: " + comException.Message + ", HResult: " + comException.ErrorCode + ")"); } } catch (SCardException scException) { tryCounter--; if (tryCounter == 0) { throw new Exception("Sprzętowy błąd wykonywania komendy APDU (Kod: " + scException.ResponseCode + ").", scException); } } catch (Exception terminalException) { tryCounter--; if (tryCounter == 0) { throw new Exception("Sprzętowy błąd wykonywania komendy APDU.", terminalException); } } } while (true); ByteArray result = new ByteArray(response.GenerateBytes()); Logger.Log("[Encoder] <- " + result); if (checkSuccessful && !response.IsSuccessful && !response.IsWarning) { throw new APDUException("Błąd wykonywania komendy APDU", command, new ByteArray(response.GenerateBytes()), response.SW1, response.SW2); } return(result); }