2beebed98b4fc7f018fb224a1e4a3ab6103a4c0bCraig McDonnell/*
2beebed98b4fc7f018fb224a1e4a3ab6103a4c0bCraig McDonnell * The contents of this file are subject to the terms of the Common Development and
2beebed98b4fc7f018fb224a1e4a3ab6103a4c0bCraig McDonnell * Distribution License (the License). You may not use this file except in compliance with the
2beebed98b4fc7f018fb224a1e4a3ab6103a4c0bCraig McDonnell * License.
2beebed98b4fc7f018fb224a1e4a3ab6103a4c0bCraig McDonnell *
2beebed98b4fc7f018fb224a1e4a3ab6103a4c0bCraig McDonnell * You can obtain a copy of the License at legal/CDDLv1.0.txt. See the License for the
2beebed98b4fc7f018fb224a1e4a3ab6103a4c0bCraig McDonnell * specific language governing permission and limitations under the License.
2beebed98b4fc7f018fb224a1e4a3ab6103a4c0bCraig McDonnell *
2beebed98b4fc7f018fb224a1e4a3ab6103a4c0bCraig McDonnell * When distributing Covered Software, include this CDDL Header Notice in each file and include
2beebed98b4fc7f018fb224a1e4a3ab6103a4c0bCraig McDonnell * the License file at legal/CDDLv1.0.txt. If applicable, add the following below the CDDL
2beebed98b4fc7f018fb224a1e4a3ab6103a4c0bCraig McDonnell * Header, with the fields enclosed by brackets [] replaced by your own identifying
2beebed98b4fc7f018fb224a1e4a3ab6103a4c0bCraig McDonnell * information: "Portions copyright [year] [name of copyright owner]".
2beebed98b4fc7f018fb224a1e4a3ab6103a4c0bCraig McDonnell *
2beebed98b4fc7f018fb224a1e4a3ab6103a4c0bCraig McDonnell * Copyright 2016 ForgeRock AS.
2beebed98b4fc7f018fb224a1e4a3ab6103a4c0bCraig McDonnell *
2beebed98b4fc7f018fb224a1e4a3ab6103a4c0bCraig McDonnell * Portions Copyright 2014 Nathaniel McCallum, Red Hat
2beebed98b4fc7f018fb224a1e4a3ab6103a4c0bCraig McDonnell */
2beebed98b4fc7f018fb224a1e4a3ab6103a4c0bCraig McDonnell
2beebed98b4fc7f018fb224a1e4a3ab6103a4c0bCraig McDonnell#import "FRAOathCode.h"
2beebed98b4fc7f018fb224a1e4a3ab6103a4c0bCraig McDonnell
caa9e77dc369fea8df9ae2c598d3c83b7214c1cfDiego Colantoni@implementation FRAOathCode
caa9e77dc369fea8df9ae2c598d3c83b7214c1cfDiego Colantoni
caa9e77dc369fea8df9ae2c598d3c83b7214c1cfDiego Colantoni#pragma mark -
caa9e77dc369fea8df9ae2c598d3c83b7214c1cfDiego Colantoni#pragma mark Class Methods
caa9e77dc369fea8df9ae2c598d3c83b7214c1cfDiego Colantoni
caa9e77dc369fea8df9ae2c598d3c83b7214c1cfDiego Colantoni+ (NSString *)hmac:(CCHmacAlgorithm)algorithm codeLength:(uint8_t)codeLength key:(NSData *)key counter:(uint64_t) counter {
caa9e77dc369fea8df9ae2c598d3c83b7214c1cfDiego Colantoni#ifdef __LITTLE_ENDIAN__
caa9e77dc369fea8df9ae2c598d3c83b7214c1cfDiego Colantoni // Network byte order
caa9e77dc369fea8df9ae2c598d3c83b7214c1cfDiego Colantoni counter = (((uint64_t) htonl(counter)) << 32) + htonl(counter >> 32);
caa9e77dc369fea8df9ae2c598d3c83b7214c1cfDiego Colantoni#endif
2beebed98b4fc7f018fb224a1e4a3ab6103a4c0bCraig McDonnell
caa9e77dc369fea8df9ae2c598d3c83b7214c1cfDiego Colantoni // Create digits divisor
caa9e77dc369fea8df9ae2c598d3c83b7214c1cfDiego Colantoni uint32_t div = 1;
caa9e77dc369fea8df9ae2c598d3c83b7214c1cfDiego Colantoni for (int i = codeLength; i > 0; i--) {
caa9e77dc369fea8df9ae2c598d3c83b7214c1cfDiego Colantoni div *= 10;
2beebed98b4fc7f018fb224a1e4a3ab6103a4c0bCraig McDonnell }
caa9e77dc369fea8df9ae2c598d3c83b7214c1cfDiego Colantoni // Create the HMAC
caa9e77dc369fea8df9ae2c598d3c83b7214c1cfDiego Colantoni int length = [self getDigestLength:algorithm];
caa9e77dc369fea8df9ae2c598d3c83b7214c1cfDiego Colantoni uint8_t digest[length];
caa9e77dc369fea8df9ae2c598d3c83b7214c1cfDiego Colantoni CCHmac(algorithm, [key bytes], [key length], &counter, sizeof(counter), digest);
2beebed98b4fc7f018fb224a1e4a3ab6103a4c0bCraig McDonnell
caa9e77dc369fea8df9ae2c598d3c83b7214c1cfDiego Colantoni // Truncate
caa9e77dc369fea8df9ae2c598d3c83b7214c1cfDiego Colantoni uint32_t binary;
caa9e77dc369fea8df9ae2c598d3c83b7214c1cfDiego Colantoni uint32_t off = digest[sizeof(digest) - 1] & 0xf;
caa9e77dc369fea8df9ae2c598d3c83b7214c1cfDiego Colantoni binary = (digest[off + 0] & 0x7f) << 0x18;
caa9e77dc369fea8df9ae2c598d3c83b7214c1cfDiego Colantoni binary |= (digest[off + 1] & 0xff) << 0x10;
caa9e77dc369fea8df9ae2c598d3c83b7214c1cfDiego Colantoni binary |= (digest[off + 2] & 0xff) << 0x08;
caa9e77dc369fea8df9ae2c598d3c83b7214c1cfDiego Colantoni binary |= (digest[off + 3] & 0xff) << 0x00;
caa9e77dc369fea8df9ae2c598d3c83b7214c1cfDiego Colantoni binary = binary % div;
caa9e77dc369fea8df9ae2c598d3c83b7214c1cfDiego Colantoni
caa9e77dc369fea8df9ae2c598d3c83b7214c1cfDiego Colantoni return [NSString stringWithFormat:[NSString stringWithFormat:@"%%0%hhulu", codeLength], binary];
2beebed98b4fc7f018fb224a1e4a3ab6103a4c0bCraig McDonnell}
2beebed98b4fc7f018fb224a1e4a3ab6103a4c0bCraig McDonnell
caa9e77dc369fea8df9ae2c598d3c83b7214c1cfDiego Colantoni+ (NSString *)asString:(CCHmacAlgorithm)algorithm {
caa9e77dc369fea8df9ae2c598d3c83b7214c1cfDiego Colantoni if (algorithm == kCCHmacAlgMD5) {
caa9e77dc369fea8df9ae2c598d3c83b7214c1cfDiego Colantoni return @"md5";
caa9e77dc369fea8df9ae2c598d3c83b7214c1cfDiego Colantoni }
caa9e77dc369fea8df9ae2c598d3c83b7214c1cfDiego Colantoni if (algorithm == kCCHmacAlgSHA256) {
caa9e77dc369fea8df9ae2c598d3c83b7214c1cfDiego Colantoni return @"sha256";
caa9e77dc369fea8df9ae2c598d3c83b7214c1cfDiego Colantoni }
caa9e77dc369fea8df9ae2c598d3c83b7214c1cfDiego Colantoni if (algorithm == kCCHmacAlgSHA512) {
caa9e77dc369fea8df9ae2c598d3c83b7214c1cfDiego Colantoni return @"sha512";
caa9e77dc369fea8df9ae2c598d3c83b7214c1cfDiego Colantoni }
caa9e77dc369fea8df9ae2c598d3c83b7214c1cfDiego Colantoni return @"sha1";
2beebed98b4fc7f018fb224a1e4a3ab6103a4c0bCraig McDonnell}
2beebed98b4fc7f018fb224a1e4a3ab6103a4c0bCraig McDonnell
caa9e77dc369fea8df9ae2c598d3c83b7214c1cfDiego Colantoni+ (CCHmacAlgorithm)fromString:(NSString *)string {
caa9e77dc369fea8df9ae2c598d3c83b7214c1cfDiego Colantoni if ([string isEqual: @"md5"]) {
caa9e77dc369fea8df9ae2c598d3c83b7214c1cfDiego Colantoni return kCCHmacAlgMD5;
2beebed98b4fc7f018fb224a1e4a3ab6103a4c0bCraig McDonnell }
caa9e77dc369fea8df9ae2c598d3c83b7214c1cfDiego Colantoni if ([string isEqual: @"sha256"]) {
caa9e77dc369fea8df9ae2c598d3c83b7214c1cfDiego Colantoni return kCCHmacAlgSHA256;
2beebed98b4fc7f018fb224a1e4a3ab6103a4c0bCraig McDonnell }
caa9e77dc369fea8df9ae2c598d3c83b7214c1cfDiego Colantoni if ([string isEqual: @"sha512"]) {
caa9e77dc369fea8df9ae2c598d3c83b7214c1cfDiego Colantoni return kCCHmacAlgSHA512;
caa9e77dc369fea8df9ae2c598d3c83b7214c1cfDiego Colantoni }
caa9e77dc369fea8df9ae2c598d3c83b7214c1cfDiego Colantoni return kCCHmacAlgSHA1;
2beebed98b4fc7f018fb224a1e4a3ab6103a4c0bCraig McDonnell}
2beebed98b4fc7f018fb224a1e4a3ab6103a4c0bCraig McDonnell
caa9e77dc369fea8df9ae2c598d3c83b7214c1cfDiego Colantoni+ (int)getDigestLength:(CCHmacAlgorithm)algorithm {
caa9e77dc369fea8df9ae2c598d3c83b7214c1cfDiego Colantoni switch (algorithm) {
caa9e77dc369fea8df9ae2c598d3c83b7214c1cfDiego Colantoni case kCCHmacAlgMD5:
caa9e77dc369fea8df9ae2c598d3c83b7214c1cfDiego Colantoni return CC_MD5_DIGEST_LENGTH;
caa9e77dc369fea8df9ae2c598d3c83b7214c1cfDiego Colantoni case kCCHmacAlgSHA256:
caa9e77dc369fea8df9ae2c598d3c83b7214c1cfDiego Colantoni return CC_SHA256_DIGEST_LENGTH;
caa9e77dc369fea8df9ae2c598d3c83b7214c1cfDiego Colantoni case kCCHmacAlgSHA512:
caa9e77dc369fea8df9ae2c598d3c83b7214c1cfDiego Colantoni return CC_SHA512_DIGEST_LENGTH;
caa9e77dc369fea8df9ae2c598d3c83b7214c1cfDiego Colantoni case kCCHmacAlgSHA1:
caa9e77dc369fea8df9ae2c598d3c83b7214c1cfDiego Colantoni default:
caa9e77dc369fea8df9ae2c598d3c83b7214c1cfDiego Colantoni return CC_SHA1_DIGEST_LENGTH;
caa9e77dc369fea8df9ae2c598d3c83b7214c1cfDiego Colantoni }
a3970d0ea62388e4ede01470a6436eb5c6c92353Craig McDonnell}
a3970d0ea62388e4ede01470a6436eb5c6c92353Craig McDonnell
2beebed98b4fc7f018fb224a1e4a3ab6103a4c0bCraig McDonnell@end