Пример #1
0
        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);
        }
Пример #2
0
        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);
        }
Пример #3
0
        /// <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);
        }
Пример #4
0
        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);
        }
Пример #5
0
        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);
        }
Пример #6
0
        /// <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);
        }