2009-04-16 3 views
60

Мне нужно создать HMAC-SHA1 в Objective C. Но я не нашел ничего, что работает. Я пробовал с CommonCrypto, используя CCHMAC, но не работал. Мне нужно сгенерировать hmac и после генерации числа HOTP.Код примера Objective-C для HMAC-SHA1

У кого-нибудь есть код примера в Objective C или C?

+0

Я не понимаю, почему вы используете тыс e base64Encoding, если все, что мы хотим, это иметь строку сгенерированного хэша. Можете ли вы объяснить, потому что в итоге мы получаем hmac-sha256 с кодировкой base64, а не hmac-sha256 ... – bruno

+0

@bruno, если вы не заметили, ваш ответ был удален и внесен в комментарий. Если у вас есть больше, чтобы опубликовать сообщение, отправьте его как новый ответ. –

ответ

73

Вот как генерировать HMAC с помощью SHA-256:

NSString *key; 
NSString *data; 

const char *cKey = [key cStringUsingEncoding:NSASCIIStringEncoding]; 
const char *cData = [data cStringUsingEncoding:NSASCIIStringEncoding]; 

unsigned char cHMAC[CC_SHA256_DIGEST_LENGTH]; 

CCHmac(kCCHmacAlgSHA256, cKey, strlen(cKey), cData, strlen(cData), cHMAC); 

NSData *HMAC = [[NSData alloc] initWithBytes:cHMAC 
             length:sizeof(cHMAC)]; 

NSString *hash = [HMAC base64Encoding]; 

Я не осведомлен о библиотеке HOTP, но алгоритм был довольно прост, если я правильно помню.

+1

base64Encoding есть в объекте c ?? Я попытался скомпилировать его, но я получаю сообщение об ошибке этой строки. [HMAC base64Encoding]; – Helena

+1

@Helena: oops, base64Encoding - это пользовательский протокол NSData. =) Я рад, что остальная часть кода работала. –

+0

Спасибо a ton .. :) – lostInTransit

2

Проведите целый день, пытаясь преобразовать сгенерированный хэш (байты) в читаемые данные. Я использовал базовое кодированное решение из ответа выше, и он не работал вообще для меня (b.t.w. вам нужно и внешний .h, чтобы иметь возможность использовать кодировку base64, которая у меня была).

Так что я сделал это (который прекрасно работает без внешнего .h):

CCHmac(kCCHmacAlgSHA256, cKey, strlen(cKey), cData, strlen(cData), cHMAC); 

// Now convert to NSData structure to make it usable again 
NSData *out = [NSData dataWithBytes:cHMAC length:CC_SHA256_DIGEST_LENGTH]; 

// description converts to hex but puts <> around it and spaces every 4 bytes 
NSString *hash = [out description]; 
hash = [hash stringByReplacingOccurrencesOfString:@" " withString:@""]; 
hash = [hash stringByReplacingOccurrencesOfString:@"<" withString:@""]; 
hash = [hash stringByReplacingOccurrencesOfString:@">" withString:@""]; 
// hash is now a string with just the 40char hash value in it 
NSLog(@"%@",hash); 
8

Это работает без использования пользовательских протоколов, используя код из http://cocoawithlove.com/2009/07/hashvalue-object-for-holding-md5-and.html

HashSHA256.h

#import <Foundation/Foundation.h> 
#import <CommonCrypto/CommonDigest.h> 

@interface HashSHA256 : NSObject { 


} 

- (NSString *) hashedValue :(NSString *) key andData: (NSString *) data ; 

@end 

HashSHA256.m

#import "HashSHA256.h" 

#import <CommonCrypto/CommonHMAC.h> 


@implementation HashSHA256 


- (NSString *) hashedValue :(NSString *) key andData: (NSString *) data { 


    const char *cKey = [key cStringUsingEncoding:NSUTF8StringEncoding]; 
    const char *cData = [data cStringUsingEncoding:NSUTF8StringEncoding]; 
    unsigned char cHMAC[CC_SHA256_DIGEST_LENGTH]; 
    CCHmac(kCCHmacAlgSHA256, cKey, strlen(cKey), cData, strlen(cData), cHMAC); 

    NSString *hash; 

    NSMutableString* output = [NSMutableString stringWithCapacity:CC_SHA256_DIGEST_LENGTH * 2]; 

    for(int i = 0; i < CC_SHA256_DIGEST_LENGTH; i++) 
     [output appendFormat:@"%02x", cHMAC[i]]; 
    hash = output; 
    return hash; 

} 

@end 

Использование:

- (NSString *) encodePassword: (NSString *) myPassword { 
    HashSHA256 * hashSHA256 = [[HashSHA256 alloc] init]; 
    NSString * result = [hashSHA256 hashedValue:mySecretSalt andData:myPassword];  
    return result;  
} 
+1

Вы не должны просто использовать строку в качестве ключа.Вместо этого вы должны получить его и сделать правильный ключ, который длиннее. PBKDF2, безусловно, станет началом. –

36

вот как вы можете создать HMAC-SHA1 base64.

Вам необходимо добавить Base64.h и Base64.m в свой проект. Вы можете получить его от here.

Если вы используете ARC, в Base64.m будут отображаться некоторые ошибки. Найдите похожие строки

return [[[self alloc] initWithBase64String:base64String] autorelease]; 

Вам необходимо удалить раздел авторекламы. Конечный результат должен выглядеть так:

return [[self alloc] initWithBase64String:base64String]; 

Теперь в вашем общем проекте импортируйте «Base64.ч» и следующий код

#import "Base64.h" 
#include <CommonCrypto/CommonDigest.h> 
#include <CommonCrypto/CommonHMAC.h> 

- (NSString *)hmacsha1:(NSString *)data secret:(NSString *)key { 

    const char *cKey = [key cStringUsingEncoding:NSASCIIStringEncoding]; 
    const char *cData = [data cStringUsingEncoding:NSASCIIStringEncoding]; 

    unsigned char cHMAC[CC_SHA1_DIGEST_LENGTH]; 

    CCHmac(kCCHmacAlgSHA1, cKey, strlen(cKey), cData, strlen(cData), cHMAC); 

    NSData *HMAC = [[NSData alloc] initWithBytes:cHMAC length:sizeof(cHMAC)]; 

    NSString *hash = [HMAC base64String]; 

    return hash; 
} 

С

NSLog(@"Hash: %@", hash); 

вы получите что-то похожее на это:

ghVEjPvxwLN1lBi0Jh46VpIchOc= 

+3

на самом деле это правильный ответ специально для требуемого ** HMAC-SHA1 ** под вопросом – beryllium

+0

Удивительный экономит время, спасибо! –

+8

Обновление iOS 7 - строка '[HMAC base64String]' выдаст ошибку. Вместо этого вы должны использовать 'base64EncodedStringWithOptions:'. – mafiOSo

22

Это комплексное решение, которое работает без каких-либо дополнительные библиотеки или хаки:

+(NSString *)hmac:(NSString *)plainText withKey:(NSString *)key 
{ 
    const char *cKey = [key cStringUsingEncoding:NSASCIIStringEncoding]; 
    const char *cData = [plainText cStringUsingEncoding:NSASCIIStringEncoding]; 

    unsigned char cHMAC[CC_SHA256_DIGEST_LENGTH]; 

    CCHmac(kCCHmacAlgSHA256, cKey, strlen(cKey), cData, strlen(cData), cHMAC); 

    NSData *HMACData = [[NSData alloc] initWithBytes:cHMAC length:sizeof(cHMAC)]; 

    const unsigned char *buffer = (const unsigned char *)[HMACData bytes]; 
    NSString *HMAC = [NSMutableString stringWithCapacity:HMACData.length * 2]; 

    for (int i = 0; i < HMACData.length; ++i) 
     HMAC = [HMAC stringByAppendingFormat:@"%02lx", (unsigned long)buffer[i]]; 

    return HMAC; 
} 

Вам не нужно включать стороннюю библиотеку base64, поскольку она уже закодирована.

+0

Вы уверены, что это уже кодировка Base 64? Что заставляет кодировать базу 64? Извините, что беспокою вас, но я устраняю трудности в создании сигнатуры oauth. Я попытался использовать ваш алгоритм, но я понимаю, что не знаю/вижу, где он кодируется Base 64. – helloB

+2

⚠️ Предупреждение для копировальных аппаратов: ** будьте осторожны с типом кодирования !! ** Я кодировал символы emoji и переключил 'NSASCIIStringEncoding' на' NSUTF16StringEncoding', который вводил нулевые терминаторы после каждого символа в возвращаемый массив c, 'strlen', чтобы предположить, что длина массива равна 1, что заставило HMAC основываться исключительно на первом символе. – Warpling

+0

Что такое CCHmac? –

2

Это как йо сделать это без внешних файлов возвращающих шестнадцатеричной строки:

-(NSString *)hmac:(NSString *)plaintext withKey:(NSString *)key 
{ 
    const char *cKey = [key cStringUsingEncoding:NSASCIIStringEncoding]; 
    const char *cData = [plaintext cStringUsingEncoding:NSASCIIStringEncoding]; 
    unsigned char cHMAC[CC_SHA1_DIGEST_LENGTH]; 
    CCHmac(kCCHmacAlgSHA1, cKey, strlen(cKey), cData, strlen(cData), cHMAC); 
    NSData *HMACData = [NSData dataWithBytes:cHMAC length:sizeof(cHMAC)]; 
    const unsigned char *buffer = (const unsigned char *)[HMACData bytes]; 
    NSMutableString *HMAC = [NSMutableString stringWithCapacity:HMACData.length * 2]; 
    for (int i = 0; i < HMACData.length; ++i){ 
     [HMAC appendFormat:@"%02x", buffer[i]]; 
    } 
    return HMAC; 
} 

Он был испытан в Xcode 5 с прошивкой 7 и работает отлично!

+0

Это прекрасно работает для меня ... Спасибо ... – Urkman

+0

Спасибо за его работу для меня .. –

1

Из интереса, почему вы создаете (unsigned char cHMAC), а затем конвертируете в (NSData), а затем конвертируете его в (NSMutableString) и затем конвертируете, наконец, в (HexString)?

Вы можете сделать это быстрее, отрезав посредника (т. Е. Без NSData и NSMutableString в целом, более быструю и лучшую производительность), также меняя (unsigned char) на (uint8_t []), ведь все они - массивы в любом случае !, ниже:

-(NSString *)hmac:(NSString *)plaintext withKey:(NSString *)key 
{ 
const char *cKey = [key cStringUsingEncoding:NSASCIIStringEncoding]; 
const char *cData = [plaintext cStringUsingEncoding:NSASCIIStringEncoding]; 

uint8_t cHMAC[CC_SHA1_DIGEST_LENGTH]; 

CCHmac(kCCHmacAlgSHA1, cKey, strlen(cKey), cData, strlen(cData), cHMAC); 

NSString *Hash1 = @""; 
for (int i=0; i< CC_SHA1_DIGEST_LENGTH; i++) 
{ 
    Hash1 = [Hash1 stringByAppendingString:[NSString stringWithFormat:@"%02X", cHMAC[i]]]; 
} 
return Hash1; 
} 

Я надеюсь, что это помогает,

С уважением

HEIDER Сати

Смежные вопросы