【问题标题】:Android base64 hash mismatch with server side hash using C# scriptAndroid base64 哈希与使用 C# 脚本的服务器端哈希不匹配
【发布时间】:2014-07-21 21:27:27
【问题描述】:

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

工作 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);
                }
           }
      }
 } 

但在android端生成的hash key与服务器端不匹配,下面是目标c代码,生成与C#代码相同

目标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[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";

       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

请帮我解决这个问题, 提前致谢。

我已经通过将 HmacSHA256 更改为 HmacMD5 解决了这个问题,它给出的哈希值与 C# 代码给出的相同。

我已经用工作代码更新了我的问题。检查一下

【问题讨论】:

  • 请注意,从 iOS 7 和 OSX 10.9 开始,有一种对 Base64 进行编码和解码的方法:base64EncodedDataWithOptions:base64EncodedStringWithOptions:
  • 您为 Android 获得了哪些价值,请参阅 psudo 答案中的 Objective-C 输出。看来这只是一个Android问题。
  • @Zaph 在 Objective-c 中的输出长度为 24,在 android 端为 42。
  • 查看我的答案,它的输出长度为 42。在您的示例中提供 NSLog 语句的输出,编辑您的问题并添加这些值。
  • @Zaph 感谢您的帮助,我已经解决了问题并进行了更新。

标签: c# android ios


【解决方案1】:

我怀疑这是一个编码问题。 在一个示例中,您指定在将字符串转换为字节数组时应使用 ASCII 对字符串进行编码。在另一个示例中,您没有指定编码。 如果默认编码不是 ASCII,则意味着字节数组将不同,从而导致不同的哈希结果。

【讨论】:

  • 可能不是编码,例子有ASCII字符。但可能是 Android getBytes 返回 UTF-16 (unichar) 字节。
  • 在两个平台上使用相同的编码。例如;在 .NET 端使用 UTF8Encoding 而不是 ASCIIEncoding,然后在 Java 端使用 secred.getBytes(Charsets.UTF_8)。这意味着双方将使用相同的编码,因此您将从文本中获得相同的字节数组。 (或使用 UTF16 或您喜欢的任何其他编码,只要确保在两个系统上都相同)。
  • @BrianO''Byrne 目前我在两边都使用了相同的编码,那就是 ASCIIEncoding。所以我无法找到问题。
【解决方案2】:

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

不是答案,而是更简单的 Obj-C 实现的演示,并提供哈希和 Base64 值:

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=

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2013-08-20
    • 2014-05-19
    • 2019-10-10
    • 1970-01-01
    • 2020-12-08
    • 2020-01-27
    • 2013-05-19
    相关资源
    最近更新 更多