⬆️ ⬇️

Calculating the hash of a string in iOS

Let's consider with you a very simple task - the calculation of the hash sum of a certain string. The task is found everywhere, it is worth remembering at least user authentication via OAuth. Solution of the problem will be considered in the development of applications for iOS. Below, I will try to show the most beautiful (in my opinion) solution to the problem in terms of software code architecture.





So, we get the following conditions of the problem:





Actually calculating the amount


So, let us be given some string NSString* string = @”Trololo” . Consider the calculation of its hash sum by the MD5 algorithm. This is done very simply:



Everything, it as a result looks as follows:

 #import <CommonCrypto/CommonDigest.h> … NSString* string = @”Trololo”; const char* data = [string UTF8String]; unsigned char hashBuffer[CC_MD5_DIGEST_LENGTH]; CC_MD5(data, strlen(data), hashBuffer); NSData* result = [NSData dataWithBytes:hashBuffer length:CC_MD5_DIGEST_LENGTH]; 


Accordingly, the function CC_MD5(...) and the constant CC_MD5_DIGEST_LENGTH declared in the file we connected.

')

In addition, let's consider the case in which the result of the hash function is processed by the HMAC algorithm. This is done, like the previous example, in almost one line - by calling the function CCHmac(...) , which as one of the parameters is passed the identifier of the hashing algorithm, in our case it is kCCHmacAlgMD5 . Do not forget only to connect in addition one more header file - <CommonCrypto/CommonHMAC.h> .



 #import <CommonCrypto/CommonDigest.h> #import <CommonCrypto/CommonHMAC.h> NSString* string = @”Trololo”; NSString* hmacKey = @”hmacKey”; const char* data = [string UTF8String]; const char* hmacData= [hmacKey UTF8String]; unsigned char hashBuffer[CC_MD5_DIGEST_LENGTH]; CCHmac(kCCHmacAlgMD5, hmacData, strlen(hmacData), data, strlen(data), hashBuffer); NSData* result = [NSData dataWithBytes:hashBuffer length:CC_MD5_DIGEST_LENGTH]; 




Interpretation of data


Now we need to interpret the result in some way to get an NSString instance as output. There are two common options for this:



As hexadecimal string


The first option is very simple and is implemented as follows:



 NSString* string = @”Trololo”; const char* data = [string UTF8String]; unsigned char hashBuffer[CC_MD5_DIGEST_LENGTH]; CC_MD5(data, strlen(data), hashBuffer); NSMutableString* result = [[NSMutableString alloc] initWithCapacity:CC_MD5_DIGEST_LENGTH*2]; for (int i= 0; i < CC_MD5_DIGEST_LENGTH; i++) [result appenFormat:@”%02X”, hashBuffer[i]]; 




As a base64 string


This option is somewhat more difficult to implement with your own hands. But this, strictly speaking, is not required, there is a fairly good implementation of encoding and decoding data in Base64, which can be found here . In this library, there is just a ready-made static method, which for an NSData instance builds an output interpretation in the form of Base64. Then the calculation of the interpretation will be as follows:

 NSData* buffer = [NSData dataWithBytes:hashBuffer length:CC_MD5_DIGEST_LENGTH]; NSString* result = [Base64 encode:buffer]; 




Category design


So it remains to solve the last problem - how to make the presented code the most compact. Here you can recall one remarkable possibility of the Objective-C language - namely, categories. Categories are a mechanism for expanding the functionality of an existing class by adding new methods to it. And you can expand them with absolutely any class, both your own and any system class. Let's write just such a category for the NSString class. We create two files, respectively the header NSString+Hash.h and the implementation file NSString+Hash.m A category is declared almost as much as any class, with the following exceptions: after the class name, the category name is indicated in brackets, the class member declaration block is omitted. Thus, we obtain the following type of header file (all methods for working with the two most common hashing algorithms MD5 and SHA1 are laid down):



 #import <Foundation/Foundation.h> #import <CommonCrypto/CommonHMAC.h> #import <CommonCrypto/CommonDigest.h> #import "Base64.h" @interface NSString (NSString_NM_HASH) //RAW - (NSData*) MD5; - (NSData*) SHA1; - (NSData*) HMAC_MD5: (NSString*)hmacKey; - (NSData*) HMAC_SHA1: (NSString*)hmacKey; //INTERPRET Base64 - (NSString*) MD5_x64; - (NSString*) SHA1_x64; - (NSString*) HMAC_MD5_x64:(NSString*)hmacKey; - (NSString*) HMAC_SHA1_x64:(NSString*)hmacKey; //INTERPRET HEX - (NSString*) MD5_HEX; - (NSString*) SHA1_HEX; - (NSString*) HMAC_MD5_HEX:(NSString*)hmacKey; - (NSString*) HMAC_SHA1_HEX:(NSString*)hmacKey; @end 




We will not completely write the implementation file - it is absolutely the same type, but we will show one method from each group using the example of the SHA1 algorithm.



 #import “NSString+Hash.h” @implementation NSString (NSString_NM_HASH) - (NSData*) HMAC_SHA1: (NSString *)hmacKey{ const char* data = [self UTF8String]; const char* hashKey = [hmacKey UTF8String]; unsigned char hashingBuffer[CC_SHA1_DIGEST_LENGTH]; CCHmac(kCCHmacAlgSHA1, hashKey, strlen(hashKey), data, strlen(data), hashingBuffer); return [NSData dataWithBytes:hashingBuffer length:CC_SHA1_DIGEST_LENGTH]; } - (NSString*) HMAC_SHA1_x64:(NSString *)hmacKey{ return [Base64 encode:[self HMAC_SHA1:hmacKey]]; } - (NSString*) HMAC_SHA1_HEX:(NSString *)hmacKey{ const char* data = [self UTF8String]; const char* hashKey = [hmacKey UTF8String]; unsigned char hashingBuffer[CC_SHA1_DIGEST_LENGTH]; CCHmac(kCCHmacAlgSHA1, hashKey, strlen(hashKey), data, strlen(data), hashingBuffer); NSMutableString* result = [[NSMutableString alloc] initWithCapacity:CC_SHA1_DIGEST_LENGTH*2]; for (int i = 0; i < CC_SHA1_DIGEST_LENGTH; i++) [result appendFormat:@"%02X", hashingBuffer[i]]; return result; } @end 




Conclusion


As a result, the calculation of the hash sum of any string can be very fast and compact. For example as follows:



 #import “NSString+Hash.h” NSString* string = @”Trololo”; NSString* string_md5 = [string MD5_HEX]; NSString* string_sh1 = [string SHA1_x64]; 

Source: https://habr.com/ru/post/133560/



All Articles