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