在iOS中使用SecRandomCopyBytes()的随机256位密钥

时间:2014-11-19 08:07:58

标签: ios objective-c encryption cryptography entropy

我一直使用UUIDString作为存储在我的i​​PAD上的文件的加密密钥,但第三方在我的应用程序上完成的安全审核提示如下。

随着应用程序的启动,生成全局数据库密钥并将其存储在密钥链中。在生成期间,使用由iOS提供的类NSUUID的方法UUIDString。此函数生成由字母A到F,数字和连字符组成的随机字符串,并且不必要地限制密钥空间,从而导致熵减弱。 由于密钥仅由应用程序逻辑使用,并且不必由个人读取,理解或处理,因此不需要将密钥空间限制为可读字符。因此,应通过SecRandomCopyBytes()生成的随机256位密钥作为主密钥。

现在我已经搜索了很多并尝试了一些代码实现,但还没找到确切的东西。 我尝试过:

NSMutableData* data = [NSMutableData dataWithLength:32];
int result = SecRandomCopyBytes(kSecRandomDefault, 32, data.mutableBytes);
NSLog(@"Description %d",result);

我的理解是,这应该给我一个整数,我应该将它转换为NSString并使用它作为我的键,但我很确定这不是这里所需的,而且上面的方法总是给出结果我完全迷失在这里,任何帮助都表示赞赏。

感谢。

5 个答案:

答案 0 :(得分:6)

SecRandomCopyBytes should always be 0结果,除非出现一些错误(我无法想象为什么会发生这种情况),然后结果为-1。您不会将那个转换为NSString。

你想要得到的东西是写入可变字节部分的随机字节,这就是你将用作“主密钥”而不是UUID字符串的东西。

我这样做的方式是:

uint8_t randomBytes[16];
int result = SecRandomCopyBytes(kSecRandomDefault, 16, randomBytes);
if(result == 0) {
    NSMutableString *uuidStringReplacement = [[NSMutableString alloc] initWithCapacity:16*2];
    for(NSInteger index = 0; index < 16; index++)
    {
        [uuidStringReplacement appendFormat: @"%02x", randomBytes[index]];
    }
    NSLog(@"uuidStringReplacement is %@", uuidStringReplacement);
} else {
    NSLog(@"SecRandomCopyBytes failed for some reason");
}

使用UUIDString对我来说足够安全,但听起来你的第三方安全审计公司正在努力证明他们的费用是合理的。

编辑:因为我现在开始收集downvotes因为Vlad的替代答案而且我不能删除我的(因为它仍然有可接受的复选标记),这是我的代码的另一个版本。我正在使用16个随机字节(在转换为Hex时会加倍)。

答案 1 :(得分:3)

生成的NSData不保证UTF16字符。

此方法将生成32byte的UTF字符串,相当于256位。 (优点是这是纯文本,可以在GET请求中发送。)

由于Base64散列的长度是=(3/4)x(输入字符串的长度),我们可以计算出生成32byte散列所需的输入长度是24字节长。注意:如果不能整除,Base64可以填充一个,两个或没有'='字符。

使用OSX 10.9&amp;您可以使用iOS 7:

-[NSData base64EncodedDataWithOptions:]

此方法可用于生成您的UUID:

+ (NSString*)generateSecureUUID {
    NSMutableData *data = [NSMutableData dataWithLength:24];

    int result = SecRandomCopyBytes(NULL, 24, data.mutableBytes);

    NSAssert(result == 0, @"Error generating random bytes: %d", errno);

    NSString *base64EncodedData = [data base64EncodedStringWithOptions:0];

    return base64EncodedData;
}

答案 2 :(得分:1)

UUID是一个16字节(128位)的唯一标识符,因此您在此处不使用256位密钥。此外,正如@zaph指出的那样,UUID使用硬件标识符和其他输入来保证唯一性。这些可预测的因素绝对不是加密安全的。

您不必使用UUID作为加密密钥,而是使用32字节的base 64或十六进制编码数据,因此您将拥有256位加密安全密钥:

/** Generates a 256 bits cryptographically secure key.
 * The output will be a 44 characters base 64 string (32 bytes data
 * before the base 64 encoding).
 * @return A base 64 encoded 256 bits secure key.
 */
+ (NSString*)generateSecureKey
{
    NSMutableData *data = [NSMutableData dataWithLength:32];
    int result = SecRandomCopyBytes(kSecRandomDefault, 32, data.mutableBytes);
    if (result != noErr) {
        return nil;
    }
    return [data base64EncodedStringWithOptions:kNilOptions];
}

要回答关于生成类UUID(安全)随机数的部分,这是一个好方法,但请记住这些只有128位密钥:

/** Generates a 128 bits cryptographically secure key, formatted as a UUID.
 * Keep that you won't have the same guarantee for uniqueness
 * as you have with regular UUIDs.
 * @return A cryptographically secure UUID.
 */
+ (NSString*)generateCryptoSecureUUID
{
    unsigned char bytes[16];
    int result = SecRandomCopyBytes(kSecRandomDefault, 16, bytes);
    if (result != noErr) {
        return nil;
    }
    return [[NSUUID alloc] initWithUUIDBytes:bytes].UUIDString;
}

密码学很棒,但做得很好非常困难(很容易出现安全漏洞)。我不建议您使用RNCryptor,这将推动您使用良好的加密标准,将确保您不会不安全地重复使用相同的密钥,将正确地从密码派生加密密钥等。< / p>

答案 3 :(得分:0)

我尝试使用长度为16和字节为16的代码:

uint8_t randomBytes[16];
NSMutableString *ivStr;
int result = SecRandomCopyBytes(kSecRandomDefault, 16, randomBytes);
if(result == 0) {
    ivStr = [[NSMutableString alloc] initWithCapacity:16];
    for(NSInteger index = 0; index < 8; index++)
    {
        [ivStr appendFormat: @"%02x", randomBytes[index]];
    }
        NSLog(@"uuidStringReplacement is %@", ivStr);
} else {
    NSLog(@"SecRandomCopyBytes failed for some reason");
}

<强>成功

答案 4 :(得分:0)

由于密钥通常需要采用UTF-8编码,并且可以读取&#34; - 即没有UTF-8控制字符 - 我决定过滤使用SecRandomCopyBytes生成的随机生成的字节,因此它只包含来自Basic Latin Unicode block的字符。

/*!
 * @brief Generates NSData from a randomly generated byte array with a specific number of bits
 * @param numberOfBits the number of bits the generated data must have
 * @return the randomly generated NSData
 */
+ (NSData *)randomKeyDataGeneratorWithNumberBits:(int)numberOfBits {
    int numberOfBytes = numberOfBits/8;
    uint8_t randomBytes[numberOfBytes];
    int result = SecRandomCopyBytes(kSecRandomDefault, numberOfBytes, randomBytes);
    if(result == 0) {
        return [NSData dataWithBytes:randomBytes length:numberOfBytes];
    } else {
        return nil;
    }
}

/*!
 * @brief Generates UTF-8 NSData from a randomly generated byte array with a specific number of bits
 * @param numberOfBits the number of bits the generated data must have
 * @return the randomly generated NSData
 */
+ (NSData *)randomKeyUTF8DataGeneratorWithNumberBits:(int)numberOfBits {
    NSMutableData *result = [[NSMutableData alloc] init];
    int numberOfBytes = numberOfBits/8;
    while (result.length < numberOfBytes) {
        // Creates a random byte
        NSData *byte = [self randomKeyDataGeneratorWithNumberBits:8];
        int asciiValue = [[[NSString alloc] initWithData:byte encoding:NSUTF8StringEncoding] characterAtIndex:0];
        // Checks if the byte is UTF-8
        if (asciiValue > 32 && asciiValue < 127) {
            [result appendData:byte];
        }
    }
    return result;
}

如果你想让你的钥匙更多一点,那就更容易理解&#34;您可以尝试使其成为Base64 URL安全

/*!
 * @brief Encodes a String Base 64 with URL and Filename Safe Alphabet
 * @discussion Base64url Encoding  The URL- and filename-safe Base64 encoding described in RFC 4648 [RFC4648] (https://tools.ietf.org/html/rfc4648)
 * @discussion Section 5 (https://tools.ietf.org/html/rfc4648#section-5)
 * @param string the string to be enconded
 * @return the encoded string
 */
+ (NSString *)base64URLandFilenameSafeString:(NSString *)string {
    NSString *base64String = string;
    base64String = [base64String stringByReplacingOccurrencesOfString:@"/"
                                                           withString:@"_"];
    base64String = [base64String stringByReplacingOccurrencesOfString:@"+"
                                                           withString:@"-"];
    return base64String;
}

生成UTF-8 256位密钥:

NSData *key = [self randomKeyUTF8DataGeneratorWithNumberBits:256];
NSString *UTF8String = [[NSString alloc] initWithBytes:[key bytes] length:data.length encoding:NSUTF8StringEncoding];
NSString *base64URLSafeString = [self base64URLandFilenameSafeString:UTF8String];