private void ComputeSessionKeys(JavaCardKeys keys, ByteArray terminalRandom, ByteArray cardRandom) { //scp01 ByteArray dataDiversifier = cardRandom.LSB(4) + terminalRandom.MSB(4) + cardRandom.MSB(4) + terminalRandom.LSB(4); _sessionKeys = new JavaCardKeys(); _sessionKeys.AuthEncKey = dataDiversifier.EncodeAsData(keys.AuthEncKey, new ByteArray(8), PaddingMode.None, CipherMode.ECB); _sessionKeys.SignKey = dataDiversifier.EncodeAsData(keys.SignKey, new ByteArray(8), PaddingMode.None, CipherMode.ECB); _sessionKeys.KEKKey = keys.KEKKey; Logger.Log("[JavaCard] Liczenie kluczy sesyjnych\n{0}:\t{1}\n{2}:\t{3}\n{4}:\t{5}", "Auth/Enc", _sessionKeys.AuthEncKey, "Mac", _sessionKeys.SignKey, "Kek", _sessionKeys.KEKKey); }
private void ComputeSessionKeys2(JavaCardKeys keys, ByteArray terminalRandom, ByteArray cardRandom) { _sessionKeys = new JavaCardKeys(); ByteArray dataDiversifierAuthEnc = new ByteArray("0182") + cardRandom.MSB(2) + new ByteArray(12); _sessionKeys.AuthEncKey = dataDiversifierAuthEnc.EncodeAsData(keys.AuthEncKey, new ByteArray(8), PaddingMode.None, CipherMode.CBC); ByteArray dataDiversifierSignC = new ByteArray("0101") + cardRandom.MSB(2) + new ByteArray(12); _sessionKeys.SignKeyC = dataDiversifierSignC.EncodeAsData(keys.SignKey, new ByteArray(8), PaddingMode.None, CipherMode.CBC); ByteArray dataDiversifierSignR = new ByteArray("0102") + cardRandom.MSB(2) + new ByteArray(12); _sessionKeys.SignKeyR = dataDiversifierSignR.EncodeAsData(keys.SignKey, new ByteArray(8), PaddingMode.None, CipherMode.CBC); ByteArray dataDiversifierKEK = new ByteArray("0181") + cardRandom.MSB(2) + new ByteArray(12); _sessionKeys.KEKKey = dataDiversifierKEK.EncodeAsData(keys.KEKKey, new ByteArray(8), PaddingMode.None, CipherMode.CBC); Logger.Log("[JavaCard] Liczenie kluczy sesyjnych\n{0}:\t{1}\n{2}:\t{3}\n{4}:\t{5}\n{6}:\t{7}", "Auth/Enc", _sessionKeys.AuthEncKey, "Mac-C", _sessionKeys.SignKeyC, "Mac-R", _sessionKeys.SignKeyR, "Kek", _sessionKeys.KEKKey); }
/// <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); }
public void PutKeysStoreData(Byte currentKeySetVersion, Byte newKeySetVersion, JavaCardKeys newKeys, KeyAlgorithm cryptAlgorithm) { //komenda PutKey ByteArray command = new ByteArray("80 e2 88 00"); ByteArray keysField = new ByteArray(); ByteArray kcvField = new ByteArray(); foreach (ByteArray key in new ByteArray[3] { newKeys.AuthEncKey, newKeys.SignKey, newKeys.KEKKey }) { //klucz zaszyfrowany kluczem KEK var x = key.EncodeAsData(_sessionKeys.KEKKey, new ByteArray(8), PaddingMode.None, CipherMode.ECB); keysField += x; //check value, 3 najbardziej znaczące bajty z operacji szyfrowania danych w postaci 8 bajtów o wartości 0x00 kluczem do załadowania var kcv = GetKcv(key); kcvField += kcv; } //tworzymy pole z danymi ByteArray dataField = new ByteArray(); dataField += "8F 01 30"; //with length dataField += keysField; dataField += "7F 01 0C"; //with length dataField += currentKeySetVersion; dataField += newKeySetVersion; dataField += (byte)cryptAlgorithm; dataField += kcvField; //ustawiamy w komendzie długość pola z danymi (Lc) command += (Byte)dataField.Length; //dodajemy pole z danymi (Data) command += dataField; //Le //command += 0x0a; //command += 0x00; //wysyłamy komendę SendSecuredCommand(command); }
public void PutKeys(Byte currentKeySetVersion, Byte newKeySetVersion, JavaCardKeys newKeys, KeyAlgorithm cryptAlgorithm, Boolean extraDataByte) { //komenda PutKey ByteArray command = new ByteArray("80 d8 00 81"); command[2] = currentKeySetVersion; //obliczamy pola z kluczami ByteArray keyStructures = new ByteArray(); foreach (ByteArray key in new ByteArray[3] { newKeys.AuthEncKey, newKeys.SignKey, newKeys.KEKKey }) { ByteArray keyStructure = new ByteArray(); //identyfikator algorytmu keyStructure += (byte)cryptAlgorithm; //długość klucza keyStructure += (Byte)key.Length; //klucz zaszyfrowany kluczem KEK keyStructure += key.EncodeAsData(_sessionKeys.KEKKey, new ByteArray(8), PaddingMode.None, CipherMode.ECB); //długość sumy kontrolnej keyStructure += 0x03; //check value, 3 najbardziej znaczące bajty z operacji szyfrowania danych w postaci 8 bajtów o wartości 0x00 kluczem do załadowania keyStructure += new ByteArray(8).EncodeAsData(key, new ByteArray(8), PaddingMode.None, CipherMode.ECB).MSB(3); keyStructures += keyStructure; } //tworzymy pole z danymi ByteArray dataField = new ByteArray(); //nowa wersja klucza dataField += newKeySetVersion; //pola z kluczami dataField += keyStructures; //znacznik końca pola z danymi (opcjonalny) if (extraDataByte) { dataField += 0xff; } //ustawiamy w komendzie długość pola z danymi (Lc) command += (Byte)dataField.Length; //dodajemy pole z danymi (Data) command += dataField; //Le //command += 0x0a; //command += 0x00; //wysyłamy komendę SendSecuredCommand(command); }
/// <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); }