Class

HIDApproveAsyncOTPGenerator

OCRA OTP generator to support asynchronous challenge-response generation.

Declaration

final class HIDApproveAsyncOTPGenerator

Overview

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);
}

See Also

OTP - Asynchronous (OCRA)