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); }
/// <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); }