npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

ton-nfc-client

v2.0.1

Published

TODO

Downloads

11

Readme

ton-nfc-client

The library is developed handle communication of Android smartphones/iPhones with NFC TON Labs Security cards. It provides a useful API to work with all functionality (i.e. APDU commands) supported by NFC TON Labs Security card. The technical specification of TON Labs Security card can be found here https://ton.surf/scard.

  • For the case of iPhone you must have iOS version >= 13 and iPhone model >= 7. For the case of Android you should also check whether it supports NFC feature.
  • Android native code of ton-nfc-client uses TonNfcClientAndroid library to handle NFC, and iOS native code respectively uses TonNfcClientSwift library.

Installation

$ npm install ton-nfc-client --save

Or take it from GitHub.

$ npm install git+https://github.com/tonlabs/ton-nfc-client

Additional steps for Android

Also you need to add NFC related stuff into AndroidManifest.xml of your React native app.

<intent-filter>
    	<action android:name="android.nfc.action.TECH_DISCOVERED" />
</intent-filter>
<meta-data android:name="android.nfc.action.TECH_DISCOVERED" android:resource="@xml/nfc_tech_filter" />

For this to work you must have an appropriate nfc_tech_filter.xml file in your xml subfolder (\app\src\main\res\xml).

<?xml version="1.0" encoding="utf-8"?>
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
	<tech-list>
		<tech>android.nfc.tech.IsoDep</tech>
	    	<tech>android.nfc.tech.NfcA</tech>
  	</tech-list>
</resources>

Additional steps for iOS

Run pod install from ios subdirectory of your React native app.

Also you must go through the following steps to make NFC working for you.

  • Open .workspace file of your project in Xcode.

  • Go to Signing & Capabilities tab and add capability Near Field Communication Tag Reading.

  • Add into info.plist the point Privacy - NFC Scan Usage Description and value for it Test NFC.

  • Add into info.plist the point ISO7816 application identifiers for NFC Tag Reader Session and add for it the following items: 313132323333343435353636, A000000151000000.

  • Add into info.plist the point com.apple.developer.nfc.readersession.formats and add for it string item TAG.

  • Check that everywhere you have iOS11+ deployment version. Otherwise, pod installation will complain about it.

  • Also there is possibility that you have to link libswiftCoreNFC library manually. For this go to Target->Application -> Build Phases -> Link Binary With Libraries and add libswiftCoreNFC.tbd.

  • Go to Project -> Application -> Build Settings -> Search Paths -> Library Search Paths and check that you have at least swift-5.2 everywhere.

Simple example

import {NfcCardModuleWrapper} from 'ton-nfc-client';

const nfcWrapper = new NfcCardModuleWrapper();
try {
	let hdIndex = "1";     
	let result = await nfcWrapper.getPublicKey(hdIndex);
	const publicKey = result.message;
  	alert("Public key: " + publicKey);
}
catch (e) {
        alert(e.message);
}

Another way to use ton-nfc-client functions looks as follows.

nfcWrapper.getPublicKey(hdIndex)
   .then((result) => alert("Public key for HD path m/44'/396'/0'/0'/" + hdIndex + "' : " + result.message))
   .catch((e) => alert(e.message));

Note: You can not work with NFC using simulator. You must run it on smartphone/iPhone. So for iPhone you should set the development team.

More about responses format and errors

To get more information about responses formats and errors please visit this pages: Android error list, iOS error list, Android readme, iOS readme.

Card activation

Detailed information about card activation is available here Android readme, iOS readme, card activation doc. Here we just give exemplary code for React native app.

import {NfcCardModuleWrapper, CardResponseMessage, CardStates, CardResponseStatus} from 'ton-nfc-client';

const nfcWrapper = new NfcCardModuleWrapper();
try {
	result = await nfcWrapper.getHashes();
	const hashOfCommonSecret = result.ecsHash;
	// check that hashOfCommonSecret is correct based on the data from smartcontract

	const hashOfEncryptedPassword = result.epHash;
	// check that hashOfEncryptedPassword is correct based on the data from smartcontract
	
	const newPin = "7777";
	// prepare authenticationPassword, commonSecret, initialVector based on the data from smartcontract
	
	const serialNumber = result.sn;

	await nfcWrapper.turnOnWallet(authenticationPassword, commonSecret, initialVector);
	//await nfcWrapper.turnOnWalletWithPin(newPin, authenticationPassword, commonSecret, initialVector)

}
catch (e) {
  console.log(e.message);
}

Recovery module

Detailed information about recovery functionality is available in Android readme, iOS readme. Here we just give the exemplary code for React native app. There is a snippet demonstrating the structure of recovery data and the way of adding it into TON Labs wallet applet.

let aesjs = require('aes-js');
try {
	// get aesKeyHexString from TON Labs service
	const aesKeyBytes = aesjs.utils.hex.toBytes(aesKeyHexString);
	const surfPublicKey = "B81F0E0E07416DAB6C320ECC6BF3DBA48A70101C5251CC31B1D8F831B36E9F2A";
	const multisigAddr = "A11F0E0E07416DAB6C320ECC6BF3DBA48A70121C5251CC31B1D8F8A1B36E0F2F";
	const authenticationPassword = "F4B072E1DF2DB7CF6CD0CD681EC5CD2D071458D278E6546763CBB4860F8082FE14418C8A8A55E2106CBC6CB1174F4BA6D827A26A2D205F99B7E00401DA4C15ACC943274B92258114B5E11C16DA64484034F93771547FBE60DA70E273E6BD64F8A4201A9913B386BCA55B6678CFD7E7E68A646A7543E9E439DD5B60B9615079FE";
	const commonSecret = "7256EFE7A77AFC7E9088266EF27A93CB01CD9432E0DB66D600745D506EE04AC4";
	//in real app take surfPublicKey, multisigAddr, authenticationPassword, commonSecret from TON Labs service
	const recoveryDataJson = JSON.stringify( {
            surfPublicKey:  surfPublicKey,
            multisigAddress:  multisigAddr,
            p1: authenticationPassword, 
            cs: commonSecret 
        });
	const recoveryDataBytes = aesjs.utils.utf8.toBytes(recoveryDataJson);
	const aesCtr = new aesjs.ModeOfOperation.ctr(aesKeyBytes, new aesjs.Counter(5));
  	const encryptedBytes = aesCtr.encrypt(recoveryDataBytes);
	const encryptedHex = aesjs.utils.hex.fromBytes(encryptedBytes);
	const result = await nfcWrapper.addRecoveryData(encryptedHex);
	const addRes = result.message;
  	console.log("Add recovery data into card result  = " + addRes);
}
catch (e) {
  	console.log(e.message);
}

There is an exemplary snippet demonstrating how to get the recovery data from TON Labs wallet applet.

try {
	// get aesKeyHexString from somewhere
	const aesKeyBytes = aesjs.utils.hex.toBytes(aesKeyHexString);
	const result = await nfcWrapper.getRecoveryData();
  	const encryptedRecoveryDataFromSecurityCard = result.message;
	const encryptedRecoveryDataFromSecurityCardBytes =  aesjs.utils.hex.toBytes(encryptedRecoveryDataFromSecurityCard);
	const aesCtr = new aesjs.ModeOfOperation.ctr(aesKeyBytes, new aesjs.Counter(5));
  	const decryptedBytes = aesCtr.decrypt(encryptedRecoveryDataFromSecurityCardBytes);
  	const decryptedRecoveryDataJson = aesjs.utils.utf8.fromBytes(decryptedBytes);
  	console.log("Decrypted recovery data : " + decryptedRecoveryDataJson);
}
catch (e) {
  console.log(e.message);
}

Protection against MITM

We protect the most critical card operations (APDU commands) against MITM attack by HMAC SHA256 signature. In this case the data field of such APDU is extended by 32-bytes sault generated by the card and the final byte array is signed. The obtained signature is added to the end of APDU data, i.e. its data field has the structure: payload || sault || sign(payload || sault). When the card gets such APDU, first it verifies sault and signature.

The secret key for HMAC SHA256 is produced based on card activation data. This key is saved into Android keystore or iOS keychain and then is used by the app to sign APDU commands data fields. Usually after correct card activation in the app (call of nfcWrapper.turnOnWallet) this key is produced and saved. So no extra code is required.

Another situation is possible. Let's suppose you activated the card earlier. After that you reinstalled the app working with NFC TON Labs security card or you started using new device. Then Android keystore/iOS keychain does not have the key to sign APDU commands. You must create it.

 nfcWrapper.createKeyForHmac(authenticationPassword, commonSecret, serialNumber)

You may work with multiple NFC TON Labs security cards. In this case in your Android keystore/iOS keychain there is a bunch of keys. Each key is marked by corresponding serial number. And you can get the list of serial numbers for which you have the key in keystore/keychain.

The list of operations protected by HMAC SHA256:

  • verifyPin, signForDefaultHdPath, sign, verifyPinAndSign, verifyPinAndSignForDefaultHdPath, checkSerialNumberAndSign, checkSerialNumberAndVerifyPinAndSign, checkSerialNumberAndSignForDefaultHdPath, checkSerialNumberAndVerifyPinAndSignForDefaultHdPath;
  • all functions related to card keychain.

Request ED25519 signature

The basic functionality provided by NFC TON Labs security card is Ed25519 signature. You may request public key and request the signature for some message.

import nacl from "tweetnacl";

hexStringToByteArray(hexStr) {
  	let bytes = [];
  	while (hexStr.length >= 2) {
     		bytes.push(parseInt(hexStr.substring(0, 2), 16));
     		hexStr = hexStr.substring(2, hexStr.length);
  	}
  	return new Uint8Array(bytes);
}

try {
	const msg = "0000"; //Some hex string of even length 
	const pin = "5555";
	let result = await nfcWrapper.verifyPinAndSignForDefaultHdPath(msg, pin);
	const signature = result.message;
	result = await nfcWrapper.getPublicKeyForDefaultPath();
  	const pubKey = result.message;
	const msgBytes = hexStringToByteArray(msg);
  	const signatureBytes = hexStringToByteArray(signature);
  	const pubKeyBytes = hexStringToByteArray(pubKey);
  	const sigVerificationRes = nacl.sign.detached.verify(msgBytes, signatureBytes, pubKeyBytes);
  	if (sigVerificationRes == false) {
       		throw new Error("Signature is not correct.");
  	}
}
catch (e) {
  console.log(e.message);
}

Note: Functions verifyPinAndSignForDefaultHdPath, verifyPinAndSign are protected by HMAC SHA256 signature. But also there is an additional protection for them by PIN code. You have 10 attempts to enter PIN. After 10th fail you will not be able to use existing seed (keys for ed25519). The only way to unblock these functions is to reset the seed (see resetWallet function) and generate new seed (see generateSeed). After resetting the seed PIN will be also reset to default value 5555.

Card keychain

The detailed information about card keychain is available here Android readme, iOS readme. Here we just give the exemplary code for React native app. The below snippet demonstrates the work with keychain. We add one key and then retrieve it from the card. Then we replace it by a new key of the same length. In the end we delete the key.

try {
  	const key = "B81F0E0E07416DAB6C320ECC6BF3DBA48A70101C5251CC31B1D8F831B36E9F2A";
  	let result = await nfcWrapper.addKeyIntoKeyChain(key);
	const keyHmac = result.message;
	result = await nfcWrapper.getKeyFromKeyChain(keyHmac);
	const keyFromCard = result.message;
	const newKey = "AA1F0E0E07416DAB6C320ECC6BF3DBA48A70101C5251CC31B1D8F831B36E9F25";
	result = await nfcWrapper.changeKey(newKey, keyHmac);
	const newKeyHmac = result.message;
	result = await nfcWrapper.getNumberOfKeys();
	let numberOfKeys = result.message;
  	console.log("Number of keys = " + numberOfKeys);
  	await nfcWrapper.deleteKeyFromKeyChain(newKeyHmac);	
	result = await nfcWrapper.getNumberOfKeys();
	numberOfKeys = result.message;
	console.log("Number of keys = " + numberOfKeys);
}
catch (e) {
  console.log(e.message)
}

Full functions list

The full list of functions provided by the library to communicate with the card you will find here

Catching NFC related events from ton-nfc-client

For Android add into your app the following exemplary code:

import {NfcEventsEmitterWrapper} from 'ton-nfc-client';
import Toast from 'react-native-simple-toast';

NfcEventsEmitterWrapper.addListener((msg) => {
  Toast.showWithGravity(msg, Toast.LONG, Toast.TOP);
  console.log(msg);
});

For iOS you additionaly should add this.

if (Platform.OS === "ios") {
  nfcCardModuleWrapper.setNfcNotificator();
}