Index: src/OFCryptoHash.h ================================================================== --- src/OFCryptoHash.h +++ src/OFCryptoHash.h @@ -20,12 +20,16 @@ /*! * @protocol OFCryptoHash OFCryptoHash.h ObjFW/OFCryptoHash.h * * @brief A protocol for classes providing cryptographic hash functions. + * + * A cryptographic hash implementing this protocol can be copied. The entire + * state is copied, allowing to calculate a new hash from there. This is + * especially useful for generating many hashes with a common prefix. */ -@protocol OFCryptoHash +@protocol OFCryptoHash /*! * A boolean whether the hash has already been calculated. */ @property (readonly, getter=isCalculated) bool calculated; Index: src/OFMD5Hash.m ================================================================== --- src/OFMD5Hash.m +++ src/OFMD5Hash.m @@ -136,10 +136,23 @@ [self OF_resetState]; return self; } + +- copy +{ + OFMD5Hash *copy = [[OFMD5Hash alloc] init]; + + memcpy(copy->_state, _state, sizeof(_state)); + copy->_bits = _bits; + memcpy(©->_buffer, &_buffer, sizeof(_buffer)); + copy->_bufferLength = _bufferLength; + copy->_calculated = _calculated; + + return copy; +} - (void)OF_resetState { _state[0] = 0x67452301; _state[1] = 0xEFCDAB89; Index: src/OFRIPEMD160Hash.m ================================================================== --- src/OFRIPEMD160Hash.m +++ src/OFRIPEMD160Hash.m @@ -150,10 +150,23 @@ [self OF_resetState]; return self; } + +- copy +{ + OFRIPEMD160Hash *copy = [[OFRIPEMD160Hash alloc] init]; + + memcpy(copy->_state, _state, sizeof(_state)); + copy->_bits = _bits; + memcpy(©->_buffer, &_buffer, sizeof(_buffer)); + copy->_bufferLength = _bufferLength; + copy->_calculated = _calculated; + + return copy; +} - (void)OF_resetState { _state[0] = 0x67452301; _state[1] = 0xEFCDAB89; Index: src/OFSHA1Hash.m ================================================================== --- src/OFSHA1Hash.m +++ src/OFSHA1Hash.m @@ -110,10 +110,23 @@ [self OF_resetState]; return self; } + +- copy +{ + OFSHA1Hash *copy = [[OFSHA1Hash alloc] init]; + + memcpy(copy->_state, _state, sizeof(_state)); + copy->_bits = _bits; + memcpy(©->_buffer, &_buffer, sizeof(_buffer)); + copy->_bufferLength = _bufferLength; + copy->_calculated = _calculated; + + return copy; +} - (void)OF_resetState { _state[0] = 0x67452301; _state[1] = 0xEFCDAB89; Index: src/OFSHA224Or256Hash.m ================================================================== --- src/OFSHA224Or256Hash.m +++ src/OFSHA224Or256Hash.m @@ -142,10 +142,23 @@ @throw e; } return self; } + +- copy +{ + OFSHA224Or256Hash *copy = [[[self class] alloc] init]; + + memcpy(copy->_state, _state, sizeof(_state)); + copy->_bits = _bits; + memcpy(©->_buffer, &_buffer, sizeof(_buffer)); + copy->_bufferLength = _bufferLength; + copy->_calculated = _calculated; + + return copy; +} - (void)updateWithBuffer: (const void*)buffer_ length: (size_t)length { const uint8_t *buffer = buffer_; Index: src/OFSHA384Or512Hash.m ================================================================== --- src/OFSHA384Or512Hash.m +++ src/OFSHA384Or512Hash.m @@ -153,10 +153,23 @@ @throw e; } return self; } + +- copy +{ + OFSHA384Or512Hash *copy = [[[self class] alloc] init]; + + memcpy(copy->_state, _state, sizeof(_state)); + memcpy(copy->_bits, _bits, sizeof(_bits)); + memcpy(©->_buffer, &_buffer, sizeof(_buffer)); + copy->_bufferLength = _bufferLength; + copy->_calculated = _calculated; + + return copy; +} - (void)updateWithBuffer: (const void*)buffer_ length: (size_t)length { const uint8_t *buffer = buffer_; Index: tests/OFMD5HashTests.m ================================================================== --- tests/OFMD5HashTests.m +++ tests/OFMD5HashTests.m @@ -34,11 +34,11 @@ @implementation TestsAppDelegate (OFMD5HashTests) - (void)MD5HashTests { OFAutoreleasePool *pool = [[OFAutoreleasePool alloc] init]; - OFMD5Hash *md5; + OFMD5Hash *md5, *copy; OFFile *f = [OFFile fileWithPath: @"testfile.bin" mode: @"rb"]; TEST(@"+[cryptoHash]", (md5 = [OFMD5Hash cryptoHash])) @@ -49,15 +49,19 @@ [md5 updateWithBuffer: buf length: len]; } [f close]; - TEST(@"-[digest]", !memcmp([md5 digest], testfile_md5, 16)) + TEST(@"-[copy]", (copy = [[md5 copy] autorelease])) + + TEST(@"-[digest]", + memcmp([md5 digest], testfile_md5, 16) == 0 && + memcmp([copy digest], testfile_md5, 16) == 0) EXPECT_EXCEPTION(@"Detect invalid call of " @"-[updateWithBuffer:length]", OFHashAlreadyCalculatedException, [md5 updateWithBuffer: "" length: 1]) [pool drain]; } @end Index: tests/OFRIPEMD160HashTests.m ================================================================== --- tests/OFRIPEMD160HashTests.m +++ tests/OFRIPEMD160HashTests.m @@ -35,11 +35,11 @@ @implementation TestsAppDelegate (OFRIPEMD160HashTests) - (void)RIPEMD160HashTests { OFAutoreleasePool *pool = [[OFAutoreleasePool alloc] init]; - OFRIPEMD160Hash *rmd160; + OFRIPEMD160Hash *rmd160, *copy; OFFile *f = [OFFile fileWithPath: @"testfile.bin" mode: @"rb"]; TEST(@"+[cryptoHash]", (rmd160 = [OFRIPEMD160Hash cryptoHash])) @@ -50,15 +50,19 @@ [rmd160 updateWithBuffer: buf length: len]; } [f close]; - TEST(@"-[digest]", !memcmp([rmd160 digest], testfile_rmd160, 20)) + TEST(@"-[copy]", (copy = [[rmd160 copy] autorelease])) + + TEST(@"-[digest]", + memcmp([rmd160 digest], testfile_rmd160, 20) == 0 && + memcmp([copy digest], testfile_rmd160, 20) == 0) EXPECT_EXCEPTION(@"Detect invalid call of " @"-[updateWithBuffer:length]", OFHashAlreadyCalculatedException, [rmd160 updateWithBuffer: "" length: 1]) [pool drain]; } @end Index: tests/OFSHA1HashTests.m ================================================================== --- tests/OFSHA1HashTests.m +++ tests/OFSHA1HashTests.m @@ -35,11 +35,11 @@ @implementation TestsAppDelegate (SHA1HashTests) - (void)SHA1HashTests { OFAutoreleasePool *pool = [[OFAutoreleasePool alloc] init]; - OFSHA1Hash *sha1; + OFSHA1Hash *sha1, *copy; OFFile *f = [OFFile fileWithPath: @"testfile.bin" mode: @"rb"]; TEST(@"+[cryptoHash]", (sha1 = [OFSHA1Hash cryptoHash])) @@ -50,15 +50,19 @@ [sha1 updateWithBuffer: buf length: len]; } [f close]; - TEST(@"-[digest]", !memcmp([sha1 digest], testfile_sha1, 20)) + TEST(@"-[copy]", (copy = [[sha1 copy] autorelease])) + + TEST(@"-[digest]", + memcmp([sha1 digest], testfile_sha1, 20) == 0 && + memcmp([copy digest], testfile_sha1, 20) == 0) EXPECT_EXCEPTION(@"Detect invalid call of " @"-[updateWithBuffer:length:]", OFHashAlreadyCalculatedException, [sha1 updateWithBuffer: "" length: 1]) [pool drain]; } @end Index: tests/OFSHA224HashTests.m ================================================================== --- tests/OFSHA224HashTests.m +++ tests/OFSHA224HashTests.m @@ -35,11 +35,11 @@ @implementation TestsAppDelegate (SHA224HashTests) - (void)SHA224HashTests { OFAutoreleasePool *pool = [[OFAutoreleasePool alloc] init]; - OFSHA224Hash *sha224; + OFSHA224Hash *sha224, *copy; OFFile *f = [OFFile fileWithPath: @"testfile.bin" mode: @"rb"]; TEST(@"+[cryptoHash]", (sha224 = [OFSHA224Hash cryptoHash])) @@ -50,15 +50,19 @@ [sha224 updateWithBuffer: buf length: len]; } [f close]; - TEST(@"-[digest]", !memcmp([sha224 digest], testfile_sha224, 28)) + TEST(@"-[copy]", (copy = [[sha224 copy] autorelease])) + + TEST(@"-[digest]", + memcmp([sha224 digest], testfile_sha224, 28) == 0 && + memcmp([copy digest], testfile_sha224, 28) == 0) EXPECT_EXCEPTION(@"Detect invalid call of " @"-[updateWithBuffer:length:]", OFHashAlreadyCalculatedException, [sha224 updateWithBuffer: "" length: 1]) [pool drain]; } @end Index: tests/OFSHA256HashTests.m ================================================================== --- tests/OFSHA256HashTests.m +++ tests/OFSHA256HashTests.m @@ -35,11 +35,11 @@ @implementation TestsAppDelegate (SHA256HashTests) - (void)SHA256HashTests { OFAutoreleasePool *pool = [[OFAutoreleasePool alloc] init]; - OFSHA256Hash *sha256; + OFSHA256Hash *sha256, *copy; OFFile *f = [OFFile fileWithPath: @"testfile.bin" mode: @"rb"]; TEST(@"+[cryptoHash]", (sha256 = [OFSHA256Hash cryptoHash])) @@ -50,15 +50,19 @@ [sha256 updateWithBuffer: buf length: len]; } [f close]; - TEST(@"-[digest]", !memcmp([sha256 digest], testfile_sha256, 32)) + TEST(@"-[copy]", (copy = [[sha256 copy] autorelease])) + + TEST(@"-[digest]", + memcmp([sha256 digest], testfile_sha256, 32) == 0 && + memcmp([copy digest], testfile_sha256, 32) == 0) EXPECT_EXCEPTION(@"Detect invalid call of " @"-[updateWithBuffer:length:]", OFHashAlreadyCalculatedException, [sha256 updateWithBuffer: "" length: 1]) [pool drain]; } @end Index: tests/OFSHA384HashTests.m ================================================================== --- tests/OFSHA384HashTests.m +++ tests/OFSHA384HashTests.m @@ -36,11 +36,11 @@ @implementation TestsAppDelegate (SHA384HashTests) - (void)SHA384HashTests { OFAutoreleasePool *pool = [[OFAutoreleasePool alloc] init]; - OFSHA384Hash *sha384; + OFSHA384Hash *sha384, *copy; OFFile *f = [OFFile fileWithPath: @"testfile.bin" mode: @"rb"]; TEST(@"+[cryptoHash]", (sha384 = [OFSHA384Hash cryptoHash])) @@ -51,15 +51,19 @@ [sha384 updateWithBuffer: buf length: len]; } [f close]; - TEST(@"-[digest]", !memcmp([sha384 digest], testfile_sha384, 48)) + TEST(@"-[copy]", (copy = [[sha384 copy] autorelease])) + + TEST(@"-[digest]", + memcmp([sha384 digest], testfile_sha384, 48) == 0 && + memcmp([copy digest], testfile_sha384, 48) == 0) EXPECT_EXCEPTION(@"Detect invalid call of " @"-[updateWithBuffer:length:]", OFHashAlreadyCalculatedException, [sha384 updateWithBuffer: "" length: 1]) [pool drain]; } @end Index: tests/OFSHA512HashTests.m ================================================================== --- tests/OFSHA512HashTests.m +++ tests/OFSHA512HashTests.m @@ -37,11 +37,11 @@ @implementation TestsAppDelegate (SHA512HashTests) - (void)SHA512HashTests { OFAutoreleasePool *pool = [[OFAutoreleasePool alloc] init]; - OFSHA512Hash *sha512; + OFSHA512Hash *sha512, *copy; OFFile *f = [OFFile fileWithPath: @"testfile.bin" mode: @"rb"]; TEST(@"+[cryptoHash]", (sha512 = [OFSHA512Hash cryptoHash])) @@ -52,15 +52,19 @@ [sha512 updateWithBuffer: buf length: len]; } [f close]; - TEST(@"-[digest]", !memcmp([sha512 digest], testfile_sha512, 64)) + TEST(@"-[copy]", (copy = [[sha512 copy] autorelease])) + + TEST(@"-[digest]", + memcmp([sha512 digest], testfile_sha512, 64) == 0 && + memcmp([copy digest], testfile_sha512, 64) == 0) EXPECT_EXCEPTION(@"Detect invalid call of " @"-[updateWithBuffer:length:]", OFHashAlreadyCalculatedException, [sha512 updateWithBuffer: "" length: 1]) [pool drain]; } @end