可以将文章内容翻译成中文,广告屏蔽插件可能会导致该功能失效(如失效,请关闭广告屏蔽插件后再试):
问题:
I need to generate HMAC-SHA1 in Objective C. But i didnt find anything that works. I tried with CommonCrypto, using CCHMAC, but didnt works. I need to generate a hmac and after generate HOTP number.
Somebody have any example code in Objective C or C?
回答1:
Here's how you generate an HMAC using 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];
I'm not aware of an HOTP library, but the algorithm was quite simple, if I recall correctly.
回答2:
here is how you can generate HMAC-SHA1 base64.
You need to add Base64.h and Base64.m to your project. You can get it from here.
If you use ARC, it will show some errors in Base64.m. Find the lines who are similar like this
return [[[self alloc] initWithBase64String:base64String] autorelease];
what you need is to delete the autorelease section. The final result should look like:
return [[self alloc] initWithBase64String:base64String];
Now in your general project import "Base64.h" and the following code
#import "Base64.h" #include #include - (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; }
With
NSLog(@"Hash: %@", hash);
you will get something similar to this:
ghVEjPvxwLN1lBi0Jh46VpIchOc=
回答3:
This is the complete solution which works without any extra libraries or hacks:
+(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
You don't have to include any third-party base64 library as it is already encoded.
回答4:
This works without using custom protocols, using some code from http://cocoawithlove.com/2009/07/hashvalue-object-for-holding-md5-and.html
HashSHA256.h
#import #import @interface HashSHA256 : NSObject { } - (NSString *) hashedValue :(NSString *) key andData: (NSString *) data ; @end
HashSHA256.m
#import "HashSHA256.h" #import @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
Usage:
- (NSString *) encodePassword: (NSString *) myPassword { HashSHA256 * hashSHA256 = [[HashSHA256 alloc] init]; NSString * result = [hashSHA256 hashedValue:mySecretSalt andData:myPassword]; return result; }
回答5:
So what I did was this (which works perfectly without an external .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 is now a string with just the 40char hash value in it NSLog(@"%@",hash);
回答6:
This is how yo do it without external files returning an hex string:
-(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
It was tested in xCode 5 with iOS 7 and works fine!
回答7:
Out of interest, why do you create (unsigned char cHMAC) and then convert into (NSData) and then convert it into (NSMutableString) and then convert finally into (HexString)?
You could do this in a quicker way by cutting the middleman (i.e. without NSData and NSMutableString altogether, quicker and better performance), also changing (unsigned char) into (uint8_t []), after all they are all hex-arrays anyway!, below:
-(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
I hope this helps,
Regards
Heider Sati
回答8:
Have you seen Jens Alfke's new MyCrypto classes?
He has some sample code on his blog.