In this section we first describe the building blocks used to construct our proposed 2-factor authentication approach. Then we describe in detail the architecture of the 2-factor authentication system and its protocols.
4.2 Architecture and Protocols
Design of hash chain for OTPs. We initiate the generation of our hash chain with the starting seed
Sk, which undergoes hashing at each step using a different hash function represented by
hi described in Equation (
1). Upon computing all the hashes, we obtain the final hash at the end of the hash chain, referred as
rootHash, which serves for verification in subsequent stages. Such a hash chain is depicted in Figure
1. To generate OTPs, we traverse the hash chain in reverse, starting from the tail which is
rootHash towards the head which is seed. The node immediately preceding the tail is regarded as the first OTP, and so forth until reaching the head. The head represents the final OTP or the
kth OTP, where
k is the length of the hash chain. In this context, even if
OTPm is revealed, it is very easy to compute the
rootHash. But the derivation of
OTPn from
OTPm where
m <
n is computationally infeasible due to the one way nature of cryptographic hash functions [
22]. To verify an
OTPm, we simply require to hash it
m times with corresponding required values of
i, get the hashed output and then further compare it with the
rootHash. If the
rootHash is equal to the generated hash output, then the
OTPm is deemed valid indicating that
OTPm is indeed a constituent of the current hash chain.
We propose a 2-factor authentication for blockchain which consists of : (1) a client C, (2) a private key software wallet W, (3) a smart contract S, and (4) an authenticator A. The client is a device running an application using which the transactions to the blockchain are initiated. The client device also holds the wallet containing the private key and public key of the user (SKU, PKU). The authenticator can be an application running on smart phone or similar device that is air-gapped from the client. The first factor is traditional public key authentication where the client prepares a transaction and digitally signs it using the private key SKU from the wallet. The transaction is then submitted to the blockchain for executing a smart contract. The blockchain network derives the user’s public key from the provided signature and the address, and verifies the authenticity of the transaction. The second factor are the OTPs which are produced by the authenticator and inputted to the client by the user to initiate a transaction. The provided OTP is then validated by a specialized smart contract that enforces the second factor of the authentication. This specialized smart contract acts as a gatekeeper, validating transactions based on encoded spending rules and security features to determine if crypto token transfers will proceed or not.
We assume a two stage protocol for the entire setup denoted as
ΠO, where first phase is bootstraping (
ΠB) and second phase is operation exceution (
ΠE). Table
1 shows all the parameters utilized in the equations, along with their respective lengths.
Bootstrap / Intial setup (ΠB) : We illustrate the initial setup process in Figure
2. As common in other schemes and protocols, by default, we assume a secure environment for initial setup, which means that
C is trusted and cannot be compromised during execution of
ΠB. Initially,
C creates a confidential seed
Sk, generates a random salt denoted as
id, records the time of setup initiation as a counter initiation value denoted as
tinit and determines the maximum number of OTPs (hash chain length) denoted as
k. Note that the time
t and
tinit here does not represent physical clock time but functions as a logical clock. For instance, during bootstrap,
tinit can be initialized to zero, while for each operation verification, the current time
t increments by one with each new OTP request. Subsequently, the user securely transfers this seed
Sk,
id,
tinit and
k from
C to
A through an air-gapped process, such as transcribing a selection of mnemonic words or scanning a QR code. Next, the client uses the hash functions defined by
hi(
x) to generate a hash chain. It’s worth noting that for each node of the hash chain, a distinct and independent hash function is utilized as shown in the folllowing equation.
The approach of deriving independent hash functions from a singular hash function across an expanded domain, commonly referred to as domain separation, and it is often attributed to Leighton and Micali [
30]. Drawing upon the described hash functions, the client iteratively computes the
rootHash as shown in Algorithm 1 by applying the hash functions
k times, where
i ranges from 1 to
k in
hi(
x).
After this stage, the secret seed
Sk as well as the hash chain is erased from the client’s storage. The client then initiates the transaction to store values in the smart contract
S using the wallet
W, requesting the user to sign the transaction using the private key stored in the wallet. The signed transaction is then broadcasted to the blockchain network. The transaction is then mined by the miners who verify the validity of the transaction signature.
S stores all public parameters like
tinit,
k,
id and
rootHash illustrated in Figure
2. The smart contract uses its state variables and initialises
tprev as
tinit and
pprev as
rootHash. Hence, the keys (
SKU,
PKU) in wallet
W enables whether the arbitrary transaction was signed by the user or not while
rootHash enables the verification whether the given OTP was produced by user’s authenticator A or not.
Execute operation (ΠE) : Once the wallet framework is initialized, it becomes ready to execute operations and do the 2-factor authentication. The initial factor involves verification through the transaction signature, while the second factor involves OTP verification. We illustrate this execution operation flow in Figure
3.
The user while initiating a transaction operation
Ot first enters the details of operation into
C creating a transaction
initOp(). This needs operation parameters like the type of operation (e.g., transfer), a numerical parameter (e.g., amount or daily limit), an address parameter (e.g., recipient), the time
t when operation is initiated and the commitment for the OTP. To generate the required OTP,
OTPt for the transaction
Ot, the client first displays the parameter
t to the user. Based on
t, the authenticator
A generates the
OTPt (Equation
3). In addition, a commitment
c for the OTP is also generated by the authenticator.
The commitment c plays a vital role to prevent front-running attacks. Sending the commitment first without revealing the OTP to the client prevents the attackers having possession of SKU from forging a valid OTP to perform their own fraudulent transactions.
The use of commitment protocol forces the attacker and user both to send the commitment first and the original OTP is revealed in later stage which results in attacker being unaware of OTPs in earlier phase of verification. Algorithm 2 shows the OTP generation and commitment generation schemes. We have discussed about the commitment scheme and its role in defending against front running attacks in detail in Section
6.4. Client sends the commitment
c for
OTPt to the smart contract via wallet by signing the transaction and then
S stores the commitment for verification at a later phase to prevent MITM front running attacks. After providing the commitment, the client now requests the authenticator for the corresponding
OTPt. After getting the OTP from authenticator through air gapped means, the client sends
OTPt to the smart contract through
W as shown in Figure
3.
When the confirmation of verifying the signature on blockchain network comes, the first factor authentication is over which establishes the fact that the transaction for request of executing operation is coming from user having private key. After the factor one authentication, the smart contract validates the commitment by hashing the OTP and comparing the resultant hashed ouptut with the stored commitment. After successful verification of commitment, the time range is verified as in t ∈ (tinit, tmax]. Here, tmax represents the maximum time limit with respect to hash chain length k after which the authentication will fail and you will require reinitialisation.
Hence, the
\(OTP_{t_{max}}\) is the last valid OTP for this hash chain. To check the validity of password, the smart contract uses the stored values,
tprev and the
OTPt and generates the resultant expected hash root to do the verification. Equation
4 shows the generation of the validation factor
pverify using the
OTPt.
If pprev = pverify, then authentication is successful, and the smart contract updates pprev to OTPt and tprev to t and allows the operation Ot to execute and transfer of crypto tokens as illustrated in Algorithm 4 . Updating the values is essential to maintain consistency in the hash chain, as the rootHash value must be shifted left after successful verification. If no successful match is found in pverify and pprev, the smart contract rejects the password as well as operation Ot. Now user needs to reinitiate the new operation and thus the entire process of operation execution will get repeated for the new value of t.
Reinitialization: Users who conduct numerous transactions would frequently need to generate new OTPs. So, A limited number of OTPs can pose challenges for both usability and security. We discussed about
\(OTP_{t_{max}}\) being the last OTP for our hash chain in section 3, when user asks for authentication at
t >
tmax, the reinitialisation gets invoked. In our model, reinitialisation requires the client to generate a new seed and salt and then it is shared with authenticator via air gapped means similar to the setup phase, there is no requirement of sharing
tinit and
k as
tinit is replaced with the
tmax and k remains same as described in Algorithm 3 . Again a new hash chain is generated at the client and the calculated
rootHashnew is shared with smart contract. The main difference between initial setup and reinitialisation is that, the client only provides the salt and the new
rootHash to the smart contract. After required updation in both authenticator and smart contract, the system is again ready to execute operations. The finite length of the hash chain necessitates periodic reinitialization, with the reinitialization frequency being dependent on the system’s operation execution rate. Since each operation requires one OTP, a higher number of operation executions will result in greater OTP consumption, thus accelerating the need for hash chain reinitialization. Considering the chain length as
k = 5*10
5 and time step
G = 60 seconds, it results in a valid hash chain without reintialization for nearly 1 year. Considering that for each minute the system requires an authentication, the given value of k would suffice for a year. Since, key rotation is crucial for updating security and is recommended (For instance, NIST suggests “cryptoperiod” of 1–2 years for private authentication keys. [
9]), we don’t consider periodic reinitalisation as a massive limitation of our scheme.