예제 #1
0
        public static void AddSDADDataToDatabase(KernelDatabaseBase database, ICCDynamicData iccdd)
        {
            if (iccdd.ApplicationCryptogram != null)
            {
                TLV ac = database.Get(EMVTagsEnum.APPLICATION_CRYPTOGRAM_9F26_KRN);
                if (ac == null)
                {
                    ac = TLV.Create(EMVTagsEnum.APPLICATION_CRYPTOGRAM_9F26_KRN.Tag);
                }
                ac.Value = iccdd.ApplicationCryptogram;
                database.AddToList(ac);
            }

            TLV iccdn = database.Get(EMVTagsEnum.ICC_DYNAMIC_NUMBER_9F4C_KRN);

            if (iccdn == null)
            {
                iccdn = TLV.Create(EMVTagsEnum.ICC_DYNAMIC_NUMBER_9F4C_KRN.Tag);
            }
            iccdn.Value = iccdd.ICCDynamicNumber;
            database.AddToList(iccdn);
        }
예제 #2
0
        public static ICCDynamicData VerifySDAD(ICCDynamicDataType iccDDType, KernelDatabaseBase database, CAPublicKeyCertificate caPublicKey, byte[] sdadRaw)
        {
            //section 6.5.2 of EMV book 2 - DDA

            //1.If the Signed Dynamic Application Data has a length different from the
            //length of the ICC Public Key Modulus, CDA has failed
            IssuerPublicKeyCertificate ipk = IssuerPublicKeyCertificate.BuildAndValidatePublicKey(database, caPublicKey.Modulus, caPublicKey.Exponent);

            if (ipk == null)
            {
                return(null);
            }
            IccPublicKeyCertificate iccpk = IccPublicKeyCertificate.BuildAndValidatePublicKey(database, database.StaticDataToBeAuthenticated, ipk.Modulus, ipk.Exponent);

            if (iccpk == null)
            {
                return(null);
            }

            if (sdadRaw.Length != iccpk.Modulus.Length)
            {
                return(null);
            }

            //2.To obtain the recovered data specified in Table 22, apply the recovery
            //function as specified in Annex A2.1 on the Signed Dynamic Application
            //Data using the ICC Public Key in conjunction with the corresponding
            //algorithm.If the Recovered Data Trailer is not equal to 'BC', CDA has
            //failed
            byte[] decrypted = PublicKeyCertificate.DecryptRSA(sdadRaw, iccpk.Modulus, iccpk.Exponent);
            SDAD   sdad      = new SDAD(decrypted);

            //3.Check the Recovered Data Header. If it is not '6A', CDA has failed.
            if (sdad.DataHeader != 0x6A)
            {
                return(null);
            }
            //4.Check the Signed Data Format. If it is not '05', CDA has failed.
            //For Visa specialpurpose readers it may return 0x95 iff offline data authentication is supported for online transactions (in the TTQ)
            if (sdad.SignedDataFormat != 0x05 && sdad.SignedDataFormat != 0x95)
            {
                return(null);
            }

            ICCDynamicData iccDD = new ICCDynamicData(database, sdad.ICCDynamicData, iccDDType);

            //5.Concatenate from left to right the second to the sixth data elements in
            //Table 17(that is, Signed Data Format through Pad Pattern), followed by
            //the data elements specified by the DDOL.
            TLV ddol = database.Get(EMVTagsEnum.DYNAMIC_DATA_AUTHENTICATION_DATA_OBJECT_LIST_DDOL_9F49_KRN);

            byte[] ddolRelatedData;
            if (ddol == null)
            {
                TLV unpred = database.Get(EMVTagsEnum.UNPREDICTABLE_NUMBER_9F37_KRN);
                unpred.Val.PackValue(unpred.Val.GetLength());
                ddolRelatedData = unpred.Value;
            }
            else
            {
                ddolRelatedData = CommonRoutines.PackRelatedDataTag(database, ddol);
            }

            byte[] dataForHash = sdad.Concat(ddolRelatedData);

            //6.Apply the indicated hash algorithm(derived from the Hash Algorithm
            //Indicator) to the result of the concatenation of the previous step to
            //produce the hash result.
            byte[] hash = SHA1.Create().ComputeHash(dataForHash);


            //7.Compare the calculated hash result from the previous step with the
            //recovered Hash Result.If they are not the same, DDA has failed.
            if (Formatting.ByteArrayToHexString(sdad.HashResult) != Formatting.ByteArrayToHexString(hash))
            {
                return(null);
            }

            return(iccDD);
        }
예제 #3
0
        public static ICCDynamicData VerifySDAD(ICCDynamicDataType iccDDType, bool isFirstGenAC, KernelDatabaseBase database, StaticDataToBeAuthenticatedList staticDataToBeAuthenticated, CAPublicKeyCertificate caPublicKey, CardResponse genACCardResponse)
        {
            EMVGenerateACResponse genAcResponse = (genACCardResponse.ApduResponse as EMVGenerateACResponse);

            //section 6.6.2 of EMV book 2 - CDA

            //1.If the Signed Dynamic Application Data has a length different from the
            //length of the ICC Public Key Modulus, CDA has failed
            byte[] sdadRaw = genAcResponse.SignedDynamicApplicationData.Value;
            IssuerPublicKeyCertificate ipk = IssuerPublicKeyCertificate.BuildAndValidatePublicKey(database, caPublicKey.Modulus, caPublicKey.Exponent);

            if (ipk == null)
            {
                return(null);
            }
            IccPublicKeyCertificate iccpk = IccPublicKeyCertificate.BuildAndValidatePublicKey(database, staticDataToBeAuthenticated, ipk.Modulus, ipk.Exponent);

            if (iccpk == null)
            {
                return(null);
            }

            if (sdadRaw.Length != iccpk.Modulus.Length)
            {
                return(null);
            }

            //2.To obtain the recovered data specified in Table 22, apply the recovery
            //function as specified in Annex A2.1 on the Signed Dynamic Application
            //Data using the ICC Public Key in conjunction with the corresponding
            //algorithm.If the Recovered Data Trailer is not equal to 'BC', CDA has
            //failed
            byte[] decrypted = PublicKeyCertificate.DecryptRSA(sdadRaw, iccpk.Modulus, iccpk.Exponent);
            SDAD   sdad      = new SDAD(decrypted);

            //3.Check the Recovered Data Header. If it is not '6A', CDA has failed.
            if (sdad.DataHeader != 0x6A)
            {
                return(null);
            }
            //4.Check the Signed Data Format. If it is not '05', CDA has failed.
            if (sdad.SignedDataFormat != 0x05)
            {
                return(null);
            }

            //5. Retrieve from the ICC Dynamic Data the data specified in Table 19
            ICCDynamicData iccDD = new ICCDynamicData(database, sdad.ICCDynamicData, iccDDType);

            //6.Check that the Cryptogram Information Data retrieved from the ICC
            //Dynamic Data is equal to the Cryptogram Information Data obtained from
            //the response to the GENERATE AC command. If this is not the case, CDA
            //has failed.
            if (genAcResponse.CryptogramInformationData.Value[0] != iccDD.CryptogramInformationData)
            {
                return(null);
            }

            //7.Concatenate from left to right the second to the sixth data elements in
            //Table 22(that is, Signed Data Format through Pad Pattern), followed by
            //the Unpredictable Number.
            byte[] unpredicatbleNumber = database.Get(EMVTagsEnum.UNPREDICTABLE_NUMBER_9F37_KRN).Value;
            byte[] dataForHash         = sdad.Concat(unpredicatbleNumber);

            //8.Apply the indicated hash algorithm (derived from the Hash Algorithm
            //Indicator) to the result of the concatenation of the previous step to
            //produce the hash result.
            byte[] hash = SHA1.Create().ComputeHash(dataForHash);

            //9.Compare the calculated hash result from the previous step with the
            //recovered Hash Result.If they are not the same, CDA has failed.
            if (Formatting.ByteArrayToHexString(sdad.HashResult) != Formatting.ByteArrayToHexString(hash))
            {
                return(null);
            }

            //10. Concatenate from left to right the values of the following data elements:
            List <byte[]> result = new List <byte[]>();

            if (isFirstGenAC)
            {
                //-The values of the data elements specified by, and in the order they
                //appear in the PDOL, and sent by the terminal in the GET
                //PROCESSING OPTIONS command.
                result.Add(database.Get(EMVTagsEnum.PDOL_RELATED_DATA_DF8111_KRN2).Value);
                //-The values of the data elements specified by, and in the order they
                //appear in the CDOL1, and sent by the terminal in the first
                //GENERATE AC command.
                result.Add(database.Get(EMVTagsEnum.CDOL1_RELATED_DATA_DF8107_KRN2).Value);
                //-The tags, lengths, and values of the data elements returned by the ICC
                //in the response to the GENERATE AC command in the order they are
                //returned, with the exception of the Signed Dynamic Application Data.
                foreach (TLV tlv in genAcResponse.GetResponseTags())
                {
                    if (tlv.Tag.TagLable != EMVTagsEnum.SIGNED_DYNAMIC_APPLICATION_DATA_9F4B_KRN.Tag)
                    {
                        result.Add(tlv.Serialize());
                    }
                }
            }
            else
            {
                //-The values of the data elements specified by, and in the order they
                //appear in the PDOL, and sent by the terminal in the GET
                //PROCESSING OPTIONS command.
                result.Add(database.Get(EMVTagsEnum.PDOL_RELATED_DATA_DF8111_KRN2).Value);
                //-The values of the data elements specified by, and in the order they
                //appear in the CDOL1, and sent by the terminal in the first
                //GENERATE AC command.
                result.Add(database.Get(EMVTagsEnum.CDOL1_RELATED_DATA_DF8107_KRN2).Value);
                //-The values of the data elements specified by, and in the order they
                //appear in the CDOL2, and sent by the terminal in the second
                //GENERATE AC command.
                TLV cdol2 = database.Get(EMVTagsEnum.CARD_RISK_MANAGEMENT_DATA_OBJECT_LIST_2_CDOL2_8D_KRN);
                if (cdol2 != null)
                {
                    result.Add(CommonRoutines.PackRelatedDataTag(database, cdol2));
                }
                //-The tags, lengths, and values of the data elements returned by the ICC
                //in the response to the GENERATE AC command in the order they are
                //returned, with the exception of the Signed Dynamic Application Data.
                foreach (TLV tlv in genAcResponse.GetResponseTags())
                {
                    if (tlv.Tag.TagLable != EMVTagsEnum.SIGNED_DYNAMIC_APPLICATION_DATA_9F4B_KRN.Tag)
                    {
                        result.Add(tlv.Serialize());
                    }
                }
            }
            byte[] transactionHashData = result.SelectMany(a => a).ToArray();

            //11.Apply the indicated hash algorithm (derived from the Hash Algorithm
            //Indicator) to the result of the concatenation of the previous step to
            //produce the Transaction Data Hash Code.
            byte[] transactionHash = SHA1.Create().ComputeHash(transactionHashData);

            //12.Compare the calculated Transaction Data Hash Code from the previous
            //step with the Transaction Data Hash Code retrieved from the ICC
            //Dynamic Data in Step 5.If they are not the same, CDA has failed.
            if (Formatting.ByteArrayToHexString(iccDD.TransactionDataHashCode) != Formatting.ByteArrayToHexString(transactionHash))
            {
                return(null);
            }

            return(iccDD);
        }
예제 #4
0
        public static ICCDynamicData VerifySDAD_K3(ICCDynamicDataType iccDDType, KernelDatabaseBase database, CAPublicKeyCertificate caPublicKey, byte[] sdadRaw)
        {
            //section 6.5.2 of EMV book 2 - DDA

            //1.If the Signed Dynamic Application Data has a length different from the
            //length of the ICC Public Key Modulus, CDA has failed
            IssuerPublicKeyCertificate ipk = IssuerPublicKeyCertificate.BuildAndValidatePublicKey(database, caPublicKey.Modulus, caPublicKey.Exponent);

            if (ipk == null)
            {
                return(null);
            }
            IccPublicKeyCertificate iccpk = IccPublicKeyCertificate.BuildAndValidatePublicKey(database, database.StaticDataToBeAuthenticated, ipk.Modulus, ipk.Exponent);

            if (iccpk == null)
            {
                return(null);
            }

            if (sdadRaw.Length != iccpk.Modulus.Length)
            {
                return(null);
            }

            //2.To obtain the recovered data specified in Table 22, apply the recovery
            //function as specified in Annex A2.1 on the Signed Dynamic Application
            //Data using the ICC Public Key in conjunction with the corresponding
            //algorithm.If the Recovered Data Trailer is not equal to 'BC', CDA has
            //failed
            byte[] decrypted = PublicKeyCertificate.DecryptRSA(sdadRaw, iccpk.Modulus, iccpk.Exponent);
            SDAD   sdad      = new SDAD(decrypted);

            //3.Check the Recovered Data Header. If it is not '6A', CDA has failed.
            if (sdad.DataHeader != 0x6A)
            {
                return(null);
            }
            //4.Check the Signed Data Format. If it is not '05', CDA has failed.
            //For Visa specialpurpose readers it may return 0x95 iff offline data authentication is supported for online transactions (in the TTQ)
            if (sdad.SignedDataFormat != 0x05 && sdad.SignedDataFormat != 0x95)
            {
                return(null);
            }

            ICCDynamicData iccDD = new ICCDynamicData(database, sdad.ICCDynamicData, iccDDType);

            //5.Concatenate from left to right the second to the sixth data elements in
            //Table 17(that is, Signed Data Format through Pad Pattern), followed by
            //the data elements specified by the DDOL.

            //C.1 K3 Kernel wants it done this way rather than they way sepecified in step 5
            //The Terminal Dynamic Data elements input to the hash algorithm shall be as
            //specified in Table C-1 instead of being specified in the DDOL(as the DDOL is
            //not a recognized data element for Kernel 3).The kernel may treat the tags
            //specified in Table C-1 as default DDOLs for fDDA version '01'
            List <byte[]> hashList = new List <byte[]>
            {
                database.Get(EMVTagsEnum.UNPREDICTABLE_NUMBER_9F37_KRN).Value,
                database.Get(EMVTagsEnum.AMOUNT_AUTHORISED_NUMERIC_9F02_KRN).Value,
                database.Get(EMVTagsEnum.TRANSACTION_CURRENCY_CODE_5F2A_KRN).Value,
                database.Get(EMVTagsEnum.CARD_AUTHENTICATION_RELATED_DATA_9F69_KRN3).Value
            };

            //6.Apply the indicated hash algorithm(derived from the Hash Algorithm
            //Indicator) to the result of the concatenation of the previous step to
            //produce the hash result.
            byte[] dataForHash = sdad.Concat(hashList.SelectMany(x => x).ToArray());
            byte[] hash        = SHA1.Create().ComputeHash(dataForHash);


            //7.Compare the calculated hash result from the previous step with the
            //recovered Hash Result.If they are not the same, DDA has failed.
            if (Formatting.ByteArrayToHexString(sdad.HashResult) != Formatting.ByteArrayToHexString(hash))
            {
                return(null);
            }

            return(iccDD);
        }