したがって、問題の次の条件を取得します。
-
NSString
インスタンスとして文字列が与えられます。 - ハッシュ和の値も文字列
NSString
形式で計算する必要があります。 - 選択したソリューションを最もコンパクトで美しいものにする必要があります。
金額の実際の計算
したがって、文字列
NSString* string = @”Trololo”
与えてみましょう。 MD5アルゴリズムによるハッシュ和の計算を検討してください。 これは非常に簡単に行われます:
- ヘッダーファイルCommonCrypto / CommonDigest.hを含めます。
- const char *として文字列の表現を取得します。
- ハッシュ出力バッファーをunsigned charとして構成します。
- ハッシュ和の実際の値を計算します。
- 最後に、NSDataのインスタンスで生バイトをラップします。
これはすべて最終的には次のようになります。
#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進数として解釈して文字列を取得します。
- また、Base64でのエンコードによる文字列のデータの解釈。
16進文字列として
最初のオプションは非常に単純で、次のように実装されます。
- 前のアルゴリズムの最後のステップを削除し(NSDataは使用しません)、生のバイトを操作します。
- 受信した生バイトの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];