- Note
- Advanced / more detailed C# code examples can also be found in the
Examples
folder inside the released SDK package. The folder contains a complete solution (Examples.sln
file) and individual projects (*.csproj
files) for each example, so that you can run them directly.
All strings, hex-strings and other values used in the examples are arbitrary, just to show the functionality of the SDK. Replace them when using the SDK in your own environment.
Device Management
List Connected Tokens/Readers
This function will list all connected readers, tokens and their respective ATRs.
Command Line Tool
To list all the readers with connected tokens, use the token-info
command:
.\CrescendoCLI.exe token-info --log-level info
An example response to this command might look like this:
[2024-05-31 15:40:50.516][INFO] Log level is set to "INFO".
[2024-05-31 15:40:50.570][INFO] All connected tokens:
- Reader Name: Circle Idaxis SecurePIV 0
- Token: Crescendo 4000
- Token ATR: 3B-D5-96-FF-81-91-FE-1F-C3-43-34-30-30-30-C9
- Assigned number for the "-t" parameter: 0
- Reader Name: VMware Virtual USB CCID 0
- Token: Crescendo Key V3
- Token ATR: 3B-D9-96-FF-81-91-FE-1F-C3-43-34-30-30-30-2D-4B-45-59-BF
- Assigned number for the "-t" parameter: 1
C#
You can use one of three possible functions to list token/reader info:
- GetAllAvailableTokens - returns a list of all available tokens with their names, ATRs, and the reader name.
- GetAllAvailableReaders - returns a list of all available reader names, regardless of whether they have tokens connected or not. Does not communicate with tokens at all, and should be faster than the other two methods.
- GetAllReaderInfo - returns a comprehensive list of ReaderInfo objects, that contain detailed information about each reader, including the connected tokens and their ATRs.
List<(string ReaderName, byte[] TokenATR, string TokenName, int TokenIndex)> allAvailableTokens = SDKCore.GetAllAvailableTokens();
List<string> allReaders = SDKCore.GetAllAvailableReaders();
List<ReaderInfo> allReadersWithDetails = SDKCore.GetAllReaderInfo();
Python
You can call GetAllAvailableTokens method directly like this:
readerList = SDKCore.GetAllAvailableTokens()
Token connection monitoring
- Note
- More detailed C# code example can be found in the
Examples/LiveReaderTokenMonitoring
folder inside the released SDK package.
You can use the SDK to monitor the present tokens and readers, to detect when a card, USB token or a reader is inserted or removed. By using the OnReadersChanged event, you can get notified about changes in the readers and tokens and then run any other code or method you want. The monitoring can be started with the StartMonitoring method and stopped with the EndMonitoring method. For example:
List<(string ReaderName, byte[] TokenATR, string TokenName, int TokenIndex)> allAvailableTokens = SDKCore.GetAllAvailableTokens();
SDKCore.OnReadersChanged += (allReaders, changes) =>
{
};
SDKCore.StartMonitoring();
using (SDKCore methods = new(allAvailableTokens[0].ReaderName))
{
}
SDKCore.EndMonitoring();
Get CUID of a token
To obtain a CUID of a token, use the token-cuid
command:
.\CrescendoCLI.exe token-cuid -t 0 --log-level info
An example response to this command might look like this:
[2025-04-28 10:16:47.333][INFO] Log level is set to "INFO".
[2025-04-28 10:16:47.493][INFO] Connected to:
[2025-04-28 10:16:47.494][INFO] - Reader: "Circle Idaxis SecurePIV 0"
[2025-04-28 10:16:47.494][INFO] - Token: "Crescendo 4000"
[2025-04-28 10:16:47.494][INFO] - ATR: 3B-D5-96-FF-81-91-FE-1F-C3-43-34-30-30-30-C9
[2025-04-28 10:16:47.581][INFO] The token CUID is: 4790D600535905872620
4790D600535905872620
C#
After the initial set-up, you can call the GetTokenCUID method like this:
SDKCore.Result<string> result = transaction.GetTokenCUID();
Python
After the initial set-up, you can call the GetTokenCUID method like this:
dllMethodsInstance.GetTokenCUID()
Change PIN
This function will change the PIN
on the token and output the newly set PIN
.
Important input parameters
--pin
- PIN
to be used for authentication. String env
can be used to read an Environment Variable PIN
as a valid key. String interactive
can be used to utilize the Windows interactive window for PIN entering.
--new-pin
- New PIN
value. If no value is entered, then a random 6 digit numeric-only number will be used as a new PIN
value.
Command Line Tool
Example of pin-change
command usage:
.\CrescendoCLI.exe pin-change -p 123456 -n 654321 --log-level info
This will change the PIN
from 123456
to 654321
. An example response to this command might look like this:
[2024-04-18 15:36:26.659][INFO] Log level is set to "INFO".
[2024-04-18 15:36:26.707][INFO] Connected to:
[2024-04-18 15:36:26.708][INFO] - Reader: "Circle Idaxis SecurePIV 0"
[2024-04-18 15:36:26.708][INFO] - Token: "Crescendo 4000"
[2024-04-18 15:36:26.708][INFO] - ATR: 3B-D5-96-FF-81-91-FE-1F-C3-43-34-30-30-30-C9
[2024-04-18 15:36:26.760][INFO] Trying to change PIN from "123456" to "654321"
[2024-04-18 15:36:26.836][INFO] PIN was successfully verified on ACA applet.
[2024-04-18 15:36:26.891][INFO] PIN was successfully verified on PIV applet.
[2024-04-18 15:36:26.929][INFO] PIN successfully changed to "654321".
654321
C#
After the initial set-up, you can call the ChangePIN method like this:
SDKCore.Result<string> result = transaction.ChangePin("123456");
Python
After the initial set-up, you can call the ChangePIN method like this:
params = {
'newPin': '654321',
}
dllMethodsInstance.ChangePIN(**params)
Set or change XAUTH
This function will set or change the XAUTH
(Management key) on the token.
Command Line Tool
Example of xauth-key-put
command usage:
.\CrescendoCLI.exe xauth-key-put -p 321321 -x 12345678123456781234567812345678 --log-level info
This will change the XAUTH
to 12345678123456781234567812345678
. An example response to this command might look like this:
[2024-09-03 15:32:22.422][INFO] Log level is set to "INFO".
[2024-09-03 15:32:22.455][INFO] Connected to:
[2024-09-03 15:32:22.455][INFO] - Reader: "HID Global OMNIKEY 5422 Smartcard Reader 0"
[2024-09-03 15:32:22.455][INFO] - Token: "Crescendo 4000"
[2024-09-03 15:32:22.455][INFO] - ATR: 3B-D5-96-FF-81-91-FE-1F-C3-43-34-30-30-30-C9
[2024-09-03 15:32:22.551][INFO] PIN was successfully verified on ACA applet.
[2024-09-03 15:32:22.627][INFO] Symmetric XAUTH "AES" key was successfully put onto the token.
C#
After the initial set-up, you can call the PutXAUTHKey method like this:
SDKCore.Result result = transaction.PutXAUTHKey("12345678123456781234567812345678", default!, "");
Python
After the initial set-up, you can call the PutXAUTHKey method like this:
params = {
'xauthKey': '12345678123456781234567812345678',
'xauthKeyType': None,
'jsonInputPath': '',
}
dllMethodsInstance1.PutXAUTHKey(**params)
Reset Token
This function will reset the token to its default state and remove any data, keys or certificates stored on the key.
Command Line Tool
Example of token-reset
command usage:
.\CrescendoCLI.exe token-reset -p 123456 --log-level info
This will reset the token. An example response to this command might look like this:
[2024-04-18 15:59:15.989][INFO] Log level is set to "INFO".
[2024-04-18 15:59:16.105][INFO] Connected to:
[2024-04-18 15:59:16.106][INFO] - Reader: "Circle Idaxis SecurePIV 0"
[2024-04-18 15:59:16.106][INFO] - Token: "Crescendo 4000"
[2024-04-18 15:59:16.106][INFO] - ATR: 3B-D5-96-FF-81-91-FE-1F-C3-43-34-30-30-30-C9
[2024-04-18 15:59:16.191][INFO] PIN was successfully verified on ACA applet.
[2024-04-18 15:59:16.192][INFO] Trying to reset the token:
[2024-04-18 15:59:16.930][INFO] PIN was successfully verified on ACA applet.
[2024-04-18 15:59:16.984][INFO] PIN was successfully verified on PIV applet.
[2024-04-18 15:59:17.133][INFO] Token was successfully reset.
C#
After the initial set-up, you can call the ResetToken method like this:
SDKCore.Result result = transaction.ResetToken();
Python
After the initial set-up, you can call the ResetToken method like this:
dllMethodsInstance.ResetToken()
PIV Configuration
Generate Key Pair / Retrieve Public Key
This function allows to generate an Asymmetric Key Pair on the token, or retrieve the Public key, if the Key Pair was already generated in the past. It will always return the public key.
Important input parameters
--crypto-mechanism
- The desired cryptographic mechanism. Valid options can be found here.
--key-reference
- Key Reference where the generated Key Pair will be stored.
--retrieve-key
- If the Key Pair was generated previously, use this to just retrieve it instead of generating a new Key Pair.
--output-file
**(Available in CLI Tool only)** - Path to an output file that should contain the public key. When left empty, the public key will simply be logged.
Command Line Tool
Example of piv-key-pair-gen
command usage:
.\CrescendoCLI.exe piv-key-pair-gen -p 123456 --crypto-mechanism RSA3072 --key-reference B0 --output-file C:\Temp\publicKey.pem --log-level info
This will generate a RSA3072
key pair on the Key Reference B0
and save the public key (modulus and exponent) to the defined file C:\Temp\publicKey.pem
. An example response to this command might look like this:
[2024-04-18 14:25:44.326][INFO] Log level is set to "INFO".
[2024-04-18 14:25:44.354][INFO] Connected to:
[2024-04-18 14:25:44.355][INFO] - Reader: "Circle Idaxis SecurePIV 0"
[2024-04-18 14:25:44.355][INFO] - Token: "Crescendo 4000"
[2024-04-18 14:25:44.355][INFO] - ATR: 3B-D5-96-FF-81-91-FE-1F-C3-43-34-30-30-30-C9
[2024-04-18 14:25:44.430][INFO] PIN was successfully verified on ACA applet.
[2024-04-18 14:25:44.448][INFO] Trying to generate asymmetric key pair on Key Reference "B0". This will take several seconds.
[2024-04-18 14:26:00.778][INFO] PIN was successfully verified on PIV applet.
[2024-04-18 14:26:00.795][INFO] Successful addition of tags and specified data to buffer "5FC160".
[2024-04-18 14:26:00.817][INFO] Successful generation of the asymmetric key pair.
C#
After the initial set-up, you can call the PIVGenerateKeyPair method like this:
SDKCore.Result<string> result = transaction.PIVGenerateKeyPair(PIVCryptographicMechanismIdentifier.RSA3072, "B0");
File.WriteAllText("C:\Temp\publicKey.pem", result.Value);
Python
After the initial set-up, you can call the PIVGenerateKeyPair method like this:
params = {
'cryptoMechanism': PIVCryptographicMechanismIdentifier.RSA3072,
'keyReference': 'B0',
'getExistingPublicKey': False,
}
dllMethodsInstance.PIVGenerateKeyPair(**params)
The CrescendoDLL.PCSC namespace contains Enums relevant to public methods from the main CrescendoDLL ...
Definition APDUEngine.cs:8
Load Key / Certificate
This function allows to put private key, certificate, or both, to the token.
Important input parameters
--input-file
- Path to an input file containing either a private key, certificate, or a combination of both. The supported file formats are *.PEM, *.CRT, *.PFX and *.P12. If there are multiple certificates present in the input file, only the first one will be imported. If the --object-type
parameter is set to both, then a first certificate that also has a private key will be imported.
--input-pass
- Password for opening the input file
--key-reference
- Key Reference where the private key will be stored.
--ber-tlv-tag
- BER-TLV Tag of the data object where the certificate will be stored.
--object-type
- Parameter for specifying what type of PKI object should be imported to the token. Valid options can be found here.
--key-name
- Key Name, that can be stored on the token and later used to identify the key.
Command Line Tool
Example of piv-pki-put
command usage:
.\CrescendoCLI.exe piv-pki-put -p 123456 --key-reference 9C --input-file "C:\Temp\ECCCert.p12" --input-pass password --object-type both --key-name MyNewKey --log-level info
This will load both Private Key and a certificate from file located at C:\Temp\ECCCert.p12
to the token. An example response to this command might look like this:
[2024-04-18 14:26:22.120][INFO] Log level is set to "INFO".
[2024-04-18 14:26:22.238][INFO] Connected to:
[2024-04-18 14:26:22.239][INFO] - Reader: "Circle Idaxis SecurePIV 0"
[2024-04-18 14:26:22.239][INFO] - Token: "Crescendo 4000"
[2024-04-18 14:26:22.239][INFO] - ATR: 3B-D5-96-FF-81-91-FE-1F-C3-43-34-30-30-30-C9
[2024-04-18 14:26:22.387][INFO] PIN was successfully verified on ACA applet.
[2024-04-18 14:26:22.441][INFO] Trying to inject RSA key - "p" component.
[2024-04-18 14:26:22.621][INFO] Trying to inject RSA key - "q" component.
[2024-04-18 14:26:22.645][INFO] Trying to inject RSA key - "q^(-1)" component.
[2024-04-18 14:26:22.670][INFO] Trying to inject RSA key - "dP" component.
[2024-04-18 14:26:22.694][INFO] Trying to inject RSA key - "dQ" component.
[2024-04-18 14:26:22.760][INFO] PIN was successfully verified on PIV applet.
[2024-04-18 14:26:22.835][INFO] PIN was successfully verified on PIV applet.
[2024-04-18 14:26:23.048][INFO] PIN was successfully verified on PIV applet.
[2024-04-18 14:26:23.088][INFO] Successful addition of tags and specified data to buffer "5FC10A".
[2024-04-18 14:26:23.089][INFO] Successful injection of private key with name "MyNewKey" to the key reference "9C".
[2024-04-18 14:26:23.128][INFO] PIN was successfully verified on PIV applet.
[2024-04-18 14:26:23.484][INFO] PIN was successfully verified on PIV applet.
[2024-04-18 14:26:23.524][INFO] Successful addition of tags and specified data to buffer "5FC10A".
C#
After the initial set-up, you can call the PIVPutPKIData method like this:
SDKCore.Result result = transaction.PIVPutPKIData("C:\\Temp\\ECCCert.p12", "password", PIVObjectType.both, "9C", "", "MyNewKey");
Python
After the initial set-up, you can call the PIVPutPKIData method like this:
params = {
'inputfilePath': 'C:\Temp\ECCCert.p12',
'password': 'password',
'pkiObjectType': PIVObjectType.both,
'keyReference': '9C',
'berTLVtag': '',
'keyName': 'MyNewKey',
}
dllMethodsInstance.PIVPutPKIData(**params)
Sign Data
This function will take data from input file or input string, create a Hash of the data and send it to the token to get the hash signed back using a specified private key.
Important input parameters
--key-reference
- Key Reference defining the private key that will be used for signing.
--input-file
- Path to file that with the data to be hashed and signed.
--input-string
- Input string that should be hashed and signed.
--input-type
- Encoding of the input string. Valid options (case-insensitive) are HEX
, BASE64
, BASE64URL
, UTF8
and BIN
. BIN
does only make sense when using an input file to read all bytes directly.
--output-file
- Path to an output file that should contain the signature. When left empty, the signature will simply be logged.
--output-type
- Encoding of the output string containing the signature. Valid options (case-insensitive) are HEX
, BASE64
, BASE64URL
, UTF8
and BIN
(to save the signature bytes directly without any encoding).
--hash
- Hash algorithm to be used for hashing the input data. Valid options (case-insensitive) are: SHA1
, SHA256
and SHA512
.
Command Line Tool
Example of piv-data-sign
command usage:
.\CrescendoCLI.exe piv-data-sign -p 123456 -i "C:\Temp\LoremIpsum.txt" --input-type utf8 --key-reference 9a --log-level info
This will return a signature of data stored in C:\Temp\LoremIpsum.txt
using a private key stored on Key Reference 9A. An example response to this command might look like this:
[2024-05-31 15:55:07.135][INFO] Log level is set to "INFO".
[2024-05-31 15:55:07.260][INFO] Connected to:
[2024-05-31 15:55:07.260][INFO] - Reader: "Circle Idaxis SecurePIV 0"
[2024-05-31 15:55:07.260][INFO] - Token: "Crescendo 4000"
[2024-05-31 15:55:07.260][INFO] - ATR: 3B-D5-96-FF-81-91-FE-1F-C3-43-34-30-30-30-C9
[2024-05-31 15:55:07.349][INFO] PIN was successfully verified on ACA applet.
[2024-05-31 15:55:07.486][INFO] PIN was successfully verified on PIV applet.
[2024-05-31 15:55:07.984][INFO] Successful signing of the input data.
ZA2XlPJ6r5JJMVhXBA2cvQFJFDc5Ua7RlW53q2HoGKptEav7jYO/lfud82YHldqw0Ln92u2Br2TYjJDhZLLs68j2EmoyifYpt+rj3wL56IkRhAm1r1pLc9B2w69ntL35YEwXjoeDGQEFzho2VwGVpPVeRVm/pb0/vJYTBRHIHe+ZzkN0WbGZ77gW4qpXHIeyM+HMq4CwFIDmNmuQ4l/X4+cgcadYtbs+AthsnrcgXytIp3vEANPul/PoS2w4VloTRIkMSCv9dZRMSJ5qrqHA/An4+x/YGdBR34a3FILTi4XUyy3ZZ7n1LBO0Dwfx1MC1b73auI2p8L9elY8T60+lgDvFPEHA2B6sQjbuF/jWe3j6Opf0yCK+Poz5rBpLx3P0iIQn40vnWK1w7enBXhyS90KG9OH/xpBpMHcFlborrWju8QdrnoivoT/O0dBW9X6bNIxz9ORUVfAttNzVpcxBBahg74sBO00ufkYeTZ6qDgIuS+T92+Xc3e0b+mH8APrsRq1T2bJbtDgTkvP4k6ZzhsSvHdED3tfYEA2IxW1OHiitkosdWDy6ZwvOPlSYw8TU/pwSvqEFm1mJrxirToEtyWddEzL6OCUM8kxGqbUKgh19BzZYI9FAFhs+oWXupHZKmdcNWiWkAQhrGimts7+88mN8nFWa2eSyW792GE/vAsY=
C#
After the initial set-up, you can call the PIVSignData method like this:
SDKCore.Result<string> result = transaction.PIVSignData("9A", DataType.UTF8, "", "C:\\Temp\\LoremIpsum.txt", DataType.BASE64, HashAlgoValues.SHA256);
Python
After the initial set-up, you can call the PIVSignData method like this:
params = {
'keyReference': '9A',
'inputType': DataType.UTF8,
'inputString': '',
'inputFilePath': 'C:\Temp\LoremIpsum.txt',
'outputType': DataType.BASE64,
'hashAlgo': HashAlgoValues.SHA256,
}
dllMethodsInstance.PIVSignData(**params)
OTP Configuration
Configure OTP
This function will configure selected OTP slot, so that it can be used for OTP generation. Various input parameters can be specified. The function will also generate (or update already existing) PKCS file.
Important input parameters
--oath-slot
- OATH slot number (case-insensitive). Valid options for V3 applet are: 1-3, valid options for V4 applet are: C0-CF for user slots, 00-0F for managed slots. The parameter --button-press
will overrule this one in case both are entered.
--button-press
- Parameter for identifying OATH button-press slots. With Crescendo Key V1 & V2 (applet V3) you can configure the single button-press slot also by using --oath-slot 1
. Valid options are 1
for single press (on both applet V3 and V4) and 2
for double press (applet V4 only).
--oath-key
- OATH key (secret) to be stored to the token.
--mode
- OATH mode to be used. Valid options can be found here
--pskc-path
- Path to a PSKC file. If the PSKC file already exists in the specified path, it will get updated. Otherwise new file will be generated. Without defining explicit path, the file will be stored in .\PSKC
under the token CUID
and *.pskc
extension.
--transport-key
- Transport key used for creation of the PSKC file content.
--friendly-name
- Friendly name for description. Must be max 64 bytes (characters) long for applet V3, 32 bytes (characters) for applet V4.
--require-touch
- Set this parameter with Crescendo Key V3 to require PIN + button press to retrieve the OTP.
Command Line Tool
Example of otp-slot-configure
command usage:
.\CrescendoCLI.exe otp-slot-configure -p 123456 --oath-slot C5 --oath-key 0910f75fb6 --mode TOTP --friendly-name "OATH TOTP" --pskc-path "c:\Temp\PSKCFile.pskc" --transport-key 12345678123456781234567812345678 --log-level info
This will configure the oath slot C5
to use TOTP
on a single button-press and store the secret 0910f75fb6
to the token, so that OTP can be used. An example response to this command might look like this:
[2024-04-18 14:39:44.373][INFO] Log level is set to "INFO".
[2024-04-18 14:39:44.421][INFO] Connected to:
[2024-04-18 14:39:44.422][INFO] - Reader: "Circle Idaxis SecurePIV 0"
[2024-04-18 14:39:44.422][INFO] - Token: "Crescendo 4000"
[2024-04-18 14:39:44.422][INFO] - ATR: 3B-D5-96-FF-81-91-FE-1F-C3-43-34-30-30-30-C9
[2024-04-18 14:39:44.506][INFO] PIN was successfully verified on ACA applet.
[2024-04-18 14:39:44.724][INFO] The OATH configuration was successfully put to slot "C5".
[2024-04-18 14:39:44.764][INFO] The OATH key was successfully put to slot "C5".
[2024-04-18 14:39:44.819][INFO] PIN was successfully verified on PIV applet.
[2024-04-18 14:39:44.978][INFO] Successfully updated the PSKC file located at "c:\Temp\PSKCFile.pskc".
C#
After the initial set-up, you can call the ConfigureOATHSlot method like this:
SDKCore.Result<string> result = transaction.ConfigureOATHSlot("C5", 0, "0910f75fb6", 30, OATHModeName.TOTP, "0000000000000000", HashAlgoValues.SHA1, 6, "OATH TOTP", 16, "12345678123456781234567812345678", "", false);
Python
After the initial set-up, you can call the ConfigureOATHSlot method like this:
params = {
'oathSlot': 'C5',
'buttonPress': 0,
'oathKey': '0910f75fb6',
'jsonInputPath': '',
'timeStep': 30,
'oathMode': OATHModeName.TOTP,
'oathCounter': '0000000000000000',
'oathHash': HashAlgoValues.SHA1,
'codeDigits': 6,
'friendlyName': 'OATH TOTP',
'truncationOffset': 16,
'transportKey': '12345678123456781234567812345678',
'pskcString': '',
'requireTouch': false,
}
dllMethodsInstance.ConfigureOATHSlot(**params)
Generate OTP
This function will return an OTP generated from the specified OTP slot.
Important input parameters
--oath-slot
- OATH slot number (case-insensitive). Valid options for V3 applet are: 1-3, valid options for V4 applet are: C0-CF for user slots, 00-0F for managed slots. The parameter --button-press
will overrule this one in case both are entered.
--button-press
- Parameter for identifying OATH button-press slots. With Crescendo Key V1 & V2 (applet V3) you can configure the single button-press slot also by using --oath-slot 1
. Valid options are 1
for single press (on both applet V3 and V4) and 2
for double press (applet V4 only).
Command Line Tool
Example of otp-generate
command usage:
.\CrescendoCLI.exe otp-generate --oath-slot C5 -p 123456 --log-level info
This will configure the oath slot C5
to use TOTP
and store the secret 0910f75fb6
to the token, so that OTP can be used. An example response to this command might look like this:
[2024-04-18 15:19:47.584][INFO] Log level is set to "INFO".
[2024-04-18 15:19:47.779][INFO] Connected to:
[2024-04-18 15:19:47.780][INFO] - Reader: "Circle Idaxis SecurePIV 0"
[2024-04-18 15:19:47.780][INFO] - Token: "Crescendo 4000"
[2024-04-18 15:19:47.780][INFO] - ATR: 3B-D5-96-FF-81-91-FE-1F-C3-43-34-30-30-30-C9
[2024-04-18 15:19:47.920][INFO] PIN was successfully verified on ACA applet.
[2024-04-18 15:19:47.925][INFO] Trying to generate OTP with key from OATH slot C5.
328482
C#
After the initial set-up, you can call the GenerateOTP method like this:
SDKCore.Result<string> result = transaction.GenerateOTP("C5", 0);
Python
After the initial set-up, you can call the GenerateOTP method like this:
params = {
'oathSlot': 'C5',
'buttonPress': 0,
}
dllMethodsInstance.GenerateOTP(**params)
FIDO Configuration
The SDK provides a set of functions that can be used to manage the FIDO configuration and perform FIDO operations, as per the FIDO CTAP2 standard. All possible request and response parameters are defined as an objects in the SDK (CrescendoDLL.PCSC.FIDODataStructures class), so the user does not have to deal with the raw byte arrays. All functions return a Result<T>
object, which contains the response object (if any) and the status of the operation. The following functions directly from the FIDO CTAP2 standard are available:
To simplify the usage of FIDO CTAP2 functions, the SDK also provides a set of functions that automatically perform the full authentication flow, meaning the user does not have to deal with externally computing the shared secret, determining the CTAP version (pinUvAuthProtocol
) etc. Functions listed below will also automatically determine CTAP versions supported by the protocol, and use the newest one (for Crescendo devices, this would most likely be CTAP2.1).
- Note
- Elevated privileges are needed to automatically determine the supported CTAP version, and therefore all methods in the list below require elevated privileges.
The following functions are available for simplified FIDO CTAP2 usage:
The SDK also provides a way to unblock the FIDO PIN without having to reset all FIDO credentials. To achieve that, there are two functions available. Elevated privileges are not needed for this workflow.
In addition, the SDK provides legacy functions for support of FIDO U2F (CTAP1) protocol. Again, all possible request and response parameters are defined as an objects in the SDK (CrescendoDLL.PCSC.FIDODataStructures class), so the user does not have to deal with the raw byte arrays, and all functions return a Result<T>
object, which contains the response object (if any) and the status of the operation. The following functions directly from the FIDO U2F standard are available:
authenticatorGetInfo
After the initial set-up, you can call the AuthenticatorGetInfo method like this:
Represents the response from FIDO CTAP2 authenticatorGetInfo command.
Definition FIDO.cs:2178
Represents the data structures used in FIDO (CTAP1 & CTAP2) communication, as defined in the latest F...
Definition FIDO.cs:862
The CrescendoDLL namespace contains classes and methods that allow the user to perform various operat...
Definition Cryptography.cs:15
When successful, the result.Value
will contain the AuthenticatorInfo object.
authenticatorClientPin
After the initial set-up, you can call the AuthenticatorClientPIN directly. For example to get the PIN
retires left, you can call the AuthenticatorClientPIN method like this:
{
PinProtocol = 2,
SubCommand = (byte)AuthenticatorClientPINSubCommand.getPINRetries
};
SDKCore.Result<FIDODataStructures.ClientPINResponse> clientPinResult = AuthenticatorClientPIN(clientPinRequest)
Represents parameters for the FIDO CTAP2 authenticatorClientPIN command.
Definition FIDO.cs:1204
When successful, the result.Value
will contain the ClientPINResponse object.
authenticatorMakeCredential
After the initial set-up, you can call the AuthenticatorMakeCredential directly.
- Note
- Shared secret needs to be established first using the authenticatorClientPin method.
Assuming you have the previously established shared secret, here is an example of registering a credential for some sample data - Relaying Party (RP) webauthn.io
, User and Public Key Credential Parameters (PubKeyCredParams) using the CTAP 2.1 protocol:
byte[] sharedSecret;
{
ClientDataHash = Convert.FromHexString("269286B9CDAF6487E00EA5F9AE93063C259BBDAD389A4C6EE365A72F9CE793E9"),
Rp = new() { Id = "webauthn.io", Name = "webauthn.io" },
User = new() { Id = System.Text.Encoding.ASCII.GetBytes("webauthnio-Tempname"), Name = "Tempname", DisplayName = "Tempname" },
PubKeyCredParams =
[
new() { Alg = -8, Type = "public-key"},
new() { Alg = -7, Type = "public-key"},
new() { Alg = -257, Type = "public-key"}
],
Extensions = new() { { "credProtect", 2 } },
Options = new() { { "rk", true } },
PinUvAuthParam = sharedSecret,
PinUvAuthProtocol = 2
};
Represents parameters for the FIDO CTAP2 authenticatorMakeCredential command.
Definition FIDO.cs:1658
Represents the response from a FIDO CTAP2 authenticatorMakeCredential command.
Definition FIDO.cs:1747
When successful, the makeCredentialResponse.Value
will contain the newly created credential inside the MakeCredentialResponse object.
authenticatorGetAssertion
After the initial set-up, you can call the AuthenticatorGetAssertion method directly.
- Note
- Shared secret needs to be established first using the authenticatorClientPin method.
Assuming you have the previously established shared secret, here is an example of asking for an assertion for Relaying Party (RP) webauthn.io
and specified ClientDataHash
using the CTAP 2.1 protocol:
byte[] sharedSecret;
{
RpId = "webauthn.io",
ClientDataHash = Convert.FromHexString("6bd0c12ffd90dfd8d38df2f8c9a450263f1cbee70b1fb629d7609d065b4b2351"),
Options = new() { { "up", false } },
PinUvAuthParam = sharedSecret,
PinUvAuthProtocol = 2
};
Represents parameters for the FIDO CTAP2 authenticatorGetAssertion command.
Definition FIDO.cs:1505
Represents the response from a FIDO CTAP2 authenticatorGetAssertion command.
Definition FIDO.cs:1578
When successful, the getAssertionResponse.Value
will contain the newly created credential inside the GetAssertionResponse object.
authenticatorGetNextAssertion
After the initial set-up, you can call the AuthenticatorGetNextAssertion method directly.
- Note
- Shared secret needs to be established using the authenticatorClientPin method, and authenticatorGetAssertion method was called. After all, you are asking for "Next assertion", implying you have asked for assertion with given parameters previously.
This would be an example of using the AuthenticatorGetNextAssertion:
byte[] sharedSecret;
{
RpId = "webauthn.io",
ClientDataHash = Convert.FromHexString("6bd0c12ffd90dfd8d38df2f8c9a450263f1cbee70b1fb629d7609d065b4b2351"),
Options = new() { { "up", false } },
PinUvAuthParam = sharedSecret,
PinUvAuthProtocol = 2
};
When successful, the getNextAssertionResponse.Value
will contain the newly created credential inside the GetAssertionResponse object.
authenticatorReset
After the initial set-up, you can call the AuthenticatorReset method directly.
- Note
- This command will erase all FIDO credentials and reset the FIDO PIN.
An example of AuthenticatorReset would look like this:
SDKCore.Result resetResult = transaction.AuthenticatorReset();
authenticatorCredentialManagement
- Note
- Shared secret needs to be established first using the authenticatorClientPin method.
- Note
- More detailed C# code example can be found in the
Examples/FIDO-ListCredentials
folder inside the released SDK package.
After the initial set-up, you can call the AuthenticatorCredentialManagement method directly. For example if we want to list a credential for a Relaying Party (RP) webauthn.io
, this is what the request using the CTAP 2.1 protocol would look like:
byte[] sharedSecret;
byte[] rpBytes = System.Text.Encoding.UTF8.GetBytes("webauth.io");
{
RpIDHash = System.Security.Cryptography.SHA256.HashData(rpBytes),
};
{
SubCommand =
CrescendoDLL.
PCSC.AuthenticatorCredentialManagementSubCommand.enumerateCredentialsBegin,
SubCommandParams = subCommandParams,
PinUvAuthParam = sharedSecret,
PinUvAuthProtocol = 2
};
Represents parameters for FIDO CTAP2 authenticatorCredentialManagement command.
Definition FIDO.cs:1878
Represents the response from FIDO CTAP2 authenticatorCredentialManagement command.
Definition FIDO.cs:1930
Represents subcommand-specific parameters for CTAP2 authenticatorCredentialManagement command.
Definition FIDO.cs:1823
When successful, the credentialManagementResponse.Value
will contain the requested details inside the CredentialManagementResponse object.
authenticatorConfig
After the initial set-up, you can call the AuthenticatorConfig method directly.
- Note
- Shared secret needs to be established first using the authenticatorClientPin method.
- Note
- Token must support CTAP 2.1 protocol to use the AuthenticatorConfig method.
For example to change the minimum PIN length to 6
, this is what the request would look like:
byte[] sharedSecret;
{
SubCommandParams = new()
{
NewMinPINLength = 6
},
};
SDKCore.Result configResult = transaction.AuthenticatorConfig(configRequest);
Represents parameters for FIDO CTAP2 authenticatorConfig command.
Definition FIDO.cs:2097
FIDOSetPIN
- Note
- Elevated privileges are required.
After the initial set-up, you can call the FIDOSetPIN method like this:
SDKCore.Result<string> result = transaction.FIDOSetPIN("123456");
When successful, the result.Value
will contain the newly set PIN
.
FIDOChangePIN
- Note
- Elevated privileges are required.
After the initial set-up, you can call the FIDOChangePIN method like this:
SDKCore.Result<string> result = transaction.FIDOChangePIN("123456");
When successful, the result.Value
will contain the newly set PIN
.
FIDOGetChallenge and FIDOUnblockPIN
After the initial set-up, you can call the FIDOGetChallenge method to get a challenge code for unblocking the FIDO PIN. This challenge code must be shared with the administrator, who can provide a response code (cryptogram) to unblock the FIDO PIN. You can then call the FIDOUnblockPIN method with the response code and the new PIN value to unblock the FIDO PIN. Neither of these methods require elevated privileges, but it is recommended to use them in a secure environment.
- Note
- The SCardTransaction must stay open between the calls to FIDOGetChallenge and FIDOUnblockPIN. MaintainTransactionAsync can be used to keep the transaction open between the calls.
- Note
- More detailed C# code example (including the transaction handling) can be found in the
Examples/FIDO-PinUnblock
folder inside the released SDK package.
This is how an example of the FIDO PIN unblocking flow would look like:
SDKCore.Result<string> challengeResponse = transaction.FIDOGetChallenge();
string newPin = "123456";
string responseCode = "0C39B515C246EC8EFE502C41FFCCB5DA";
SDKCore.Result unblockResult = transaction.FIDOUnblockPIN(responseCode, newPin);
When successful, the FIDO PIN will be newly set to the value newPin
, and all FIDO credentials will remain intact.
FIDOMakeCredential
- Note
- Elevated privileges are required.
- Note
- More detailed C# code example (including the following
authneticatorGetAssertion
) can be found in the Examples/FIDO-MakeCredentialAndGetAssertion
folder inside the released SDK package.
After the initial set-up, you can call the FIDOMakeCredential method directly. First fill out the MakeCredentialRequest object with the desired credentials, then use it as an input to the FIDOMakeCredential method. For example here is a request object with some sample data for Relaying Party (RP), User and Public Key Credential Parameters (PubKeyCredParams):
{
ClientDataHash = Convert.FromHexString("269286B9CDAF6487E00EA5F9AE93063C259BBDAD389A4C6EE365A72F9CE793E9"),
Rp = new() { Id = "webauthn.io", Name = "webauthn.io" },
User = new() { Id = System.Text.Encoding.ASCII.GetBytes("webauthnio-Tempname"), Name = "Tempname", DisplayName = "Tempname" },
PubKeyCredParams =
[
new() { Alg = -8, Type = "public-key"},
new() { Alg = -7, Type = "public-key"},
new() { Alg = -257, Type = "public-key"}
],
Extensions = new() { { "credProtect", 2 } },
Options = new() { { "rk", true } }
};
When successful, the makeCredentialResponse.Value
will contain the newly created credential inside the MakeCredentialResponse object.
FIDOGetAssertion
- Note
- Elevated privileges are required.
- Note
- More detailed C# code example (including the preceding
authneticatorMakeCredential
) can be found in the Examples/FIDO-MakeCredentialAndGetAssertion
folder inside the released SDK package.
After the initial set-up, you can call the FIDOGetAssertion method directly. First fill out the GetAssertionRequest object with the desired credentials, then use it as an input to the FIDOGetAssertion method. For example here is a request object asking for an assertion for Relaying Party (RP) webauthn.io
and specified ClientDataHash
:
{
RpId = "webauthn.io",
ClientDataHash = Convert.FromHexString("6bd0c12ffd90dfd8d38df2f8c9a450263f1cbee70b1fb629d7609d065b4b2351"),
Options = new() { { "up", false } }
};
When successful, the getAssertionResponse.Value
will contain the newly created credential inside the GetAssertionResponse object.
FIDOCredentialManagement
- Note
- Elevated privileges are required.
- Note
- More detailed C# code example can be found in the
Examples/FIDO-ListCredentials
folder inside the released SDK package.
After the initial set-up, you can call the FIDOCredentialManagement method directly. First fill out the CredentialManagementRequest object with the desired credentials, then use it as an input to the FIDOCredentialManagement method.
For example if we want to list a credential for a Relaying Party (RP) webauthn.io
, this is what the request object would look like:
byte[] rpBytes = System.Text.Encoding.UTF8.GetBytes("webauth.io");
{
RpIDHash = System.Security.Cryptography.SHA256.HashData(rpBytes),
};
{
SubCommand =
CrescendoDLL.
PCSC.AuthenticatorCredentialManagementSubCommand.enumerateCredentialsBegin,
SubCommandParams = subCommandParams
};
When successful, the credentialManagementResponse.Value
will contain the requested details inside the CredentialManagementResponse object.
FIDOConfig
- Note
- Token must support CTAP 2.1 protocol to use the FIDOConfig method.
- Note
- Elevated privileges are required.
- Note
- More detailed C# code example (including the mandatory PIN change) can be found in the
Examples/FIDO-ConfigurationAndPinChange
folder inside the released SDK package.
After the initial set-up, you can call the FIDOConfig method directly. For example to change the minimum PIN length to 6
, this is what it would look like:
{
SubCommandParams = new()
{
NewMinPINLength = 6
},
};
SDKCore.Result configResult = transaction.FIDOConfig(configRequest);
U2FRegistration
- Note
- Elevated privileges are required.
- Note
- More detailed C# code example (including the following
U2F Authentication
) can be found in the Examples/FIDO-U2FRegistrationAndAuthentication
folder inside the released SDK package.
After the initial set-up, you can call the U2FRegistration method directly. First fill out the U2FRegistrationRequest object with the desired credentials, then use it as an input to the U2FRegistration method.
Here is an example of registering a credential for some sample data - Relaying Party (RP) webauthn.io
, and some 32-byte challenge using the FIDO U2F protocol:
{
ChallengeParameter = Convert.FromHexString("269286B9CDAF6487E00EA5F9AE93063C259BBDAD389A4C6EE365A72F9CE793E9"),
ApplicationParameter = System.Security.Cryptography.SHA256.HashData(System.Text.Encoding.UTF8.GetBytes("webauthn.io"))
};
Represents a U2F registration request per FIDO U2F (CTAP 1) specification.
Definition FIDO.cs:867
Represents a U2F registration response per FIDO U2F (CTAP 1) specification.
Definition FIDO.cs:889
When successful, the u2FRegistrationResponse.Value
will contain the requested details inside the U2FRegistrationResponse object.
U2FAuthentication
- Note
- Elevated privileges are required.
- Note
- More detailed C# code example (including the preceding
U2F Registration
) can be found in the Examples/FIDO-U2FRegistrationAndAuthentication
folder inside the released SDK package.
After the initial set-up, you can call the U2FAuthentication method directly. First fill out the U2FAuthenticationRequest object with the desired credentials and previously learned information from U2FRegistration, then use it as an input to the U2FAuthentication method.
Here is an example of authenticating with a credential for some sample data - Relaying Party (RP) webauthn.io
, some 32-byte challenge and previously gained KayHandle
using the FIDO U2F protocol:
{
ChallengeParameter = Convert.FromHexString("269286B9CDAF6487E00EA5F9AE93063C259BBDAD389A4C6EE365A72F9CE793E9"),
ApplicationParameter = System.Security.Cryptography.SHA256.HashData(System.Text.Encoding.UTF8.GetBytes("webauthn.io")),
KeyHandle = u2FRegistrationResponse.Value.KeyHandle,
UserPresence =
CrescendoDLL.
PCSC.U2FAuthenticationOptions.EnforceUserPresenceAndSign
};
Represents a U2F authentication request per FIDO U2F (CTAP 1) specification.
Definition FIDO.cs:984
byte KeyHandleLength
Length of key handle in bytes.
Definition FIDO.cs:998
Represents a U2F authentication response per FIDO U2F (CTAP 1) specification.
Definition FIDO.cs:1016
When successful, the u2FAuthenticationResponse.Value
will contain the requested details inside the U2FAuthenticationResponse object.
U2FGetVersion
- Note
- Elevated privileges are required.
After the initial set-up, you can call the U2FGetVersion method directly.
SDKCore.Result<string> getVersionString = methods.U2FGetVersion();
When successful, the getVersionString.Value
will contain the version string (e.g., "U2F_V2").