MYKeychain.m
author Jens Alfke <jens@mooseyard.com>
Fri Jun 05 08:57:18 2009 -0700 (2009-06-05)
changeset 20 df9da0f6b358
parent 4 f4709533c816
child 26 d9c2a06d4e4e
permissions -rw-r--r--
Factored out the name accessors of MYParsedCertificate into a new class MYCertificateName, so that both subject and issuer can be accessed. A bit of other cleanup too.
snej@0
     1
//
snej@0
     2
//  MYKeychain.m
snej@0
     3
//  MYCrypto
snej@0
     4
//
snej@0
     5
//  Created by Jens Alfke on 3/23/09.
snej@0
     6
//  Copyright 2009 Jens Alfke. All rights reserved.
snej@0
     7
//
snej@0
     8
snej@0
     9
#import "MYKeychain.h"
snej@0
    10
#import "MYCrypto_Private.h"
snej@0
    11
#import "MYDigest.h"
snej@4
    12
#import "MYIdentity.h"
snej@4
    13
snej@0
    14
snej@2
    15
#if !MYCRYPTO_USE_IPHONE_API
snej@0
    16
snej@0
    17
snej@0
    18
@interface MYKeyEnumerator : NSEnumerator
snej@0
    19
{
snej@4
    20
    @private
snej@0
    21
    MYKeychain *_keychain;
snej@0
    22
    SecKeychainSearchRef _search;
snej@0
    23
    SecItemClass _itemClass;
snej@0
    24
}
snej@0
    25
snej@0
    26
- (id) initWithKeychain: (MYKeychain*)keychain
snej@0
    27
              itemClass: (SecItemClass)itemClass
snej@0
    28
             attributes: (SecKeychainAttribute[])attributes 
snej@0
    29
                  count: (unsigned)count;
snej@0
    30
@end
snej@0
    31
snej@0
    32
snej@4
    33
@interface MYIdentityEnumerator : NSEnumerator
snej@4
    34
{
snej@4
    35
    @private
snej@4
    36
    SecIdentitySearchRef _searchRef;
snej@4
    37
}
snej@4
    38
snej@4
    39
- (id) initWithKeychain: (MYKeychain*)keychain;
snej@4
    40
@end
snej@4
    41
snej@4
    42
snej@4
    43
snej@0
    44
snej@0
    45
@implementation MYKeychain
snej@0
    46
snej@0
    47
snej@0
    48
- (id) initWithKeychainRef: (SecKeychainRef)keychainRef
snej@0
    49
{
snej@0
    50
    self = [super init];
snej@0
    51
    if (self != nil) {
snej@0
    52
        if (keychainRef) {
snej@0
    53
            CFRetain(keychainRef);
snej@0
    54
            _keychain = keychainRef;
snej@0
    55
        }
snej@0
    56
    }
snej@0
    57
    return self;
snej@0
    58
}
snej@0
    59
snej@0
    60
+ (MYKeychain*) _readableKeychainWithRef: (SecKeychainRef)keychainRef fromPath: (NSString*)path {
snej@0
    61
    if (!keychainRef)
snej@0
    62
        return nil;
snej@0
    63
    SecKeychainStatus status;
snej@0
    64
    BOOL ok = check(SecKeychainGetStatus(keychainRef, &status), @"SecKeychainGetStatus");
snej@0
    65
    if (ok && !(status & kSecReadPermStatus)) {
snej@0
    66
        Warn(@"Can't open keychain at %@ : not readable (status=%i)", path,status);
snej@0
    67
        ok = NO;
snej@0
    68
    }
snej@0
    69
    MYKeychain *keychain = nil;
snej@0
    70
    if (ok)
snej@0
    71
        keychain = [[[self alloc] initWithKeychainRef: keychainRef] autorelease];
snej@0
    72
    CFRelease(keychainRef);
snej@0
    73
    return keychain;
snej@0
    74
}
snej@0
    75
snej@0
    76
+ (MYKeychain*) openKeychainAtPath: (NSString*)path
snej@0
    77
{
snej@0
    78
    Assert(path);
snej@0
    79
    SecKeychainRef keychainRef = NULL;
snej@0
    80
    if (!check(SecKeychainOpen(path.fileSystemRepresentation, &keychainRef), @"SecKeychainOpen"))
snej@0
    81
        return nil;
snej@0
    82
    return [self _readableKeychainWithRef: keychainRef fromPath: path];
snej@0
    83
}
snej@0
    84
snej@0
    85
+ (MYKeychain*) createKeychainAtPath: (NSString*)path
snej@0
    86
                        withPassword: (NSString*)password
snej@0
    87
{
snej@0
    88
    Assert(path);
snej@0
    89
    const char *passwordStr = [password UTF8String];
snej@0
    90
    SecKeychainRef keychainRef = NULL;
snej@0
    91
    if (!check(SecKeychainCreate(path.fileSystemRepresentation,
snej@0
    92
                                 passwordStr ?strlen(passwordStr) :0,
snej@0
    93
                                 passwordStr, 
snej@0
    94
                                 (password==nil), 
snej@0
    95
                                 NULL, 
snej@0
    96
                                 &keychainRef),
snej@0
    97
               @"SecKeychainCreate"))
snej@0
    98
        return nil;
snej@0
    99
    return [self _readableKeychainWithRef: keychainRef fromPath: path];
snej@0
   100
}
snej@0
   101
snej@0
   102
- (BOOL) deleteKeychainFile {
snej@0
   103
    Assert(_keychain);
snej@0
   104
    return check(SecKeychainDelete(_keychain), @"SecKeychainDelete");
snej@0
   105
}
snej@0
   106
snej@0
   107
snej@0
   108
- (void) dealloc
snej@0
   109
{
snej@0
   110
    if (_keychain) CFRelease(_keychain);
snej@0
   111
    [super dealloc];
snej@0
   112
}
snej@0
   113
snej@2
   114
- (void) finalize
snej@2
   115
{
snej@2
   116
    if (_keychain) CFRelease(_keychain);
snej@2
   117
    [super finalize];
snej@2
   118
}
snej@2
   119
snej@0
   120
snej@0
   121
+ (MYKeychain*) allKeychains
snej@0
   122
{
snej@0
   123
    static MYKeychain *sAllKeychains;
snej@0
   124
    @synchronized(self) {
snej@0
   125
        if (!sAllKeychains)
snej@0
   126
            sAllKeychains = [[self alloc] initWithKeychainRef: nil];
snej@0
   127
    }
snej@0
   128
    return sAllKeychains;
snej@0
   129
}
snej@0
   130
snej@0
   131
snej@0
   132
+ (MYKeychain*) defaultKeychain
snej@0
   133
{
snej@0
   134
    static MYKeychain *sDefaultKeychain;
snej@0
   135
    @synchronized(self) {
snej@0
   136
        if (!sDefaultKeychain) {
snej@0
   137
            SecKeychainRef kc = NULL;
snej@0
   138
            OSStatus err = SecKeychainCopyDomainDefault(kSecPreferencesDomainUser,&kc);
snej@0
   139
#if TARGET_OS_IPHONE
snej@0
   140
            // In the simulator, an app is run in a sandbox that has no keychain by default.
snej@0
   141
            // As a convenience, create one if necessary:
snej@0
   142
            if (err == errSecNoDefaultKeychain) {
snej@0
   143
                Log(@"No default keychain in simulator; creating one...");
snej@0
   144
                NSString *path = [NSSearchPathForDirectoriesInDomains(NSLibraryDirectory,
snej@0
   145
                                                                      NSUserDomainMask, YES) objectAtIndex: 0];
snej@0
   146
                path = [path stringByAppendingPathComponent: @"MYCrypto.keychain"];
snej@0
   147
                sDefaultKeychain = [[self createKeychainAtPath: path withPassword: nil] retain];
snej@0
   148
                Assert(sDefaultKeychain, @"Couldn't create default keychain");
snej@0
   149
                SecKeychainSetDomainDefault(kSecPreferencesDomainUser, sDefaultKeychain.keychainRef);
snej@0
   150
                Log(@"...created %@", sDefaultKeychain);
snej@0
   151
                return sDefaultKeychain;
snej@0
   152
            }
snej@0
   153
#endif
snej@0
   154
            if (!check(err, @"SecKeychainCopyDefault"))
snej@0
   155
                kc = NULL;
snej@0
   156
snej@0
   157
            Assert(kc, @"No default keychain");
snej@0
   158
            sDefaultKeychain = [[self alloc] initWithKeychainRef: kc];
snej@0
   159
            CFRelease(kc);
snej@0
   160
        }
snej@0
   161
    }
snej@0
   162
    return sDefaultKeychain;
snej@0
   163
}
snej@0
   164
snej@0
   165
snej@0
   166
- (id) copyWithZone: (NSZone*)zone {
snej@0
   167
    // It's not necessary to make copies of Keychain objects. This makes it more efficient
snej@0
   168
    // to use instances as NSDictionary keys or store them in NSSets.
snej@0
   169
    return [self retain];
snej@0
   170
}
snej@0
   171
snej@0
   172
- (BOOL) isEqual: (id)obj {
snej@0
   173
    return (obj == self) || 
snej@0
   174
            ([obj isKindOfClass: [MYKeychain class]] && CFEqual(_keychain, [obj keychainRef]));
snej@0
   175
}
snej@0
   176
snej@0
   177
snej@0
   178
- (SecKeychainRef) keychainRef {
snej@0
   179
    return _keychain;
snej@0
   180
}
snej@0
   181
snej@0
   182
snej@0
   183
- (SecKeychainRef) keychainRefOrDefault {
snej@0
   184
    if (_keychain)
snej@0
   185
        return _keychain;
snej@0
   186
    else
snej@0
   187
        return [[[self class] defaultKeychain] keychainRef];
snej@0
   188
}
snej@0
   189
    
snej@0
   190
    
snej@0
   191
- (NSString*) path {
snej@0
   192
    if (!_keychain)
snej@0
   193
        return nil;
snej@0
   194
    char pathBuf[PATH_MAX];
snej@0
   195
    UInt32 pathLen = sizeof(pathBuf);
snej@0
   196
    if (!check(SecKeychainGetPath(_keychain, &pathLen, pathBuf), @"SecKeychainGetPath"))
snej@0
   197
        return nil;
snej@0
   198
    return [[NSFileManager defaultManager] stringWithFileSystemRepresentation: pathBuf length: pathLen];
snej@0
   199
}
snej@0
   200
snej@0
   201
- (NSString*) description {
snej@0
   202
    if (_keychain)
snej@0
   203
        return $sprintf(@"%@[%p, %@]", [self class], _keychain, self.path);
snej@0
   204
    else
snej@0
   205
        return $sprintf(@"%@[all]", [self class]);
snej@0
   206
}
snej@0
   207
snej@0
   208
jens@16
   209
+ (void) setUserInteractionAllowed: (BOOL)allowed {
jens@16
   210
    SecKeychainSetUserInteractionAllowed(allowed);
jens@16
   211
}
jens@16
   212
jens@16
   213
snej@0
   214
#pragma mark -
snej@0
   215
#pragma mark SEARCHING:
snej@0
   216
snej@0
   217
snej@0
   218
- (MYKeychainItem*) itemOfClass: (SecItemClass)itemClass 
snej@0
   219
                     withDigest: (MYSHA1Digest*)pubKeyDigest 
snej@0
   220
{
snej@0
   221
    SecKeychainAttribute attr = {.tag= (itemClass==kSecCertificateItemClass ?kSecPublicKeyHashItemAttr :kSecKeyLabel), 
snej@0
   222
                                 .length= pubKeyDigest.length, 
snej@0
   223
                                 .data= (void*) pubKeyDigest.bytes};
snej@0
   224
    MYKeyEnumerator *e = [[MYKeyEnumerator alloc] initWithKeychain: self
snej@0
   225
                                                         itemClass: itemClass
snej@0
   226
                                                        attributes: &attr count: 1];
snej@0
   227
    MYKeychainItem *item = e.nextObject;
snej@0
   228
    [e release];
snej@0
   229
    return item;
snej@0
   230
}
snej@0
   231
snej@0
   232
- (MYPublicKey*) publicKeyWithDigest: (MYSHA1Digest*)pubKeyDigest {
snej@0
   233
    return (MYPublicKey*) [self itemOfClass: kSecPublicKeyItemClass withDigest: pubKeyDigest];
snej@0
   234
}   
snej@0
   235
snej@0
   236
- (NSEnumerator*) enumeratePublicKeys {
snej@0
   237
    return [[[MYKeyEnumerator alloc] initWithKeychain: self
snej@0
   238
                                            itemClass: kSecPublicKeyItemClass
snej@0
   239
                                           attributes: NULL count: 0] autorelease];
snej@0
   240
}
snej@0
   241
snej@0
   242
- (NSEnumerator*) publicKeysWithAlias: (NSString*)alias {
snej@0
   243
    NSData *utf8 = [alias dataUsingEncoding: NSUTF8StringEncoding];
snej@0
   244
    SecKeychainAttribute attr = {.tag=kSecKeyAlias, .length=utf8.length, .data=(void*)utf8.bytes};
snej@0
   245
    return [[[MYKeyEnumerator alloc] initWithKeychain: self
snej@0
   246
                                            itemClass: kSecPublicKeyItemClass
snej@0
   247
                                           attributes: &attr count: 1] autorelease];
snej@0
   248
}
snej@0
   249
snej@0
   250
snej@3
   251
- (MYPrivateKey*) privateKeyWithDigest: (MYSHA1Digest*)pubKeyDigest {
snej@3
   252
    return (MYPrivateKey*) [self itemOfClass: kSecPrivateKeyItemClass withDigest: pubKeyDigest];
snej@0
   253
}
snej@0
   254
snej@3
   255
- (NSEnumerator*) enumeratePrivateKeys {
snej@0
   256
    return [[[MYKeyEnumerator alloc] initWithKeychain: self
snej@0
   257
                                            itemClass: kSecPrivateKeyItemClass
snej@0
   258
                                           attributes: NULL count: 0] autorelease];
snej@0
   259
}
snej@0
   260
snej@0
   261
- (MYCertificate*) certificateWithDigest: (MYSHA1Digest*)pubKeyDigest {
snej@0
   262
    return (MYCertificate*) [self itemOfClass: kSecCertificateItemClass withDigest: pubKeyDigest];
snej@0
   263
}
snej@0
   264
snej@0
   265
- (NSEnumerator*) enumerateCertificates {
snej@0
   266
    return [[[MYKeyEnumerator alloc] initWithKeychain: self
snej@0
   267
                                            itemClass: kSecCertificateItemClass
snej@0
   268
                                           attributes: NULL count: 0] autorelease];
snej@0
   269
}
snej@0
   270
snej@4
   271
- (NSEnumerator*) enumerateIdentities {
snej@4
   272
    return [[[MYIdentityEnumerator alloc] initWithKeychain: self] autorelease];
snej@4
   273
}
snej@4
   274
snej@0
   275
- (NSEnumerator*) enumerateSymmetricKeys {
snej@0
   276
    return [[[MYKeyEnumerator alloc] initWithKeychain: self
snej@0
   277
                                            itemClass: kSecSymmetricKeyItemClass
snej@0
   278
                                           attributes: NULL count: 0] autorelease];
snej@0
   279
}
snej@0
   280
snej@0
   281
- (NSEnumerator*) symmetricKeysWithAlias: (NSString*)alias {
snej@0
   282
    NSData *utf8 = [alias dataUsingEncoding: NSUTF8StringEncoding];
snej@0
   283
    SecKeychainAttribute attr = {.tag=kSecKeyAlias, .length=utf8.length, .data=(void*)utf8.bytes};
snej@0
   284
    return [[[MYKeyEnumerator alloc] initWithKeychain: self
snej@0
   285
                                            itemClass: kSecSymmetricKeyItemClass
snej@0
   286
                                           attributes: &attr count: 1] autorelease];
snej@0
   287
}
snej@0
   288
snej@0
   289
snej@0
   290
snej@0
   291
#pragma mark -
snej@0
   292
#pragma mark IMPORT:
snej@0
   293
snej@0
   294
snej@0
   295
- (MYPublicKey*) importPublicKey: (NSData*)keyData {
snej@0
   296
    return [[[MYPublicKey alloc] _initWithKeyData: keyData 
snej@0
   297
                                      forKeychain: self.keychainRefOrDefault]
snej@0
   298
            autorelease];
snej@0
   299
}
snej@0
   300
snej@3
   301
- (MYPrivateKey*) importPublicKey: (NSData*)pubKeyData 
snej@0
   302
                    privateKey: (NSData*)privKeyData 
snej@0
   303
                    alertTitle: (NSString*)title
snej@0
   304
                   alertPrompt: (NSString*)prompt {
snej@3
   305
    return [[[MYPrivateKey alloc] _initWithKeyData: privKeyData
snej@3
   306
                                     publicKeyData: pubKeyData
snej@3
   307
                                       forKeychain: self.keychainRefOrDefault
snej@3
   308
                                        alertTitle: (NSString*)title
snej@3
   309
                                       alertPrompt: (NSString*)prompt]
snej@0
   310
            autorelease];
snej@0
   311
}
snej@0
   312
snej@3
   313
- (MYPrivateKey*) importPublicKey: (NSData*)pubKeyData 
snej@0
   314
                    privateKey: (NSData*)privKeyData 
snej@0
   315
{
snej@0
   316
    return [self importPublicKey: pubKeyData privateKey: privKeyData
snej@0
   317
                      alertTitle: @"Import Private Key"
snej@0
   318
                     alertPrompt: @"To import your saved private key, please re-enter the "
snej@0
   319
                                   "passphrase you used when you exported it."];
snej@0
   320
}
snej@0
   321
snej@0
   322
- (MYCertificate*) importCertificate: (NSData*)data
snej@0
   323
                                type: (CSSM_CERT_TYPE) type
snej@0
   324
                            encoding: (CSSM_CERT_ENCODING) encoding;
snej@0
   325
{
snej@0
   326
    MYCertificate *cert = [[[MYCertificate alloc] initWithCertificateData: data 
snej@0
   327
                                                                    type: type
snej@0
   328
                                                                encoding: encoding]
snej@0
   329
                           autorelease];
snej@0
   330
    if (cert) {
snej@0
   331
        if (!check(SecCertificateAddToKeychain(cert.certificateRef, self.keychainRefOrDefault),
snej@0
   332
                   @"SecCertificateAddToKeychain"))
snej@0
   333
            cert = nil;
snej@0
   334
    }
snej@0
   335
    return cert;
snej@0
   336
}
snej@0
   337
snej@0
   338
- (MYCertificate*) importCertificate: (NSData*)data {
snej@0
   339
    return [self importCertificate: data 
snej@0
   340
                              type: CSSM_CERT_X_509v3 
snej@0
   341
                          encoding: CSSM_CERT_ENCODING_BER];
snej@0
   342
}
snej@0
   343
snej@4
   344
- (BOOL) addCertificate: (MYCertificate*)certificate {
snej@4
   345
    Assert(certificate);
snej@4
   346
    return check(SecCertificateAddToKeychain(certificate.certificateRef, self.keychainRefOrDefault),
snej@4
   347
                 @"SecCertificateAddToKeychain");
snej@4
   348
}
snej@4
   349
snej@0
   350
snej@0
   351
- (MYSymmetricKey*) generateSymmetricKeyOfSize: (unsigned)keySizeInBits
snej@0
   352
                                     algorithm: (CCAlgorithm)algorithm
snej@0
   353
{
snej@0
   354
    return [MYSymmetricKey _generateSymmetricKeyOfSize: keySizeInBits
snej@0
   355
                                             algorithm: algorithm inKeychain: self];
snej@0
   356
}
snej@0
   357
snej@3
   358
- (MYPrivateKey*) generateRSAKeyPairOfSize: (unsigned)keySize {
snej@3
   359
    return [MYPrivateKey _generateRSAKeyPairOfSize: keySize inKeychain: self];
snej@0
   360
}
snej@0
   361
snej@0
   362
snej@0
   363
- (CSSM_CSP_HANDLE) CSPHandle {
snej@0
   364
    CSSM_CSP_HANDLE cspHandle = 0;
snej@0
   365
    Assert(check(SecKeychainGetCSPHandle(self.keychainRefOrDefault, &cspHandle), @"SecKeychainGetCSPHandle"));
snej@0
   366
    return cspHandle;
snej@0
   367
}
snej@0
   368
snej@0
   369
snej@0
   370
@end
snej@0
   371
snej@0
   372
snej@0
   373
snej@0
   374
#pragma mark -
snej@0
   375
@implementation MYKeyEnumerator
snej@0
   376
snej@0
   377
- (id) initWithKeychain: (MYKeychain*)keychain
snej@0
   378
              itemClass: (SecItemClass)itemClass
snej@0
   379
             attributes: (SecKeychainAttribute[])attributes 
snej@0
   380
                  count: (unsigned)count {
snej@0
   381
    self = [super init];
snej@0
   382
    if (self) {
snej@0
   383
        _keychain = [keychain retain];
snej@0
   384
        _itemClass = itemClass;
snej@0
   385
        SecKeychainAttributeList list = {.count=count, .attr=attributes};
snej@0
   386
        if (!check(SecKeychainSearchCreateFromAttributes(keychain.keychainRef,
snej@0
   387
                                                         itemClass,
snej@0
   388
                                                         &list,
snej@0
   389
                                                         &_search),
snej@0
   390
                   @"SecKeychainSearchCreateFromAttributes")) {
snej@0
   391
            [self release];
snej@0
   392
            return nil;
snej@0
   393
        }
snej@0
   394
    }
snej@0
   395
    return self;
snej@0
   396
}
snej@0
   397
snej@0
   398
- (void) dealloc
snej@0
   399
{
snej@0
   400
    [_keychain release];
snej@0
   401
    if (_search) CFRelease(_search);
snej@0
   402
    [super dealloc];
snej@0
   403
}
snej@0
   404
snej@2
   405
- (void) finalize
snej@2
   406
{
snej@2
   407
    [_keychain release];
snej@2
   408
    if (_search) CFRelease(_search);
snej@2
   409
    [super finalize];
snej@2
   410
}
snej@2
   411
snej@0
   412
snej@0
   413
- (id) nextObject {
snej@0
   414
    if (!_search)
snej@0
   415
        return nil;
snej@0
   416
    MYPublicKey *key = nil;
snej@0
   417
    do{
snej@0
   418
        SecKeychainItemRef found = NULL;
snej@0
   419
        OSStatus err = SecKeychainSearchCopyNext(_search, &found);
snej@0
   420
        if (err || !found) {
snej@0
   421
            if (err != errSecItemNotFound)
snej@0
   422
                check(err,@"SecKeychainSearchCopyNext");
snej@0
   423
            CFRelease(_search);
snej@0
   424
            _search = NULL;
snej@0
   425
            return nil;
snej@0
   426
        }
snej@0
   427
        
snej@0
   428
        switch (_itemClass) {
snej@0
   429
            case kSecPrivateKeyItemClass: {
snej@3
   430
                key = [[MYPrivateKey alloc] initWithKeyRef: (SecKeyRef)found];
snej@0
   431
                break;
snej@0
   432
            }
snej@0
   433
            case kSecCertificateItemClass:
snej@0
   434
                key = [[[MYCertificate alloc] initWithCertificateRef: (SecCertificateRef)found] autorelease];
snej@0
   435
                break;
snej@0
   436
            case kSecPublicKeyItemClass:
snej@0
   437
                key = [[[MYPublicKey alloc] initWithKeyRef: (SecKeyRef)found] autorelease];
snej@0
   438
                break;
snej@0
   439
        }
snej@0
   440
        CFRelease(found);
snej@0
   441
    } while (key==nil);
snej@0
   442
    return key;
snej@0
   443
}
snej@0
   444
snej@4
   445
@end
snej@4
   446
snej@4
   447
snej@4
   448
snej@4
   449
@implementation MYIdentityEnumerator
snej@4
   450
snej@4
   451
- (id) initWithKeychain: (MYKeychain*)keychain {
snej@4
   452
    self = [super init];
snej@4
   453
    if (self) {
snej@4
   454
        if (!check(SecIdentitySearchCreate(keychain.keychainRef, 0, &_searchRef),
snej@4
   455
                   @"SecIdentitySearchCreate")) {
snej@4
   456
            [self release];
snej@4
   457
            return nil;
snej@4
   458
        }
snej@4
   459
    }
snej@4
   460
    return self;
snej@4
   461
}
snej@4
   462
snej@4
   463
- (id) nextObject {
snej@4
   464
    SecIdentityRef identityRef = NULL;
snej@4
   465
    OSStatus err = SecIdentitySearchCopyNext(_searchRef, &identityRef);
snej@4
   466
    if (err==errKCItemNotFound || !check(err, @"SecIdentitySearchCopyNext"))
snej@4
   467
        return nil;
snej@4
   468
    return [[[MYIdentity alloc] initWithIdentityRef: identityRef] autorelease];
snej@4
   469
}
snej@0
   470
snej@0
   471
@end
snej@0
   472
snej@0
   473
snej@2
   474
#endif !MYCRYPTO_USE_IPHONE_API
snej@0
   475
snej@0
   476
snej@0
   477
snej@0
   478
/*
snej@0
   479
 Copyright (c) 2009, Jens Alfke <jens@mooseyard.com>. All rights reserved.
snej@0
   480
 
snej@0
   481
 Redistribution and use in source and binary forms, with or without modification, are permitted
snej@0
   482
 provided that the following conditions are met:
snej@0
   483
 
snej@0
   484
 * Redistributions of source code must retain the above copyright notice, this list of conditions
snej@0
   485
 and the following disclaimer.
snej@0
   486
 * Redistributions in binary form must reproduce the above copyright notice, this list of conditions
snej@0
   487
 and the following disclaimer in the documentation and/or other materials provided with the
snej@0
   488
 distribution.
snej@0
   489
 
snej@0
   490
 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
snej@0
   491
 IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND 
snej@0
   492
 FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRI-
snej@0
   493
 BUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
snej@0
   494
 (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 
snej@0
   495
  PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 
snej@0
   496
 CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF 
snej@0
   497
 THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
snej@0
   498
 */