Computes OTP using externally provided challenge or transaction data. Provided by method getDefaultOTPGenerator().
Overview
Asynchronous one-time password (OTP) algorithms generate cryptographic responses based on a challenge, rather than relying on a shared counter or time window. This means the server sends a unique challenge for each authentication attempt, and the client computes a response using a shared secret.
OCRA (defined in RFC 6287 extends HOTP to support challenge–response authentication and transaction signing.
Two modes are supported:
In challenge–response mode, the user’s device generates a one-time code bound to the server’s challenge.
In signature mode, the response can also incorporate transaction data (such as an amount or recipient), effectively creating a cryptographic signature that protects against replay and tampering via man-in-the-middle attacks.
Challenge-Response Authentication
For this use case, the OTP generator computes a response from a challenge provided by the authentication server (typically, the challenge is displayed by the web application of the service provider, or sent by email or sms).
Example Code:
do{ // Find keys available for the usage OTP; if several are available, we need to distinguish them with their labels let filter = HIDApproveKeyFilter(keyUsage: .OTP) if let keys = try self.getContainer()?.findKeys(filter: [filter]) { for key in keys { // To identify the protection policy used : look at the type of the protectionPolicy. // HIDApprovePolicyType.Device : no password required // HIDApprovePolicyType.Password : password required // HIDApprovePolicyType.BioPassword : see the protection policy documentation for usage. let policyType = try key.getProtectionPolicy().type let algo = key.algorithm let label = try key.getProperty(propertyId: .LABEL) NSLog("Found key: PolicyType=%@, Algorithm=%@, Label=%@", policyType.description, algo, label) } let key = keys.first let otpGenerator = try key?.getDefaultOTPGenerator() // Get the next OTP // We assume the generator is Asynchronous (OCRA algorithm) // We assume the key is not password protected (password nil) let asyncOtpGenerator = otpGenerator as! HIDApproveAsyncOTPGenerator // With an ocra algorithm, inputs data depends of the algorithm used. // You can get parameters specific to the generator and key. // The type of parameters depends on the generator name NSLog("Found generator: Name=%@, Type=%@", asyncOtpGenerator.name, asyncOtpGenerator.type.hashValue) // Get the authentication modes supported from parameters let algoParameters = asyncOtpGenerator.getAlgorithmParameters() NSLog("Generator modes: %@", algoParameters.modes.description) // We assume the challenge/response mode is supported. // We assume the OTP key is not password protected. ( password null ) // Check if pin or session is required and set it in InputOCRAParameters if so // You can validate the server challenge against the expected format let ocraSuite = algoParameters.clientOCRASuite var ocraInput = HIDApproveOCRAInputAlgorithmParameters() if(ocraSuite.isPinRequired == true) { NSLog("Pin hash: %@", ocraSuite.pinHashAlgo) ocraInput.pin = "myPin" } if(ocraSuite.isSessionRequired == true) { NSLog("SessionInfo is required") ocraInput.sessionInfo = "mySessionData" } NSLog("Challenge format: %@", ocraSuite.challengeFormat.description) // Compute the response with the provided challenge. // We assume the key is not password protected (password nil) let otp = try asyncOtpGenerator.computeResponse(password: nil, challenge: "myChallenge", inputParams: ocraInput) }}catch let error as NSError{ NSLog("Failed to generate OTP: %@",error.localizedDescription);}
Signature Authentication
For this use case, the end user supplies a number of strings to concatenate in order to form a challenge client-side. For example, to sign a bank transaction, the bank portal might ask the end user to sign the:
Account number (“11223344”)
Amount (“100EUR”)
Beneficiary (“JohnDoe”)
The SDK formats the challenge based on the server OCRA suite configured server-side, following OCRA Standalone Client Profile v1.0 (section 3.2.4, c, d and e).
The OTP generator computes the response based on this challenge.
The mobile application can use the SDK to format the challenge from these input strings (formatSignatureChallenge(inputData:)) using the values (not the associated labels).
Example Code:
do{ // Find keys available for the usage OTP; if several are available, we need to distinguish them with their labels let filter = HIDApproveKeyFilter(keyUsage: .OTP) if let keys = try self.getContainer()?.findKeys(filter: [filter]) { for key in keys { // To identify the protection policy used : look at the type of the protectionPolicy. // HIDApprovePolicyType.Device : no password required // HIDApprovePolicyType.Password : password required // HIDApprovePolicyType.BioPassword : see the protection policy documentation for usage. let policyType = try key.getProtectionPolicy().type let algo = key.algorithm let label = try key.getProperty(propertyId: .LABEL) NSLog("Found key: PolicyType=%@, Algorithm=%@, Label=%@", policyType.description, algo, label) } let key = keys.first let otpGenerator = try key?.getDefaultOTPGenerator() // Get the next OTP // We assume the generator is Asynchronous (OCRA algorithm) // We assume the key is not password protected (password nil) let asyncOtpGenerator = otpGenerator as! HIDApproveAsyncOTPGenerator // With an ocra algorithm, inputs data depends of the algorithm used. // You can get parameters specific to the generator and key. // The type of parameters depends on the generator name NSLog("Found generator: Name=%@, Type=%@", asyncOtpGenerator.name, asyncOtpGenerator.type.hashValue) // Get the authentication modes supported from parameters let algoParameters = asyncOtpGenerator.getAlgorithmParameters() NSLog("Generator modes: %@", algoParameters.modes.description) // We assume the signature mode is supported. // We assume required parameter set : let ocraInput = HIDApproveOCRAInputAlgorithmParameters(pin: "mypin", sessionInfo: "sessiondata") // The end-user has filled the form, input strings are in inputStrings, NSArray of NSString // Format the challenge let inputStrings = ["1","2","3"] let challenge = try asyncOtpGenerator.formatSignatureChallenge(inputData: inputStrings) // Compute the signature for one-way or two-way signature. For one-way signature, clientChallenge is empty. // We assume the key is not password protected (password nil) let otp = try asyncOtpGenerator.computeSignature(password: nil, sigChallenge: myChallenge, clientChallenge: nil, inputParams: ocraInput) }}catch let error as NSError{ NSLog("Failed to generate signature: %@",error.localizedDescription);}