2014-07-18 47 views
0

我正在使用HMAC SHA256在我的Android应用程序中创建base64哈希。并将其发送到服务器以与服务器端哈希匹配。
正在关注this教程。使用C#脚本的Android base64哈希与服务器端哈希不匹配

工作Android的代码:

public String getHash(String data,String key) 
{ 

    try 
    { 
     String secret = key; 
     String message = data; 

     Mac sha256_HMAC = Mac.getInstance("HmacMD5"); 
     SecretKeySpec secret_key = new SecretKeySpec(secret.getBytes(), "HmacMD5"); 
     sha256_HMAC.init(secret_key); 

     String hash = Base64.encodeBase64String(sha256_HMAC.doFinal(message.getBytes())); 
     System.out.println(hash); 
     return hash; 
} 
catch (Exception e){ 
    System.out.println("Error"); 
} 

}

服务器代码是在C#脚本及其按以下

using System.Security.Cryptography; 

namespace Test 
{ 
     public class MyHmac 
     { 
      private string CreateToken(string message, string secret) 
      { 
       secret = secret ?? ""; 
       var encoding = new System.Text.ASCIIEncoding(); 
       byte[] keyByte = encoding.GetBytes(secret); 
       byte[] messageBytes = encoding.GetBytes(message); 
       using (var hmacsha256 = new HMACSHA256(keyByte)) 
       { 
        byte[] hashmessage = hmacsha256.ComputeHash(messageBytes); 
        return Convert.ToBase64String(hashmessage); 
       } 
      } 
     } 
} 

但散列键在机器人侧没有与服务器相匹配生成下面是客观的C代码,其生成与C#代码相同的代码

ob jective的C代码:

#import "AppDelegate.h" 
    #import <CommonCrypto/CommonHMAC.h> 

    @implementation AppDelegate 

    - (void)applicationDidFinishLaunching:(NSNotification *)aNotification 
    { 
     NSString* key = @"secret"; 
     NSString* data = @"Message"; 

     const char *cKey = [key cStringUsingEncoding:NSASCIIStringEncoding]; 
     const char *cData = [data cStringUsingEncoding:NSASCIIStringEncoding]; 
     unsigned char cHMAC[CC_SHA256_DIGEST_LENGTH]; 
     CCHmac(kCCHmacAlgSHA256, cKey, strlen(cKey), cData, strlen(cData), cHMAC); 
     NSData *hash = [[NSData alloc] initWithBytes:cHMAC length:sizeof(cHMAC)]; 

     NSLog(@"%@", hash); 

     NSString* s = [AppDelegate base64forData:hash]; 
     NSLog(s); 
    } 

    + (NSString*)base64forData:(NSData*)theData 
    { 
     const uint8_t* input = (const uint8_t*)[theData bytes]; 
     NSInteger length = [theData length]; 

     static char table[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz/="; 

     NSMutableData* data = [NSMutableData dataWithLength:((length + 2)/3) * 4]; 
     uint8_t* output = (uint8_t*)data.mutableBytes; 

     NSInteger i; 
     for (i=0; i < length; i += 3) { 
      NSInteger value = 0; 
      NSInteger j; 
      for (j = i; j < (i + 3); j++) { 
       value <<= 8; 

       if (j < length) { value |= (0xFF & input[j]); 
      } 
     } 
       NSInteger theIndex = (i/3) * 4; output[theIndex + 0] = table[(value >> 18) & 0x3F]; 
       output[theIndex + 1] = table[(value >> 12) & 0x3F]; 
       output[theIndex + 2] = (i + 1) < length ? table[(value >> 6) & 0x3F] : '='; 
       output[theIndex + 3] = (i + 2) < length ? table[(value >> 0) & 0x3F] : '='; 
    } 

    return [[NSString alloc] initWithData:data encoding:NSASCIIStringEncoding]; 
} 

@end 

请大家帮我出SOVE这个问题, 在此先感谢。

我已经通过将HmacSHA256更改为HmacMD5并且给出了与C#代码相同的哈希值来解决此问题。

我已更新我的问题与工作代码。检查它

+0

请注意,自iOS 7和OSX 10.9以来,有一种方法可以对Base64进行编码和解码:'base64EncodedDataWithOptions:'和'base64EncodedStringWithOptions:'。 – zaph

+0

您获得Android的价值,请参阅psudo答案中的Objective-C输出。看起来这只是一个Android问题。 – zaph

+0

@Zaph in Objective-c得到输出长度为24,在android侧为42. – user1269656

回答

0

在android secret.getBytes可能会得到UTF-16字节,检查结果的长度。通常将这些功能分成单独的语句以便于调试。

不是答案,一个简单的OBJ-C实现的,而示范,并提供哈希和Base64编码vaules:

NSString* key = @"secret"; 
NSString* data = @"Message"; 

NSData *keyData = [key dataUsingEncoding:NSASCIIStringEncoding]; 
NSData *dataData = [data dataUsingEncoding:NSASCIIStringEncoding]; 
NSMutableData *hash = [NSMutableData dataWithLength:CC_SHA256_DIGEST_LENGTH]; 
CCHmac(kCCHmacAlgSHA256, keyData.bytes, keyData.length , dataData.bytes, dataData.length, hash.mutableBytes); 

NSLog(@"hash: %@", hash); 

NSString* s = [hash base64EncodedStringWithOptions:0]; 
NSLog(@"s: %@", s); 

输出:

hash: <aa747c50 2a898200 f9e4fa21 bac68136 f886a0e2 7aec70ba 06daf2e2 a5cb5597> 
s: qnR8UCqJggD55PohusaBNviGoOJ67HC6Btry4qXLVZc= 
0

我怀疑这是一个编码问题。 在一个示例中,指定将字符串转换为字节数组时,应使用ASCII对字符串进行编码。在另一个示例中,您不指定编码。 如果默认编码是ASCII以外的任何其他字符,则意味着字节数组将不同,导致不同的散列结果。

+0

可能不是编码,例子有ASCII字符。但可能是Android'getBytes'返回UTF-16(unichar)字节。 – zaph

+0

@Zaph我该如何解决这个问题? – user1269656

+0

在两个平台上使用相同的编码。例如;在.NET端使用UTF8Encoding而不是ASCIIEncoding,然后在Java端使用secred.getBytes(Charsets.UTF_8)。这将意味着双方将使用相同的编码,以便从文本中获得相同的字节数组。 (或者使用UTF16或其他任何你喜欢的编码,只要确保它们在两个系统上都是相同的)。 –