【问题标题】:Decrypting iOS with Objective c and SwiftUI使用 Objective c 和 SwiftUI 解密 iOS
【发布时间】:2021-02-17 20:08:11
【问题描述】:

我计划在我的应用程序中实施 AES 加密,为此我阅读了 Rob Napier 的内容丰富的教程:

这是一篇精彩的文章,我可以使用以下方法加密几个字符串:

使用 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;
}

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

【问题讨论】:

  • stackoverflow.com/questions/64679465/… 这是我之前发布的问题,以防您需要更多说明,但我无法像 IV 一样添加盐值...所以请建议我使用正确的代码...这会更有帮助
  • 简而言之,我只想在(IV + 密文)之前添加盐,然后用它来解密
  • 当这个;在你的代码中的实现端,那么任何结果都必须为零。
  • 是的,但我仍然没有得到正确的解密,它返回 nil ...。我正在使用 salt 和 IV 寻找一个好的解密代码......所以如果你能帮助我请这将非常有用
  • 为什么在加密时加减 BlockSizeAES128?您是否尝试仅加密最后一个字节?

标签: ios objective-c xcode commoncrypto


【解决方案1】:

您提到的示例中给出的方法是指Rob Napiers Github Repo。 只需使用您给定的密码、盐等对其进行测试,它就可以正常工作!
是的,明白了,你想在解密时扔掉password:iv:以及salt:参数,只用key:。好吧,您至少需要iv: 才能做到这一点。但正如 Rob 对您的另一个问题所评论的那样,不要重新发明轮子。

我上面链接的方法与您的解密参数配合得很好。与您的代码唯一不同的是,passwordivsalt 用于解密。

除了您想开发无需密码即可解密的东西之外,您还必须深入研究CCKeyDerivationPBKDF() (CommonKeyDerivation.h) 的工作原理。

编辑:当您要求有一种方法来打包和解包您的 saltivcypher使用 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 );

所以你的解密方法仍然需要密码参数。 这并不完美,但因为您永远不应该将加密数据与其密码一起扔掉 - 这应该没问题 - 您只需在用户端处理密码即可。我的意思是,否则整个加密都没用!

【讨论】:

  • 谢谢 OI 你能解释一下如何在不通过它的情况下生成随机盐吗?
  • Rob 提到了将盐添加到数据输出中,就像使用 IV 一样,你能帮我实现同样的目标吗?
  • 再次感谢您的解释,但如果您看到 stackoverflow.com/questions/64679465/… 我已经制作了一个动态 IV 并添加到 Encrypt key 之前。与我想以 [0-16] salt 、 [16-32] IV 和 [16 - length] 密码文本形式添加动态 Salt 的方式大致相同。所以作为一个整体,我只需要像往常一样传递密钥和字符串...... :)
  • 哦,所以你的意思是如果我将 salt 作为 Nil 和 IV 作为 nil 传递,代码将自动生成 IV 和 Salt 并将其添加到加密密钥?
  • 那是机器人嗅探的乐趣。很容易敲任何门。好吧,但为什么不……你是对的
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2013-03-01
  • 2014-01-13
  • 1970-01-01
  • 2016-01-21
  • 1970-01-01
  • 1970-01-01
  • 2015-11-15
相关资源
最近更新 更多