Ejemplo n.º 1
0
        private GPKeySet DeriveSessionKeysSCP03(GPKeySet staticKeys, byte[] host_challenge, byte[] card_challenge)
        {
            GPKeySet sessionKeys   = new GPKeySet();
            byte     mac_constant  = 0x06;
            byte     enc_constant  = 0x04;
            byte     rmac_constant = 0x07;

            byte[] context = Arrays.Concatenate(host_challenge, card_challenge);

            // MAC
            byte[] kdf = SCP03Wrapper.Scp03_kdf(staticKeys.GetKey(KeySessionType.MAC), mac_constant, context, 128);
            sessionKeys.SetKey(KeySessionType.MAC, new GPKey(kdf, KeyType.AES));
            // ENC
            kdf = SCP03Wrapper.Scp03_kdf(staticKeys.GetKey(KeySessionType.ENC), enc_constant, context, 128);
            sessionKeys.SetKey(KeySessionType.ENC, new GPKey(kdf, KeyType.AES));
            // RMAC
            kdf = SCP03Wrapper.Scp03_kdf(staticKeys.GetKey(KeySessionType.MAC), rmac_constant, context, 128);
            sessionKeys.SetKey(KeySessionType.RMAC, new GPKey(kdf, KeyType.AES));

            // KEK remains the same
            sessionKeys.SetKey(KeySessionType.KEK, staticKeys.GetKey(KeySessionType.KEK));
            return(sessionKeys);
        }
Ejemplo n.º 2
0
        public void OpenSecureChannel(GPPlaintextKeys keys, List <APDUMode> securityLevel, byte[] hostChallenge = null, byte[] initUpdateResponse = null, byte[] externalAuthReponse = null)
        {
            if (securityLevel.Contains(APDUMode.ENC) && !securityLevel.Contains(APDUMode.MAC))
            {
                securityLevel.Add(APDUMode.MAC);
            }

            if (hostChallenge == null)
            {
                // Generate host challenge
                hostChallenge = new byte[8];
                SecureRandom sr = new SecureRandom();
                sr.NextBytes(hostChallenge);
            }

            GPInitializeUpdateReqest initUpdate = new GPInitializeUpdateReqest(keys.GetKeysetVersion(), keys.GetKeysetID(), hostChallenge);
            //System.Diagnostics.Debug.WriteLine(initUpdate.ToPrintString());
            GPInitializeUpdateResponse response;

            if (initUpdateResponse != null)
            {
                response = new GPInitializeUpdateResponse();
                response.Deserialize(initUpdateResponse);
                System.Diagnostics.Debug.WriteLine(response.ToPrintString());
            }
            else
            {
                response = (GPInitializeUpdateResponse)SendCommand(initUpdate);
            }


            // Detect and report locked cards in a more sensible way.
            if ((response.SW == (ushort)ISO7816ReturnCodes.SW_SECURITY_STATUS_NOT_SATISFIED) || (response.SW == (ushort)ISO7816ReturnCodes.SW_AUTHENTICATION_METHOD_BLOCKED))
            {
                throw new Exception("INITIALIZE UPDATE failed, Card possibly locked.");
            }

            if (response.SW != (ushort)ISO7816ReturnCodes.SW_NO_ERROR)
            {
                throw new Exception("INITIALIZE UPDATE failed");
            }

            // Verify response length (SCP01/SCP02 + SCP03 + SCP03 w/ pseudorandom)
            if (response.ResponseData.Length != 28 && response.ResponseData.Length != 29 && response.ResponseData.Length != 32)
            {
                throw new Exception("Invalid INITIALIZE UPDATE response length: " + response.ResponseData.Length);
            }

            System.Diagnostics.Debug.WriteLine("Host challenge: " + Formatting.ByteArrayToHexString(hostChallenge));
            System.Diagnostics.Debug.WriteLine("Card challenge: " + Formatting.ByteArrayToHexString(response.CardChallenge));

            // Verify response
            // If using explicit key version, it must match.
            if ((keys.GetKeysetVersion() > 0) && (response.KeyVersionNumber != keys.GetKeysetVersion()))
            {
                throw new Exception("Key version mismatch: " + keys.GetKeysetVersion() + " != " + response.KeyVersionNumber);
            }

            System.Diagnostics.Debug.WriteLine("Card reports SCP0" + response.SCPId + " with version " + response.KeyVersionNumber + " keys");
            if (response.SCPId == 3)
            {
                System.Diagnostics.Debug.WriteLine("SCP03 i=" + response.SCPI);
            }

            SCPVersions scpVersion;
            // Derive session keys
            GPKeySet sessionKeys;

            if (response.SCPId == 1)
            {
                if (securityLevel.Contains(APDUMode.RMAC))
                {
                    throw new Exception("SCP01 does not support RMAC");
                }

                scpVersion  = SCPVersions.SCP_01_05;
                sessionKeys = keys.GetSessionKeys(response.SCPId, response.KeyDiversificationData, hostChallenge, response.CardChallenge);
            }
            else if (response.SCPId == 2)
            {
                scpVersion  = SCPVersions.SCP_02_15;
                sessionKeys = keys.GetSessionKeys(response.SCPId, response.KeyDiversificationData, response.CardChallengeSeq);
            }
            else if (response.SCPId == 3)
            {
                scpVersion  = SCPVersions.SCP_03;
                sessionKeys = keys.GetSessionKeys(response.SCPId, response.KeyDiversificationData, hostChallenge, response.CardChallenge);
            }
            else
            {
                throw new Exception("Unsupported scpVersion: " + response.SCPId);
            }

            // Verify card cryptogram
            byte[] my_card_cryptogram = null;
            byte[] cntx;
            if (response.SCPId == 2)
            {
                cntx = Formatting.ConcatArrays(hostChallenge, response.CardChallengeSeq, response.CardChallenge);
            }
            else
            {
                cntx = Arrays.Concatenate(hostChallenge, response.CardChallenge);
            }

            if (response.SCPId == 1 || response.SCPId == 2)
            {
                my_card_cryptogram = SCP0102Wrapper.Mac_3des_nulliv(sessionKeys.GetKey(KeySessionType.ENC), cntx);
            }
            else
            {
                my_card_cryptogram = SCP03Wrapper.Scp03_kdf(sessionKeys.GetKey(KeySessionType.MAC), (byte)0x00, cntx, 64);
            }

            // This is the main check for possible successful authentication.
            if (!Arrays.AreEqual(response.CardCryptogram, my_card_cryptogram))
            {
                string message = "Card cryptogram invalid." +
                                 "\nCard: " + Formatting.ByteArrayToHexString(response.CardCryptogram) +
                                 "\nCalculated: " + Formatting.ByteArrayToHexString(my_card_cryptogram) +
                                 "\nRetrying the same parameters may disable the card";

                System.Diagnostics.Debug.WriteLine(message);
                throw new Exception(message);
            }
            else
            {
                System.Diagnostics.Debug.WriteLine("Verified card cryptogram: " + Formatting.ByteArrayToHexString(my_card_cryptogram));
            }

            // Calculate host cryptogram and initialize SCP wrapper
            byte[] host_cryptogram = null;
            if (response.SCPId == 1 || response.SCPId == 2)
            {
                if (response.SCPId == 2)
                {
                    host_cryptogram = SCP0102Wrapper.Mac_3des_nulliv(sessionKeys.GetKey(KeySessionType.ENC), Formatting.ConcatArrays(response.CardChallengeSeq, response.CardChallenge, hostChallenge));
                }
                else
                {
                    host_cryptogram = SCP0102Wrapper.Mac_3des_nulliv(sessionKeys.GetKey(KeySessionType.ENC), Arrays.Concatenate(response.CardChallenge, hostChallenge));
                }
                wrapper = new SCP0102Wrapper(sessionKeys, scpVersion, new List <APDUMode>()
                {
                    APDUMode.MAC
                }, null, null, blockSize);
            }
            else
            {
                host_cryptogram = SCP03Wrapper.Scp03_kdf(sessionKeys.GetKey(KeySessionType.MAC), (byte)0x01, cntx, 64);
                wrapper         = new SCP03Wrapper(sessionKeys, scpVersion, new List <APDUMode>()
                {
                    APDUMode.MAC
                }, null, null, blockSize);
            }
            System.Diagnostics.Debug.WriteLine("Calculated host cryptogram: " + Formatting.ByteArrayToHexString(host_cryptogram));

            GPExternalAuthenticateReqest   externalAuthenticate = new GPExternalAuthenticateReqest(GetSetValue(securityLevel), host_cryptogram);
            GPExternalAuthenticateResponse response2;

            if (externalAuthReponse != null)
            {
                response2 = new GPExternalAuthenticateResponse();
                response2.Deserialize(externalAuthReponse);
                System.Diagnostics.Debug.WriteLine(response2.ToPrintString());
            }
            else
            {
                response2 = (GPExternalAuthenticateResponse)SendCommand(externalAuthenticate);
            }


            if (response2.SW != (ushort)ISO7816ReturnCodes.SW_NO_ERROR)
            {
                throw new Exception("External authenticate failed");
            }

            wrapper.SetSecurityLevel(securityLevel);
        }