EMVCard.Core 1.0.1

There is a newer version of this package available.
See the version list below for details.
dotnet add package EMVCard.Core --version 1.0.1
                    
NuGet\Install-Package EMVCard.Core -Version 1.0.1
                    
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="EMVCard.Core" Version="1.0.1" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="EMVCard.Core" Version="1.0.1" />
                    
Directory.Packages.props
<PackageReference Include="EMVCard.Core" />
                    
Project file
For projects that support Central Package Management (CPM), copy this XML node into the solution Directory.Packages.props file to version the package.
paket add EMVCard.Core --version 1.0.1
                    
#r "nuget: EMVCard.Core, 1.0.1"
                    
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
#:package EMVCard.Core@1.0.1
                    
#:package directive can be used in C# file-based apps starting in .NET 10 preview 4. Copy this into a .cs file before any lines of code to reference the package.
#addin nuget:?package=EMVCard.Core&version=1.0.1
                    
Install as a Cake Addin
#tool nuget:?package=EMVCard.Core&version=1.0.1
                    
Install as a Cake Tool

EMVCard.Core

High-level EMV chip card reading library with support for PSE/PPSE application selection, GPO processing, record reading, TLV parsing, and SL Token generation.

.NET Framework NuGet License

?? Installation

Package Manager Console

Install-Package EMVCard.Core

.NET CLI

dotnet add package EMVCard.Core

PackageReference

<PackageReference Include="EMVCard.Core" Version="1.0.0" />

?? Target Framework

  • .NET Framework 4.7.2

Compatible with:

  • .NET Framework 4.7.2+
  • .NET Standard 2.0+
  • .NET Core 2.0+
  • .NET 5+

? Features

Core EMV Functionality

  • ??? PSE/PPSE Support - Payment System Environment enumeration (contact & contactless)
  • ?? Multi-Application Cards - Handle cards with multiple payment applications
  • ?? GPO Processing - Get Processing Options command handling with PDOL
  • ?? Record Reading - Read card records via AFL (Application File Locator)
  • ??? TLV Parsing - Complete EMV Tag-Length-Value parsing
  • ?? SL Token Generation - SHA-256 based tokens from ICC certificates
  • ? Async Operations - Non-blocking asynchronous card operations

Data Extraction

  • ?? Card Number (PAN) - Primary Account Number (Tag 5A)
  • ?? Expiry Date - Card expiration (Tag 5F24)
  • ?? Cardholder Name - Name on card (Tag 5F20)
  • ?? Track 2 Data - Magnetic stripe equivalent (Tag 57)
  • ?? ICC Certificate - ICC Public Key Certificate (Tag 9F46)
  • ?? SL Token - Unique card identifier

?? Quick Start

Basic Card Reading

using EMVCard;
using NfcReaderLib;

// Step 1: Initialize card reader
var cardReader = new EmvCardReader();
cardReader.LogMessage += (s, msg) => Console.WriteLine(msg);

var readers = await cardReader.InitializeAsync();
await cardReader.ConnectAsync(readers[0]);

// Step 2: Load applications
var appSelector = new EmvApplicationSelector(cardReader);
appSelector.LogMessage += (s, msg) => Console.WriteLine(msg);

var apps = await appSelector.LoadPPSEAsync(); // or LoadPSEAsync() for contact

// Step 3: Select application
var selectedApp = apps[0];
var (selectSuccess, fciData) = await appSelector.SelectApplicationAsync(selectedApp.AID);

if (!selectSuccess)
{
    Console.WriteLine("Failed to select application");
    return;
}

// Step 4: Send GPO
var gpoProcessor = new EmvGpoProcessor(cardReader);
var (gpoSuccess, gpoResponse) = await gpoProcessor.SendGPOAsync(fciData);

// Step 5: Parse and read records
var dataParser = new EmvDataParser();
var cardData = new EmvDataParser.EmvCardData();

if (gpoSuccess)
{
    dataParser.ParseTLV(gpoResponse, 0, gpoResponse.Length - 2, cardData, 0);
    
    var aflList = dataParser.ParseAFL(gpoResponse, gpoResponse.Length);
    
    var recordReader = new EmvRecordReader(cardReader, dataParser);
    await recordReader.ReadAFLRecordsAsync(aflList, cardData);
}

// Step 6: Extract missing data from Track2
dataParser.ExtractFromTrack2(cardData);

// Step 7: Generate SL Token
var tokenGenerator = new EmvTokenGenerator();
var tokenResult = await tokenGenerator.GenerateTokenAsync(cardData, cardData.PAN, selectedApp.AID);

// Step 8: Display results
Console.WriteLine($"Card Number: {cardData.PAN}");
Console.WriteLine($"Expiry Date: {cardData.ExpiryDate}");
Console.WriteLine($"Cardholder: {cardData.CardholderName}");
Console.WriteLine($"SL Token: {tokenResult.Token}");

// Cleanup
await cardReader.DisconnectAsync();
await cardReader.ReleaseAsync();

?? Main Classes

EmvCardReader

Purpose: PC/SC card reader communication and APDU handling

Key Methods:

  • InitializeAsync() - Detect available card readers
  • ConnectAsync(readerName) - Connect to specific reader
  • SendApduWithAutoFix(apdu, out response) - Send APDU with automatic error retry
  • DisconnectAsync() / ReleaseAsync() - Cleanup

Features:

  • ? Automatic 6C/67 Le adjustment
  • ? Automatic 61 XX GET RESPONSE
  • ? Comprehensive APDU logging
  • ? Async/await support

Example:

var cardReader = new EmvCardReader();
cardReader.LogMessage += (s, msg) => Console.WriteLine(msg);

var readers = await cardReader.InitializeAsync();
bool connected = await cardReader.ConnectAsync(readers[0]);

byte[] selectCmd = new byte[] { 0x00, 0xA4, 0x04, 0x00, 0x07, 0xA0, 0x00, 0x00, 0x00, 0x03, 0x10, 0x10, 0x00 };
bool success = cardReader.SendApduWithAutoFix(selectCmd, out byte[] response);

EmvApplicationSelector

Purpose: PSE/PPSE application enumeration and selection

Key Methods:

  • LoadPSEAsync() - Load Payment System Environment (contact cards)
  • LoadPPSEAsync() - Load Proximity PSE (contactless cards)
  • SelectApplicationAsync(aid) - Select specific application

Returns:

  • List<ApplicationInfo> - List of available applications
  • (bool success, byte[] fciData) - Selection result with FCI template

Supported AIDs:

  • Visa (A0000000031010)
  • Mastercard (A0000000041010)
  • UnionPay, Discover, JCB, Amex, etc.

Example:

var appSelector = new EmvApplicationSelector(cardReader);

// For contactless cards
var apps = await appSelector.LoadPPSEAsync();

foreach (var app in apps)
{
    Console.WriteLine($"{app.DisplayName} - AID: {app.AID}");
}

var (success, fciData) = await appSelector.SelectApplicationAsync(apps[0].AID);

EmvGpoProcessor

Purpose: Get Processing Options (GPO) command handling

Key Methods:

  • SendGPOAsync(fciData) - Execute GPO command with PDOL processing

Returns:

  • (bool success, byte[] gpoResponse) - GPO result with AIP and AFL

Features:

  • ? Automatic PDOL extraction from FCI
  • ? Default values for common PDOL tags
  • ? Fallback to simplified GPO if PDOL fails

Example:

var gpoProcessor = new EmvGpoProcessor(cardReader);
var (gpoSuccess, gpoResponse) = await gpoProcessor.SendGPOAsync(fciData);

if (gpoSuccess)
{
    // GPO response contains AIP and AFL
}

EmvRecordReader

Purpose: Read card records specified in AFL

Key Methods:

  • ReadAFLRecordsAsync(aflList, cardData) - Read all AFL records
  • TryReadCommonRecordsAsync(cardData) - Fallback to common SFI/record combinations

Features:

  • ? Handles multiple SFI (Short File Identifier) files
  • ? Reads all records in AFL range
  • ? Automatic TLV parsing of record data
  • ? Fallback to common records if AFL parsing fails

Example:

var recordReader = new EmvRecordReader(cardReader, dataParser);

var aflList = dataParser.ParseAFL(gpoResponse, gpoResponse.Length);
await recordReader.ReadAFLRecordsAsync(aflList, cardData);

// Or try common records if AFL is not available
await recordReader.TryReadCommonRecordsAsync(cardData);

EmvDataParser

Purpose: TLV parsing and data extraction

Key Methods:

  • ParseTLV(buffer, startIndex, endIndex, cardData, priority) - Parse EMV TLV structures
  • ParseAFL(buffer, length) - Extract Application File Locator
  • ExtractFromTrack2(cardData) - Extract PAN/expiry from Track 2

Supported Tags:

  • 5A - Application PAN
  • 5F20 - Cardholder Name
  • 5F24 - Expiration Date
  • 57 - Track 2 Equivalent Data
  • 9F46 - ICC Public Key Certificate
  • 9F47 - ICC Public Key Exponent
  • 9F48 - ICC Public Key Remainder
  • All standard EMV tags

Features:

  • ? Recursive TLV parsing
  • ? Priority-based field updates
  • ? Nested template support (tags 70, 77)
  • ? Comprehensive tag recognition

Example:

var dataParser = new EmvDataParser();
var cardData = new EmvDataParser.EmvCardData();

dataParser.ParseTLV(gpoResponse, 0, gpoResponse.Length - 2, cardData, 0);

var aflList = dataParser.ParseAFL(gpoResponse, gpoResponse.Length);
dataParser.ExtractFromTrack2(cardData);

Console.WriteLine($"PAN: {cardData.PAN}");
Console.WriteLine($"Expiry: {cardData.ExpiryDate}");
Console.WriteLine($"Name: {cardData.CardholderName}");

EmvTokenGenerator

Purpose: SL Token generation from ICC certificates

Key Methods:

  • GenerateTokenAsync(cardData, pan, aid) - Generate token from card data
  • GenerateTokenFromCertificateAsync(certificate) - Generate from certificate bytes

Returns:

  • TokenResult with:
    • bool Success - Whether generation succeeded
    • string Token - Generated SL Token (if successful)
    • string ErrorMessage - Error details (if failed)

Example:

var tokenGenerator = new EmvTokenGenerator();
tokenGenerator.LogMessage += (s, msg) => Console.WriteLine(msg);

var tokenResult = await tokenGenerator.GenerateTokenAsync(
    cardData, 
    cardData.PAN, 
    selectedApp.AID
);

if (tokenResult.Success)
{
    Console.WriteLine($"SL Token: {tokenResult.Token}");
}
else
{
    Console.WriteLine($"Error: {tokenResult.ErrorMessage}");
}

??? EMV Tags Reference

Card Data Tags

Tag Name Description Type
5A Application PAN Primary Account Number Binary
5F20 Cardholder Name Name on card ASCII
5F24 Expiration Date YYMMDD format Binary
5F25 Effective Date Card effective date Binary
5F28 Issuer Country Code ISO 3166-1 numeric Binary
57 Track 2 Equivalent Magnetic stripe data Binary

Processing Tags

Tag Name Description Type
9F38 PDOL Processing Options DOL Binary
94 AFL Application File Locator Binary
82 AIP Application Interchange Profile Binary

Cryptographic Tags

Tag Name Description Type
9F46 ICC Public Key Certificate For DDA/CDA Binary
9F47 ICC Public Key Exponent Usually 03 Binary
9F48 ICC Public Key Remainder Extra modulus bytes Binary

Template Tags

Tag Name Description Type
70 Data Template EMV response template Constructed
77 Response Template Format 2 Response data Constructed
61 Application Template Application info Constructed

?? SL Token Details

What is SL Token?

The SL (Secure Link) Token is a unique cryptographic identifier derived from the card's ICC Public Key Certificate using SHA-256 hashing.

How It Works

ICC Certificate (Tag 9F46) ? SHA-256 Hash ? Hex String ? SL Token

Example Output:

E3 B0 C4 42 98 FC 1C 14 9A FB F4 C8 99 6F B9 24 27 AE 41 E4 64 9B 93 4C A4 95 99 1B 78 52 B8 55

Properties

? Unique - Each card generates a unique token
? Consistent - Same card always produces the same token
? Secure - One-way hash, cannot be reversed
? Privacy-Friendly - No PAN or sensitive data exposed
? Format - 64 bytes as space-separated hex (191 characters)

Use Cases

  • ?? Loyalty program card identification
  • ?? Card binding to user accounts
  • ?? Transaction correlation
  • ?? Duplicate card detection
  • ?? Analytics without storing sensitive data

??? Advanced Usage

Error Handling

try
{
    var cardReader = new EmvCardReader();
    var readers = await cardReader.InitializeAsync();
    
    if (readers.Count == 0)
    {
        Console.WriteLine("No card readers found");
        return;
    }
    
    bool connected = await cardReader.ConnectAsync(readers[0]);
    if (!connected)
    {
        Console.WriteLine("Failed to connect to card");
        return;
    }
    
    // ... card operations ...
}
catch (Exception ex)
{
    Console.WriteLine($"Error: {ex.Message}");
}
finally
{
    await cardReader?.DisconnectAsync();
    await cardReader?.ReleaseAsync();
}

Logging Integration

// Subscribe to log events from all components
var cardReader = new EmvCardReader();
var appSelector = new EmvApplicationSelector(cardReader);
var gpoProcessor = new EmvGpoProcessor(cardReader);
var recordReader = new EmvRecordReader(cardReader, dataParser);
var tokenGenerator = new EmvTokenGenerator();

// Centralized logging
EventHandler<string> logHandler = (s, msg) => 
{
    File.AppendAllText("card_operations.log", $"[{DateTime.Now}] {msg}\n");
    Console.WriteLine(msg);
};

cardReader.LogMessage += logHandler;
appSelector.LogMessage += logHandler;
gpoProcessor.LogMessage += logHandler;
recordReader.LogMessage += logHandler;
tokenGenerator.LogMessage += logHandler;

Custom PDOL Values

// The GPO processor uses these default PDOL values:
// - Terminal Transaction Qualifiers (9F66): 26000000
// - Amount Authorized (9F02): 000000000100
// - Amount Other (9F03): 000000000000
// - Transaction Date (9A): Current date (YYMMDD)
// - Transaction Type (9C): 00 (Purchase)
// - Unpredictable Number (9F37): Random 4 bytes

// To customize, you can modify the EmvGpoProcessor source or
// send GPO command directly through EmvCardReader

?? Dependencies

  • NfcReaderLib (v1.0.0) - PC/SC communication and utilities

?? Requirements

  • .NET Framework 4.7.2 or later
  • Windows 7 or later (for PC/SC support)
  • PC/SC compatible smart card reader
  • EMV chip card (Visa, Mastercard, etc.)

Tested Readers

  • ? ACR122U (contactless)
  • ? SCM SCR331 (contact)
  • ? Omnikey 5321 (dual interface)
  • ? Generic PC/SC readers

? Troubleshooting

No Applications Found

Problem: PSE/PPSE returns no applications

Solutions:

  1. Try both LoadPSEAsync() (contact) and LoadPPSEAsync() (contactless)
  2. Card may not support PSE - check APDU logs for 6A 82 (File not found)
  3. Ensure card is properly seated in reader

SL Token Generation Error

Problem: Token generation fails

Solutions:

  1. Verify card supports DDA/CDA (check for Tag 9F46 in logs)
  2. Some cards only support SDA (no ICC certificate available)
  3. Check logs for "ICC Public Key Certificate" presence

Common Status Words

Status Word Meaning Auto-Handled Action
90 00 Success - None
6C XX Wrong Le ? Yes Automatic retry with correct Le
67 00 Wrong length ? Yes Automatic retry
61 XX More data available ? Yes Automatic GET RESPONSE
6A 82 File not found ? No Try alternative method (PPSE vs PSE)
6A 83 Record not found ? No Use TryReadCommonRecords
6985 Conditions not satisfied ? No Card may be locked
6A 86 Incorrect P1/P2 ? No Check command parameters

?? Documentation

For complete documentation and usage examples, visit:

  • NfcReaderLib - Low-level PC/SC communication and utilities (required dependency)

?? License

Copyright � Johan Henningsson 2026

This project is licensed under the MIT License.

?? Author

Johan Henningsson

?? Acknowledgments

  • EMV specifications by EMVCo
  • PC/SC Workgroup
  • Original EMVReader by Eternal TUTU (2008)

Made with ?? by Johan Henningsson | 2008-2026

? Star this package on GitHub if you find it useful!

Product Compatible and additional computed target framework versions.
.NET Framework net472 is compatible.  net48 was computed.  net481 was computed. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.

NuGet packages

This package is not used by any NuGet packages.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last Updated
2.1.1 109 1/23/2026
2.1.0 93 1/18/2026
2.0.4 99 1/14/2026
2.0.1 98 1/14/2026
1.0.3 98 1/13/2026
1.0.2 104 1/1/2026
1.0.1 105 1/1/2026
1.0.0 103 12/31/2025

v1.0.1 - Updated copyright to 2026, improved documentation, depends on NfcReaderLib 1.0.1, no functional changes.