This commit is contained in:
2025-12-04 20:57:39 +08:00
parent 6ac6514f89
commit 40d9b5aad4
5 changed files with 67 additions and 7 deletions

View File

@@ -0,0 +1,32 @@
//
// KBSignUtils.h
// keyBoard
//
// Created by Mac on 2025/12/4.
//
#import <Foundation/Foundation.h>
NS_ASSUME_NONNULL_BEGIN
@interface KBSignUtils : NSObject
/// URL 编码(与后端保持一致)
+ (NSString *)urlEncode:(NSString *)value;
/// HMAC-SHA256返回十六进制小写字符串
+ (NSString *)hmacSHA256:(NSString *)data secret:(NSString *)secret;
/// 生成签名:传入参与签名的所有参数(不含 sign 自身)
+ (NSString *)signWithParams:(NSDictionary<NSString *, NSString *> *)params
secret:(NSString *)secret;
/// 秒级时间戳(字符串)
+ (NSString *)currentTimestamp;
/// 简单 nonce 生成(默认 16 位)
+ (NSString *)generateNonceWithLength:(NSUInteger)length;
@end
NS_ASSUME_NONNULL_END

View File

@@ -0,0 +1,92 @@
//
// KBSignUtils.m
// keyBoard
//
// Created by Mac on 2025/12/4.
//
#import "KBSignUtils.h"
#import <CommonCrypto/CommonCrypto.h>
@implementation KBSignUtils
+ (NSString *)urlEncode:(NSString *)value {
if (!value) return @"";
// Swift .urlQueryAllowed
NSCharacterSet *allowed = [NSCharacterSet URLQueryAllowedCharacterSet];
NSString *encoded = [value stringByAddingPercentEncodingWithAllowedCharacters:allowed];
return encoded ?: value;
}
+ (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<NSString *, NSString *> *)params
secret:(NSString *)secret {
// 1. & sign
NSMutableDictionary<NSString *, NSString *> *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<NSString *> *sortedKeys = [[filtered allKeys] sortedArrayUsingSelector:@selector(compare:)];
// 3. key=value&key2=value2...&secret=xxx
NSMutableArray<NSString *> *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];
NSString *dataString = [components componentsJoinedByString:@"&"];
// 4. HMAC-SHA256
NSString *sign = [self hmacSHA256:dataString secret:secret];
return sign;
}
+ (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