Auth API

Physical authenticity validation

The VivoKey Authenticity API gives applications and services the ability to check the authenticity of components and products containing VivoKey technology using strong standards based cryptographic proofs over NFC (contactless near field communication).

Table of Contents

Cryptographic authenticity flow

The exact steps taken depend on the type of VivoKey NFC technology being used, but there are two basic flows. Depending on the product or technology being used you will want to use either the "Challenge / Response" or Signature authenticity flow.

Challenge / Response Flow

The Challenge / Response flow is the most secure method of verifying authenticity of the VivoKey chip or technology being validated. Once the VivoKey enabled product is scanned with NFC, a cryptographic challenge is obtained from the VivoKey API. That challenge is then passed to the VivoKey product and a secure cryptographic response is generated. This response is sent back to the VivoKey API for an authenticity check. If verified, a signed authenticity JWT is issued.

CMAC Signature Flow

For applications where it is not possible to establish bidirectional communication with the VivoKey chip or technology being validated, the Signature flow is supported by some VivoKey products to facilitate authenticity validation using a standard web browser on any NFC smartphone. For example, if it is not possible or desirable to require a special mobile app to be installed on the mobile device being used, Signature flow can offer reasonable authenticity protection for lower risk applications and use cases. Signature flow works by embedding a CMAC signature value into a standard NFC based URL sharing mechanism. The user simply scans the VivoKey enabled product with their phone, a browser will open a special signed website URL sent from the chip, and the web server then validates the embedded signature with VivoKey API servers. If the signature is valid and has not expired, a signed authenticity JWT is issued.

VivoKey authenticity token (JWT)

Once a successful cryptographic verification of VivoKey product authenticity is completed using the API, a signed VivoKey authenticity token is issued in JWT format. The typical format of a JWT is made up of three Base64-URL strings separated by dots that can be easily passed in HTML and HTTP environments, while being more compact when compared to XML-based standards such as SAML.

Example Json Web Token (JWT)

Various aspects of the authenticity token will be referenced in the API documentation below, so you might want to gain a cursory understanding of its structure and purpose before proceeding with the API documentation.

Working with the API

The VivoKey Authenticity API is designed to be open and extremely easy to use. You will need an API key to talk to the Authenticity API, but the only requirement to get one is to submit your email address. An API key will be automatically generated and emailed to you instantly. The API key must be included in the HTTP header X-API-VIVOKEY for every call to an API endpoint. The Content-Type must be application/json and the JSON object data must be posted as raw data, not form encoded data, or your posted data will not be processed.

Interface URL, http headers, etc.

Base URL: https://auth.vivokey.com

Content-Type: application/json

X header: X-API-VIVOKEY

API key: Get one here!

Get your API key

Getting your own VivoKey API key is as simple as submitting your email address. The email address you use will be the basis for your developer account ID, and any API keys sent to this email address will all be registered to the same developer account ID. This becomes important when considering multiple applications which may use a VivoKey API key. The Developer ID is also included as a claim in the authenticity JWT returned by this API upon successful authenticity validation.

Now that you have your own API key, you would submit it with your calls to VivoKey API endpoints as an http header value. For example, when using CURL to interact with the API, you would prepare your parameters like so;

curl -H "Content-Type: application/json" -H "X-API-VIVOKEY: d28a293f-44ec-4f2a-bf56-6bd546f47e1f" -X POST https://auth.vivokey.com/challenge -d '{"scheme": 1}'

Error or failure modes are rather simple;


  • HTTP error code 400 (Bad Request) will be returned if there are syntactical problems with the data submitted.
  • HTTP error code 401 (Unauthorized) will be returned if you forget to include the X-API-VIVOKEY header or provide an invalid API key.
  • HTTP error code 406 (Not acceptable) will be returned from /session if there is a problem verifying authenticity of the chip
  • HTTP error code 418 (I'm a teapot) will be returned if requests to /session use expired tokens.

API endpoints

The base URL for the authenticity API is https://auth.vivokey.com and there are only three relevant endpoints; challenge, session, and validate. These endpoints consume and return JSON objects. Remember to ensure your posts have the HTTP header Content-Type set to application/json or your post data will not be processed.

/challenge

This endpoint consumes a JSON object that contains one or more key-value pairs (KVP), depending on which chip type is being challenged. The endpoint will return a JSON object that contains a payload and token KVP. Challenges expire after 30 seconds.

KVPs sent to /challenge

Key Description

scheme

The scheme value can be 1 or 2. The scheme informs the challenge generator which type of VivoKey chip is being challenged. Scheme 1 requires no other KVPs, and generates a basic challenge for Spark 1 chips. Scheme 2 requires both uid and message KVPs, and generates a challenge for Spark 2 chips as well as Apex chips running the Spark app.

uid

[conditional] The UID is the unique identifier or serial number of the chip being challenged. Certain VivoKey chips have a 7 byte UID while others have an 8 byte UID. Value is represented in hexadecimal notation. The uid KVP is not required for scheme 1 challenges. 

message

[conditional] For Spark 2 and Apex chips running the Spark app, the chip will generate a PCD challenge as part of the mutual authentication scheme used by the chip. This message is passed to the /challenge endpoint and an appropriate chip challenge is generated. Value is represented in hexadecimal notation. The message KVP is not required for scheme 1 challenges. 

KVPs received back from /challenge

Key Description

payload

The payload value is the VivoKey authenticity challenge which must be passed to the chip for processing.

token

The token value is an encrypted JWT called a challenge token. The challenge token must be passed to /session along with the chip response for the associated payload to /session. Challenge tokens expire after 30 seconds.

/session

This endpoint consumes a JSON object that contains three KPVs. The endpoint will return a JSON object that contains a token KVP, the value of which is an authenticity JWT. The purpose of a signed token is to carry all of the valuable validated authenticity information inside itself, ensuring you can verify that a specific VivoKey chip scan was validated as authentic at a specific time, and has not been altered by any 3rd parties in transit. Authenticity tokens expire after 30 seconds and should not be used after it has expired (after exp). The endpoint is called session because the authenticity token is meant to be used to establish and maintain an authenticated session for VivoKey services, but you can also use it within your own services and applications.

KVPs sent to /session

Key Description

uid

The UID is the unique identifier or serial number of the chip being challenged. Certain VivoKey chips have a 7 byte UID while others have an 8 byte UID. Value is represented in hexadecimal notation.

response

For Spark 1, the response is a basic challenge response. For Spark 2 and Apex chips running the Spark app, the chip will generate a mutually authenticated response. The value is represented in hexadecimal notation.

token

The challenge token obtained from /challenge is sent back to /session.

cld

You have the option of passing any properly json encoded arbitrary data along with the chip response to /session (up to 1024 bytes). This data will be encoded into the authenticity token as a JWT claim called cld (client data). This allows you to embed application and user / client session relevant data to the chip scan event, making it part of the authenticity token. Passing the authenticity token to your backend or other services offers the same verifiable integrity protection to this data, meaning you can simply pass the token around your various external and internal endpoints with your application data rather than along side it.

KVPs received back from /session

Key Description
token

The token value contains a signed JWT called an authenticity token. The token payload contains important verified data which can be used by your application or service, as well as passed between services as necessary. Each service or application which receives the authenticity token can validate its signature to verify authenticity of the token and its contents without ever having to call an API.

/validate

This endpoint is used to validate unique counter based CMAC signatures generated for each unique NFC scan of certain VivoKey chip and product types. Reading the CMAC signature is easily done with any NFC enabled smartphone. No special app is needed, just scanning the product will open the signed URL on the phone's web browser. The web server can then pass the CMAC signature to the /validate endpoint for authenticity checking.

 

The CMAC signature received by the web server can then be sent to the /validate endpoint to check for uniqueness and authenticity. The endpoint consumes the signature value and returns a JSON object containing a result value. If the signature is valid and not expired (already used), a token value is also returned containing a signed authenticity JWT. The atp value within the JWT will be cmac.

 

WARNING! Counter based CMAC signature authenticity checks are not as secure as other forms of challenge / response checks like tam and mau, so CMAC should not be used for high risk applications.

KVPs sent to /validate

Key Description

signature

The signature data from the VivoKey product. See below ⤷ for examples.

KVPs received back from /validate

Key Description
result

The result of the signature check. Possible values are success, expired, and invalid. The response value success means that the signature is valid and current, as in this signature is the most recent CMAC or highest counter value the server has validated from this product to date. A result of expired means that the signature contains a counter value that is not as recent as what has already been validated by the server. A result of invalid means there is a problem with the signature.

token

[conditional] The token value contains a signed JWT called an authenticity token. The token payload contains important verified data which can be used by your application or service, as well as passed between services as necessary. Each service or application which receives the authenticity token can validate its signature to verify authenticity of the token and its contents without ever having to call an API. The token KVP will only be supplied if the result key value is success.

Challenge / Response over NFC

Sending data to a passive RFID transponder (all NFC transponders are RFID transponders, but not all RFID transponders comply with NFC standards) is done using commands over a particular "air interface" for the product in question. VivoKey products communicate using 13.56MHz RFID standards ISO14443A and ISO15693, and comply with NFC standards for Type 4 and Type 5.

Exactly how you send commands to VivoKey products over NFC depends on the operating environment. For example, using Swift for iOS to submit a TAM1 challenge to a Spark 1 means you would use the authenticate command. On Android you would use NfcV and transcieve. If you are using PC/SC to communicate, Spark 2 speaks APDUs natively while the Spark 1 may need commands sent over PC/SC as the payload of a standard "transparent" APDU. Response data would also be suffixed with standard APDU status words (SW1, SW2) with values of 90 00 which means "command successfully executed".

Spark 1

The Spark 1 is an ISO15693 RFID transponder which complies with NFC Type 5 (NfcV for Android, NFCTagTypeISO15693 for iOS). If you are communicating with the Spark 1 over PC/SC using a CCID compliant reader, you may need to send ISO15693 commands using an APDU compliant command format or command wrapper. Check your reader's documentation.

Authentication using TAM1 challenge response (tam)

For this example we will use a Spark 1 with an 8 byte UID of e0 04 01 18 00 9c 5d 52 (in MSB byte order). While not important for our API, it's useful to know the UID format of ISO15693 transponders is broken down into the following structure;

 

Byte 1: This is the Manufacturer code. It is assigned by the NFC Forum to each manufacturer. For example, Texas Instruments has the manufacturer code 0x01, NXP Semiconductors has 0x04, and so on.

 

Byte 2-3: These bytes represent the chip type. This is a unique code assigned by the manufacturer to each type of chip they produce.

 

Byte 4-8: These bytes represent the chip serial number. This is a unique number assigned by the manufacturer to each chip. It ensures that each chip produced by the manufacturer has a unique identifier.

STEP 1. Obtain a challenge from the /challenge endpoint

 

For Spark 1, send scheme value 1 to the API endpoint and receive a challenge payload and challenge token back.

 

{"scheme": 1}

 

{"payload":"3bc96bc85fa3405fe416","token":"eyJhbGciOiJkaXIiLCJlbmMiOiJBMjU2R0NNIn0..MhqTUKrdDjZSHSq9.EFn2Utl-hR1dTIwX_l9EREO4UPI6U2R1VtiFMcJfZUeSDiWBQCBan887f2cDKG0PRZWCwAL6gZim4dv02ruIyQZk3_OuMrMsmElEeDxkEzrOVOloLpiFL2wjug06fKcWXbhh5flImmRyuH5bbB_k8qWjD6HfDPiz8R0wFJ3gArx6-8sPbfLBF2UqIBIGBISMqerfz4nzsJY.f0f2S0RA5wGVUGfE2my8bg"}

STEP 2. Send authenticate command to Spark 1

The ISO15693 command represented in hexadecimal format below must be sent to the Spark 1 as an "addressed command", meaning you must include the UID of the transponder the command is intended for within the command structure itself, and the UID must be sent in LSB order. The challenge obtained from the server is appended to the end.

 

Command Code: 20 (authenticate)

Request Flag: 35

UID: 52 5d 9c 00 18 01 04 e0 (8 bytes of UID in LSB order)

CSI: 00 (AES)

RFU: 00

Key: 02

Challenge: 3b c9 6b c8 5f a3 40 5f e4 16

 

Complete command: 20 35 52 5d 9c 00 18 01 04 e0 00 00 02 3b c9 6b c8 5f a3 40 5f e4 16

 

How you send this command depends entirely on the operating environment. For example, using Swift for iOS means you use the authenticate command, which handles the command 20 and UID details for you. On Android you would use NfcV and transcieve. You should receive 12 bytes of data back which is the encrypted response data for the challenge you sent to the chip. If you are using PC/SC to communicate with the Spark 1, this data may be suffixed with APDU status words (SW1, SW2) with a success value of 90 00.

STEP 3. Submit the TAM1 response to the /session endpoint

 

{"uid":"e0040118009c5d52","response":"8d77260aea0fb3a68dc158aabbecb7a3","token":"eyJhbGciOiJkaXIiLCJlbmMiOiJBMjU2R0NNIn0..MhqTUKrdDjZSHSq9.EFn2Utl-hR1dTIwX_l9EREO4UPI6U2R1VtiFMcJfZUeSDiWBQCBan887f2cDKG0PRZWCwAL6gZim4dv02ruIyQZk3_OuMrMsmElEeDxkEzrOVOloLpiFL2wjug06fKcWXbhh5flImmRyuH5bbB_k8qWjD6HfDPiz8R0wFJ3gArx6-8sPbfLBF2UqIBIGBISMqerfz4nzsJY.f0f2S0RA5wGVUGfE2my8bg"}

 

{"token":"eyJ0eXAiOiJKV1QiLCJhbGciOiJFUzI1NiIsImtpZCI6ImprM3JXNEhBVm9HSzl6QVhsdnVzdnMxdTFLeVlMRUxYRG10OXlTOXViYUkifQ.eyJ0eXBlIjoxLCJwcm9kdWN0IjozLCJhdHAiOiJ0YW0iLCJzdWIiOiJlOGU5OGQ0MTVmM2I5NzI2MTE1ZjRiYjQ1NTNkZThmYTgxZTM3MjY5ZDUxMDkxNDgzMzUxMDYyMTMwOGFjN2IwIiwiaWF0IjoxNjg4NTgyNjkxLCJleHAiOjE2ODg1ODI3MjEsImlzcyI6Imh0dHBzOi8vYXV0aC52aXZva2V5LmNvbSIsImp0aSI6ImIzMTM5NmRmYzA0MGJjZmRmOTI4MGYwY2JlZDVjMWE2Zjk2NDUzZmZlM2VlMDljNWU0NTNmM2JkODIwMjM0ZjkifQ.Ep6PL6ySPagUHVeq-DSmASmui2VwJhaBk9ifSpIqTMQ_mlGrrAVxnCApjSC9jqQV2h5YGCISNpQN8ELWh0-YtQ"}

 

Inspect authenticity JWT with jwt.io (includes public key to validate signature)

Spark 2 / AuthentiChip

Spark 2 and AuthentiChip products are based on ISO14443A RFID transponders which comply with NFC Type 4 (NfcA for Android, NFCTagTypeISO7816Compatible for iOS). They use a traditional APDU compliant command format so communicating with a CCID reader over PS/SC should be straightforward.

Authentication using mutual authentication (mau)

For this example, we will use a Spark 2 chip with a 7 byte UID of 04 29 38 22 2f 5c 80. The Spark 2 mutual authentication functions are tied to the standard NFC NDEF application ID (AID) for NFC Forum Type 4 transponders (D2 76 00 00 85 01 01 00), so we must start by selecting this AID using the standard select APDU command.

STEP 1. Select the NDEF AID

 

CLA: 00

INS: A4

P1: 04

P2: 0C

Lc: 07

Data: D2 76 00 00 85 01 01 00

 

Complete command: 00 A4 04 0C 07 D2 76 00 00 85 01 01 00

 

Receive: 90 00

 

You should receive no payload response, only status words SW1, SW1 with values of 90 00 which means "success".

STEP 2. Request PCD challenge

 

The Spark 2 begins mutual authentication by issuing a PCD challenge - a challenge to the API to prove we know the same key it does. This must be sent to the /challenge endpoint to obtain a PICC challenge - a challenge to the Spark 2 to prove it knows the same key we do.

 

CLA: 90

INS: 71

P1: 00

P2: 00

Lc: 02

Key: 02

Data: 00 00

 

Complete APDU: 90 71 00 00 02 02 00 00

 

Receive: 87 86 b1 2d 5e e7 14 de 5a 97 c5 c0 98 00 b6 68 91 af

 

The data received back should contain a 16 byte PCD challenge followed by two status words (SW1, SW2) with the values 91 AF which means "additional frame" expected. The Spark 2 is now expecting the next thing sent to it be a response to the PCD challenge along with a PICC challenge from the API.

STEP 3. Obtain a challenge from /challenge endpoint

 

For Spark 2, send scheme value 2 along with the PCD challenge and UID of the Spark 2. You will receive a payload that contains the PCD response and PICC challenge and a challenge token.

 

{"scheme": 2, "message":"8786b12d5ee714de5a97c5c09800b668", "uid":"042938222f5c80"}

 

{"payload":"cebee779170430704d6f9b28e5a2cad5eff20ce410233b19e4a9ae64e030c10f","token":"eyJhbGciOiJkaXIiLCJlbmMiOiJBMjU2R0NNIn0..7E30dAWbIIDnmTAK.N6EIEvT2VshQZd30z7S1IjKavR5IvHHOVxnrYDaEnMxX1rhghXHcxbdjnHIr2sTaAaGJfq5s_6gosLnbrAMJmmZloBAcsPuuUztp6sket9s8ZijXy7npChU9XrlTW-0RMGNx2l5X8BMVL4yAP5varLD7lMMnFPHqrJ6XvNx4N0ehW4pTRg_VqpJ08HeTbgR42zjFV8V_yIUQP28Ia7SCDmIn6ot-5Rl0.mmnJMa-1iv37SHXI_sOtEw"}

STEP 4. Send PCD response and PICC challenge

 

The Spark 2 now wants a 16 byte response along with a 16 byte PICC challenge it will respond to.

 

CLA: 90

INS: AF

P1: 00

P2: 00

Lc: 20

Data: ce be e7 79 17 04 30 70 4d 6f 9b 28 e5 a2 ca d5 ef f2 0c e4 10 23 3b 19 e4 a9 ae 64 e0 30 c1 0f

 

Complete APDU: 90 AF 00 00 20 ce be e7 79 17 04 30 70 4d 6f 9b 28 e5 a2 ca d5 ef f2 0c e4 10 23 3b 19 e4 a9 ae 64 e0 30 c1 0f

 

Receive: b6 0b 6b 38 ad 5c 8e d6 f0 b4 27 85 90 ce 9f 63 85 62 92 47 05 c7 c6 3f 89 d5 3d 67 4c 99 04 19 91 00

 

The data received should contain a 32 byte response followed by two status words (SW1, SW2) with the values 91 00 which means "ok".

STEP 5. Submit the mutual auth response to the /session endpoint

 

{"uid":"042938222f5c80","response":"b60b6b38ad5c8ed6f0b4278590ce9f638562924705c7c63f89d53d674c990419","cld":"{\u0022data\u0022:\u0022testing\u0022}","token":"eyJhbGciOiJkaXIiLCJlbmMiOiJBMjU2R0NNIn0..7E30dAWbIIDnmTAK.N6EIEvT2VshQZd30z7S1IjKavR5IvHHOVxnrYDaEnMxX1rhghXHcxbdjnHIr2sTaAaGJfq5s_6gosLnbrAMJmmZloBAcsPuuUztp6sket9s8ZijXy7npChU9XrlTW-0RMGNx2l5X8BMVL4yAP5varLD7lMMnFPHqrJ6XvNx4N0ehW4pTRg_VqpJ08HeTbgR42zjFV8V_yIUQP28Ia7SCDmIn6ot-5Rl0.mmnJMa-1iv37SHXI_sOtEw"}

 

{"token":"eyJ0eXAiOiJKV1QiLCJhbGciOiJFUzI1NiIsImtpZCI6ImprM3JXNEhBVm9HSzl6QVhsdnVzdnMxdTFLeVlMRUxYRG10OXlTOXViYUkifQ.eyJ0eXBlIjoyLCJwcm9kdWN0IjoyLCJhdHAiOiJtYXUiLCJjbGQiOiJ7XCJkYXRhXCI6XCJ0ZXN0aW5nXCJ9Iiwic3ViIjoiNjQ4ZmU2NThkYTdjNDg3NzkxZTg4ODc3NTE1M2Q3NjRmZWNlMzJmYjNkMTg5NWU1N2YxZDNjMzY5ZGFkYTk1MyIsImlhdCI6MTY4ODU4MzM4NSwiZXhwIjoxNjg4NTgzNDE1LCJpc3MiOiJodHRwczovL2F1dGgudml2b2tleS5jb20iLCJqdGkiOiIwZTgyYzFlZTllN2I4M2Q0Mzg1NWU2YjM4OGYxZmZiODI3OTE2MzQxNWJiNWU2NTMzODU4MDc4ZGY5YjM4ZTVhIn0.7xNJ6fSjf_CuawElJMZvnwvDF5VwBr6j4Wac2r2F7R0BoNydCXeQ72MUteZdwHDE6Z5_roh1sBrY-zs9pmQ-UA"}

 

Inspect authenticity JWT with jwt.io (includes public key to validate signature)

Spark application for Apex

The Spark applet for Apex enables Auth API mutual authentication to the Apex chip platform. The Spark applet uses traditional APDU compliant command format so communicating with a CCID reader over PS/SC should be straightforward.

Mutual authentication using Spark applet on Apex

For this example, we will use an Apex chip with Spark application loaded. The Spark applet on Apex does not use the chip UID. Instead, the Spark applet is programmed with an 8 byte "Spark ID" that is returned as a result of selecting the Spark application. In this example, we will use ff 00 01 8d 2c 10 16 79 as the Spark ID. Start by selecting the Spark applet AID A000000846737061726B3201 using the standard select APDU command.

STEP 1. Select the Spark AID

 

CLA: 00

INS: A4

P1: 04

P2: 00

Lc: 0C

Data: A0 00 00 08 46 73 70 61 72 6B 32 01

Le: 00

 

Complete APDU: 00 A4 04 00 0C A0 00 00 08 46 73 70 61 72 6B 32 01 00

 

Receive: ff 0a 01 8d 2c 10 16 79 90 00

 

For this example, we will receive a payload response containing an 8 byte Spark ID (ff0a018d2c101679) followed by status words SW1, SW1 with values of 90 00 which means "success". You will need to use this Spark ID instead of the Apex chip UID when interacting with the Auth API.

STEP 2. Request PCD challenge

 

The Spark applet begins mutual authentication by issuing a PCD challenge - a challenge to the API to prove we know the same key it does. This must be sent to the /challenge endpoint to obtain a PICC challenge - a challenge to the Spark applet to prove it knows the same key we do.

 

CLA: 90

INS: 71

P1: 00

P2: 00

Lc: 02

Key: 02

Data: 00 00

 

Complete APDU: 90 71 00 00 02 02 00 00

 

Receive: 87 86 b1 2d 5e e7 14 de 5a 97 c5 c0 98 00 b6 68 91 af

 

The data received back should contain a 16 byte PCD challenge followed by two status words (SW1, SW2) with the values 91 AF which means "additional frame" expected. This PCD challenge is what we will send to the /challenge endpoint to obtain a PICC challenge along with a PCD response. The Spark applet is now expecting the next thing we send to be a response to the PCD challenge along with a PICC challenge from the API.

STEP 3. Obtain a challenge from /challenge endpoint

 

Send scheme value 2 along with the PCD challenge and Spark ID (not the UID of the Apex) to the /challenge endpoint. You will receive a payload that contains the PCD response, a PICC challenge, and a challenge token.

 

{"scheme": 2, "message":"8786b12d5ee714de5a97c5c09800b668", "uid":"ff0a018d2c101679"}

 

{"payload":"cebee779170430704d6f9b28e5a2cad5eff20ce410233b19e4a9ae64e030c10f","token":"eyJhbGciOiJkaXIiLCJlbmMiOiJBMjU2R0NNIn0..7E30dAWbIIDnmTAK.N6EIEvT2VshQZd30z7S1IjKavR5IvHHOVxnrYDaEnMxX1rhghXHcxbdjnHIr2sTaAaGJfq5s_6gosLnbrAMJmmZloBAcsPuuUztp6sket9s8ZijXy7npChU9XrlTW-0RMGNx2l5X8BMVL4yAP5varLD7lMMnFPHqrJ6XvNx4N0ehW4pTRg_VqpJ08HeTbgR42zjFV8V_yIUQP28Ia7SCDmIn6ot-5Rl0.mmnJMa-1iv37SHXI_sOtEw"}

STEP 4. Send PCD response and PICC challenge

 

The Spark applet is waiting for a 16 byte PCD response along with a 16 byte PICC challenge it will respond to.

 

CLA: 90

INS: AF

P1: 00

P2: 00

Lc: 20

Data: ce be e7 79 17 04 30 70 4d 6f 9b 28 e5 a2 ca d5 ef f2 0c e4 10 23 3b 19 e4 a9 ae 64 e0 30 c1 0f

 

Complete APDU: 90 AF 00 00 20 ce be e7 79 17 04 30 70 4d 6f 9b 28 e5 a2 ca d5 ef f2 0c e4 10 23 3b 19 e4 a9 ae 64 e0 30 c1 0f

 

Receive: b6 0b 6b 38 ad 5c 8e d6 f0 b4 27 85 90 ce 9f 63 85 62 92 47 05 c7 c6 3f 89 d5 3d 67 4c 99 04 19 91 00

 

The data received back should contain a 32 byte response followed by two status words (SW1, SW2) with the values 91 00 which means "ok". The 32 bytes of data is what we send to the /session endpoint for final validation.

STEP 5. Submit the mutual auth response to the /session endpoint

 

{"uid":"ff0a018d2c101679","response":"b60b6b38ad5c8ed6f0b4278590ce9f638562924705c7c63f89d53d674c990419","cld":"{\u0022data\u0022:\u0022testing\u0022}","token":"eyJhbGciOiJkaXIiLCJlbmMiOiJBMjU2R0NNIn0..7E30dAWbIIDnmTAK.N6EIEvT2VshQZd30z7S1IjKavR5IvHHOVxnrYDaEnMxX1rhghXHcxbdjnHIr2sTaAaGJfq5s_6gosLnbrAMJmmZloBAcsPuuUztp6sket9s8ZijXy7npChU9XrlTW-0RMGNx2l5X8BMVL4yAP5varLD7lMMnFPHqrJ6XvNx4N0ehW4pTRg_VqpJ08HeTbgR42zjFV8V_yIUQP28Ia7SCDmIn6ot-5Rl0.mmnJMa-1iv37SHXI_sOtEw"}

 

{"token":"eyJ0eXAiOiJKV1QiLCJhbGciOiJFUzI1NiIsImtpZCI6ImprM3JXNEhBVm9HSzl6QVhsdnVzdnMxdTFLeVlMRUxYRG10OXlTOXViYUkifQ.eyJ0eXBlIjoyLCJwcm9kdWN0IjoyLCJhdHAiOiJtYXUiLCJjbGQiOiJ7XCJkYXRhXCI6XCJ0ZXN0aW5nXCJ9Iiwic3ViIjoiNjQ4ZmU2NThkYTdjNDg3NzkxZTg4ODc3NTE1M2Q3NjRmZWNlMzJmYjNkMTg5NWU1N2YxZDNjMzY5ZGFkYTk1MyIsImlhdCI6MTY4ODU4MzM4NSwiZXhwIjoxNjg4NTgzNDE1LCJpc3MiOiJodHRwczovL2F1dGgudml2b2tleS5jb20iLCJqdGkiOiIwZTgyYzFlZTllN2I4M2Q0Mzg1NWU2YjM4OGYxZmZiODI3OTE2MzQxNWJiNWU2NTMzODU4MDc4ZGY5YjM4ZTVhIn0.7xNJ6fSjf_CuawElJMZvnwvDF5VwBr6j4Wac2r2F7R0BoNydCXeQ72MUteZdwHDE6Z5_roh1sBrY-zs9pmQ-UA"}

 

Inspect authenticity JWT with jwt.io (includes public key to validate signature)

CMAC Signature validation

There are some circumstances where doing direct NFC authentication with a VivoKey product might not be possible or preferred. For example, retail items with a VivoKey authenticity NFC transponder embedded or affixed to it. It would not be ideal to ask customers to have to install a special application in order to verify the authenticity of a product. They should just be able to tap their phone to bring up a browser that shows the product is authentic. This is exactly the kind of low risk scenario that CMAC based validations are good for.

 

  • Spark 1 - Does not support CMAC signatures
  • Spark 2 - Supports CMAC signatures
  • AuthentiChip - Supports CMAC signatures
  • Apex - NFC Sharing applet supports CMAC signatures

In order to validate a unique signature generated per each unique scan, you must simply extract the signature data from the scanned data and submit to the /validate API endpoint. Examples of this are outlined below for each type of chip which supports CMAC signatures.

Spark 2 / AuthentiChip CMAC Signatures

Spark 2 and AuthentiChip products have an NDEF record which contains a unique URL with CMAC signature appended. This URL cannot be changed, but the CMAC changes each time the Spark 2 is scanned. The URL written to the Spark 2 begins with https://vivokey.co/ followed by a unique ID and then the CMAC signature. To validate the signature, you must submit the CMAC data portion of the URL to /validate. For example, if you read the URL from the Spark 2 as https://vivokey.co/3c8d418757dcce5459f5b8576a5fb652/?sun=042468222F5C80-00003C-AE4F60A1AF728AB4 then you would submit the following to the /validate endpoint.

 

{“signature“: “042468222F5C80-00003C-AE4F60A1AF728AB4”}

 

{result“: “success”,token“: “eyJ0eXAiOiJKV1QiLCJhbGciOiJFUzI1NiIsImtpZCI6ImprM3JXNEhBVm9HSzl6QVhsdnVzdnMxdTFLeVlMRUxYRG10OXlTOXViYUkifQ.eyJ0eXBlIjoyLCJwcm9kdWN0IjoyLCJhdHAiOiJjbWFjIiwic3ViIjoiZDYwOGFhZGYwYjI1MmE4N2EwYmEyMGQ3NTQ1NDM1N2Y3Y2Y5NDZlNWZjM2VjMmQ4YjViZmY4NGRhODg4Yzk5ZSIsImlhdCI6MTY4Nzg0MjAzMSwiZXhwIjoxNjg3ODQyMDYxLCJpc3MiOiJodHRwczovL2F1dGgudml2b2tleS5jb20iLCJqdGkiOiI2ODY0NTdjMjBmNjZkOWU1YWI3ZWQyMzMxYmYyOGMyNWE0ZjI4NGQ0MTAyZWFjMmE2YTUxNjc0NjdmMTcxYTI2In0.guSNm14-Nwf7nniN2Am9efCZCyW86ZXjC4F5Y08UzAVCqO4lbYTT5Wb6ip3g4Wf-OFCQNoe1G-E1NNZBlz-FeA”}

 

Inspect authenticity JWT with jwt.io (includes public key to validate signature)

CMAC Signatures with NFC Sharing for Apex

The NFC Sharing app for Apex may have (this feature is optional) an NDEF record which contains a unique URL with CMAC signature data included. The CMAC changes each time NFC data is read from the applet. To validate the signature, you must submit the entire AES CMAC data element. For example, if you program the NFC Sharing app for Apex with the following URL data;

 

https://testing.com/signature/?s={AES128_CMAC_SIGNATURE_XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX}

 

When read data is read back from the NFC Sharing app, the marker will be replaced with signature data such as;

 

https://testing.com/signature/?s=FF0A01128731FBB6-000005-E92AB4B81AAA1FEAB2C4D2AF4665AD19

 

You would then submit the signature data to the /validate endpoint like this;

 

{“signature“: “FF042468222F5C80-00003C-AE4F60A1AF728AB4”}

 

{result“: “success”,token“: “eyJ0eXAiOiJKV1QiLCJhbGciOiJFUzI1NiIsImtpZCI6ImprM3JXNEhBVm9HSzl6QVhsdnVzdnMxdTFLeVlMRUxYRG10OXlTOXViYUkifQ.eyJ0eXBlIjoyLCJwcm9kdWN0IjoyLCJhdHAiOiJjbWFjIiwic3ViIjoiZDYwOGFhZGYwYjI1MmE4N2EwYmEyMGQ3NTQ1NDM1N2Y3Y2Y5NDZlNWZjM2VjMmQ4YjViZmY4NGRhODg4Yzk5ZSIsImlhdCI6MTY4Nzg0MjAzMSwiZXhwIjoxNjg3ODQyMDYxLCJpc3MiOiJodHRwczovL2F1dGgudml2b2tleS5jb20iLCJqdGkiOiI2ODY0NTdjMjBmNjZkOWU1YWI3ZWQyMzMxYmYyOGMyNWE0ZjI4NGQ0MTAyZWFjMmE2YTUxNjc0NjdmMTcxYTI2In0.guSNm14-Nwf7nniN2Am9efCZCyW86ZXjC4F5Y08UzAVCqO4lbYTT5Wb6ip3g4Wf-OFCQNoe1G-E1NNZBlz-FeA”}

 

Inspect authenticity JWT with jwt.io (includes public key to validate signature)

Live CMAC Signature test

Using the form below you can test CMAC signature validation using your API key and the CMAC data and signature.

Appendix

APDU Response Codes

When working with PC/SC readers, APDU messages are  used to exchange data between the application and both the transponder on the reader and the reader itself. Responses returned generally will contain a two "status word" byte suffix which gives clues as to the result of your request.

SW1SW2(Info/Warning/Error/Security) Description
6(E) Class not supported.
61(I) Response bytes still available
61XX(I) Command successfully executed; ‘XX’ bytes of data are available and can be requested using GET RESPONSE.
62(W) State of non-volatile memory unchanged
6200(W) No information given (NV-Ram not changed)
6201(W) NV-Ram not changed 1.
6281(W) Part of returned data may be corrupted
6282(W) End of file/record reached before reading Le bytes
6283(W) Selected file invalidated
6284(W) Selected file is not valid. FCI not formated according to ISO
6285(W) No input data available from a sensor on the card. No Purse Engine enslaved for R3bc
62A2(W) Wrong R-MAC
62A4(W) Card locked (during reset( ))
62CX(W) Counter with value x (command dependent)
62F1(W) Wrong C-MAC
62F3(W) Internal reset
62F5(W) Default agent locked
62F7(W) Cardholder locked
62F8(W) Basement is current agent
62F9(W) CALC Key Set not unblocked
62FX(W) –
62XX(W) RFU
63(W) State of non-volatile memory changed
6300(W) No information given (NV-Ram changed)
6381(W) File filled up by the last write. Loading/updating is not allowed.
6382(W) Card key not supported.
6383(W) Reader key not supported.
6384(W) Plaintext transmission not supported.
6385(W) Secured transmission not supported.
6386(W) Volatile memory is not available.
6387(W) Non-volatile memory is not available.
6388(W) Key number not valid.
6389(W) Key length is not correct.
63C0(W) Verify fail, no try left.
63C1(W) Verify fail, 1 try left.
63C2(W) Verify fail, 2 tries left.
63C3(W) Verify fail, 3 tries left.
63CX(W) The counter has reached the value ‘x’ (0 = x = 15) (command dependent).
63F1(W) More data expected.
63F2(W) More data expected and proactive command pending.
63FX(W) –
63XX(W) RFU
64(E) State of non-volatile memory unchanged
6400(E) No information given (NV-Ram not changed)
6401(E) Command timeout. Immediate response required by the card.
64XX(E) RFU
65(E) State of non-volatile memory changed
6500(E) No information given
6501(E) Write error. Memory failure. There have been problems in writing or reading the EEPROM. Other hardware problems may also bring this error.
6581(E) Memory failure
65FX(E) –
65XX(E) RFU
66(S)
6600(S) Error while receiving (timeout)
6601(S) Error while receiving (character parity error)
6602(S) Wrong checksum
6603(S) The current DF file without FCI
6604(S) No SF or KF under the current DF
6669(S) Incorrect Encryption/Decryption Padding
66XX(S) –
67(E)
6700(E) Wrong length
67XX(E) length incorrect (procedure)(ISO 7816-3)
68(E) Functions in CLA not supported
6800(E) No information given (The request function is not supported by the card)
6881(E) Logical channel not supported
6882(E) Secure messaging not supported
6883(E) Last command of the chain expected
6884(E) Command chaining not supported
68FX(E) –
68XX(E) RFU
69(E) Command not allowed
6900(E) No information given (Command not allowed)
6901(E) Command not accepted (inactive state)
6981(E) Command incompatible with file structure
6982(E) Security condition not satisfied.
6983(E) Authentication method blocked
6984(E) Referenced data reversibly blocked (invalidated)
6985(E) Conditions of use not satisfied.
6986(E) Command not allowed (no current EF)
6987(E) Expected secure messaging (SM) object missing
6988(E) Incorrect secure messaging (SM) data object
698DReserved
6996(E) Data must be updated again
69E1(E) POL1 of the currently Enabled Profile prevents this action.
69F0(E) Permission Denied
69F1(E) Permission Denied – Missing Privilege
69FX(E) –
69XX(E) RFU
6A(E) Wrong parameter(s) P1-P2
6A00(E) No information given (Bytes P1 and/or P2 are incorrect)
6A80(E) The parameters in the data field are incorrect.
6A81(E) Function not supported
6A82(E) File not found
6A83(E) Record not found
6A84(E) There is insufficient memory space in record or file
6A85(E) Lc inconsistent with TLV structure
6A86(E) Incorrect P1 or P2 parameter.
6A87(E) Lc inconsistent with P1-P2
6A88(E) Referenced data not found
6A89(E) File already exists
6A8A(E) DF name already exists.
6AF0(E) Wrong parameter value
6AFX(E) –
6AXX(E) RFU
6B(E)
6B00(E) Wrong parameter(s) P1-P2
6BXX(E) Reference incorrect (procedure byte), (ISO 7816-3)
6C(E) Wrong length Le
6C00(E) Incorrect P3 length.
6CXX(E) Bad length value in Le; ‘xx’ is the correct exact Le
6D(E)
6D00(E) Instruction code not supported or invalid
6DXX(E) Instruction code not programmed or invalid (procedure byte), (ISO 7816-3)
6E(E)
6E00(E) Class not supported
6EXX(E) Instruction class not supported (procedure byte), (ISO 7816-3)
6F(E) Internal exception
6F00(E) Command aborted – more exact diagnosis not possible (e.g., operating system error).
6FFF(E) Card dead (overuse, …)
6FXX(E) No precise diagnosis (procedure byte), (ISO 7816-3)
9-
9000(I) Command successfully executed (OK).
9004(W) PIN not succesfully verified, 3 or more PIN tries left
9008Key/file not found
9080(W) Unblock Try Counter has reached zero
9100OK
9101States.activity, States.lock Status or States.lockable has wrong value
9102Transaction number reached its limit
910CNo changes
910EInsufficient NV-Memory to complete command
911CCommand code not supported
911ECRC or MAC does not match data
9140Invalid key number specified
917ELength of command string invalid
919DNot allow the requested command
919EValue of the parameter invalid
91A0Requested AID not present on PICC
91A1Unrecoverable error within application
91AEAuthentication status does not allow the requested command
91AFAdditional data frame is expected to be sent
91BEOut of boundary
91C1Unrecoverable error within PICC
91CAPrevious Command was not fully completed
91CDPICC was disabled by an unrecoverable error
91CENumber of Applications limited to 28
91DEFile or application already exists
91EECould not complete NV-write operation due to loss of power
91F0Specified file number does not exist
91F1Unrecoverable error within file
920x(I) Writing to EEPROM successful after ‘x’ attempts.
9210(E) Insufficient memory. No more storage available.
9240(E) Writing to EEPROM not successful.
9301Integrity error
9302Candidate S2 invalid
9303(E) Application is permanently locked
9400(E) No EF selected.
9401Candidate currency code does not match purse currency
9402Candidate amount too high
9402(E) Address range exceeded.
9403Candidate amount too low
9404(E) FID not found, record not found or comparison pattern not found.
9405Problems in the data field
9406(E) Required MAC unavailable
9407Bad currency : purse engine has no slot with R3bc currency
9408R3bc currency not supported in purse engine
9408(E) Selected file type does not match command.
9580Bad sequence
9681Slave not found
9700PIN blocked and Unblock Try Counter is 1 or 2
9702Main keys are blocked
9704PIN not succesfully verified, 3 or more PIN tries left
9784Base key
9785Limit exceeded – C-MAC key
9786SM error – Limit exceeded – R-MAC key
9787Limit exceeded – sequence counter
9788Limit exceeded – R-MAC length
9789Service not available
9802(E) No PIN defined.
9804(E) Access conditions not satisfied, authentication failed.
9835(E) ASK RANDOM or GIVE RANDOM not executed.
9840(E) PIN verification not successful.
9850(E) INCREASE or DECREASE could not be executed because a limit has been reached.
9862(E) Authentication Error, application specific (incorrect MAC)
99001 PIN try left
9904PIN not succesfully verified, 1 PIN try left
9985Wrong status – Cardholder lock
9986(E) Missing privilege
9987PIN is not installed
9988Wrong status – R-MAC state
9A002 PIN try left
9A04PIN not succesfully verified, 2 PIN try left
9A71Wrong parameter value – Double agent AID
9A72Wrong parameter value – Double agent Type
9D05(E) Incorrect certificate type
9D07(E) Incorrect session data size
9D08(E) Incorrect DIR file record size
9D09(E) Incorrect FCI record size
9D0A(E) Incorrect code size
9D10(E) Insufficient memory to load application
9D11(E) Invalid AID
9D12(E) Duplicate AID
9D13(E) Application previously loaded
9D14(E) Application history list full
9D15(E) Application not open
9D17(E) Invalid offset
9D18(E) Application already loaded
9D19(E) Invalid certificate
9D1A(E) Invalid signature
9D1B(E) Invalid KTU
9D1D(E) MSM controls not set
9D1E(E) Application signature does not exist
9D1F(E) KTU does not exist
9D20(E) Application not loaded
9D21(E) Invalid Open command data length
9D30(E) Check data parameter is incorrect (invalid start address)
9D31(E) Check data parameter is incorrect (invalid length)
9D32(E) Check data parameter is incorrect (illegal memory check area)
9D40(E) Invalid MSM Controls ciphertext
9D41(E) MSM controls already set
9D42(E) Set MSM Controls data length less than 2 bytes
9D43(E) Invalid MSM Controls data length
9D44(E) Excess MSM Controls ciphertext
9D45(E) Verification of MSM Controls data failed
9D50(E) Invalid MCD Issuer production ID
9D51(E) Invalid MCD Issuer ID
9D52(E) Invalid set MSM controls data date
9D53(E) Invalid MCD number
9D54(E) Reserved field error
9D55(E) Reserved field error
9D56(E) Reserved field error
9D57(E) Reserved field error
9D60(E) MAC verification failed
9D61(E) Maximum number of unblocks reached
9D62(E) Card was not blocked
9D63(E) Crypto functions not available
9D64(E) No application loaded
9E00PIN not installed
9E04PIN not succesfully verified, PIN not installed
9F00PIN blocked and Unblock Try Counter is 3
9F04PIN not succesfully verified, PIN blocked and Unblock Try Counter is 3
9FXXCommand successfully executed; ‘xx’ bytes of data are available and can be requested using GET RESPONSE.
9xXXApplication related status, (ISO 7816-3)

Get an API key!

No complicated sign up process required! Simply submit your email address and an API key will be sent to you immediately.

If you have already received one or more API keys at this email address, all previous keys will remain functional, and a new key will be created and sent to you.