PPOTSimpleKeychain.m 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128
  1. // adapted from https://raw.github.com/rackspace/rackspace-ios/master/Classes/Keychain.m
  2. //
  3. // PPOTSimpleKeychain.m
  4. // OpenStack
  5. //
  6. // Based on CardIOKeychain
  7. // Based on KeychainWrapper in BadassVNC by Dylan Barrie
  8. //
  9. // Created by Mike Mayo on 10/1/10.
  10. // The OpenStack project is provided under the Apache 2.0 license.
  11. //
  12. #import "PPOTSimpleKeychain.h"
  13. #import "PPOTMacros.h"
  14. #import <Security/Security.h>
  15. #import <TargetConditionals.h>
  16. @implementation PPOTSimpleKeychain
  17. + (NSString *)keychainKeyForKey:(NSString *)key {
  18. // WARNING: don't change this line unless you know what you doing
  19. // If the app upgraded from mSDK (PayPal Touch) to OTC, we want to re-use app GUID;
  20. // therefore we are using the same keychain key.
  21. return [NSString stringWithFormat:CARDIO_STR(@"card.io - %@"), key];
  22. }
  23. + (BOOL)setData:(NSData *)data forKey:(NSString *)key {
  24. if (!key) {
  25. return NO;
  26. }
  27. BOOL success = YES;
  28. key = [self keychainKeyForKey:key];
  29. #if TARGET_IPHONE_SIMULATOR
  30. // since keychain sometimes is not available when running unit tests from the terminal
  31. // we decided to simply use user defaults
  32. [[NSUserDefaults standardUserDefaults] setValue:data ? data : [NSData data] forKey:key];
  33. [[NSUserDefaults standardUserDefaults] synchronize];
  34. return success;
  35. #else
  36. // First check if it already exists, by creating a search dictionary and requesting that
  37. // nothing be returned, and performing the search anyway.
  38. NSMutableDictionary *existsQueryDictionary = [NSMutableDictionary dictionary];
  39. [existsQueryDictionary setObject:(__bridge id)kSecClassGenericPassword forKey:(__bridge id)kSecClass];
  40. // Add the keys to the search dict
  41. [existsQueryDictionary setObject:CARDIO_STR(@"service") forKey:(__bridge id)kSecAttrService];
  42. [existsQueryDictionary setObject:key forKey:(__bridge id)kSecAttrAccount];
  43. OSStatus res = SecItemCopyMatching((__bridge CFDictionaryRef)existsQueryDictionary, NULL);
  44. if (res == errSecItemNotFound) {
  45. if (data) {
  46. NSMutableDictionary *addDict = existsQueryDictionary;
  47. [addDict setObject:data forKey:(__bridge id)kSecValueData];
  48. [addDict setObject:(__bridge id)kSecAttrAccessibleWhenUnlockedThisDeviceOnly forKey:(__bridge id)kSecAttrAccessible];
  49. res = SecItemAdd((__bridge CFDictionaryRef)addDict, NULL);
  50. if (res != errSecSuccess) {
  51. success = NO;
  52. }
  53. }
  54. } else if (res == errSecSuccess) {
  55. if(data) {
  56. // Modify an existing one
  57. // Actually pull it now off the keychain at this point.
  58. NSDictionary *attributeDict = [NSDictionary dictionaryWithObject:data forKey:(__bridge id)kSecValueData];
  59. res = SecItemUpdate((__bridge CFDictionaryRef)existsQueryDictionary, (__bridge CFDictionaryRef)attributeDict);
  60. if (res != errSecSuccess) {
  61. success = NO;
  62. }
  63. } else {
  64. SecItemDelete((__bridge CFDictionaryRef)existsQueryDictionary);
  65. }
  66. } else {
  67. success = NO;
  68. }
  69. return success;
  70. #endif
  71. }
  72. + (NSData *)dataForKey:(NSString *)key {
  73. key = [self keychainKeyForKey:key];
  74. #if TARGET_IPHONE_SIMULATOR
  75. return [[NSUserDefaults standardUserDefaults] valueForKey:key];
  76. #else
  77. NSMutableDictionary *existsQueryDictionary = [NSMutableDictionary dictionary];
  78. [existsQueryDictionary setObject:(__bridge id)kSecClassGenericPassword forKey:(__bridge id)kSecClass];
  79. // Add the keys to the search dict
  80. [existsQueryDictionary setObject:CARDIO_STR(@"service") forKey:(__bridge id)kSecAttrService];
  81. [existsQueryDictionary setObject:key forKey:(__bridge id)kSecAttrAccount];
  82. // We want the data back!
  83. [existsQueryDictionary setObject:(id)kCFBooleanTrue forKey:(__bridge id)kSecReturnData];
  84. CFTypeRef cfData = NULL;
  85. OSStatus res = SecItemCopyMatching((__bridge CFDictionaryRef)existsQueryDictionary, &cfData);
  86. NSData *data = (id)CFBridgingRelease(cfData);
  87. if (res == errSecSuccess) {
  88. return data;
  89. }
  90. return nil;
  91. #endif
  92. }
  93. + (id)unarchiveObjectWithDataForKey:(NSString *)key {
  94. NSData *data = [PPOTSimpleKeychain dataForKey:key];
  95. if ([data length]) {
  96. return [NSKeyedUnarchiver unarchiveObjectWithData:data];
  97. }
  98. else {
  99. return nil;
  100. }
  101. }
  102. @end