在目标 c 中,如何使用 md5 作为密钥进行 AES256 加密?

Posted

技术标签:

【中文标题】在目标 c 中,如何使用 md5 作为密钥进行 AES256 加密?【英文标题】:In objective c, how to do AES256 encryption using md5 doubled as the key? 【发布时间】:2018-01-13 08:26:44 【问题描述】:

我一直在尝试复制一个使用 md5 作为密钥进行 AES256 加密的 android 代码。一切似乎都很好,但加密后的值似乎不一样。请通过我的以下代码

安卓:-

public static String encrypt(String key, String value) 
    try 
        byte[] keyArr = new byte[32];
        MessageDigest md = MessageDigest.getInstance("MD5");
        byte[] hash = md.digest(key.getBytes("US-ASCII"));//in md5 function 1st line
        keyArr = arrayCopy(0, hash, 0, keyArr, 16);//in md5 function 1st for loop
        keyArr = arrayCopy(0, hash, 15, keyArr, 16);//in md5 function 2nd for loop
        SecretKeySpec skeySpec = new SecretKeySpec(keyArr, "AES");
        Cipher cipher = Cipher.getInstance("AES");
        cipher.init(Cipher.ENCRYPT_MODE, skeySpec);
        byte[] encrypted = cipher.doFinal(value.getBytes());
        String encryptedB64 = new String(Base64.encode(encrypted, Base64.DEFAULT));
        return encryptedB64;
     catch (Exception ex) 
        ex.printStackTrace();
    
    return null;

private static byte[] arrayCopy(int sourceIndex,byte[] source,int targetIndex,byte[] target,int transferSize)
    if(!(transferSize >0))
        return null;
    if(sourceIndex>=0 && sourceIndex < source.length)
        int transferCnt=0;
        int i=sourceIndex;
        for(int j=targetIndex;;j++,i++)
            if(targetIndex>=target.length || sourceIndex>=source.length || (++transferCnt>transferSize))
                break;
            
            target[j] = source[i];
        
    else
        return null;
    
    return target;

ios 目标-c

+ (NSString *) getFalconEncryptedValueForKey:(NSString *)theKey forString:(NSString *)theString

    char keyPtr[kCCKeySizeAES256+1]; // room for terminator (unused)
    bzero(keyPtr, sizeof(keyPtr)); // fill with zeroes (for padding)
    NSData *rawData = [theString dataUsingEncoding:NSUTF8StringEncoding];
    NSString *md5Key = [self md5:theKey];
    [md5Key getCString:keyPtr maxLength:sizeof(keyPtr) encoding:NSUTF8StringEncoding];
    NSUInteger dataLength = [rawData length];
    size_t bufferSize = dataLength + kCCBlockSizeAES128;
    void *buffer = malloc(bufferSize);
    size_t numBytesEncrypted = 0;
    CCCryptorStatus cryptStatus = CCCrypt(kCCEncrypt, kCCAlgorithmAES128, kCCOptionPKCS7Padding + kCCOptionECBMode,
                                          keyPtr, kCCKeySizeAES256,
                                          NULL /* initialization vector (optional) */,
                                          [rawData bytes], dataLength, /* input */
                                          buffer, bufferSize, /* output */
                                          &numBytesEncrypted);
    if (cryptStatus == kCCSuccess)
    
        NSData *tempData = [NSData dataWithBytesNoCopy:buffer length:numBytesEncrypted];
        NSString* encrypted64 = [tempData base64EncodedStringWithOptions:0];//Even i have tried base 64 encding with other options available
        return encrypted64;
    

    free(buffer); //free the buffer;
    return nil;



+ (NSString *) md5:(NSString *) input

//    const char * pointer = [self UTF8String];
    const char *cStr = [input cStringUsingEncoding:NSASCIIStringEncoding];
    unsigned char result[CC_MD5_DIGEST_LENGTH];
    CC_MD5( cStr, (CC_LONG)strlen(cStr), result );

    NSMutableString *md5String = [NSMutableString stringWithCapacity:CC_MD5_DIGEST_LENGTH * 2];
    for (int i = 0; i < CC_MD5_DIGEST_LENGTH; i++)
        [md5String appendFormat:@"%02x",result[i]];
    for (int i = 0; i < CC_MD5_DIGEST_LENGTH; i++)
        [md5String appendFormat:@"%02x",result[i]];

    return md5String;
    //for 32 byte. md5 produces only 16 byte info. we are replicating it again to make it 32 byte for aes256

任何对我做错的方向的指导都会非常有帮助。提前致谢

【问题讨论】:

如果没有实现arrayCopy,这纯属猜测。 这就是你的意思——java-samples.com/showtutorial.php?tutorialid=641 此代码有几个问题: 1. 可能使用 128 位密钥并将其扩展到 256 位,没有任何额外的安全性。 2.如果key实际上是一个密码,那么简单的散列是不够的。使用 PBKDF2 或类似的。 3.Cipher.getInstance("AES");可能使用ECB模式,这与insecure相当。 4. 密文没有认证,所以攻击者可能会在你没有察觉的情况下修改密文。使用 GCM 等认证模式或将 HMAC 应用于密文。 不,那是另一回事。 其实java-samples.com/showtutorial.php?tutorialid=641也就是已经使用的函数了。它也是由第三方供应商编写的代码,我对此没有发言权。不,密钥不是密码。它是一个加密的字符串。你能帮我找出我在转换代码时遗漏的地方吗? 【参考方案1】:

AES256加密使用md5加倍作为密钥

不,事实并非如此。

在 Android 中,keyArr 中第一个 hash 的最后一个字节被第二个 hash 覆盖(更准确地说是第二个 hash 的第一个字节)。所以keyArr的最后一个字节总是0。

我不精通Objective-C,但我认为,应该这样做:

NSMutableString *md5String = [NSMutableString stringWithCapacity:CC_MD5_DIGEST_LENGTH * 2];
for (int i = 0; i < CC_MD5_DIGEST_LENGTH-1; i++)
    [md5String appendFormat:@"%02x",result[i]];
for (int i = 0; i < CC_MD5_DIGEST_LENGTH; i++)
    [md5String appendFormat:@"%02x",result[i]];
[md5String appendFormat:@"%02x",0];

(顺便说一句,arrayCopy 可以产生一个 IndexOutOfBoundsException,尽管它进行了多次检查)。

当然,这会生成一个长度为 64 个字符的十六进制编码字符串。这不是你想要的。相反,您应该生成长度为 32 的实际字节。

正确的代码(由 OP 提供)

+ (NSString *) getEncryptedValueWithKey:(NSString *)theKey forString:(NSString *)theString

    NSData *rawData = [theString dataUsingEncoding:NSUTF8StringEncoding];

    unsigned char md5Buffer[kCCKeySizeAES256+1];
    memset(md5Buffer, 0, kCCKeySizeAES256+1);
    const char *cStr = [theKey UTF8String];

    // do md5 hashing
    CC_MD5(cStr, CC_MD5_DIGEST_LENGTH, md5Buffer);

    unsigned char lastChar = md5Buffer[15];
    for (NSInteger i = 15; i <= 30; i++) 
        md5Buffer[i] = md5Buffer[i-15];
    
    md5Buffer[30] = lastChar;
    //MD5 key obtaining end

    NSUInteger dataLength = [rawData length];
    size_t bufferSize = dataLength + kCCBlockSizeAES128;
    void *buffer = malloc(bufferSize);
    size_t numBytesEncrypted = 0;
    CCCryptorStatus cryptStatus = CCCrypt(kCCEncrypt, kCCAlgorithmAES128, kCCOptionPKCS7Padding + kCCOptionECBMode, md5Buffer, kCCKeySizeAES256, NULL /* initialization vector (optional) */, [rawData bytes], dataLength, /* input */ buffer, bufferSize, /* output */ &numBytesEncrypted);
    if (cryptStatus == kCCSuccess)
    
        NSData *tempData = [NSData dataWithBytesNoCopy:buffer length:numBytesEncrypted];
        NSString* encrypted64 = [tempData base64EncodedStringWithOptions:0];//Even i have tried base 64 encding with other options available
        return encrypted64;
    

    free(buffer); //free the buffer;
    return nil;

【讨论】:

哇,很好的发现......所以他们所说的和所做的似乎不同。让我试试这个改变 不,仍然与他们发送的值不匹配。我一定是在转换过程中遗漏了一些非常重要的东西。 我看到的另一个可能的问题是您在 obj-c 中生成了一个十六进制编码的字符串(我不完全确定 appendFormat:@"%02x" 做了什么),但您实际上需要二进制文件钥匙。在使用它进行加密之前,您需要在某些时候解码十六进制编码的字符串。

以上是关于在目标 c 中,如何使用 md5 作为密钥进行 AES256 加密?的主要内容,如果未能解决你的问题,请参考以下文章

获取APK证书MD5、SHA1、SHA256等秘钥

常见加密算法原理及概念

springboot-接口安全设计

springboot-接口安全设计

将记录作为键映射 - 如何检查Erlang中是否存在密钥

AES,SHA1,DES,RSA,MD5区别[转]