One time password(OTP) is one of the common forms of Multi-Factor Authentication present on most web applications today. In this tutorial, we will give an overview of how TOTP works and then guide you through implementing an iOS authenticator application to generate the TOTP and share it to a nearby web application using Chirp.
Here’s the full project in action
Using just a “shared secret” as a form of authentication is vulnerable to replay attacks. A replay attack is a version of the “Man in the middle” attacks. It is an attack on the network where the hashed shared secret sent across the network is intercepted and reused to gain access.
TOTP (Time-based OTP) is an open standard algorithm that computes a one-time password using a combination of a secret key, shared between a client and the server, and the time. This prevents the user from memorizing the shared secret and makes it difficult for a replay attack, as the pin changes with time.
TOTP is an extension of HOTP (HMAC based one time passwords) (explained in detail below). For both HOTP and TOTP, a shared base-32 secret key is generated between the client and the server. This key is encoded with a message (in our case is the timestamp) to form the HMAC-SHA1 cryptographic hash payload. TOTP uses the UNIX epoch as the time, formatted in seconds. By default, we refresh the TOTP every 30 seconds. This starts at the top of the minute(xx:xx:00) and 30 seconds after the minute (xx:xx:30).
Let us try to understand how the TOTP is obtained from the HMAC-SHA-1 generated pin. An example to generate the pin using OpenSSL on a MacOS terminal is shown below.
$ KEY=`openssl rand -hex 16`
$ echo $KEY
$ date +%s | openssl sha1 -hmac “$KEY”
$ date +%s | openssl sha1 -hmac “$KEY” # After 30 Seconds
We generate a random hex string as the key, the unix epoch time is obtained using
date + %s. Here we obtain the HMAC-SHA-1 string as “b3c377e581fff1119ae11384481ad95712da1510”. We notice that we obtain a 40-character hexadecimal string.
Dynamic Truncation is performed next to convert this long string into something smaller and more secure. In dynamic truncation we look at the last character of this string, that is the number ‘0’, highlighted below.
To determine the truncation, we use the last character as the starting index of our string. In our example, the hexadecimal character ‘0’ when converted to decimal is also ‘0’. So starting with the 0th Index we read the next 31-bits to obtain our dynamically truncated string.
From the original HMAC-SHA-1 hash of “b3c377e581fff1119ae11384481ad95712da1510”, we have dynamically truncated it to “B3C377E5”.
The final step to obtain the pin is to convert this truncated string into a ‘decimal’. We can do it on the terminal by running the commands below.
$ echo “ibase=16; B3C377E5” | bc
Finally, we pick the required number of digits needed for the pin from this decimal value. If we need 6 digits, we modulo 1,000,000 and we get the last 6 digits and we end up with TOTP = 931877
What are we trying to accomplish?
The procedure for generation of TOTP pin is automated. The verification the of TOTP pin is automated.
But we still manually input the pin digits every single time. There are instances where we type in a couple of digits and the PIN changes (Oh! drat).
Our mission at Chirp is to make everyday tasks like this simpler. Tasks that are frustrating for humans but easy for machines.
Building the Chirp + TOTP iOS Application
The Chirp Connect SDK enables your apps to send and receive data using sound. The Chirp Connect SDK encodes the generated TOTP as an audio signal and then transmits it to the web application.
Before we begin, let’s make sure we have the following set up.
Install from the App Store
Chirp iOS SDK
Sign up for it here
We will develop the application using Objective-C, start by setting up the project.
- Create an Xcode project.
- Download the latest Chirp iOS SDK from here
- Follow steps at the Chirp Developers Page to integrate Chirp into Xcode. This involves importing the framework and updating your info.plist file to include microphone usage.
- With the above completed, we are all set to start coding the application. Start by initialising the Chirp Connect in the `viewDidLoad` method. Chirp Developer Hub should also provide your appropriate key and secret.
self.connect = [[ChirpConnect alloc] initWithAppKey:CHIRP_APP_KEY andSecret:CHIRP_APP_SECRET];
[self.connect getLicenceStringWithCompletion:^(NSString * _Nullable licence, NSError * _Nullable error)
// set the licence
NSError *licenceError = [self.connect setLicenceString:licence]; // start the SDK
NSError *startError = [self.connect start];
5. To begin the integration, we would need the following classes,
Base32Additions — Needed to generate an HMAC-SHA-1 value of the secret key.
OTPGenerator — Needed to generate the PIN.
TOTPGenerator—An extension of the OTPGenerator class which utilises the Timestamp to generate the PIN.
Drag and drop the Classes folder from the Chirp iOS examples repository into to your project.
This consists of the required Base32 additions for `NSString` and `NSData` as well as the barebones google-authenticator classes from the opensource Google repo.
NOTE: Classes obtained from b and c are not ARC-compliant so you would have to set the Objective-C Automatic Reference Counting flag to NO in the Project Build Settings.
Before, we write the function to utilise the aforementioned classes and generate our PIN.
We need to calculate the timestamp using details from the inbuilt `NSDate` class, we can write the following function to obtain that
NSDate *now = [NSDate date];
NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
[dateFormatter setDateFormat:@”yyyy-MM-dd HH:mm:ss”];
NSTimeZone *timeZone = [NSTimeZone timeZoneWithAbbreviation:@”GMT”];
[dateFormatter setTimeZone:timeZone]; long timestamp = (long)[now timeIntervalSince1970];
if(timestamp % [self.expiryTextField.text integerValue] != 0)
timestamp -= timestamp % [self.expiryTextField.text integerValue];
} return ([[NSString stringWithFormat:@”%ld”,timestamp] integerValue]);
Perform the Base32 Encoding on our shared secret key and pass it onto the TOTP Generator along with the calculated timestamp
NSString *secret = YOUR_SHARED_SECRET;
NSData *secretData = [NSData dataWithBase32String:[secret base32String]]; NSTimeInterval timestamp = [self calculateTimeInterval]; TOTPGenerator *generator = [[TOTPGenerator alloc] initWithSecret:secretData algorithm:kOTPGeneratorSHA1Algorithm digits:YOUR_NUM_DIGITS period:YOUR_REFRESH_PERIOD];
NSString *pin = [generator generateOTPForDate:[NSDate dateWithTimeIntervalSince1970:timestamp]];
Chirp payloads are byte arrays represented by the `NSData` type. Since our generated PIN is an `NSString` object, we need to create a method to encode the message.
-(NSData *) encodeMessage:(NSString *)message
NSString *string = [NSString stringWithUTF8String:message.UTF8String];
if ([string lengthOfBytesUsingEncoding:NSUTF8StringEncoding] > [self.connect maxPayloadLength])
NSData *stringData = [string dataUsingEncoding:NSUTF8StringEncoding];
return [self.connect isValidPayload:stringData] ? stringData : nil;
Now we are ready to send the PIN, lets create a button to send the PIN as a sequence of tones using Chirp.
NSString *chirpPIN = self.PINLabel.text;
NSData *data = [self encodeMessage:chirpPIN];
And voila! You should now have a simple application through which you can generate a TOTP PIN based on your secret key and transmit it over to the web application with the click of a button.
You can find the complete Chirp + TOTP integrated Demo iOS App here
Coming up next is a tutorial to integrate your web application with the receiver and authenticating your login. Watch this space!
Amogh is applying his MSc research in Sound and Music Computing to Chirp’s digital signal processing tech stack, measuring performance metrics and prototyping new techniques to improve performance.
Chirp is a technology company enabling a seamless transfer of digital information via soundwaves, using a device’s loudspeaker and microphone only. The transmission uses audible or inaudible ultrasound tones and takes place with no network connection. To learn more visit chirp.io