iOSでの行文字列のハッシュの計算

非常に簡単なタスクを見てみましょう-いくつかの文字列のハッシュ和を計算します。 問題はいたるところにあり、少なくともOAuthによるユーザー認証を思い出す価値があります。 iOS向けアプリケーションの開発の一環として、問題の解決策を検討します。 以下では、ソフトウェアコードアーキテクチャの観点から、この問題に対する最も美しい(私の意見では)ソリューションを示します。





したがって、問題の次の条件を取得します。





金額の実際の計算


したがって、文字列NSString* string = @”Trololo”



与えてみましょう。 MD5アルゴリズムによるハッシュ和の計算を検討してください。 これは非常に簡単に行われます:



これはすべて最終的には次のようになります。

 #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];
      
      





したがって、関数CC_MD5(...)



と定数CC_MD5_DIGEST_LENGTH



、接続したファイルで宣言されます。



さらに、ハッシュ関数の結果がHMACアルゴリズムによって処理される場合を見てみましょう。 これは、前の例と同様に、ハッシュアルゴリズム識別子をパラメーターの1つとしてCCHmac(...)



するCCHmac(...)



関数を呼び出すことにより、ほぼ同じ行で行われます。この例ではkCCHmacAlgMD5



です。 さらにもう1つのヘッダーファイル<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];
      
      







データ解釈


NSStringのインスタンスを取得するには、結果を何らかの方法で解釈する必要があります。 これには2つの最も一般的なオプションがあります。



16進文字列として


最初のオプションは非常に単純で、次のように実装されます。



 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]];
      
      







Base64文字列として


このオプションは、自分の手ではやや難しいです。 しかし、これは実際には必須ではなく、Base64でのデータのエンコードとデコードのかなり良い実装があります 。これはここにあります 。 このライブラリには、NSDataのインスタンスに対して、出力でBase64の形式で解釈を構築する既製の静的メソッドが既にあります。 すると、解釈の計算は次のようになります。

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







カテゴリーデザイン


したがって、最後の問題-提示されたコードを最もコンパクトにする方法を解決することは残っています。 ここで、Objective-C言語の顕著な特徴の1つ、つまりカテゴリを思い出すことができます。 カテゴリは、新しいメソッドを追加することで既存のクラスの機能を拡張するメカニズムです。 さらに、独自のクラスでもシステムのクラスでも、絶対に任意のクラスを拡張できます。 NSString



クラスのこのようなカテゴリを作成します。 それぞれ、ヘッダーNSString+Hash.h



と実装ファイルNSString+Hash.m



2つのファイルを作成します。 カテゴリは、ほとんどのクラスと同様に宣言されますが、次の例外があります。クラス名の後に、カテゴリの名前が括弧で示され、クラスメンバーを宣言するためのブロックは省略されます。 したがって、次のタイプのヘッダーファイルを取得します(最も一般的な2つのハッシュアルゴリズムMD5およびSHA1を操作するためのすべての方法が規定されています)。



 #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
      
      







実装ファイルを完全に書き留めるわけではありません-まったく同じタイプですが、SHA1アルゴリズムの例として、各グループから1つのメソッドを示します。



 #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
      
      







おわりに


その結果、任意の文字列のハッシュ和の計算は非常に高速でコンパクトになります。 たとえば、次のとおりです。



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






All Articles