BTKeychain.m 3.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899
  1. #import "BTKeychain.h"
  2. #import <Security/Security.h>
  3. @implementation BTKeychain
  4. + (BOOL)setString:(NSString *)string forKey:(NSString *)key {
  5. NSData *data = [string dataUsingEncoding:NSUTF8StringEncoding];
  6. return [self setData:data forKey:key];
  7. }
  8. + (NSString *)stringForKey:(NSString *)key {
  9. NSData *data = [self dataForKey:key];
  10. return data == nil ? nil : [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
  11. }
  12. + (NSString *)keychainKeyForKey:(NSString *)key {
  13. return [NSString stringWithFormat:@"com.braintreepayments.Braintree-API.%@", key];
  14. }
  15. + (BOOL)setData:(NSData *)data forKey:(NSString *)key {
  16. if(!key) {
  17. return NO;
  18. }
  19. BOOL success = YES;
  20. key = [self keychainKeyForKey:key];
  21. // First check if it already exists, by creating a search dictionary and requesting that
  22. // nothing be returned, and performing the search anyway.
  23. NSMutableDictionary *existsQueryDictionary = [NSMutableDictionary dictionary];
  24. [existsQueryDictionary setObject:(__bridge id)kSecClassGenericPassword forKey:(__bridge id)kSecClass];
  25. // Add the keys to the search dict
  26. [existsQueryDictionary setObject:@"Service" forKey:(__bridge id)kSecAttrService];
  27. [existsQueryDictionary setObject:key forKey:(__bridge id)kSecAttrAccount];
  28. OSStatus res = SecItemCopyMatching((__bridge CFDictionaryRef)existsQueryDictionary, NULL);
  29. if(res == errSecItemNotFound) {
  30. if(data) {
  31. NSMutableDictionary *addDict = existsQueryDictionary;
  32. [addDict setObject:data forKey:(__bridge id)kSecValueData];
  33. [addDict setObject:(__bridge id)kSecAttrAccessibleWhenUnlockedThisDeviceOnly forKey:(__bridge id)kSecAttrAccessible];
  34. res = SecItemAdd((__bridge CFDictionaryRef)addDict, NULL);
  35. if (res != errSecSuccess) {
  36. success = NO;
  37. }
  38. }
  39. }
  40. else if(res == errSecSuccess) {
  41. if(data) {
  42. // Modify an existing one
  43. // Actually pull it now of the keychain at this point.
  44. NSDictionary *attributeDict = [NSDictionary dictionaryWithObject:data forKey:(__bridge id)kSecValueData];
  45. res = SecItemUpdate((__bridge CFDictionaryRef)existsQueryDictionary, (__bridge CFDictionaryRef)attributeDict);
  46. if (res != errSecSuccess) {
  47. success = NO;
  48. }
  49. } else {
  50. SecItemDelete((__bridge CFDictionaryRef)existsQueryDictionary);
  51. }
  52. }
  53. else {
  54. success = NO;
  55. }
  56. return success;
  57. }
  58. + (NSData *)dataForKey:(NSString *)key {
  59. key = [self keychainKeyForKey:key];
  60. NSMutableDictionary *existsQueryDictionary = [NSMutableDictionary dictionary];
  61. [existsQueryDictionary setObject:(__bridge id)kSecClassGenericPassword forKey:(__bridge id)kSecClass];
  62. // Add the keys to the search dict
  63. [existsQueryDictionary setObject:@"Service" forKey:(__bridge id)kSecAttrService];
  64. [existsQueryDictionary setObject:key forKey:(__bridge id)kSecAttrAccount];
  65. // We want the data back!
  66. [existsQueryDictionary setObject:(id)kCFBooleanTrue forKey:(__bridge id)kSecReturnData];
  67. CFTypeRef cfData = NULL;
  68. OSStatus res = SecItemCopyMatching((__bridge CFDictionaryRef)existsQueryDictionary, &cfData);
  69. NSData *data = (id)CFBridgingRelease(cfData);
  70. if(res == errSecSuccess) {
  71. return data;
  72. }
  73. return nil;
  74. }
  75. @end