微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

使用Objective C解密AES iOS

如何解决使用Objective C解密AES iOS

我打算在我的应用程序中实现AES加密,为此,我看了Rob Napier提供的内容丰富的教程:

这是一本很棒的书,我可以使用:p加密一些字符串

使用ROB NAPIER RNCRYPTOR类别

Nsstring * const
kRNCryptManagerErrorDomain = @"net.robnapier.RNCryptManager";

const CCAlgorithm kAlgorithm = kCCAlgorithmAES128;
const NSUInteger kAlgorithmKeySize = kCCKeySizeAES128;
const NSUInteger kAlgorithmBlockSize = kCCBlockSizeAES128;
const NSUInteger kAlgorithmIVSize = kCCBlockSizeAES128;
const NSUInteger kPBKDFSaltSize = 8;
const NSUInteger kPBKDFRounds = 10000;  // ~80ms on an iPhone 4

// ===================

+ (NSData *)encryptedDataForData:(NSData *)data
                        password:(Nsstring *)password
                              iv:(NSData **)iv
                            salt:(NSData **)salt
                           error:(NSError **)error {
  NSAssert(iv,@"IV must not be NULL");
  NSAssert(salt,@"salt must not be NULL");
  
  *iv = [self randomDataOfLength:kAlgorithmIVSize];
  *salt = [self randomDataOfLength:kPBKDFSaltSize];
  
  NSData *key = [self AESKeyForPassword:password salt:*salt];
  
  size_t outLength;
  NSMutableData *
  cipherData = [NSMutableData dataWithLength:data.length +
                kAlgorithmBlockSize];

  CCCryptorStatus
  result = CCCrypt(kCCEncrypt,// operation
                   kAlgorithm,// Algorithm
                   kCcoptionPKCS7Padding,// options
                   key.bytes,// key
                   key.length,// keylength
                   (*iv).bytes,// iv
                   data.bytes,// dataIn
                   data.length,// dataInLength,cipherData.mutableBytes,// dataOut
                   cipherData.length,// dataOutAvailable
                   &outLength); // dataOutMoved

  if (result == kCCSuccess) {
    cipherData.length = outLength;
  }
  else {
    if (error) {
      *error = [NSError errorWithDomain:kRNCryptManagerErrorDomain
                                   code:result
                               userInfo:nil];
    }
    return nil;
  }
  
  return cipherData;
}

// ===================

+ (NSData *)randomDataOfLength:(size_t)length {
  NSMutableData *data = [NSMutableData dataWithLength:length];
  
  int result = SecRandomcopyBytes(kSecRandomDefault,length,data.mutableBytes);
  NSAssert(result == 0,@"Unable to generate random bytes: %d",errno);
  
  return data;
}

// ===================

// Replace this with a 10,000 hash calls if you don't have CCKeyDerivationPBKDF
+ (NSData *)AESKeyForPassword:(Nsstring *)password 
                         salt:(NSData *)salt {
  NSMutableData *
  derivedKey = [NSMutableData dataWithLength:kAlgorithmKeySize];
  
  int 
  result = CCKeyDerivationPBKDF(kCCPBKDF2,// algorithm
                                password.UTF8String,// password
                                [password lengthOfBytesUsingEncoding:NSUTF8StringEncoding],// passwordLength
                                salt.bytes,// salt
                                salt.length,// saltLen
                                kCCPRFHmacAlgSHA1,// PRF
                                kPBKDFRounds,// rounds
                                derivedKey.mutableBytes,// derivedKey
                                derivedKey.length); // derivedKeyLen
  
  // Do not log password here
  NSAssert(result == kCCSuccess,@"Unable to create AES key for password: %d",result);
  
  return derivedKey;
}

但是在解密时,我无法正确解密,在这种情况下,我得到的是空值:供您参考的解密代码是:

    + (NSData*)decryptData:(NSData*)data key:(NSData*)key error:(NSError **)error
{
    if (key.length != 16 && key.length != 24 && key.length != 32) {
        *error = [NSError errorWithDomain:@"keyLengthError" code:-1 userInfo:nil];
        return nil;
    }

    
    CCCryptorStatus ccStatus   = kCCSuccess;
    int             ivLength   = kCCBlockSizeAES128;
    size_t          clearBytes = 0;
    NSMutableData *dataOut     = [NSMutableData dataWithLength:data.length - ivLength];
    
    NSLog(@"Data Out String Decrypt%@",dataOut);

    ccStatus = CCCrypt(kCCDecrypt,kCCAlgorithmAES,kCcoptionPKCS7Padding,key.bytes,key.length,data.bytes,data.bytes + ivLength,data.length - ivLength,dataOut.mutableBytes,dataOut.length,&clearBytes);

    if (ccStatus == kCCSuccess) {
        dataOut.length = clearBytes;
    }
    else {
        if (error) {
            *error = [NSError errorWithDomain:@"kEncryptionError" code:ccStatus userInfo:nil];
        }
        dataOut = nil;
    }

    return dataOut;
}

在这种情况下我哪里出错了?我已经尝试了几天以解决问题。有人可以帮我吗?

解决方法

在您提到的示例中给出的方法引用了Rob Napiers Github Repo。 只需使用您提供的密码,盐等对它进行测试,就可以了!
可以理解,您想在解密时扔掉password:iv:参数以及salt:参数,并且只使用key:。那么,您至少需要iv:才能做到这一点。但是,正如罗布(Rob)在评论您的其他问题时一样,请不要重新发明轮子。

我上面链接的方法与您要解密的参数配合得很好。与您的代码唯一的区别在于,passwordivsalt可以解密。

除了您想要开发无需密码即可解密的内容的想法外,您还必须深入研究CCKeyDerivationPBKDF()(CommonKeyDerivation.h)的工作方式。

编辑:当您要求提供一种打包和解压缩 iv 密码的方法时使用NSData非常简单。

+ (NSData *)packWithSalt:(NSData*)salt IV:(NSData*)iv Cypher:(NSData*)tocypher {
    
    //adding Salt + IV + Cipher text
    NSMutableData *combi = [NSMutableData data];
    
    //[combi appendBytes:salt.bytes length:16];
    //[combi appendBytes:iv.bytes length:16]; //16
    //[combi appendBytes:tocypher.bytes length:tocypher.length];
    
    [combi appendData:salt];
    [combi appendData:iv];
    [combi appendData:tocypher];
    
    return combi;
}

+ (NSData*)cypherUnpackToSalt:(NSMutableData**)salt andIV:(NSMutableData**)iv fromPackData:(NSData*)pack {
    
    void *sBuff[16] = {};
    void *iBuff[16] = {};
    NSUInteger len = pack.length - 16 - 16; //keep length flexible
    void *pBuff = malloc(sizeof(Byte)*len); //needs dynamically size of buff
    [pack getBytes:sBuff range:NSMakeRange(0,16)];
    [pack getBytes:iBuff range:NSMakeRange(16,32)];
    [pack getBytes:pBuff range:NSMakeRange(32,len)];
    
    [(*salt) replaceBytesInRange:NSMakeRange(0,16) withBytes:sBuff];
    [(*iv) replaceBytesInRange:NSMakeRange(0,16) withBytes:iBuff];

    NSMutableData *unpack = [NSMutableData dataWithLength:len];
    [unpack replaceBytesInRange:NSMakeRange(0,len) withBytes:pBuff];
    free(pBuff);
    return unpack;
} 

将这两种方法的加密和解密集成起来应该非常简单。

概念证明:我们可以将所有内容打包在一起吗?并再次打开包装?

NSData *salt = [CryptAES randomDataOfLength:16];
NSData *iv = [CryptAES randomDataOfLength:16];
NSData *chunk = [CryptAES packWithSalt:salt IV:iv Cypher:plaintextData];
NSLog(@"salt=%@ iv=%@ pack=%@ ",[salt base64EncodedStringWithOptions:0],[iv base64EncodedStringWithOptions:0],[chunk base64EncodedStringWithOptions:0] );
    
NSMutableData *unSalt = [NSMutableData dataWithLength:16];
NSMutableData *unIv = [NSMutableData dataWithLength:16];
NSData *unchunk = [CryptAES cypherUnpackToSalt:&unSalt andIV:&unIv fromPackData:chunk];
NSString *plainAgain = [[NSString alloc] initWithData:unchunk encoding:NSUTF8StringEncoding];
NSLog(@"salt=%@ iv=%@ unpack=%@",[unSalt base64EncodedStringWithOptions:0],[unIv base64EncodedStringWithOptions:0],plainAgain );

因此,您的解密方法仍将需要密码参数。 这不是完美的方法,但是您绝不应该将加密数据及其密码一起扔掉(应该没问题),您只需要在用户端处理密码即可。我的意思是,否则整个加密都是没用的!

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。