记录编写的验签部分逻辑
主要用到ascii、unicode编码、sha256
-
IFSignatureHelper.h代码
#import <Foundation/Foundation.h> #import <CommonCrypto/CommonDigest.h> #import <CommonCrypto/CommonHMAC.h> // key的公共部分 #define KEY_BASIC @"catface@catface@catface-2021" NS_ASSUME_NONNULL_BEGIN @interface IFSignatureHelper : NSObject // key的动态部分 @property(nonatomic,strong)NSString *key; // 生成验签的对外方法 -(NSString*)signature: (NSString*)keyPrivate withNormalParamsDict:(NSDictionary*)normalParamsDict withQueryParamsDict:(NSDictionary*)queryParamsDict withBodyParamsDict:(NSDictionary*)bodyParamsDict; // 字符串内中文转unicode -(NSString*)utf8ToUnicode:(NSString*)string; // 字符串encode编码 -(NSString*)encodeString:(NSString*)unencodedString; // 单纯的sha256摘要计算 -(NSString *)hmac:(NSString*)plaintext:(NSString *)key; // sha256生成验签 -(NSString*) hmac_sha256: (NSString*)value; @end NS_ASSUME_NONNULL_END
-
IFSignatureHelper.m代码
#import "IFSignatureHelper.h" #import "NSString+SHA256HMAC.h" @implementation IFSignatureHelper -(NSString*)utf8ToUnicode:(NSString*)string{ NSUInteger length = [string length]; NSMutableString *s = [NSMutableString stringWithCapacity:0]; for (int i = 0;i < length; i++) { unichar _char = [string characterAtIndex:i]; if (_char <= '9' && _char >='0') { [s appendFormat:@"%@",[string substringWithRange:NSMakeRange(i,1)]]; }else if(_char >='a' && _char <= 'z') { [s appendFormat:@"%@",[string substringWithRange:NSMakeRange(i,1)]]; }else if(_char >='A' && _char <= 'Z') { [s appendFormat:@"%@",[string substringWithRange:NSMakeRange(i,1)]]; }else if(_char >= 0x4e00 && _char <=0x9fff) { [s appendFormat:@"\\u%x",[string characterAtIndex:i]]; } else { [s appendFormat:@"%@",[string substringWithRange:NSMakeRange(i,1)]]; } } return s; } -(NSString*)encodeString:(NSString*)unencodedString{ NSString *encodedString = (NSString *) CFBridgingRelease(CFURLCreateStringByAddingPercentEscapes(kCFAllocatorDefault, (CFStringRef)unencodedString, NULL, (CFStringRef)@"!*'();:@&=+$,/?%#[]", kCFStringEncodingUTF8)); return encodedString; } -(NSString*)hmac:(NSString*)plaintext:(NSString*)key{ const char *cKey = [key cStringUsingEncoding:NSUTF8StringEncoding]; 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 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; } -(NSString*)hmac_sha256:(NSString*)value{ NSString *tempKey = [KEY_BASIC stringByAppendingString:[self key]]; NSString *temp = [[self key] substringToIndex:1]; int tempASCII = [temp characterAtIndex:0] + 200; NSMutableArray *new_key = [[NSMutableArray alloc] init]; for (int i = 0, keyLength = tempKey.length; i < keyLength; i++) { int characterAtIndex = [tempKey characterAtIndex:i]; // char转ascii int new_temp = (characterAtIndex ^ tempASCII) & 255; char charactor = [tempKey characterAtIndex:i]; // ascii转char [new_key addObject:[NSString stringWithFormat:@"%c", new_temp]]; } // componentsJoinedByString即数组转字符串 return [self hmac:value:[new_key componentsJoinedByString:@""]]; } -(NSString*)signature: (NSString*)keyPrivate withNormalParamsDict:(NSDictionary*)normalParamsDict withQueryParamsDict:(NSDictionary*)queryParamsDict withBodyParamsDict:(NSDictionary*)bodyParamsDict{ [self setKey:keyPrivate]; // 组合params NSMutableDictionary* allParamsDict = [[NSMutableDictionary alloc]initWithDictionary:normalParamsDict]; // 添加query params if (nil != queryParamsDict) { [allParamsDict setValue:[queryParamsDict objectForKey:@"queryString"] forKey:@"queryString"]; } // 添加body params[// todo 转json会乱序,可能需要处理顺序] if (nil != bodyParamsDict) { NSData *jsonData = [NSJSONSerialization dataWithJSONObject:bodyParamsDict options:NSJSONWritingSortedKeys error:0]; NSString *dataStr = [[NSString alloc] initWithData:jsonData encoding:NSUTF8StringEncoding]; dataStr = [self utf8ToUnicode:dataStr]; [allParamsDict setValue:dataStr forKey:@"bodyString"]; } // params排序[最后组合成按顺序的数组,如akey=avalue&bkey=bvalue] NSMutableDictionary* allSortedParams = [[NSMutableDictionary alloc]init]; NSArray* keys = allParamsDict.allKeys; NSArray* sortedKeys = [keys sortedArrayUsingComparator:^NSComparisonResult(id obj1, id obj2) { return [(NSString *)obj1 compare:(NSString *)obj2 options:NSNumericSearch]; }]; NSMutableArray* resultArray = [[NSMutableArray alloc]init]; for (int i = 0; i < sortedKeys.count; i++) { NSString* key = sortedKeys[i]; NSString* value = [allParamsDict objectForKey:sortedKeys[i]]; // key和value进行unicode编码 key = [self encodeString:key]; value = [self encodeString:value]; NSString* keyAndValue =[NSString stringWithFormat:@"%@=%@", key, value]; [resultArray addObject:keyAndValue]; } NSString* resultString = [resultArray componentsJoinedByString:@"&"]; // 空格和引号后补充加号+ resultString = [resultString stringByReplacingOccurrencesOfString:@"%3A" withString:@"%3A+"]; resultString = [resultString stringByReplacingOccurrencesOfString:@"%2C" withString:@"%2C+"]; return [self hmac_sha256:resultString]; } @end
-
使用示例
#define sig_key @"123456789_987654321" // 添加中文测试unicode编码是否正确且符合逻辑 - (IBAction)generateSignature:(id)sender { NSDictionary* normalParams = @{ @"name":@"zhangsan张三", @"pass":@"password密码" }; NSDictionary* queryParams = @{ @"queryString":@"q1=v1&q2=值2" }; NSDictionary* bodyParams = @{ @"b1":@"v1", @"b3":@"v值3", @"b2":@"值z2", }; IFSignatureHelper *helper = [[IFSignatureHelper alloc]init]; NSString *result = [helper signature:sig_key withNormalParamsDict:normalParams withQueryParamsDict:queryParams withBodyParamsDict:bodyParams]; NSLog(@"signature result is:%@", result); }