private byte[] GenerateCryptogram(CryptogramType cryptogramType)
        {
            var data = new List <byte>();

            switch (cryptogramType)
            {
            case CryptogramType.Card:
                data.AddRange(this.HostChallenge);
                data.AddRange(this.SequenceCounter);
                data.AddRange(this.CardChallenge);
                break;

            case CryptogramType.Host:
                data.AddRange(this.SequenceCounter);
                data.AddRange(this.CardChallenge);
                data.AddRange(this.HostChallenge);
                break;
            }

            data.Pad();

            byte[] cryptogram = MAC.Algorithm1(data.ToArray(), this.EncryptionKey);

            return(cryptogram);
        }
Example #2
0
        /// <summary>
        /// Process the GENERATE APPLICATION CRYPTOGRAM 1 of an EMV transaction.
        /// </summary>
        /// <param name="cryptogramType">Type of the cryptogram to be generated.</param>
        /// <param name="unpredictableNumber">Unpredictable number.</param>
        /// <returns>Last status word.</returns>
        public UInt16 GenerateAc1(CryptogramType cryptogramType, byte[] unpredictableNumber)
        {
            BeforeGenerateAC1Event.Raise(this, new EmvEventArgs());

            _tlvGenerateAC1UnpredictableNumber = new TlvData(0x9F37, (uint)unpredictableNumber.Length, unpredictableNumber);

            _requestedAC1Type = cryptogramType;

            byte referenceControlParameter;

            switch (cryptogramType)
            {
            case CryptogramType.AAC:
                referenceControlParameter = 0x00;
                break;

            case CryptogramType.ARQC:
                referenceControlParameter = 0x80;
                break;

            case CryptogramType.TC:
                referenceControlParameter = 0x40;
                break;

            default:
                throw new Exception(String.Format("EMVApplication.generateAC1: bad Cryptogram Type [{0}]", cryptogramType));
            }

            // TODO: if CDA signature requested, set bit 5 to 1 (0x08)

            // Build CDOL1 data
            byte[] cdolDataValue;
            if (Cdol1 != null)
            {
                // Use CDOL1 to build data
                var tlvAll = new List <TlvData> {
                    TlvFci, TlvProcessingOptions, _tlvGenerateAC1UnpredictableNumber
                };
                tlvAll.AddRange(TlvRecords);
                tlvAll.AddRange(TlvTerminalData);
                tlvAll.Add(Tvr.Tlv);
                cdolDataValue = Cdol1.BuildData(tlvAll);
            }
            else
            {
                cdolDataValue = new byte[0];
            }

            // Execute GENERATE AC
            var cAPDU = new CommandAPDU(0x80, 0xAE, referenceControlParameter, 0x00, (UInt32)cdolDataValue.Length, cdolDataValue, 0); // Bad APDU !
            var crp   = new CommandResponsePair(cAPDU);

            crp.Transmit(_cardChannel);

            _lastStatusWord = crp.RApdu.StatusWord;

            // If GET RESPONSE needed, do it
            if (crp.RApdu.Sw1 == 0x61)
            {
                _tlvGenerateAC1Response = new TlvData();
                crp = new CommandResponsePair(new GetResponseCommand(crp.RApdu.Sw2));
                crp.Transmit(_cardChannel);
                _lastStatusWord = crp.RApdu.StatusWord;
            }

            // Finally, store result
            if (crp.RApdu.StatusWord == 0x9000)
            {
                _tlvGenerateAC1Response = new TlvData(crp.RApdu.Udr);
            }

            AfterGenerateAC1Event.Raise(this, new EmvEventArgs());

            return(_lastStatusWord);
        }