MYKey-iPhone.m
author Jens Alfke <jens@mooseyard.com>
Fri Aug 07 11:24:53 2009 -0700 (2009-08-07)
changeset 28 54b373aa65ab
parent 26 d9c2a06d4e4e
permissions -rw-r--r--
Fixed iPhone OS build. (issue 3)
     1 //
     2 //  MYKey-iPhone.m
     3 //  MYCrypto-iPhone
     4 //
     5 //  Created by Jens Alfke on 4/4/09.
     6 //  Copyright 2009 Jens Alfke. All rights reserved.
     7 //
     8 
     9 
    10 #import "MYCrypto_Private.h"
    11 
    12 #if MYCRYPTO_USE_IPHONE_API
    13 
    14 #import "MYDigest.h"
    15 #import "MYErrorUtils.h"
    16 
    17 
    18 #pragma mark -
    19 @implementation MYKey
    20 
    21 
    22 - (id) initWithKeyRef: (SecKeyRef)key {
    23     return [self initWithKeychainItemRef: (SecKeychainItemRef)key];
    24 }
    25 
    26 
    27 - (id) _initWithKeyData: (NSData*)data
    28             forKeychain: (SecKeychainRef)keychain
    29 {
    30     NSMutableDictionary *info = $mdict({(id)kSecClass, (id)kSecClassKey},
    31                                         {(id)kSecAttrKeyType, (id)self.keyType},
    32                                         {(id)kSecValueData, data},
    33                                         {(id)kSecAttrIsPermanent, (keychain ?$true :$false)},
    34                                         {(id)kSecReturnPersistentRef, (keychain ?$true :$false)} );
    35     SecKeyRef key = (SecKeyRef)[MYKeychain _addItemWithInfo: info];
    36     if (!key) {
    37         [self release];
    38         return nil;
    39     }
    40     self = [self initWithKeyRef: (SecKeyRef)key];
    41     if (self) {
    42         if (!keychain)
    43             _keyData = [data copy];
    44         
    45         //TEMP For debugging:
    46         AssertEqual(self.keyData, data);
    47     }
    48     return self;
    49 }
    50 
    51 - (id) initWithKeyData: (NSData*)data {
    52     return [self _initWithKeyData: data forKeychain: nil];
    53 }
    54 
    55 - (void) dealloc
    56 {
    57     [_keyData release];
    58     [super dealloc];
    59 }
    60 
    61 
    62 /*- (NSData*) persistentRef {
    63     NSDictionary *info = $dict( {(id)kSecValueRef, (id)self.keyRef},
    64                               //{(id)kSecAttrIsPermanent, (self.isPersistent ?$true :$false)},
    65                                 {(id)kSecReturnPersistentRef, $true} );
    66     CFDataRef data;
    67     if (!check(SecItemCopyMatching((CFDictionaryRef)info, (CFTypeRef*)&data), @"SecItemCopyMatching"))
    68         return nil;
    69     if (!data)
    70         Warn(@"MYKey persistentRef couldn't get ref");
    71     return [NSMakeCollectable(data) autorelease];
    72 }*/
    73 
    74 
    75 - (SecExternalItemType) keyClass {
    76     AssertAbstractMethod();
    77 }
    78 
    79 - (SecExternalItemType) keyType {
    80     return NULL;
    81 }
    82 
    83 - (NSData*) keyData {
    84     if (_keyData)
    85         return _keyData;
    86     
    87     NSDictionary *info = $dict( {(id)kSecValueRef, (id)self.keyRef},
    88                               //{(id)kSecAttrIsPermanent, (self.isPersistent ?$true :$false)},
    89                                 {(id)kSecReturnData, $true} );
    90     CFDataRef data;
    91     if (!check(SecItemCopyMatching((CFDictionaryRef)info, (CFTypeRef*)&data), @"SecItemCopyMatching")) {
    92         Log(@"SecItemCopyMatching failed; input = %@", info);
    93         return nil;
    94     } else {
    95         Assert(data!=NULL);
    96         _keyData = NSMakeCollectable(data);
    97         return _keyData;
    98     }
    99     // The format of this data is not documented. There's been some reverse-engineering:
   100     // https://devforums.apple.com/message/32089#32089
   101     // Apparently it is a DER-formatted sequence of a modulus followed by an exponent.
   102     // This can be converted to OpenSSL format by wrapping it in some additional DER goop.
   103 }
   104 
   105 - (MYSHA1Digest*) _keyDigest {
   106     return [self.keyData my_SHA1Digest];
   107 }
   108 
   109 - (unsigned) keySizeInBits {
   110     return [[self _attribute: kSecAttrKeySizeInBits] intValue];
   111 }
   112 
   113 - (SecKeyRef) keyRef {
   114     return (SecKeyRef) self.keychainItemRef;
   115 }
   116 
   117 
   118 - (id) _attribute: (CFTypeRef)attribute {
   119     NSDictionary *info = $dict({(id)kSecValueRef, (id)self.keyRef},
   120             {(id)kSecAttrIsPermanent, (self.isPersistent ?$true :$false)},
   121                                {(id)kSecReturnAttributes, $true});
   122     CFDictionaryRef attrs = NULL;
   123     if (!check(SecItemCopyMatching((CFDictionaryRef)info, (CFTypeRef*)&attrs), @"SecItemCopyMatching"))
   124         return nil;
   125     CFTypeRef rawValue = CFDictionaryGetValue(attrs,attribute);
   126     id value = rawValue ?[[(id)CFMakeCollectable(rawValue) retain] autorelease] :nil;
   127     CFRelease(attrs);
   128     return value;
   129 }
   130 
   131 - (BOOL) setValue: (NSString*)value ofAttribute: (SecKeychainAttrType)attribute {
   132     if (!value)
   133         value = (id)[NSNull null];
   134     NSDictionary *query = $dict( {(id)kSecValueRef, (id)self.keyRef} );
   135     NSDictionary *attrs = $dict( {(id)attribute, value} );
   136     return check(SecItemUpdate((CFDictionaryRef)query, (CFDictionaryRef)attrs), @"SecItemUpdate");
   137 }
   138 
   139 
   140 - (NSString*) name {
   141     return [self _attribute: kSecAttrLabel];
   142 }
   143 
   144 - (void) setName: (NSString*)name {
   145     [self setValue: name ofAttribute: kSecAttrLabel];
   146 }
   147 
   148 - (NSString*) alias {
   149     return [self _attribute: kSecAttrApplicationTag];
   150 }
   151 
   152 - (void) setAlias: (NSString*)alias {
   153     [self setValue: alias ofAttribute: kSecAttrApplicationTag];
   154 }
   155 
   156 
   157 
   158 
   159 /** Asymmetric encryption/decryption; used by MYPublicKey and MYPrivateKey. */
   160 - (NSData*) _crypt: (NSData*)data operation: (BOOL)operation {
   161     CAssert(data);
   162     size_t dataLength = data.length;
   163     SecKeyRef key = self.keyRef;
   164     size_t outputLength = MAX(dataLength, SecKeyGetBlockSize(key));
   165     void *outputBuf = malloc(outputLength);
   166     if (!outputBuf) return nil;
   167     OSStatus err;
   168     if (operation)
   169         err = SecKeyEncrypt(key, kSecPaddingNone,//PKCS1, 
   170                             data.bytes, dataLength,
   171                             outputBuf, &outputLength);
   172     else
   173         err = SecKeyDecrypt(key, kSecPaddingNone,//PKCS1, 
   174                             data.bytes, dataLength,
   175                             outputBuf, &outputLength);
   176     if (err) {
   177         free(outputBuf);
   178         Warn(@"%scrypting failed (%i)", (operation ?"En" :"De"), err);
   179         // Note: One of the errors I've seen is -9809, which is errSSLCrypto (SecureTransport.h)
   180         return nil;
   181     } else
   182         return [NSData dataWithBytesNoCopy: outputBuf length: outputLength freeWhenDone: YES];
   183 }
   184 
   185 
   186 @end
   187 
   188 
   189 #endif MYCRYPTO_USE_IPHONE_API
   190 
   191 
   192 
   193 /*
   194  Copyright (c) 2009, Jens Alfke <jens@mooseyard.com>. All rights reserved.
   195  
   196  Redistribution and use in source and binary forms, with or without modification, are permitted
   197  provided that the following conditions are met:
   198  
   199  * Redistributions of source code must retain the above copyright notice, this list of conditions
   200  and the following disclaimer.
   201  * Redistributions in binary form must reproduce the above copyright notice, this list of conditions
   202  and the following disclaimer in the documentation and/or other materials provided with the
   203  distribution.
   204  
   205  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
   206  IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND 
   207  FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRI-
   208  BUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
   209  (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 
   210   PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 
   211  CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF 
   212  THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
   213  */