#import "KeychainWrapper.h"
#import "ChristmasConstants.h"
@implementation KeychainWrapper
// *** NOTE *** This class is ARC compliant - any references to CF classes must be paired with a "__bridge" statement to
// cast between Objective-C and Core Foundation Classes. WWDC 2011 Video "Introduction to Automatic Reference Counting" explains this.
// *** END NOTE ***
+ (NSMutableDictionary *)setupSearchDirectoryForIdentifier:(NSString *)identifier {
// Setup dictionary to access keychain.
NSMutableDictionary *searchDictionary = [[NSMutableDictionary alloc] init];
// Specify we are using a password (rather than a certificate, internet password, etc).
[searchDictionary setObject:(__bridge id)kSecClassGenericPassword forKey:(__bridge id)kSecClass];
// Uniquely identify this keychain accessor.
[searchDictionary setObject:APP_NAME forKey:(__bridge id)kSecAttrService];
// Uniquely identify the account who will be accessing the keychain.
NSData *encodedIdentifier = [identifier dataUsingEncoding:NSUTF8StringEncoding];
[searchDictionary setObject:encodedIdentifier forKey:(__bridge id)kSecAttrGeneric];
[searchDictionary setObject:encodedIdentifier forKey:(__bridge id)kSecAttrAccount];
return searchDictionary;
}
+ (NSData *)searchKeychainCopyMatchingIdentifier:(NSString *)identifier
{
NSMutableDictionary *searchDictionary = [self setupSearchDirectoryForIdentifier:identifier];
// Limit search results to one.
[searchDictionary setObject:(__bridge id)kSecMatchLimitOne forKey:(__bridge id)kSecMatchLimit];
// Specify we want NSData/CFData returned.
[searchDictionary setObject:(__bridge id)kCFBooleanTrue forKey:(__bridge id)kSecReturnData];
// Search.
NSData *result = nil;
CFTypeRef foundDict = NULL;
OSStatus status = SecItemCopyMatching((__bridge CFDictionaryRef)searchDictionary, &foundDict);
if (status == noErr) {
result = (__bridge_transfer NSData *)foundDict;
} else {
result = nil;
}
return result;
}
+ (NSString *)keychainStringFromMatchingIdentifier:(NSString *)identifier
{
NSData *valueData = [self searchKeychainCopyMatchingIdentifier:identifier];
if (valueData) {
NSString *value = [[NSString alloc] initWithData:valueData
encoding:NSUTF8StringEncoding];
return value;
} else {
return nil;
}
}
+ (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;
}
}
+ (BOOL)updateKeychainValue:(NSString *)value forIdentifier:(NSString *)identifier
{
NSMutableDictionary *searchDictionary = [self setupSearchDirectoryForIdentifier:identifier];
NSMutableDictionary *updateDictionary = [[NSMutableDictionary alloc] init];
NSData *valueData = [value dataUsingEncoding:NSUTF8StringEncoding];
[updateDictionary setObject:valueData forKey:(__bridge id)kSecValueData];
// Update.
OSStatus status = SecItemUpdate((__bridge CFDictionaryRef)searchDictionary,
(__bridge CFDictionaryRef)updateDictionary);
if (status == errSecSuccess) {
return YES;
} else {
return NO;
}
}
+ (void)deleteItemFromKeychainWithIdentifier:(NSString *)identifier
{
NSMutableDictionary *searchDictionary = [self setupSearchDirectoryForIdentifier:identifier];
CFDictionaryRef dictionary = (__bridge CFDictionaryRef)searchDictionary;
//Delete.
SecItemDelete(dictionary);
}
+ (BOOL)compareKeychainValueForMatchingPIN:(NSUInteger)pinHash
{
if ([[self keychainStringFromMatchingIdentifier:PIN_SAVED] isEqualToString:[self securedSHA256DigestHashForPIN:pinHash]]) {
return YES;
} else {
return NO;
}
}
// This is where most of the magic happens (the rest of it happens in computeSHA256DigestForString: method below).
// Here we are passing in the hash of the PIN that the user entered so that we can avoid manually handling the PIN itself.
// Then we are extracting the username that the user supplied during setup, so that we can add another unique element to the hash.
// From there, we mash the user name, the passed-in PIN hash, and the secret key (from ChristmasConstants.h) together to create
// one long, unique string.
// Then we send that entire hash mashup into the SHA256 method below to create a "Digital Digest," which is considered
// a one-way encryption algorithm. "One-way" means that it can never be reverse-engineered, only brute-force attacked.
// The algorthim we are using is Hash = SHA256(Name + Salt + (Hash(PIN))). This is called "Digest Authentication."
+ (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;
}
// This is where the rest of the magic happens.
// Here we are taking in our string hash, placing that inside of a C Char Array, then parsing it through the SHA256 encryption method.
+ (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];
// This is an iOS5-specific method.
// It takes in the data, how much data, and then output format, which in this case is an int array.
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;
}
@end
GiftsViewController.h
// Happy Christmas
//
// Created by Sachin Bhardwaj on 21/12/12.
// Copyright (c) 2012 Sachin Bhardwaj. All rights reserved.
//
#import <UIKit/UIKit.h>
@interface GiftsViewController : UITableViewController
{
NSMutableArray *arr1,*arr2,*arr3;
}
@property(nonatomic,strong)NSMutableArray *arr1,*arr2,*arr3;
@end
GiftsViewController.m
// Happy Christmas
//
// Created by Sachin Bhardwaj on 21/12/12.
// Copyright (c) 2012 Sachin Bhardwaj. All rights reserved.
//
#import "GiftsViewController.h"
#import "CustomTableCell.h"
#import "CategoryTable.h"
@interface GiftsViewController ()
@end
@implementation GiftsViewController
@synthesize arr1,arr2,arr3;
- (id)initWithStyle:(UITableViewStyle)style
{
self = [super initWithStyle:style];
if (self) {
// Custom initialization
}
return self;
}
- (void)viewDidLoad
{
[super viewDidLoad];
arr2 = [[NSMutableArray alloc]init];
UIImage *img1 = [UIImage imageNamed:@"images (1).jpeg"];
UIImage *img2 = [UIImage imageNamed:@"images(2).jpeg"];
UIImage *img3 = [UIImage imageNamed:@"images(3).jpeg"];
UIImage *img4 = [UIImage imageNamed:@"images(4).jpeg"];
UIImage *img5 = [UIImage imageNamed:@"images(5).jpeg"];
UIImage *img6 = [UIImage imageNamed:@"images(6).jpeg"];
arr1 = [[NSMutableArray alloc] initWithObjects:@"HONDA CBR",@"SUZUKI",@"BMW",@"DUCATI",@"ROYAL ENFIELD",@"YAMAHA R15",nil];
[arr2 addObject:img1];
[arr2 addObject:img2];
[arr2 addObject:img3];
[arr2 addObject:img4];
[arr2 addObject:img5];
[arr2 addObject:img6];
arr3 = [[NSMutableArray alloc]init];
[arr3 addObject:@"HONDA CBR,VEHICLE SUMMARY Model:Version 1.0, Type: sports, Gears:6, Fuel Consumption:32, Stroke:58, Clutch:Wet Multiplate "];
[arr3 addObject:@"SUZUKI VEHICLE SUMMARY Model:Version 2.0, Type: sports, Gears:5, Fuel Consumption:34, Stroke:57, Clutch:Wet Multiplate"];
[arr3 addObject:@"BMW VEHICLE SUMMARY Model:Version 3.0, Type: sports, Gears:4, Fuel Consumption:50, Stroke:56, Clutch:Wet Multiplate"];
[arr3 addObject:@"DUCATI VEHICLE SUMMARY Model:Version 4.0, Type: sports, Gears:6, Fuel Consumption:30, Stroke:52, Clutch:Wet Multiplate"];
[arr3 addObject:@"ROYAL ENFIELD VEHICLE SUMMARY Model:Version 2.0, Type: sports, Gears:6, Fuel Consumption:20, Stroke:58, Clutch:Wet Multiplate"];
[arr3 addObject:@"YAMAHA R15 VEHICLE SUMMARY Model:Version 2.0, Type: sports, Gears:6, Fuel Consumption:32, Stroke:58, Clutch:Wet Multiplate"];
// Uncomment the following line to preserve selection between presentations.
// self.clearsSelectionOnViewWillAppear = NO;
// Uncomment the following line to display an Edit button in the navigation bar for this view controller.
// self.navigationItem.rightBarButtonItem = self.editButtonItem;
}
-(CGFloat) tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
return 100;
}
- (void)viewDidUnload
{
[super viewDidUnload];
// Release any retained subviews of the main view.
// e.g. self.myOutlet = nil;
}
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
return (interfaceOrientation == UIInterfaceOrientationPortrait);
}
#pragma mark - Table view data source
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
//#warning Potentially incomplete method implementation.
// Return the number of sections.
return 1;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
//#warning Incomplete method implementation.
// Return the number of rows in the section.
return [arr1 count];
//return [arr2 count];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = @"CustomTableCell";
CustomTableCell *cell = (CustomTableCell *)[tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
// NSArray *topLevelObjects = [[NSBundle mainBundle] loadNibNamed:@"CustomTableCell" owner:self options:nil];
//
// for (id currentObject in topLevelObjects)
// {
// if ([currentObject isKindOfClass:[UITableViewCell class]])
// {
// cell = (CustomTableCell *) currentObject;
// break;
// }
// }
if (cell==nil) {
cell=[[CustomTableCell alloc]initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:CellIdentifier];
}
[cell setSelectionStyle:UITableViewCellSelectionStyleNone];
}
cell.img1.image = [arr2 objectAtIndex:indexPath.row];
cell.lbl1.text = [arr1 objectAtIndex:indexPath.row];
return cell;
}
#pragma mark - Table view delegate
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
// Navigation logic may go here. Create and push another view controller.
CategoryTable *third = [[CategoryTable alloc]init];
// ...
// Pass the selected object to the new view controller.
[self.navigationController pushViewController:third animated:YES];
third.image.image = [arr2 objectAtIndex:indexPath.row];
third.lbl1.text = [arr1 objectAtIndex:indexPath.row];
third.txt.text = [arr3 objectAtIndex:indexPath.row];
[third release];
}
@end
CustomTableCell.h
#import <UIKit/UIKit.h>
@interface CustomTableCell : UITableViewCell
{
UILabel *lbl1;
UIImageView *img1;
}
@property(nonatomic,strong)UILabel *lbl1;
@property(nonatomic,strong)UIImageView *img1;
@end
CustomTableCell.m
#import "CustomTableCell.h"
@implementation CustomTableCell
@synthesize lbl1,img1;
- (id)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier
{
self = [super initWithStyle:style reuseIdentifier:reuseIdentifier];
if (self) {
lbl1=[[UILabel alloc]initWithFrame:CGRectMake(10,5,150,40) ];
img1=[[UIImageView alloc]initWithFrame:CGRectMake(160,5,90,70)];
[self.contentView addSubview:lbl1];
[self.contentView addSubview:img1];
}
return self;
}
- (void)setSelected:(BOOL)selected animated:(BOOL)animated
{
[super setSelected:selected animated:animated];
// Configure the view for the selected state
}
@end
Step 6
Finally we click on the run button to show the output.
Step 7
Splash in iPhone:
Output 1 in iPhone:
Here we provide the user name and password.
Output 2 in iPhone:
Output 3 in iPhone:
When we click on the button we move to the table view controller class.
Output 4 in iPhone:
Now when we click on the navigation button "Happy Christmas" it is again asking for a user password to authenticate the user.
Output 5 in iPhone:
Here we type again the same password.
Output 6 in iPhone:
Now when we select any row it moves to another view.
Output 7 in iPhone:
For security purposes it again asks for the user's Password to authenticate the user.
Output 8 in iPhone:
Now again run your app and enjoy your Christmas Gift.
Happy Christmas!!