Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

Updated to version 1.3

  • Loading branch information...
commit 2bbaa02210fdd857b85c471bead203b1e243e881 1 parent 8d38251
@nicklockwood authored
View
4 FXKeychain.podspec
@@ -1,11 +1,11 @@
Pod::Spec.new do |s|
s.name = 'FXKeychain'
- s.version = '1.2'
+ s.version = '1.3'
s.license = 'zlib'
s.summary = 'FXKeychain is a lightweight wrapper around the Apple keychain APIs that provides a simple dictionary-like interface.'
s.homepage = 'https://github.com/nicklockwood/FXKeychain'
s.authors = 'Nick Lockwood'
- s.source = { :git => 'https://github.com/nicklockwood/FXKeychain.git', :tag => '1.2' }
+ s.source = { :git => 'https://github.com/nicklockwood/FXKeychain.git', :tag => '1.3' }
s.source_files = 'FXKeychain'
s.requires_arc = true
s.ios.deployment_target = '4.3'
View
12 FXKeychain/FXKeychain.h
@@ -1,7 +1,7 @@
//
// FXKeychain.h
//
-// Version 1.2
+// Version 1.3
//
// Created by Nick Lockwood on 29/12/2012.
// Copyright 2012 Charcoal Design
@@ -45,10 +45,10 @@
- (id)initWithService:(NSString *)service
accessGroup:(NSString *)accessGroup;
-- (BOOL)setObject:(id<NSCoding>)object forKey:(id<NSCopying>)key;
-- (BOOL)setObject:(id<NSCoding>)object forKeyedSubscript:(id<NSCopying>)key;
-- (BOOL)removeObjectForKey:(id<NSCopying>)key;
-- (id)objectForKey:(id<NSCopying>)key;
-- (id)objectForKeyedSubscript:(id<NSCopying>)key;
+- (BOOL)setObject:(id)object forKey:(id)key;
+- (BOOL)setObject:(id)object forKeyedSubscript:(id)key;
+- (BOOL)removeObjectForKey:(id)key;
+- (id)objectForKey:(id)key;
+- (id)objectForKeyedSubscript:(id)key;
@end
View
43 FXKeychain/FXKeychain.m
@@ -1,7 +1,7 @@
//
// FXKeychain.m
//
-// Version 1.2
+// Version 1.3
//
// Created by Nick Lockwood on 29/12/2012.
// Copyright 2012 Charcoal Design
@@ -70,13 +70,13 @@ - (id)initWithService:(NSString *)service
return self;
}
-- (BOOL)setObject:(id<NSCoding>)object forKey:(id<NSCopying>)key
+- (BOOL)setObject:(id)object forKey:(id)key
{
//generate query
NSMutableDictionary *query = [NSMutableDictionary dictionary];
if ([_service length]) query[(__bridge NSString *)kSecAttrService] = _service;
query[(__bridge NSString *)kSecClass] = (__bridge id)kSecClassGenericPassword;
- query[(__bridge NSString *)kSecAttrAccount] = key;
+ query[(__bridge NSString *)kSecAttrAccount] = [key description];
#if defined __IPHONE_OS_VERSION_MAX_ALLOWED && !TARGET_IPHONE_SIMULATOR
if ([_accessGroup length]) query[(__bridge NSString *)kSecAttrAccessGroup] = _accessGroup;
@@ -84,17 +84,21 @@ - (BOOL)setObject:(id<NSCoding>)object forKey:(id<NSCopying>)key
//encode object
NSData *data = nil;
+ NSError *error = nil;
if ([(id)object isKindOfClass:[NSString class]])
{
data = [(NSString *)object dataUsingEncoding:NSUTF8StringEncoding];
}
else if (object)
{
- data = [NSKeyedArchiver archivedDataWithRootObject:object];
+ data = [NSPropertyListSerialization dataWithPropertyList:object
+ format:NSPropertyListBinaryFormat_v1_0
+ options:0
+ error:&error];
}
if (object && !data)
{
- NSLog(@"FXKeychain failed to encode object for key '%@'", key);
+ NSLog(@"FXKeychain failed to encode object for key '%@', error: %@", key, error);
return NO;
}
@@ -120,17 +124,17 @@ - (BOOL)setObject:(id<NSCoding>)object forKey:(id<NSCopying>)key
return YES;
}
-- (BOOL)setObject:(id<NSCoding>)object forKeyedSubscript:(id<NSCopying>)key
+- (BOOL)setObject:(id)object forKeyedSubscript:(id)key
{
return [self setObject:object forKey:key];
}
-- (BOOL)removeObjectForKey:(id<NSCopying>)key
+- (BOOL)removeObjectForKey:(id)key
{
return [self setObject:nil forKey:key];
}
-- (id)objectForKey:(id<NSCopying>)key
+- (id)objectForKey:(id)key
{
//generate query
NSMutableDictionary *query = [NSMutableDictionary dictionary];
@@ -138,7 +142,7 @@ - (id)objectForKey:(id<NSCopying>)key
query[(__bridge NSString *)kSecClass] = (__bridge id)kSecClassGenericPassword;
query[(__bridge NSString *)kSecMatchLimit] = (__bridge id)kSecMatchLimitOne;
query[(__bridge NSString *)kSecReturnData] = (__bridge id)kCFBooleanTrue;
- query[(__bridge NSString *)kSecAttrAccount] = key;
+ query[(__bridge NSString *)kSecAttrAccount] = [key description];
#if defined __IPHONE_OS_VERSION_MAX_ALLOWED && !TARGET_IPHONE_SIMULATOR
if ([_accessGroup length]) query[(__bridge NSString *)kSecAttrAccessGroup] = _accessGroup;
@@ -146,20 +150,21 @@ - (id)objectForKey:(id<NSCopying>)key
//recover data
id object = nil;
+ NSError *error = nil;
CFDataRef data = nil;
OSStatus status = SecItemCopyMatching((__bridge CFDictionaryRef)query, (CFTypeRef *)&data);
if (status == errSecSuccess && data)
{
- //check if file is a plist
- NSDictionary *dict = [NSPropertyListSerialization propertyListWithData:(__bridge NSData *)data
- options:NSPropertyListImmutable
- format:NULL
- error:NULL];
+ //attempt to decode as a plist
+ object = [NSPropertyListSerialization propertyListWithData:(__bridge NSData *)data
+ options:NSPropertyListImmutable
+ format:NULL
+ error:&error];
- if ([dict respondsToSelector:@selector(objectForKey:)] && dict[@"$archiver"])
+ if ([object respondsToSelector:@selector(objectForKey:)] && object[@"$archiver"])
{
- //data represents a dictionary. attempt to decode as NSCoded archive
- object = [NSKeyedUnarchiver unarchiveObjectWithData:(__bridge NSData *)data];
+ //data represents an NSCoded archive. don't trust it
+ object = nil;
}
else if (!object)
{
@@ -168,7 +173,7 @@ - (id)objectForKey:(id<NSCopying>)key
}
if (!object)
{
- NSLog(@"FXKeychain failed to decode data for key '%@'", key);
+ NSLog(@"FXKeychain failed to decode data for key '%@', error: %@", key, error);
}
CFRelease(data);
return object;
@@ -180,7 +185,7 @@ - (id)objectForKey:(id<NSCopying>)key
}
}
-- (id)objectForKeyedSubscript:(id<NSCopying>)key
+- (id)objectForKeyedSubscript:(id)key
{
return [self objectForKey:key];
}
View
2  LICENCE.md
@@ -1,6 +1,6 @@
FXKeychain
-Version 1.2, March 21st, 2013
+Version 1.3, March 25th, 2013
Copyright (C) 2012 Charcoal Design
View
22 README.md
@@ -30,6 +30,16 @@ Installation
To use FXKeychain, just drag the class files into your project and add the Security framework. You can use the [FXKeychain defaultKeychain] shared instance, or create new instance as and when you need them.
+Security
+------------
+
+Caution is advised when storing and retrieving non-string objects from the keychain. On iOS, the keychain is sandboxed to a single app or to a group of apps shared by a single developer. But on Mac OS, any app can read or write to any entry in the keychain. This offers the potential for a malicious app to attempt to manipulate the behaviour of another by changing its keychain data.
+
+Version 1.2 and earlier of FXKeychain allowed arbitrary classes to be stored in the keychain using NSCoding. This feature has been removed in 1.3 to mitigate the risk that an app might change the encoded classes in your app's keychain in order to get it to load and run code that it isn't supposed to.
+
+Using version 1.3 should protect you from this, as only plist-compatible classes are now supported, which cannot easily be used in a malicious way. It is still recommended however that you verify that the data being loaded from the keychain matches the type and structure that you are expecting in order to protect against malicious or mischevious tinkering with the data that might crash your app or cause it to behave strangely.
+
+
Properties
------------------
@@ -56,16 +66,16 @@ This method returns a shared default keychain instance, which uses the app's bun
This method creates a new FXKeychain instance with the specified parameters. Each FXKeychain can contain as many key/value pairs as you want, so you may only need a single FXKeychain per application. Each FXKeychain is uniquely identified by the service parameter; see the Properties description for how to use this. You can specify nil for the service, in which case it will act as "wildcard" selector and calls to objectForKey: will return the first value found within any service stored in the keychain. The accessGroup parameter is used for setting up shared keychains that can be accessed by multiple different apps; leave this as nil if you do not require that functionality.
- - (BOOL)setObject:(id<NSCoding>)object forKey:(id<NSCopying>)key;
- - (BOOL)setObject:(id<NSCoding>)object forKeyedSubscript:(id<NSCopying>)key;
+ - (BOOL)setObject:(id)object forKey:(id)key;
+ - (BOOL)setObject:(id)object forKeyedSubscript:(id)key;
-These methods will save the specified object in the keychain. The object can be of any class that implements the NSCoding protocol. Values of type NSString will be stored as UTF8-encoded data, and are intercompatible with other keychain solutions. Any other object type will be stored as NSCoded data. Passing a value of nil as the object will remove the key from the keychain. The second form of this method is functionally identical to the first, but is included to support the modern objective C keyed subscripting syntax.
+These methods will save the specified object in the keychain. Any plist-compatible object (NSDictionary, NSArray, NSNumber, etc.) can be stored. Objects of type NSString will be stored as UTF8-encoded data, and are intercompatible with other keychain solutions. Any other object type will be stored using binary plist encoding. Passing a value of nil as the object will remove the key from the keychain. The second form of this method is functionally identical to the first, but is included to support the modern objective C keyed subscripting syntax.
- - (BOOL)removeObjectForKey:(id<NSCopying>)key;
+ - (BOOL)removeObjectForKey:(id)key;
This method deletes the specified key from the keychain.
- - (id)objectForKey:(id<NSCopying>)key;
- - (id)objectForKeyedSubscript:(id<NSCopying>)key;
+ - (id)objectForKey:(id)key;
+ - (id)objectForKeyedSubscript:(id)key;
This method returns the value for the specified key from the keychain. If the key does not exist it will return nil. The second form of this method is functionally identical to the first, but is included to support the modern objective C keyed subscripting syntax.
View
4 RELEASE NOTES.md
@@ -1,3 +1,7 @@
+Version 1.3
+
+- Removed ability to store arbitrary classes in keychain for security reasons (see README). It is still possible to store dictionaries, arrays, etc.
+
Version 1.2
- It is now possible to actually store more than one value per FXKeychain
Please sign in to comment.
Something went wrong with that request. Please try again.