سؤال

in my app i store a NSString encrypted in the keychain with this method

NSUInteger fieldHash = [myStringToSave hash];
        // Encrypt
        NSString *fieldString = [KeychainWrapper securedSHA256DigestHashForPIN:fieldHash];
        // Save in Keychain
        if ([KeychainWrapper createKeychainValue:fieldString forIdentifier:PASSWORD]) {
            [[NSUserDefaults standardUserDefaults] setBool:YES forKey:PASSWORD];
            [[NSUserDefaults standardUserDefaults] synchronize];

in the KeychainWrapper.m there is this method

+ (BOOL)createKeychainValue:(NSString *)value forIdentifier:(NSString *)identifier
{

    NSMutableDictionary *dictionary = [self setupSearchDirectoryForIdentifier:identifier];
    NSData *valueData = [value dataUsingEncoding:NSUTF8StringEncoding];
    [dictionary setObject:valueData forKey:(__bridge id)kSecValueData];

    // Protect the keychain entry so it's only valid when the device is unlocked.
    [dictionary setObject:(__bridge id)kSecAttrAccessibleWhenUnlocked forKey:(__bridge id)kSecAttrAccessible];

    // Add.
    OSStatus status = SecItemAdd((__bridge CFDictionaryRef)dictionary, NULL);

    // If the addition was successful, return. Otherwise, attempt to update existing key or quit (return NO).
    if (status == errSecSuccess) {
        return YES;
    } else if (status == errSecDuplicateItem){
        return [self updateKeychainValue:value forIdentifier:identifier];
    } else {
        return NO;
    }
}

and this

+ (NSString *)securedSHA256DigestHashForPIN:(NSUInteger)pinHash
{
    // 1
    NSString *name = [[NSUserDefaults standardUserDefaults] stringForKey:USERNAME];
    name = [name stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
    // 2
    NSString *computedHashString = [NSString stringWithFormat:@"%@%i%@", name, pinHash, SALT_HASH];
    // 3
    NSString *finalHash = [self computeSHA256DigestForString:computedHashString];
    //NSLog(@"** Computed hash: %@ for SHA256 Digest: %@", computedHashString, finalHash);
    return finalHash;
}

+ (NSString*)computeSHA256DigestForString:(NSString*)input
{

    const char *cstr = [input cStringUsingEncoding:NSUTF8StringEncoding];
    NSData *data = [NSData dataWithBytes:cstr length:input.length];
    uint8_t digest[CC_SHA256_DIGEST_LENGTH];

    CC_SHA256(data.bytes, data.length, digest);

    // Setup our Objective-C output.
    NSMutableString* output = [NSMutableString stringWithCapacity:CC_SHA256_DIGEST_LENGTH * 2];

    // Parse through the CC_SHA256 results (stored inside of digest[]).
    for(int i = 0; i < CC_SHA256_DIGEST_LENGTH; i++) {
        [output appendFormat:@"%02x", digest[i]];
    }

    return output;
}

In order to get a value stored in the keychain i'm using this

+ (NSString *)keychainStringFromMatchingIdentifier:(NSString *)identifier
{
    NSData *valueData = [self searchKeychainCopyMatchingIdentifier:identifier];
    if (valueData) {
        NSString *value = [[NSString alloc] initWithData:valueData
                                                encoding:NSUTF8StringEncoding];
        return value;
    } else {
        return nil;
    }
}

passing the identifier PASSWORD like this

NSString *myNewString = [KeychainWrapper keychainStringFromMatchingIdentifier:PASSWORD];

The problem is that it come out a string encrypted which i cannot use. Any advice on how to decrypt it? Thanks in advance

هل كانت مفيدة؟

المحلول

Nothing in the above code encrypts anything. You appear to be running your value through NSString hash and then SHA-256. Both of these are one-way hashes. By design, they cannot be reversed.

In general, this code is very confusing, and it's not clear what you're trying to achieve. You don't usually encrypt data that you're putting into keychain.

Note that your hash function will truncate multi-byte strings (Chinese, for example).

const char *cstr = [input cStringUsingEncoding:NSUTF8StringEncoding];
NSData *data = [NSData dataWithBytes:cstr length:input.length];

This should be:

NSData *data = [input dataUsingEncoding:NSUTF8StringEncoding];

نصائح أخرى

This code is from one of tutorials on Ray Wenderlich's website. See: http://www.raywenderlich.com/6475/basic-security-in-ios-5-tutorial-part-1 for more information

The basic idea is that you encrypt the password before you save it in the keychain, using the methods:

  • (NSString *)securedSHA256DigestHashForPIN:(NSUInteger)pinHash;
  • (NSString*)computeSHA256DigestForString:(NSString*)input;

Then when a user enters a password, you can encrypt it the same way and compare the two values to see if the user has entered the correct password. As the other answers says you cannot reverse the encryption to find the password, but you do not need to if you are just comparing the stored password with the entered password.

I think encrypting the password on the way into the keychain maybe overkill as the password should be encrypted and secure anyway, but cant see any harm in doing it anyway (unless you need to retrieve the original password).

If you are looking to encrypt and decrypt a string then check out this question:

AES Encryption for an NSString on the iPhone

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top