Index: src/OFCryptoHash.h ================================================================== --- src/OFCryptoHash.h +++ src/OFCryptoHash.h @@ -42,10 +42,15 @@ /*! * @brief The block size of the cryptographic hash, in bytes. */ @property (readonly, nonatomic) size_t blockSize; +/*! + * @brief Whether data may be stored in swappable memory. + */ +@property (readonly, nonatomic) bool allowsSwappableMemory; + /*! * @brief A boolean whether the hash has already been calculated. */ @property (readonly, nonatomic, getter=isCalculated) bool calculated; @@ -59,13 +64,14 @@ OF_RETURNS_INNER_POINTER; /*! * @brief Creates a new cryptographic hash. * - * @return A new autoreleased OFCryptoHash + * @return A new autoreleased cryptographic hash */ -+ (instancetype)cryptoHash; ++ (instancetype)cryptoHashWithAllowsSwappableMemory: + (bool)allowsSwappableMemory; /*! * @brief Returns the digest size of the cryptographic hash, in bytes. * * @return The digest size of the cryptographic hash, in bytes @@ -77,10 +83,19 @@ * * @return The block size of the cryptographic hash, in bytes */ + (size_t)blockSize; +/*! + * @brief Initializes an already allocated cryptographic hash. + * + * @return An initialized cryptographic hash + */ +- (instancetype)initWithAllowsSwappableMemory: (bool)allowsSwappableMemory; + +- (instancetype)init OF_UNAVAILABLE; + /*! * @brief Adds a buffer to the cryptographic hash to be calculated. * * @param buffer The buffer which should be included into the calculation * @param length The length of the buffer Index: src/OFData+CryptoHashing.m ================================================================== --- src/OFData+CryptoHashing.m +++ src/OFData+CryptoHashing.m @@ -32,11 +32,12 @@ @implementation OFData (CryptoHashing) - (OFString *)of_cryptoHashWithClass: (Class )class { void *pool = objc_autoreleasePoolPush(); - id hash = [class cryptoHash]; + id hash = + [class cryptoHashWithAllowsSwappableMemory: true]; size_t digestSize = [class digestSize]; const unsigned char *digest; char cString[digestSize * 2]; [hash updateWithBuffer: _items Index: src/OFGZIPStream.m ================================================================== --- src/OFGZIPStream.m +++ src/OFGZIPStream.m @@ -49,11 +49,11 @@ @try { if (![mode isEqual: @"r"]) @throw [OFNotImplementedException exceptionWithSelector: _cmd - object: self]; + object: nil]; _stream = [stream retain]; _CRC32 = ~0; } @catch (id e) { [self release]; Index: src/OFHMAC.h ================================================================== --- src/OFHMAC.h +++ src/OFHMAC.h @@ -27,10 +27,11 @@ */ OF_SUBCLASSING_RESTRICTED @interface OFHMAC: OFObject { Class _hashClass; + bool _allowsSwappableMemory; id _Nullable _outerHash, _innerHash; id _Nullable _outerHashCopy, _innerHashCopy; bool _calculated; } @@ -37,10 +38,15 @@ /*! * @brief The class for the cryptographic hash used by the HMAC. */ @property (readonly, nonatomic) Class hashClass; +/*! + * @brief Whether data may be stored in swappable memory. + */ +@property (readonly, nonatomic) bool allowsSwappableMemory; + /*! * @brief A buffer containing the HMAC. * * The size of the buffer depends on the hash used. The buffer is part of the * receiver's memory pool. @@ -55,24 +61,28 @@ /*! * @brief Returns a new OFHMAC with the specified hashing algorithm. * * @param hashClass The class of the hashing algorithm + * @param allowsSwappableMemory Whether data may be stored in swappable memory * @return A new, autoreleased OFHMAC */ -+ (instancetype)HMACWithHashClass: (Class )hashClass; ++ (instancetype)HMACWithHashClass: (Class )hashClass + allowsSwappableMemory: (bool)allowsSwappableMemory; - (instancetype)init OF_UNAVAILABLE; /*! * @brief Initialized an already allocated OFHMAC with the specified hashing * algorithm. * * @param hashClass The class of the hashing algorithm + * @param allowsSwappableMemory Whether data may be stored in swappable memory * @return An initialized OFHMAC */ - (instancetype)initWithHashClass: (Class )hashClass + allowsSwappableMemory: (bool)allowsSwappableMemory OF_DESIGNATED_INITIALIZER; /*! * @brief Sets the key for the HMAC. * Index: src/OFHMAC.m ================================================================== --- src/OFHMAC.m +++ src/OFHMAC.m @@ -23,26 +23,32 @@ #import "OFHashAlreadyCalculatedException.h" #import "OFInvalidArgumentException.h" @implementation OFHMAC @synthesize hashClass = _hashClass; +@synthesize allowsSwappableMemory = _allowsSwappableMemory; + (instancetype)HMACWithHashClass: (Class )class + allowsSwappableMemory: (bool)allowsSwappableMemory { - return [[[self alloc] initWithHashClass: class] autorelease]; + return [[[self alloc] initWithHashClass: class + allowsSwappableMemory: allowsSwappableMemory] + autorelease]; } - (instancetype)init { OF_INVALID_INIT_METHOD } - (instancetype)initWithHashClass: (Class )class + allowsSwappableMemory: (bool)allowsSwappableMemory { self = [super init]; _hashClass = class; + _allowsSwappableMemory = allowsSwappableMemory; return self; } - (void)dealloc @@ -58,12 +64,16 @@ - (void)setKey: (const void *)key length: (size_t)length { void *pool = objc_autoreleasePoolPush(); size_t blockSize = [_hashClass blockSize]; - OFSecureData *outerKeyPad = [OFSecureData dataWithCount: blockSize]; - OFSecureData *innerKeyPad = [OFSecureData dataWithCount: blockSize]; + OFSecureData *outerKeyPad = [OFSecureData + dataWithCount: blockSize + allowsSwappableMemory: _allowsSwappableMemory]; + OFSecureData *innerKeyPad = [OFSecureData + dataWithCount: blockSize + allowsSwappableMemory: _allowsSwappableMemory]; unsigned char *outerKeyPadItems = outerKeyPad.mutableItems; unsigned char *innerKeyPadItems = innerKeyPad.mutableItems; [_outerHash release]; [_innerHash release]; @@ -71,11 +81,13 @@ [_innerHashCopy release]; _outerHash = _innerHash = _outerHashCopy = _innerHashCopy = nil; @try { if (length > blockSize) { - id hash = [_hashClass cryptoHash]; + id hash = [_hashClass + cryptoHashWithAllowsSwappableMemory: + _allowsSwappableMemory]; [hash updateWithBuffer: key length: length]; length = hash.digestSize; @@ -95,12 +107,14 @@ for (size_t i = 0; i < blockSize; i++) { outerKeyPadItems[i] ^= 0x5C; innerKeyPadItems[i] ^= 0x36; } - _outerHash = [[_hashClass cryptoHash] retain]; - _innerHash = [[_hashClass cryptoHash] retain]; + _outerHash = [[_hashClass cryptoHashWithAllowsSwappableMemory: + _allowsSwappableMemory] retain]; + _innerHash = [[_hashClass cryptoHashWithAllowsSwappableMemory: + _allowsSwappableMemory] retain]; [_outerHash updateWithBuffer: outerKeyPadItems length: blockSize]; [_innerHash updateWithBuffer: innerKeyPadItems length: blockSize]; Index: src/OFMD5Hash.h ================================================================== --- src/OFMD5Hash.h +++ src/OFMD5Hash.h @@ -37,10 +37,11 @@ uint8_t bytes[64]; uint32_t words[16]; } buffer; size_t bufferLength; } *_iVars; + bool _allowsSwappableMemory; bool _calculated; } @end OF_ASSUME_NONNULL_END Index: src/OFMD5Hash.m ================================================================== --- src/OFMD5Hash.m +++ src/OFMD5Hash.m @@ -122,10 +122,11 @@ state[3] += new[3]; } @implementation OFMD5Hash @synthesize calculated = _calculated; +@synthesize allowsSwappableMemory = _allowsSwappableMemory; + (size_t)digestSize { return DIGEST_SIZE; } @@ -133,32 +134,40 @@ + (size_t)blockSize { return BLOCK_SIZE; } -+ (instancetype)cryptoHash ++ (instancetype)cryptoHashWithAllowsSwappableMemory: (bool)allowsSwappableMemory { - return [[[self alloc] init] autorelease]; + return [[[self alloc] initWithAllowsSwappableMemory: + allowsSwappableMemory] autorelease]; } -- (instancetype)init +- (instancetype)initWithAllowsSwappableMemory: (bool)allowsSwappableMemory { self = [super init]; @try { _iVarsData = [[OFSecureData alloc] - initWithCount: sizeof(*_iVars)]; + initWithCount: sizeof(*_iVars) + allowsSwappableMemory: allowsSwappableMemory]; _iVars = _iVarsData.mutableItems; + _allowsSwappableMemory = allowsSwappableMemory; [self of_resetState]; } @catch (id e) { [self release]; @throw e; } return self; } + +- (instancetype)init +{ + OF_INVALID_INIT_METHOD +} - (instancetype)of_init { return [super init]; } @@ -184,10 +193,11 @@ { OFMD5Hash *copy = [[OFMD5Hash alloc] of_init]; copy->_iVarsData = [_iVarsData copy]; copy->_iVars = copy->_iVarsData.mutableItems; + copy->_allowsSwappableMemory = _allowsSwappableMemory; copy->_calculated = _calculated; return copy; } Index: src/OFRIPEMD160Hash.h ================================================================== --- src/OFRIPEMD160Hash.h +++ src/OFRIPEMD160Hash.h @@ -37,10 +37,11 @@ uint8_t bytes[64]; uint32_t words[16]; } buffer; size_t bufferLength; } *_iVars; + bool _allowsSwappableMemory; bool _calculated; } @end OF_ASSUME_NONNULL_END Index: src/OFRIPEMD160Hash.m ================================================================== --- src/OFRIPEMD160Hash.m +++ src/OFRIPEMD160Hash.m @@ -136,10 +136,11 @@ state[0] = new2[3]; } @implementation OFRIPEMD160Hash @synthesize calculated = _calculated; +@synthesize allowsSwappableMemory = _allowsSwappableMemory; + (size_t)digestSize { return DIGEST_SIZE; } @@ -147,32 +148,40 @@ + (size_t)blockSize { return BLOCK_SIZE; } -+ (instancetype)cryptoHash ++ (instancetype)cryptoHashWithAllowsSwappableMemory: (bool)allowsSwappableMemory { - return [[[self alloc] init] autorelease]; + return [[[self alloc] initWithAllowsSwappableMemory: + allowsSwappableMemory] autorelease]; } -- (instancetype)init +- (instancetype)initWithAllowsSwappableMemory: (bool)allowsSwappableMemory { self = [super init]; @try { _iVarsData = [[OFSecureData alloc] - initWithCount: sizeof(*_iVars)]; + initWithCount: sizeof(*_iVars) + allowsSwappableMemory: allowsSwappableMemory]; _iVars = _iVarsData.mutableItems; + _allowsSwappableMemory = allowsSwappableMemory; [self of_resetState]; } @catch (id e) { [self release]; @throw e; } return self; } + +- (instancetype)init +{ + OF_INVALID_INIT_METHOD +} - (instancetype)of_init { return [super init]; } @@ -198,10 +207,11 @@ { OFRIPEMD160Hash *copy = [[OFRIPEMD160Hash alloc] of_init]; copy->_iVarsData = [_iVarsData copy]; copy->_iVars = copy->_iVarsData.mutableItems; + copy->_allowsSwappableMemory = _allowsSwappableMemory; copy->_calculated = _calculated; return copy; } Index: src/OFSHA1Hash.h ================================================================== --- src/OFSHA1Hash.h +++ src/OFSHA1Hash.h @@ -37,10 +37,11 @@ uint8_t bytes[64]; uint32_t words[80]; } buffer; size_t bufferLength; } *_iVars; + bool _allowsSwappableMemory; bool _calculated; } @end OF_ASSUME_NONNULL_END Index: src/OFSHA1Hash.m ================================================================== --- src/OFSHA1Hash.m +++ src/OFSHA1Hash.m @@ -96,10 +96,11 @@ state[4] += new[4]; } @implementation OFSHA1Hash @synthesize calculated = _calculated; +@synthesize allowsSwappableMemory = _allowsSwappableMemory; + (size_t)digestSize { return DIGEST_SIZE; } @@ -107,32 +108,40 @@ + (size_t)blockSize { return BLOCK_SIZE; } -+ (instancetype)cryptoHash ++ (instancetype)cryptoHashWithAllowsSwappableMemory: (bool)allowsSwappableMemory { - return [[[self alloc] init] autorelease]; + return [[[self alloc] initWithAllowsSwappableMemory: + allowsSwappableMemory] autorelease]; } -- (instancetype)init +- (instancetype)initWithAllowsSwappableMemory: (bool)allowsSwappableMemory { self = [super init]; @try { _iVarsData = [[OFSecureData alloc] - initWithCount: sizeof(*_iVars)]; + initWithCount: sizeof(*_iVars) + allowsSwappableMemory: allowsSwappableMemory]; _iVars = _iVarsData.mutableItems; + _allowsSwappableMemory = allowsSwappableMemory; [self of_resetState]; } @catch (id e) { [self release]; @throw e; } return self; } + +- (instancetype)init +{ + OF_INVALID_INIT_METHOD +} - (instancetype)of_init { return [super init]; } @@ -158,10 +167,11 @@ { OFSHA1Hash *copy = [[OFSHA1Hash alloc] of_init]; copy->_iVarsData = [_iVarsData copy]; copy->_iVars = copy->_iVarsData.mutableItems; + copy->_allowsSwappableMemory = _allowsSwappableMemory; copy->_calculated = _calculated; return copy; } Index: src/OFSHA224Or256Hash.h ================================================================== --- src/OFSHA224Or256Hash.h +++ src/OFSHA224Or256Hash.h @@ -39,11 +39,12 @@ uint32_t words[64]; } buffer; size_t bufferLength; } *_iVars; @private + bool _allowsSwappableMemory; bool _calculated; OF_RESERVE_IVARS(4) } @end OF_ASSUME_NONNULL_END Index: src/OFSHA224Or256Hash.m ================================================================== --- src/OFSHA224Or256Hash.m +++ src/OFSHA224Or256Hash.m @@ -117,10 +117,11 @@ state[7] += new[7]; } @implementation OFSHA224Or256Hash @synthesize calculated = _calculated; +@synthesize allowsSwappableMemory = _allowsSwappableMemory; + (size_t)digestSize { OF_UNRECOGNIZED_SELECTOR } @@ -128,23 +129,26 @@ + (size_t)blockSize { return BLOCK_SIZE; } -+ (instancetype)cryptoHash ++ (instancetype)cryptoHashWithAllowsSwappableMemory: (bool)allowsSwappableMemory { - return [[[self alloc] init] autorelease]; + return [[[self alloc] initWithAllowsSwappableMemory: + allowsSwappableMemory] autorelease]; } -- (instancetype)init +- (instancetype)initWithAllowsSwappableMemory: (bool)allowsSwappableMemory { self = [super init]; @try { _iVarsData = [[OFSecureData alloc] - initWithCount: sizeof(*_iVars)]; + initWithCount: sizeof(*_iVars) + allowsSwappableMemory: allowsSwappableMemory]; _iVars = _iVarsData.mutableItems; + _allowsSwappableMemory = allowsSwappableMemory; if (self.class == [OFSHA224Or256Hash class]) { [self doesNotRecognizeSelector: _cmd]; abort(); } @@ -155,10 +159,15 @@ @throw e; } return self; } + +- (instancetype)init +{ + OF_INVALID_INIT_METHOD +} - (instancetype)of_init { return [super init]; } @@ -184,10 +193,11 @@ { OFSHA224Or256Hash *copy = [[[self class] alloc] of_init]; copy->_iVarsData = [_iVarsData copy]; copy->_iVars = copy->_iVarsData.mutableItems; + copy->_allowsSwappableMemory = _allowsSwappableMemory; copy->_calculated = _calculated; return copy; } Index: src/OFSHA384Or512Hash.h ================================================================== --- src/OFSHA384Or512Hash.h +++ src/OFSHA384Or512Hash.h @@ -39,11 +39,12 @@ uint64_t words[80]; } buffer; size_t bufferLength; } *_iVars; @private + bool _allowsSwappableMemory; bool _calculated; OF_RESERVE_IVARS(4) } @end OF_ASSUME_NONNULL_END Index: src/OFSHA384Or512Hash.m ================================================================== --- src/OFSHA384Or512Hash.m +++ src/OFSHA384Or512Hash.m @@ -128,10 +128,11 @@ state[7] += new[7]; } @implementation OFSHA384Or512Hash @synthesize calculated = _calculated; +@synthesize allowsSwappableMemory = _allowsSwappableMemory; + (size_t)digestSize { OF_UNRECOGNIZED_SELECTOR } @@ -139,23 +140,26 @@ + (size_t)blockSize { return BLOCK_SIZE; } -+ (instancetype)cryptoHash ++ (instancetype)cryptoHashWithAllowsSwappableMemory: (bool)allowsSwappableMemory { - return [[[self alloc] init] autorelease]; + return [[[self alloc] initWithAllowsSwappableMemory: + allowsSwappableMemory] autorelease]; } -- (instancetype)init +- (instancetype)initWithAllowsSwappableMemory: (bool)allowsSwappableMemory { self = [super init]; @try { _iVarsData = [[OFSecureData alloc] - initWithCount: sizeof(*_iVars)]; + initWithCount: sizeof(*_iVars) + allowsSwappableMemory: allowsSwappableMemory]; _iVars = _iVarsData.mutableItems; + _allowsSwappableMemory = allowsSwappableMemory; if (self.class == [OFSHA384Or512Hash class]) { [self doesNotRecognizeSelector: _cmd]; abort(); } @@ -166,10 +170,15 @@ @throw e; } return self; } + +- (instancetype)init +{ + OF_INVALID_INIT_METHOD +} - (instancetype)of_init { return [super init]; } @@ -195,10 +204,11 @@ { OFSHA384Or512Hash *copy = [[[self class] alloc] of_init]; copy->_iVarsData = [_iVarsData copy]; copy->_iVars = copy->_iVarsData.mutableItems; + copy->_allowsSwappableMemory = _allowsSwappableMemory; copy->_calculated = _calculated; return copy; } Index: src/OFSecureData.h ================================================================== --- src/OFSecureData.h +++ src/OFSecureData.h @@ -32,17 +32,17 @@ */ OF_SUBCLASSING_RESTRICTED @interface OFSecureData: OFData { struct page *_page; - bool _swappable; + bool _allowsSwappableMemory; } /*! - * @brief Whether the OFSecureData is in swappable memory. + * @brief Whether the data may be stored in swappable memory. */ -@property (readonly, nonatomic, getter=isSwappable) bool swappable; +@property (readonly, nonatomic) bool allowsSwappableMemory; /*! * @brief All items of the OFSecureData as a C array. * * Modifying the returned array directly is allowed and will change the contents @@ -49,70 +49,114 @@ * of the data. */ @property (readonly, nonatomic) void *mutableItems OF_RETURNS_INNER_POINTER; /*! - * @brief Preallocates the specified number of bytes. + * @brief Preallocates the specified number of bytes for unswappable memory. * - * This is useful to allocate secure memory before enabling a sandbox that does - * not allow it anymore. + * This is useful to allocate unswappable memory before enabling a sandbox that + * does not allow it anymore. * * @note This may only be called once per thread! - * @note Preallocated memory is only available for OFSecureData that is smaller - * than a single page! + * @note Preallocated unswappable memory is only available for data that is + * smaller than a single page! * - * @param size The number of bytes to preallocate + * @param size The number of bytes of unswappable memory to preallocate */ -+ (void)preallocateMemoryWithSize: (size_t)size; ++ (void)preallocateUnswappableMemoryWithSize: (size_t)size; /*! * @brief Creates a new, autoreleased OFSecureData with count items of item * size 1, all set to zero. * * @param count The number of zero items the OFSecureData should contain + * @param allowsSwappableMemory Whether the data may be stored in swappable + * memory * @return A new, autoreleased OFSecureData */ -+ (instancetype)dataWithCount: (size_t)count; ++ (instancetype)dataWithCount: (size_t)count + allowsSwappableMemory: (bool)allowsSwappableMemory; /*! * @brief Creates a new, autoreleased OFSecureData with count items of the * specified item size, all set to zero. * * @param itemSize The size of a single item in the OFSecureData in bytes * @param count The number of zero items the OFSecureData should contain + * @param allowsSwappableMemory Whether the data may be stored in swappable + * memory * @return A new, autoreleased OFSecureData */ + (instancetype)dataWithItemSize: (size_t)itemSize - count: (size_t)count; + count: (size_t)count + allowsSwappableMemory: (bool)allowsSwappableMemory; ++ (instancetype)dataWithItems: (const void *)items + count: (size_t)count OF_UNAVAILABLE; ++ (instancetype)dataWithItems: (const void *)items + itemSize: (size_t)itemSize + count: (size_t)count OF_UNAVAILABLE; ++ (instancetype)dataWithItemsNoCopy: (void *)items + count: (size_t)count + freeWhenDone: (bool)freeWhenDone OF_UNAVAILABLE; ++ (instancetype)dataWithItemsNoCopy: (void *)items + itemSize: (size_t)itemSize + count: (size_t)count + freeWhenDone: (bool)freeWhenDone OF_UNAVAILABLE; #ifdef OF_HAVE_FILES + (instancetype)dataWithContentsOfFile: (OFString *)path OF_UNAVAILABLE; #endif + (instancetype)dataWithContentsOfURL: (OFURL *)URL OF_UNAVAILABLE; + (instancetype)dataWithStringRepresentation: (OFString *)string OF_UNAVAILABLE; + (instancetype)dataWithBase64EncodedString: (OFString *)string OF_UNAVAILABLE; -+ (instancetype)dataWithSerialization: (OFXMLElement *)element OF_UNAVAILABLE; /*! * @brief Initializes an already allocated OFSecureData with count items of * item size 1, all set to zero. * * @param count The number of zero items the OFSecureData should contain + * @param allowsSwappableMemory Whether the data may be stored in swappable + * memory * @return An initialized OFSecureData */ -- (instancetype)initWithCount: (size_t)count; +- (instancetype)initWithCount: (size_t)count + allowsSwappableMemory: (bool)allowsSwappableMemory; /*! * @brief Initializes an already allocated OFSecureData with count items of the * specified item size, all set to zero. * * @param itemSize The size of a single item in the OFSecureData in bytes * @param count The number of zero items the OFSecureData should contain + * @param allowsSwappableMemory Whether the data may be stored in swappable + * memory * @return An initialized OFSecureData */ - (instancetype)initWithItemSize: (size_t)itemSize - count: (size_t)count; + count: (size_t)count + allowsSwappableMemory: (bool)allowsSwappableMemory + OF_DESIGNATED_INITIALIZER; + +- (instancetype)initWithItems: (const void *)items + count: (size_t)count OF_UNAVAILABLE; +- (instancetype)initWithItems: (const void *)items + itemSize: (size_t)itemSize + count: (size_t)count OF_UNAVAILABLE; +- (instancetype)initWithItemsNoCopy: (void *)items + count: (size_t)count + freeWhenDone: (bool)freeWhenDone OF_UNAVAILABLE; +- (instancetype)initWithItemsNoCopy: (void *)items + itemSize: (size_t)itemSize + count: (size_t)count + freeWhenDone: (bool)freeWhenDone OF_UNAVAILABLE; +#ifdef OF_HAVE_FILES +- (instancetype)initWithContentsOfFile: (OFString *)path OF_UNAVAILABLE; +#endif +- (instancetype)initWithContentsOfURL: (OFURL *)URL OF_UNAVAILABLE; +- (instancetype)initWithStringRepresentation: (OFString *)string OF_UNAVAILABLE; +- (instancetype)initWithBase64EncodedString: (OFString *)string OF_UNAVAILABLE; +- (instancetype)initWithSerialization: (OFXMLElement *)element OF_UNAVAILABLE; /*! * @brief Returns a specific item of the OFSecureData. * * Modifying the returned item directly is allowed and will change the contents Index: src/OFSecureData.m ================================================================== --- src/OFSecureData.m +++ src/OFSecureData.m @@ -28,122 +28,114 @@ #import "OFString.h" #import "OFSystemInfo.h" #import "OFInitializationFailedException.h" #import "OFInvalidArgumentException.h" +#import "OFNotImplementedException.h" #import "OFOutOfMemoryException.h" #import "OFOutOfRangeException.h" #ifdef OF_HAVE_THREADS # import "tlskey.h" #endif #define CHUNK_SIZE 16 +#if defined(HAVE_MMAP) && defined(HAVE_MLOCK) && defined(MAP_ANON) struct page { struct page *next, *previous; void *map; - bool swappable; unsigned char *page; }; -#if defined(OF_HAVE_COMPILER_TLS) +# if defined(OF_HAVE_COMPILER_TLS) static thread_local struct page *firstPage = NULL; static thread_local struct page *lastPage = NULL; static thread_local struct page **preallocatedPages = NULL; static thread_local size_t numPreallocatedPages = 0; -#elif defined(OF_HAVE_THREADS) +# elif defined(OF_HAVE_THREADS) static of_tlskey_t firstPageKey, lastPageKey; static of_tlskey_t preallocatedPagesKey, numPreallocatedPagesKey; -#else +# else static struct page *firstPage = NULL; static struct page *lastPage = NULL; static struct page **preallocatedPages = NULL; static size_t numPreallocatedPages = 0; -#endif +# endif static void * -mapPages(size_t numPages, bool *swappable) +mapPages(size_t numPages) { size_t pageSize = [OFSystemInfo pageSize]; void *pointer; if (numPages > SIZE_MAX / pageSize) @throw [OFOutOfRangeException exception]; -#if defined(HAVE_MMAP) && defined(HAVE_MLOCK) && defined(MAP_ANON) if ((pointer = mmap(NULL, numPages * pageSize, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANON, -1, 0)) == MAP_FAILED) @throw [OFOutOfMemoryException - exceptionWithRequestedSize: pageSize]; + exceptionWithRequestedSize: numPages * pageSize]; - *swappable = (mlock(pointer, numPages * pageSize) != 0); -#else - if ((pointer = malloc(numPages * pageSize)) == NULL) + if (mlock(pointer, numPages * pageSize) != 0) { + munmap(pointer, numPages * pageSize); @throw [OFOutOfMemoryException - exceptionWithRequestedSize: pageSize]; - - *swappable = true; -#endif + exceptionWithRequestedSize: numPages * pageSize]; + } return pointer; } static void -unmapPages(void *pointer, size_t numPages, bool swappable) +unmapPages(void *pointer, size_t numPages) { size_t pageSize = [OFSystemInfo pageSize]; if (numPages > SIZE_MAX / pageSize) @throw [OFOutOfRangeException exception]; -#if defined(HAVE_MMAP) && defined(HAVE_MLOCK) && defined(MAP_ANON) - if (!swappable) - munlock(pointer, numPages * pageSize); + munlock(pointer, numPages * pageSize); munmap(pointer, numPages * pageSize); -#else - free(pointer); -#endif } static struct page * addPage(bool allowPreallocated) { size_t pageSize = [OFSystemInfo pageSize]; size_t mapSize = OF_ROUND_UP_POW2(8, pageSize / CHUNK_SIZE) / 8; struct page *page; -#if !defined(OF_HAVE_COMPILER_TLS) && defined(OF_HAVE_THREADS) +# if !defined(OF_HAVE_COMPILER_TLS) && defined(OF_HAVE_THREADS) struct page *lastPage; -#endif +# endif if (allowPreallocated) { -#if !defined(OF_HAVE_COMPILER_TLS) && defined(OF_HAVE_THREADS) +# if !defined(OF_HAVE_COMPILER_TLS) && defined(OF_HAVE_THREADS) uintptr_t numPreallocatedPages = (uintptr_t)of_tlskey_get(numPreallocatedPagesKey); -#endif +# endif if (numPreallocatedPages > 0) { -#if !defined(OF_HAVE_COMPILER_TLS) && defined(OF_HAVE_THREADS) +# if !defined(OF_HAVE_COMPILER_TLS) && defined(OF_HAVE_THREADS) struct page **preallocatedPages = of_tlskey_get(preallocatedPagesKey); -#endif +# endif numPreallocatedPages--; -#if !defined(OF_HAVE_COMPILER_TLS) && defined(OF_HAVE_THREADS) +# if !defined(OF_HAVE_COMPILER_TLS) && defined(OF_HAVE_THREADS) OF_ENSURE(of_tlskey_set(numPreallocatedPagesKey, (void *)numPreallocatedPages)); -#endif +# endif page = preallocatedPages[numPreallocatedPages]; if (numPreallocatedPages == 0) { free(preallocatedPages); preallocatedPages = NULL; -#if !defined(OF_HAVE_COMPILER_TLS) && defined(OF_HAVE_THREADS) +# if !defined(OF_HAVE_COMPILER_TLS) && defined(OF_HAVE_THREADS) OF_ENSURE(of_tlskey_set(preallocatedPagesKey, preallocatedPages)); -#endif +# endif } return page; } } @@ -154,34 +146,34 @@ if ((page->map = calloc(1, mapSize)) == NULL) @throw [OFOutOfMemoryException exceptionWithRequestedSize: mapSize]; - page->page = mapPages(1, &page->swappable); + page->page = mapPages(1); of_explicit_memset(page->page, 0, pageSize); -#if !defined(OF_HAVE_COMPILER_TLS) && defined(OF_HAVE_THREADS) +# if !defined(OF_HAVE_COMPILER_TLS) && defined(OF_HAVE_THREADS) lastPage = of_tlskey_get(lastPageKey); -#endif +# endif page->previous = lastPage; page->next = NULL; if (lastPage != NULL) lastPage->next = page; -#if defined(OF_HAVE_COMPILER_TLS) || !defined(OF_HAVE_THREADS) +# if defined(OF_HAVE_COMPILER_TLS) || !defined(OF_HAVE_THREADS) lastPage = page; if (firstPage == NULL) firstPage = page; -#else +# else OF_ENSURE(of_tlskey_set(lastPageKey, page)); if (of_tlskey_get(firstPageKey) == NULL) OF_ENSURE(of_tlskey_set(firstPageKey, page)); -#endif +# endif return page; } static void @@ -193,29 +185,29 @@ for (size_t i = 0; i < mapSize; i++) if (map[i] != 0) return; - unmapPages(page->page, 1, page->swappable); + unmapPages(page->page, 1); free(page->map); if (page->previous != NULL) page->previous->next = page->next; if (page->next != NULL) page->next->previous = page->previous; -#if defined(OF_HAVE_COMPILER_TLS) || !defined(OF_HAVE_THREADS) +# if defined(OF_HAVE_COMPILER_TLS) || !defined(OF_HAVE_THREADS) if (firstPage == page) firstPage = page->next; if (lastPage == page) lastPage = page->previous; -#else +# else if (of_tlskey_get(firstPageKey) == page) OF_ENSURE(of_tlskey_set(firstPageKey, page->next)); if (of_tlskey_get(lastPageKey) == page) OF_ENSURE(of_tlskey_set(lastPageKey, page->previous)); -#endif +# endif free(page); } static void * @@ -261,13 +253,14 @@ of_explicit_memset(pointer, 0, bytes); for (size_t i = 0; i < chunks; i++) of_bitset_clear(page->map, chunkIndex + i); } +#endif @implementation OFSecureData -@synthesize swappable = _swappable; +@synthesize allowsSwappableMemory = _allowsSwappableMemory; #if !defined(OF_HAVE_COMPILER_TLS) && defined(OF_HAVE_THREADS) + (void)initialize { if (self != [OFSecureData class]) @@ -279,51 +272,90 @@ @throw [OFInitializationFailedException exceptionWithClass: self]; } #endif -+ (void)preallocateMemoryWithSize: (size_t)size ++ (void)preallocateUnswappableMemoryWithSize: (size_t)size { +#if defined(HAVE_MMAP) && defined(HAVE_MLOCK) && defined(MAP_ANON) size_t pageSize = [OFSystemInfo pageSize]; size_t numPages = OF_ROUND_UP_POW2(pageSize, size) / pageSize; -#if !defined(OF_HAVE_COMPILER_TLS) && defined(OF_HAVE_THREADS) +# if !defined(OF_HAVE_COMPILER_TLS) && defined(OF_HAVE_THREADS) struct page **preallocatedPages = of_tlskey_get(preallocatedPagesKey); size_t numPreallocatedPages; -#endif +# endif if (preallocatedPages != NULL) @throw [OFInvalidArgumentException exception]; preallocatedPages = calloc(numPages, sizeof(struct page)); if (preallocatedPages == NULL) @throw [OFOutOfMemoryException exceptionWithRequestedSize: numPages * sizeof(struct page)]; -#if !defined(OF_HAVE_COMPILER_TLS) && defined(OF_HAVE_THREADS) +# if !defined(OF_HAVE_COMPILER_TLS) && defined(OF_HAVE_THREADS) of_tlskey_set(preallocatedPagesKey, preallocatedPages); -#endif +# endif for (size_t i = 0; i < numPages; i++) preallocatedPages[i] = addPage(false); numPreallocatedPages = numPages; -#if !defined(OF_HAVE_COMPILER_TLS) && defined(OF_HAVE_THREADS) +# if !defined(OF_HAVE_COMPILER_TLS) && defined(OF_HAVE_THREADS) of_tlskey_set(numPreallocatedPagesKey, (void *)(uintptr_t)numPreallocatedPages); +# endif +#else + @throw [OFNotImplementedException exceptionWithSelector: _cmd + object: self]; #endif } + (instancetype)dataWithCount: (size_t)count + allowsSwappableMemory: (bool)allowsSwappableMemory { - return [[[self alloc] initWithCount: count] autorelease]; + return [[[self alloc] initWithCount: count + allowsSwappableMemory: allowsSwappableMemory] + autorelease]; } + (instancetype)dataWithItemSize: (size_t)itemSize count: (size_t)count + allowsSwappableMemory: (bool)allowsSwappableMemory { return [[[self alloc] initWithItemSize: itemSize - count: count] autorelease]; + count: count + allowsSwappableMemory: allowsSwappableMemory] + autorelease]; +} + ++ (instancetype)dataWithItems: (const void *)items + count: (size_t)count +{ + OF_UNRECOGNIZED_SELECTOR +} + ++ (instancetype)dataWithItems: (const void *)items + itemSize: (size_t)itemSize + count: (size_t)count +{ + OF_UNRECOGNIZED_SELECTOR +} + ++ (instancetype)dataWithItemsNoCopy: (void *)items + count: (size_t)count + freeWhenDone: (bool)freeWhenDone +{ + OF_UNRECOGNIZED_SELECTOR +} + ++ (instancetype)dataWithItemsNoCopy: (void *)items + itemSize: (size_t)itemSize + count: (size_t)count + freeWhenDone: (bool)freeWhenDone +{ + OF_UNRECOGNIZED_SELECTOR } #ifdef OF_HAVE_FILES + (instancetype)dataWithContentsOfFile: (OFString *)path { @@ -344,39 +376,43 @@ + (instancetype)dataWithBase64EncodedString: (OFString *)string { OF_UNRECOGNIZED_SELECTOR } -+ (instancetype)dataWithSerialization: (OFXMLElement *)element -{ - OF_UNRECOGNIZED_SELECTOR -} - (instancetype)initWithCount: (size_t)count + allowsSwappableMemory: (bool)allowsSwappableMemory { return [self initWithItemSize: 1 - count: count]; + count: count + allowsSwappableMemory: allowsSwappableMemory]; } - (instancetype)initWithItemSize: (size_t)itemSize count: (size_t)count + allowsSwappableMemory: (bool)allowsSwappableMemory { self = [super init]; @try { size_t pageSize = [OFSystemInfo pageSize]; if (count > SIZE_MAX / itemSize) @throw [OFOutOfRangeException exception]; - if (count * itemSize >= pageSize) + if (allowsSwappableMemory) { + _items = [self allocMemoryWithSize: itemSize + count: count]; + memset(_items, 0, count * itemSize); + } else if (count * itemSize >= pageSize) _items = mapPages(OF_ROUND_UP_POW2(pageSize, - count * itemSize) / pageSize, &_swappable); + count * itemSize) / pageSize); else { -#if !defined(OF_HAVE_COMPILER_TLS) && defined(OF_HAVE_THREADS) +#if defined(HAVE_MMAP) && defined(HAVE_MLOCK) && defined(MAP_ANON) +# if !defined(OF_HAVE_COMPILER_TLS) && defined(OF_HAVE_THREADS) struct page *lastPage = of_tlskey_get(lastPageKey); -#endif +# endif for (struct page *page = lastPage; page != NULL; page = page->previous) { _items = allocateMemory(page, count * itemSize); @@ -394,51 +430,54 @@ if (_items == NULL) @throw [OFOutOfMemoryException exceptionWithRequestedSize: count * itemSize]; } - - _swappable = _page->swappable; +#else + @throw [OFNotImplementedException + exceptionWithSelector: _cmd + object: nil]; +#endif } _itemSize = itemSize; _count = count; + _allowsSwappableMemory = allowsSwappableMemory; } @catch (id e) { [self release]; @throw e; } return self; } + +- (instancetype)initWithItems: (const void *)items + count: (size_t)count +{ + OF_INVALID_INIT_METHOD +} - (instancetype)initWithItems: (const void *)items itemSize: (size_t)itemSize count: (size_t)count { - self = [self initWithItemSize: itemSize - count: count]; + OF_INVALID_INIT_METHOD +} - memcpy(_items, items, count * itemSize); - - return self; +- (instancetype)initWithItemsNoCopy: (void *)items + count: (size_t)count + freeWhenDone: (bool)freeWhenDone +{ + OF_INVALID_INIT_METHOD } - (instancetype)initWithItemsNoCopy: (void *)items itemSize: (size_t)itemSize count: (size_t)count freeWhenDone: (bool)freeWhenDone { - self = [self initWithItems: items - itemSize: itemSize - count: count]; - - if (freeWhenDone) { - of_explicit_memset(items, 0, count * itemSize); - free(items); - } - - return self; + OF_INVALID_INIT_METHOD } #ifdef OF_HAVE_FILES - (instancetype)initWithContentsOfFile: (OFString *)path { @@ -466,22 +505,28 @@ OF_INVALID_INIT_METHOD } - (void)dealloc { - size_t pageSize = [OFSystemInfo pageSize]; - - if (_count * _itemSize > pageSize) - unmapPages(_items, - OF_ROUND_UP_POW2(pageSize, _count * _itemSize) / pageSize, - _swappable); - else if (_page != NULL) { - if (_items != NULL) - freeMemory(_page, _items, _count * _itemSize); - - removePageIfEmpty(_page); - } + [self zero]; + +#if defined(HAVE_MMAP) && defined(HAVE_MLOCK) && defined(MAP_ANON) + if (!_allowsSwappableMemory) { + size_t pageSize = [OFSystemInfo pageSize]; + + if (_count * _itemSize > pageSize) + unmapPages(_items, + OF_ROUND_UP_POW2(pageSize, _count * _itemSize) / + pageSize); + else if (_page != NULL) { + if (_items != NULL) + freeMemory(_page, _items, _count * _itemSize); + + removePageIfEmpty(_page); + } + } +#endif [super dealloc]; } - (void *)mutableItems @@ -502,20 +547,30 @@ of_explicit_memset(_items, 0, _count * _itemSize); } - (id)copy { - return [[OFSecureData alloc] initWithItems: _items - itemSize: _itemSize - count: _count]; + OFSecureData *copy = [[OFSecureData alloc] + initWithItemSize: _itemSize + count: _count + allowsSwappableMemory: _allowsSwappableMemory]; + + memcpy(copy.mutableItems, _items, _count * _itemSize); + + return copy; } - (id)mutableCopy { - return [[OFSecureData alloc] initWithItems: _items - itemSize: _itemSize - count: _count]; + OFSecureData *copy = [[OFSecureData alloc] + initWithItemSize: _itemSize + count: _count + allowsSwappableMemory: _allowsSwappableMemory]; + + memcpy(copy.mutableItems, _items, _count * _itemSize); + + return copy; } - (bool)isEqual: (id)object { OFData *otherData; Index: src/OFString+CryptoHashing.m ================================================================== --- src/OFString+CryptoHashing.m +++ src/OFString+CryptoHashing.m @@ -31,11 +31,12 @@ @implementation OFString (CryptoHashing) - (OFString *)of_cryptoHashWithClass: (Class )class { void *pool = objc_autoreleasePoolPush(); - id hash = [class cryptoHash]; + id hash = [class + cryptoHashWithAllowsSwappableMemory: true]; size_t digestSize = [class digestSize]; const unsigned char *digest; char cString[digestSize * 2]; [hash updateWithBuffer: self.UTF8String Index: src/OFZIPArchive.m ================================================================== --- src/OFZIPArchive.m +++ src/OFZIPArchive.m @@ -752,11 +752,11 @@ initWithStream: stream]; break; default: @throw [OFNotImplementedException exceptionWithSelector: _cmd - object: self]; + object: nil]; } _entry = [entry copy]; _toRead = entry.uncompressedSize; _CRC32 = ~0; Index: src/exceptions/OFNotImplementedException.h ================================================================== --- src/exceptions/OFNotImplementedException.h +++ src/exceptions/OFNotImplementedException.h @@ -27,11 +27,11 @@ * implemented. */ @interface OFNotImplementedException: OFException { SEL _selector; - id _object; + id _Nullable _object; } /*! * @brief The selector which is not or not fully implemented. */ @@ -50,11 +50,11 @@ * @param selector The selector which is not or not fully implemented * @param object The object which does not (fully) implement the selector * @return A new, autoreleased not implemented exception */ + (instancetype)exceptionWithSelector: (SEL)selector - object: (id)object; + object: (nullable id)object; - (instancetype)init OF_UNAVAILABLE; /*! * @brief Initializes an already allocated not implemented exception. @@ -62,9 +62,9 @@ * @param selector The selector which is not or not fully implemented * @param object The object which does not (fully) implement the selector * @return An initialized not implemented exception */ - (instancetype)initWithSelector: (SEL)selector - object: (id)object OF_DESIGNATED_INITIALIZER; + object: (nullable id)object OF_DESIGNATED_INITIALIZER; @end OF_ASSUME_NONNULL_END Index: src/exceptions/OFNotImplementedException.m ================================================================== --- src/exceptions/OFNotImplementedException.m +++ src/exceptions/OFNotImplementedException.m @@ -58,10 +58,17 @@ [super dealloc]; } - (OFString *)description { - return [OFString stringWithFormat: - @"The selector %s is not understood by an object of type %@ or not " - @"(fully) implemented!", sel_getName(_selector), [_object class]]; + if (_object != nil) + return [OFString stringWithFormat: + @"The selector %s is not understood by an object of type " + @"%@ or not (fully) implemented!", + sel_getName(_selector), [_object class]]; + else + return [OFString stringWithFormat: + @"The selector %s is not understood by an unknown object " + @"or not (fully) implemented!", + sel_getName(_selector)]; } @end Index: src/pbkdf2.h ================================================================== --- src/pbkdf2.h +++ src/pbkdf2.h @@ -48,15 +48,16 @@ * @param password The password to derive a key from * @param passwordLength The length of the password * @param key The buffer to write the key to * @param keyLength The desired length for the derived key (key needs to have * enough storage) + * @param allowsSwappableMemory Whether data may be stored in swappable memory */ extern void of_pbkdf2(OFHMAC *HMAC, size_t iterations, const unsigned char *salt, size_t saltLength, const char *password, size_t passwordLength, - unsigned char *key, size_t keyLength); + unsigned char *key, size_t keyLength, bool allowsSwappableMemory); #ifdef __cplusplus } #endif OF_ASSUME_NONNULL_END Index: src/pbkdf2.m ================================================================== --- src/pbkdf2.m +++ src/pbkdf2.m @@ -29,16 +29,20 @@ #import "pbkdf2.h" void of_pbkdf2(OFHMAC *HMAC, size_t iterations, const unsigned char *salt, size_t saltLength, const char *password, size_t passwordLength, - unsigned char *key, size_t keyLength) + unsigned char *key, size_t keyLength, bool allowsSwappableMemory) { void *pool = objc_autoreleasePoolPush(); size_t blocks, digestSize = HMAC.digestSize; - OFSecureData *buffer = [OFSecureData dataWithCount: digestSize]; - OFSecureData *digest = [OFSecureData dataWithCount: digestSize]; + OFSecureData *buffer = [OFSecureData + dataWithCount: digestSize + allowsSwappableMemory: allowsSwappableMemory]; + OFSecureData *digest = [OFSecureData + dataWithCount: digestSize + allowsSwappableMemory: allowsSwappableMemory]; unsigned char *bufferItems = buffer.mutableItems; unsigned char *digestItems = digest.mutableItems; OFSecureData *extendedSalt; unsigned char *extendedSaltItems; @@ -51,11 +55,12 @@ blocks++; if (saltLength > SIZE_MAX - 4 || blocks > UINT32_MAX) @throw [OFOutOfRangeException exception]; - extendedSalt = [OFSecureData dataWithCount: saltLength + 4]; + extendedSalt = [OFSecureData dataWithCount: saltLength + 4 + allowsSwappableMemory: allowsSwappableMemory]; extendedSaltItems = extendedSalt.mutableItems; @try { uint32_t i = OF_BSWAP32_IF_LE(1); Index: src/scrypt.h ================================================================== --- src/scrypt.h +++ src/scrypt.h @@ -39,11 +39,11 @@ extern void of_scrypt_romix(uint32_t *buffer, size_t blockSize, size_t costFactor, uint32_t *tmp); extern void of_scrypt(size_t blockSize, size_t costFactor, size_t parallelization, const unsigned char *salt, size_t saltLength, const char *password, size_t passwordLength, - unsigned char *key, size_t keyLength); + unsigned char *key, size_t keyLength, bool allowsSwappableMemory); #ifdef __cplusplus } #endif OF_ASSUME_NONNULL_END Index: src/scrypt.m ================================================================== --- src/scrypt.m +++ src/scrypt.m @@ -17,10 +17,11 @@ #include "config.h" #import "OFHMAC.h" #import "OFSHA256Hash.h" +#import "OFSecureData.h" #import "OFInvalidArgumentException.h" #import "OFOutOfMemoryException.h" #import "OFOutOfRangeException.h" @@ -139,13 +140,13 @@ } void of_scrypt(size_t blockSize, size_t costFactor, size_t parallelization, const unsigned char *salt, size_t saltLength, const char *password, size_t passwordLength, - unsigned char *key, size_t keyLength) + unsigned char *key, size_t keyLength, bool allowsSwappableMemory) { - uint32_t *tmp = NULL, *buffer = NULL; + OFSecureData *tmp = nil, *buffer = nil; OFHMAC *HMAC = nil; if (blockSize == 0 || costFactor <= 1 || (costFactor & (costFactor - 1)) != 0 || parallelization == 0) @throw [OFInvalidArgumentException exception]; @@ -157,47 +158,47 @@ */ OVERFLOW_CHECK_1 OVERFLOW_CHECK_2 @try { - if (costFactor > SIZE_MAX - 1 || - (costFactor + 1) > SIZE_MAX / 128 || - (costFactor + 1) * 128 > SIZE_MAX / blockSize) - @throw [OFOutOfRangeException exception]; - - if ((tmp = malloc((costFactor + 1) * 128 * blockSize)) == NULL) - @throw [OFOutOfMemoryException - exceptionWithRequestedSize: (blockSize + - costFactor) * 128]; - - if (parallelization > SIZE_MAX / 128 || - parallelization * 128 > SIZE_MAX / blockSize) - @throw [OFOutOfRangeException exception]; - - if ((buffer = malloc(parallelization * 128 * - blockSize)) == NULL) - @throw [OFOutOfMemoryException - exceptionWithRequestedSize: parallelization * 128 * - blockSize]; - - HMAC = [[OFHMAC alloc] initWithHashClass: [OFSHA256Hash class]]; + uint32_t *tmpItems, *bufferItems; + + if (costFactor > SIZE_MAX - 1 || + (costFactor + 1) > SIZE_MAX / 128) + @throw [OFOutOfRangeException exception]; + + tmp = [[OFSecureData alloc] + initWithItemSize: blockSize + count: (costFactor + 1) * 128 + allowsSwappableMemory: allowsSwappableMemory]; + tmpItems = tmp.mutableItems; + + if (parallelization > SIZE_MAX / 128) + @throw [OFOutOfRangeException exception]; + + buffer = [[OFSecureData alloc] + initWithItemSize: blockSize + count: parallelization * 128 + allowsSwappableMemory: allowsSwappableMemory]; + bufferItems = buffer.mutableItems; + + HMAC = [[OFHMAC alloc] + initWithHashClass: [OFSHA256Hash class] + allowsSwappableMemory: allowsSwappableMemory]; of_pbkdf2(HMAC, 1, salt, saltLength, password, passwordLength, - (unsigned char *)buffer, parallelization * 128 * blockSize); + (unsigned char *)bufferItems, + parallelization * 128 * blockSize, allowsSwappableMemory); for (size_t i = 0; i < parallelization; i++) - of_scrypt_romix(buffer + i * 32 * blockSize, blockSize, - costFactor, tmp); + of_scrypt_romix(bufferItems + i * 32 * blockSize, + blockSize, costFactor, tmpItems); - of_pbkdf2(HMAC, 1, (unsigned char *)buffer, parallelization * - 128 * blockSize, password, passwordLength, key, keyLength); + of_pbkdf2(HMAC, 1, (unsigned char *)bufferItems, + parallelization * 128 * blockSize, password, passwordLength, + key, keyLength, allowsSwappableMemory); } @finally { - of_explicit_memset(tmp, 0, (costFactor + 1) * blockSize * 128); - free(tmp); - - of_explicit_memset(buffer, 0, - parallelization * 128 * blockSize); - free(buffer); - + [tmp release]; + [buffer release]; [HMAC release]; } } Index: tests/OFHMACTests.m ================================================================== --- tests/OFHMACTests.m +++ tests/OFHMACTests.m @@ -57,21 +57,27 @@ mode: @"r"]; OFHMAC *HMAC_MD5, *HMAC_SHA1, *HMAC_RMD160; OFHMAC *HMAC_SHA256, *HMAC_SHA384, *HMAC_SHA512; TEST(@"+[HMACWithHashClass:] with MD5", - (HMAC_MD5 = [OFHMAC HMACWithHashClass: [OFMD5Hash class]])) + (HMAC_MD5 = [OFHMAC HMACWithHashClass: [OFMD5Hash class] + allowsSwappableMemory: true])) TEST(@"+[HMACWithHashClass:] with SHA-1", - (HMAC_SHA1 = [OFHMAC HMACWithHashClass: [OFSHA1Hash class]])) + (HMAC_SHA1 = [OFHMAC HMACWithHashClass: [OFSHA1Hash class] + allowsSwappableMemory: true])) TEST(@"+[HMACWithHashClass:] with RIPEMD-160", - (HMAC_RMD160 = [OFHMAC HMACWithHashClass: [OFRIPEMD160Hash class]])) + (HMAC_RMD160 = [OFHMAC HMACWithHashClass: [OFRIPEMD160Hash class] + allowsSwappableMemory: true])) TEST(@"+[HMACWithHashClass:] with SHA-256", - (HMAC_SHA256 = [OFHMAC HMACWithHashClass: [OFSHA256Hash class]])) + (HMAC_SHA256 = [OFHMAC HMACWithHashClass: [OFSHA256Hash class] + allowsSwappableMemory: true])) TEST(@"+[HMACWithHashClass:] with SHA-384", - (HMAC_SHA384 = [OFHMAC HMACWithHashClass: [OFSHA384Hash class]])) + (HMAC_SHA384 = [OFHMAC HMACWithHashClass: [OFSHA384Hash class] + allowsSwappableMemory: true])) TEST(@"+[HMACWithHashClass:] with SHA-512", - (HMAC_SHA512 = [OFHMAC HMACWithHashClass: [OFSHA512Hash class]])) + (HMAC_SHA512 = [OFHMAC HMACWithHashClass: [OFSHA512Hash class] + allowsSwappableMemory: true])) EXPECT_EXCEPTION(@"Detection of missing key", OFInvalidArgumentException, [HMAC_MD5 updateWithBuffer: "" length: 0]) Index: tests/OFMD5HashTests.m ================================================================== --- tests/OFMD5HashTests.m +++ tests/OFMD5HashTests.m @@ -32,11 +32,12 @@ void *pool = objc_autoreleasePoolPush(); OFMD5Hash *md5, *copy; OFFile *f = [OFFile fileWithPath: @"testfile.bin" mode: @"r"]; - TEST(@"+[cryptoHash]", (md5 = [OFMD5Hash cryptoHash])) + TEST(@"+[cryptoHashWithAllowsSwappableMemory:]", + (md5 = [OFMD5Hash cryptoHashWithAllowsSwappableMemory: true])) while (!f.atEndOfStream) { char buf[64]; size_t len = [f readIntoBuffer: buf length: 64]; Index: tests/OFRIPEMD160HashTests.m ================================================================== --- tests/OFRIPEMD160HashTests.m +++ tests/OFRIPEMD160HashTests.m @@ -33,11 +33,13 @@ void *pool = objc_autoreleasePoolPush(); OFRIPEMD160Hash *rmd160, *copy; OFFile *f = [OFFile fileWithPath: @"testfile.bin" mode: @"r"]; - TEST(@"+[cryptoHash]", (rmd160 = [OFRIPEMD160Hash cryptoHash])) + TEST(@"+[cryptoHashWithAllowsSwappableMemory:]", + (rmd160 = [OFRIPEMD160Hash + cryptoHashWithAllowsSwappableMemory: true])) while (!f.atEndOfStream) { char buf[64]; size_t len = [f readIntoBuffer: buf length: 64]; Index: tests/OFSHA1HashTests.m ================================================================== --- tests/OFSHA1HashTests.m +++ tests/OFSHA1HashTests.m @@ -33,11 +33,12 @@ void *pool = objc_autoreleasePoolPush(); OFSHA1Hash *sha1, *copy; OFFile *f = [OFFile fileWithPath: @"testfile.bin" mode: @"r"]; - TEST(@"+[cryptoHash]", (sha1 = [OFSHA1Hash cryptoHash])) + TEST(@"+[cryptoHashWithAllowsSwappableMemory:]", + (sha1 = [OFSHA1Hash cryptoHashWithAllowsSwappableMemory: true])) while (!f.atEndOfStream) { char buf[64]; size_t len = [f readIntoBuffer: buf length: 64]; Index: tests/OFSHA224HashTests.m ================================================================== --- tests/OFSHA224HashTests.m +++ tests/OFSHA224HashTests.m @@ -33,11 +33,12 @@ void *pool = objc_autoreleasePoolPush(); OFSHA224Hash *sha224, *copy; OFFile *f = [OFFile fileWithPath: @"testfile.bin" mode: @"r"]; - TEST(@"+[cryptoHash]", (sha224 = [OFSHA224Hash cryptoHash])) + TEST(@"+[cryptoHashWithAllowsSwappableMemory:]", + (sha224 = [OFSHA224Hash cryptoHashWithAllowsSwappableMemory: true])) while (!f.atEndOfStream) { char buf[64]; size_t len = [f readIntoBuffer: buf length: 64]; Index: tests/OFSHA256HashTests.m ================================================================== --- tests/OFSHA256HashTests.m +++ tests/OFSHA256HashTests.m @@ -33,11 +33,12 @@ void *pool = objc_autoreleasePoolPush(); OFSHA256Hash *sha256, *copy; OFFile *f = [OFFile fileWithPath: @"testfile.bin" mode: @"r"]; - TEST(@"+[cryptoHash]", (sha256 = [OFSHA256Hash cryptoHash])) + TEST(@"+[cryptoHashWithAllowsSwappableMemory:]", + (sha256 = [OFSHA256Hash cryptoHashWithAllowsSwappableMemory: true])) while (!f.atEndOfStream) { char buf[64]; size_t len = [f readIntoBuffer: buf length: 64]; Index: tests/OFSHA384HashTests.m ================================================================== --- tests/OFSHA384HashTests.m +++ tests/OFSHA384HashTests.m @@ -34,11 +34,12 @@ void *pool = objc_autoreleasePoolPush(); OFSHA384Hash *sha384, *copy; OFFile *f = [OFFile fileWithPath: @"testfile.bin" mode: @"r"]; - TEST(@"+[cryptoHash]", (sha384 = [OFSHA384Hash cryptoHash])) + TEST(@"+[cryptoHashWithAllowsSwappableMemory:]", + (sha384 = [OFSHA384Hash cryptoHashWithAllowsSwappableMemory: true])) while (!f.atEndOfStream) { char buf[128]; size_t len = [f readIntoBuffer: buf length: 128]; Index: tests/OFSHA512HashTests.m ================================================================== --- tests/OFSHA512HashTests.m +++ tests/OFSHA512HashTests.m @@ -35,11 +35,12 @@ void *pool = objc_autoreleasePoolPush(); OFSHA512Hash *sha512, *copy; OFFile *f = [OFFile fileWithPath: @"testfile.bin" mode: @"r"]; - TEST(@"+[cryptoHash]", (sha512 = [OFSHA512Hash cryptoHash])) + TEST(@"+[cryptoHashWithAllowsSwappableMemory:]", + (sha512 = [OFSHA512Hash cryptoHashWithAllowsSwappableMemory: true])) while (!f.atEndOfStream) { char buf[128]; size_t len = [f readIntoBuffer: buf length: 128]; Index: tests/PBKDF2Tests.m ================================================================== --- tests/PBKDF2Tests.m +++ tests/PBKDF2Tests.m @@ -25,53 +25,54 @@ @implementation TestsAppDelegate (PBKDF2Tests) - (void)PBKDF2Tests { void *pool = objc_autoreleasePoolPush(); - OFHMAC *HMAC = [OFHMAC HMACWithHashClass: [OFSHA1Hash class]]; + OFHMAC *HMAC = [OFHMAC HMACWithHashClass: [OFSHA1Hash class] + allowsSwappableMemory: true]; unsigned char key[25]; /* Test vectors from RFC 6070 */ TEST(@"PBKDF2-SHA1, 1 iteration", R(of_pbkdf2(HMAC, 1, (unsigned char *)"salt", 4, "password", 8, key, - 20)) && + 20, true)) && memcmp(key, "\x0C\x60\xC8\x0F\x96\x1F\x0E\x71\xF3\xA9\xB5\x24\xAF" "\x60\x12\x06\x2F\xE0\x37\xA6", 20) == 0) TEST(@"PBKDF2-SHA1, 2 iterations", R(of_pbkdf2(HMAC, 2, (unsigned char *)"salt", 4, "password", 8, key, - 20)) && + 20, true)) && memcmp(key, "\xEA\x6C\x01\x4D\xC7\x2D\x6F\x8C\xCD\x1E\xD9\x2A\xCE" "\x1D\x41\xF0\xD8\xDE\x89\x57", 20) == 0) TEST(@"PBKDF2-SHA1, 4096 iterations", R(of_pbkdf2(HMAC, 4096, (unsigned char *)"salt", 4, "password", 8, - key, 20)) && + key, 20, true)) && memcmp(key, "\x4B\x00\x79\x01\xB7\x65\x48\x9A\xBE\xAD\x49\xD9\x26" "\xF7\x21\xD0\x65\xA4\x29\xC1", 20) == 0) /* This test takes too long, even on a fast machine. */ #if 0 TEST(@"PBKDF2-SHA1, 16777216 iterations", R(of_pbkdf2(HMAC, 16777216, (unsigned char *)"salt", 4, "password", - 8, key, 20)) && + 8, key, 20, true)) && memcmp(key, "\xEE\xFE\x3D\x61\xCD\x4D\xA4\xE4\xE9\x94\x5B\x3D\x6B" "\xA2\x15\x8C\x26\x34\xE9\x84", 20) == 0) #endif TEST(@"PBKDF2-SHA1, 4096 iterations, key > 1 block", R(of_pbkdf2(HMAC, 4096, (unsigned char *)"saltSALTsaltSALTsaltSALTsaltSALTsalt", 36, - "passwordPASSWORDpassword", 24, key, 25)) && + "passwordPASSWORDpassword", 24, key, 25, true)) && memcmp(key, "\x3D\x2E\xEC\x4F\xE4\x1C\x84\x9B\x80\xC8\xD8\x36\x62" "\xC0\xE4\x4A\x8B\x29\x1A\x96\x4C\xF2\xF0\x70\x38", 25) == 0) TEST(@"PBKDF2-SHA1, 4096 iterations, key < 1 block", R(of_pbkdf2(HMAC, 4096, (unsigned char *)"sa\0lt", 5, "pass\0word", - 9, key, 16)) && + 9, key, 16, true)) && memcmp(key, "\x56\xFA\x6A\xA7\x55\x48\x09\x9D\xCC\x37\xD7\xF0\x34" "\x25\xE0\xC3", 16) == 0) objc_autoreleasePoolPop(pool); } @end Index: tests/ScryptTests.m ================================================================== --- tests/ScryptTests.m +++ tests/ScryptTests.m @@ -154,28 +154,28 @@ R(memcpy(ROMixBuffer, ROMixInput, 128)) && R(of_scrypt_romix(ROMixBuffer, 1, 16, ROMixTmp)) && memcmp(ROMixBuffer, ROMixOutput, 128) == 0) TEST(@"scrypt test vector #1", - R(of_scrypt(1, 16, 1, (unsigned char *)"", 0, "", 0, output, 64)) && - memcmp(output, testVector1, 64) == 0) + R(of_scrypt(1, 16, 1, (unsigned char *)"", 0, "", 0, output, 64, + true)) && memcmp(output, testVector1, 64) == 0) TEST(@"scrypt test vector #2", R(of_scrypt(8, 1024, 16, (unsigned char *)"NaCl", 4, "password", 8, - output, 64)) && memcmp(output, testVector2, 64) == 0) + output, 64, true)) && memcmp(output, testVector2, 64) == 0) TEST(@"scrypt test vector #3", R(of_scrypt(8, 16384, 1, (unsigned char *)"SodiumChloride", 14, - "pleaseletmein", 13, output, 64)) && + "pleaseletmein", 13, output, 64, true)) && memcmp(output, testVector3, 64) == 0) /* The forth test vector is too expensive to include it in the tests. */ #if 0 TEST(@"scrypt test vector #4", R(of_scrypt(8, 1048576, 1, (unsigned char *)"SodiumChloride", 14, - "pleaseletmein", 13, output, 64)) && + "pleaseletmein", 13, output, 64, true)) && memcmp(output, testVector4, 64) == 0) #endif objc_autoreleasePoolPop(pool); } @end Index: utils/ofhash/OFHash.m ================================================================== --- utils/ofhash/OFHash.m +++ utils/ofhash/OFHash.m @@ -121,25 +121,10 @@ [OFApplication terminateWithStatus: 1]; break; } } - if (calculateMD5) - MD5Hash = [OFMD5Hash cryptoHash]; - if (calculateRIPEMD160) - RIPEMD160Hash = [OFRIPEMD160Hash cryptoHash]; - if (calculateSHA1) - SHA1Hash = [OFSHA1Hash cryptoHash]; - if (calculateSHA224) - SHA224Hash = [OFSHA224Hash cryptoHash]; - if (calculateSHA256) - SHA256Hash = [OFSHA256Hash cryptoHash]; - if (calculateSHA384) - SHA384Hash = [OFSHA384Hash cryptoHash]; - if (calculateSHA512) - SHA512Hash = [OFSHA512Hash cryptoHash]; - #ifdef OF_HAVE_SANDBOX OFSandbox *sandbox = [OFSandbox sandbox]; @try { sandbox.allowsStdIO = true; sandbox.allowsReadingFiles = true; @@ -164,10 +149,31 @@ help(); if (optionsParser.remainingArguments.count < 1) help(); + if (calculateMD5) + MD5Hash = [OFMD5Hash cryptoHashWithAllowsSwappableMemory: true]; + if (calculateRIPEMD160) + RIPEMD160Hash = + [OFRIPEMD160Hash cryptoHashWithAllowsSwappableMemory: true]; + if (calculateSHA1) + SHA1Hash = + [OFSHA1Hash cryptoHashWithAllowsSwappableMemory: true]; + if (calculateSHA224) + SHA224Hash = + [OFSHA224Hash cryptoHashWithAllowsSwappableMemory: true]; + if (calculateSHA256) + SHA256Hash = + [OFSHA256Hash cryptoHashWithAllowsSwappableMemory: true]; + if (calculateSHA384) + SHA384Hash = + [OFSHA384Hash cryptoHashWithAllowsSwappableMemory: true]; + if (calculateSHA512) + SHA512Hash = + [OFSHA512Hash cryptoHashWithAllowsSwappableMemory: true]; + for (OFString *path in optionsParser.remainingArguments) { void *pool = objc_autoreleasePoolPush(); OFStream *file; if ([path isEqual: @"-"])