// // KBSignUtils.m // keyBoard // // Created by Mac on 2025/12/4. // #import "KBSignUtils.h" #import @implementation KBSignUtils + (NSString *)urlEncode:(NSString *)value { if (!value) return @""; // 按 application/x-www-form-urlencoded 规则编码(更贴近后端常见实现) NSMutableCharacterSet *allowed = [NSMutableCharacterSet alphanumericCharacterSet]; [allowed addCharactersInString:@"-._*"]; NSString *encoded = [value stringByAddingPercentEncodingWithAllowedCharacters:allowed]; if (!encoded) { return value; } // 空格改为 +(URLEncoder 风格) encoded = [encoded stringByReplacingOccurrencesOfString:@"%20" withString:@"+"]; return encoded; } + (NSString *)hmacSHA256:(NSString *)data secret:(NSString *)secret { const char *cKey = [secret cStringUsingEncoding:NSUTF8StringEncoding]; const char *cData = [data cStringUsingEncoding:NSUTF8StringEncoding]; unsigned char cHMAC[CC_SHA256_DIGEST_LENGTH]; CCHmac(kCCHmacAlgSHA256, cKey, strlen(cKey), cData, strlen(cData), cHMAC); // 转十六进制小写字符串 NSMutableString *output = [NSMutableString stringWithCapacity:CC_SHA256_DIGEST_LENGTH * 2]; for (int i = 0; i < CC_SHA256_DIGEST_LENGTH; i++) { [output appendFormat:@"%02x", cHMAC[i]]; } return output; } + (NSString *)signWithParams:(NSDictionary *)params secret:(NSString *)secret { NSString *dataString = [self signSourceStringWithParams:params secret:secret]; return [self hmacSHA256:dataString secret:secret]; } + (NSString *)signSourceStringWithParams:(NSDictionary *)params secret:(NSString *)secret { // 1. 过滤空值 & sign 自身 NSMutableDictionary *filtered = [NSMutableDictionary dictionary]; [params enumerateKeysAndObjectsUsingBlock:^(NSString *key, NSString *obj, BOOL *stop) { if (!obj || obj.length == 0) return; if ([[key lowercaseString] isEqualToString:@"sign"]) return; filtered[key] = obj; }]; // 2. 按 key 字典序排序 NSArray *sortedKeys = [[filtered allKeys] sortedArrayUsingSelector:@selector(compare:)]; // 3. 拼接 key=value&key2=value2...&secret=xxx NSMutableArray *components = [NSMutableArray array]; for (NSString *key in sortedKeys) { NSString *value = filtered[key] ?: @""; NSString *encodedValue = [self urlEncode:value]; NSString *part = [NSString stringWithFormat:@"%@=%@", key, encodedValue]; [components addObject:part]; } NSString *encodedSecret = [self urlEncode:secret ?: @""]; NSString *secretPart = [NSString stringWithFormat:@"secret=%@", encodedSecret]; [components addObject:secretPart]; return [components componentsJoinedByString:@"&"]; } + (NSString *)currentTimestamp { NSTimeInterval ts = [[NSDate date] timeIntervalSince1970]; long long seconds = (long long)ts; return [NSString stringWithFormat:@"%lld", seconds]; } + (NSString *)generateNonceWithLength:(NSUInteger)length { // 用 UUID 生成,去掉 - , 再截取前 length 位 NSString *uuid = [[NSUUID UUID].UUIDString stringByReplacingOccurrencesOfString:@"-" withString:@""]; if (length == 0 || length > uuid.length) { return uuid; } return [uuid substringToIndex:length]; } @end