![](/img/trans.png)
[英]How to make a Base64 HmacSHA256 signature of bytes payload in JavaScript equivalent to Java?
[英]From objective-c to swift base64 and hmacsha1
我有一个问题,尝试在几天内解决,确实需要您的帮助。
我需要连接到API并获得带有签名参数示例的发布请求
URL = yourapi.com//mobile/register?client_id=3tme3bnmepmibhvv1toq4xfed&device_id=866faaa06aa1b139D&phone= 79653502956&signature=1WVoLPXcqJVKaxSK50ArFHtKtnM=
原始数据
data ="3tme3bnmepmibhvv1toq4xfed866faaa06aa1b13979653502956"
key = "0gkp7n6tnwdn816kyzfp26s3e"
主要问题在于签名。 它需要像这样生成
Java示例
signature = Base64.encode(HMAC_SHA1.digest(data, Base64.decode(client_secret)))
我有与base64和hamcsha1(CommonCrypto)一起使用的旧的Objective-C代码
#import "Base64.h"
@interface Base64()
@end
@implementation Base64
static const char _base64EncodingTable[64] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
static const short _base64DecodingTable[256] = {
-2, -2, -2, -2, -2, -2, -2, -2, -2, -1, -1, -2, -1, -1, -2, -2,
-2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2,
-1, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, 62, -2, -2, -2, 63,
52, 53, 54, 55, 56, 57, 58, 59, 60, 61, -2, -2, -2, -2, -2, -2,
-2, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, -2, -2, -2, -2, -2,
-2, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40,
41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, -2, -2, -2, -2, -2,
-2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2,
-2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2,
-2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2,
-2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2,
-2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2,
-2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2,
-2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2,
-2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2
};
+ (NSString *) encodeString: (NSString *) strData {
return [self encodeData: [strData dataUsingEncoding: NSUTF8StringEncoding] ];
}
+ (NSString *) encodeData: (NSData *) objData {
const unsigned char * objRawData = [objData bytes];
char * objPointer;
char * strResult;
// Get the Raw Data length and ensure we actually have data
unsigned long intLength = [objData length];
if (intLength == 0) return nil;
// Setup the String-based Result placeholder and pointer within that placeholder
strResult = (char *)calloc(((intLength + 2) / 3) * 4, sizeof(char));
objPointer = strResult;
// Iterate through everything
while (intLength > 2) { // keep going until we have less than 24 bits
*objPointer++ = _base64EncodingTable[objRawData[0] >> 2];
*objPointer++ = _base64EncodingTable[((objRawData[0] & 0x03) << 4) + (objRawData[1] >> 4)];
*objPointer++ = _base64EncodingTable[((objRawData[1] & 0x0f) << 2) + (objRawData[2] >> 6)];
*objPointer++ = _base64EncodingTable[objRawData[2] & 0x3f];
// we just handled 3 octets (24 bits) of data
objRawData += 3;
intLength -= 3;
}
// now deal with the tail end of things
if (intLength != 0) {
*objPointer++ = _base64EncodingTable[objRawData[0] >> 2];
if (intLength > 1) {
*objPointer++ = _base64EncodingTable[((objRawData[0] & 0x03) << 4) + (objRawData[1] >> 4)];
*objPointer++ = _base64EncodingTable[(objRawData[1] & 0x0f) << 2];
*objPointer++ = '=';
} else {
*objPointer++ = _base64EncodingTable[(objRawData[0] & 0x03) << 4];
*objPointer++ = '=';
*objPointer++ = '=';
}
}
// Terminate the string-based result
*objPointer = '\0';
// Return the results as an NSString object
NSString *result = @(strResult);
free(strResult);
return result;
}
+ (NSData *) decodeString: (NSString *) strBase64 {
const char * objPointer = [strBase64 cStringUsingEncoding:NSASCIIStringEncoding];
unsigned long intLength = strlen(objPointer);
int intCurrent;
int i = 0, j = 0, k;
unsigned char * objResult;
objResult = calloc(intLength, sizeof(unsigned char));
// Run through the whole string, converting as we go
while ( ((intCurrent = *objPointer++) != '\0') && (intLength-- > 0) ) {
if (intCurrent == '=') {
if (*objPointer != '=' && ((i % 4) == 1)) {// || (intLength > 0)) {
// the padding character is invalid at this point -- so this entire string is invalid
free(objResult);
return nil;
}
continue;
}
intCurrent = _base64DecodingTable[intCurrent];
if (intCurrent == -1) {
// we're at a whitespace -- simply skip over
continue;
} else if (intCurrent == -2) {
// we're at an invalid character
free(objResult);
return nil;
}
switch (i % 4) {
case 0:
objResult[j] = intCurrent << 2;
break;
case 1:
objResult[j++] |= intCurrent >> 4;
objResult[j] = (intCurrent & 0x0f) << 4;
break;
case 2:
objResult[j++] |= intCurrent >>2;
objResult[j] = (intCurrent & 0x03) << 6;
break;
case 3:
objResult[j++] |= intCurrent;
break;
}
i++;
}
// mop things up if we ended on a boundary
k = j;
if (intCurrent == '=') {
switch (i % 4) {
case 1:
// Invalid state
free(objResult);
return nil;
case 2:
k++;
// flow through
case 3:
objResult[k] = 0;
}
}
// Cleanup and setup the return NSData
NSData * objData = [[NSData alloc] initWithBytes:objResult length:j] ;
free(objResult);
return objData;
}
@end
其他客户的Objective-C
+ (NSString*)signParametersWithString:(NSString*)parameters
withSecret:(NSString*)clientSecret
{
// Base64 Decode.
NSData* keyData = [Base64 decodeString:clientSecret];
NSString *strData = [[NSString alloc]initWithData:keyData encoding:NSUTF8StringEncoding];
// DO NOT USE !!! [[NSData alloc] initWithBase64EncodedString:clientSecret options:0];
const char* cData = [parameters cStringUsingEncoding:NSASCIIStringEncoding];
unsigned char cHMAC[CC_SHA1_DIGEST_LENGTH];
// Sign with HMAC SHA1.
CCHmac(kCCHmacAlgSHA1, [keyData bytes], [keyData length], cData, strlen(cData), cHMAC);
NSData* HMAC = [[NSData alloc] initWithBytes:cHMAC length:sizeof(cHMAC)];
// Base64 Encode.
NSLog(@"%@", HMAC);
return [HMAC base64EncodedStringWithOptions:0];
}
我试图通过StackOverflow社区迅速开展工作,但无法正常工作。
SWIFT代码
let data = Data("3tme3bnmepmibhvv1toq4xfed866faaa06aa1b13979653502956".utf8)
let key = Data("0gkp7n6tnwdn816kyzfp26s3e".utf8).base64EncodedString()
let hmac = data.hmacsha1(key: key)
extension Data {
func hmacsha1(key: String) -> String? {
guard let keyData = Data(base64Encoded: key) else {
return nil
}
var digest = [UInt8](repeating: 0, count: Int(CC_SHA1_DIGEST_LENGTH))
self.withUnsafeBytes({ dataBytes in
keyData.withUnsafeBytes({ keyDataBytes in
CCHmac(CCHmacAlgorithm(kCCHmacAlgSHA1), keyDataBytes, keyData.count, dataBytes, self.count, &digest)
})
})
return Data(bytes: digest).base64EncodedString()
}
}
它正在产生。
signature = "pd6oB8P8Yq92gn7eYH0qAnSLFbI="
但是我需要这个
signature = "1WVoLPXcqJVKaxSK50ArFHtKtnM="
我需要帮助来修复Swift函数或如何使obj-c代码在Swift项目中工作。 我认为那是解码base64的错,但是我现在不知道如何解决。
问题解决了
let keyData: NSData = Base64.decode(secret_key) as NSData
let cData = param_signature
let hmacResult: String = cData.hmac(algorithm: HMACAlgorithm.SHA1, key: keyData)
enum HMACAlgorithm {
case MD5, SHA1, SHA224, SHA256, SHA384, SHA512
func toCCHmacAlgorithm() -> CCHmacAlgorithm {
var result: Int = 0
switch self {
case .MD5:
result = kCCHmacAlgMD5
case .SHA1:
result = kCCHmacAlgSHA1
case .SHA224:
result = kCCHmacAlgSHA224
case .SHA256:
result = kCCHmacAlgSHA256
case .SHA384:
result = kCCHmacAlgSHA384
case .SHA512:
result = kCCHmacAlgSHA512
}
return CCHmacAlgorithm(result)
}
func digestLength() -> Int {
var result: CInt = 0
switch self {
case .MD5:
result = CC_MD5_DIGEST_LENGTH
case .SHA1:
result = CC_SHA1_DIGEST_LENGTH
case .SHA224:
result = CC_SHA224_DIGEST_LENGTH
case .SHA256:
result = CC_SHA256_DIGEST_LENGTH
case .SHA384:
result = CC_SHA384_DIGEST_LENGTH
case .SHA512:
result = CC_SHA512_DIGEST_LENGTH
}
return Int(result)
}
}
extension String {
func hmac(algorithm: HMACAlgorithm, key: NSData) -> String {
let cKey = key
let cData = self.cString(using: String.Encoding.ascii)
var cHMAC = [CC_SHA1_DIGEST_LENGTH]
CCHmac(algorithm.toCCHmacAlgorithm(), cKey.bytes, cKey.length, cData, Int(strlen(cData!)), &cHMAC)
let hmacData:NSData = NSData(bytes: cHMAC, length: (Int(algorithm.digestLength())))
let hmacBase64 = hmacData.base64EncodedString(options: NSData.Base64EncodingOptions(rawValue: 0))
return String(hmacBase64)
}
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.