PageRenderTime 45ms CodeModel.GetById 17ms RepoModel.GetById 1ms app.codeStats 0ms

/Source/SPDataAdditions.m

https://gitlab.com/sheldonels/sequel-pro
Objective C | 289 lines | 161 code | 64 blank | 64 comment | 29 complexity | fc3748e421a6bcbbd468bbde7d9f10b7 MD5 | raw file
  1. //
  2. // $Id: SPDataAdditions.m 891 2009-06-19 10:01:14Z bibiko $
  3. //
  4. // SPDataAdditions.m
  5. // sequel-pro
  6. //
  7. // dataEncryptedWithPassword and dataDecryptedWithPassword:
  8. // License: FREEWARE http://aquaticmac.com/cocoa.php
  9. // Copyright (c) 2005, Lucas Newman
  10. // All rights reserved.
  11. //
  12. // Created by Hans-Jörg Bibiko on June 19, 2009
  13. //
  14. // This program is free software; you can redistribute it and/or modify
  15. // it under the terms of the GNU General Public License as published by
  16. // the Free Software Foundation; either version 2 of the License, or
  17. // (at your option) any later version.
  18. //
  19. // This program is distributed in the hope that it will be useful,
  20. // but WITHOUT ANY WARRANTY; without even the implied warranty of
  21. // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  22. // GNU General Public License for more details.
  23. //
  24. // You should have received a copy of the GNU General Public License
  25. // along with this program; if not, write to the Free Software
  26. // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
  27. //
  28. // More info at <http://code.google.com/p/sequel-pro/>
  29. #import "SPDataAdditions.h"
  30. #include <zlib.h>
  31. #include <openssl/aes.h>
  32. #include <openssl/sha.h>
  33. @implementation NSData (SPDataAdditions)
  34. - (NSData *)dataEncryptedWithPassword:(NSString *)password
  35. {
  36. // Create a random 128-bit initialization vector
  37. srand((unsigned int)time(NULL));
  38. NSInteger ivIndex;
  39. unsigned char iv[16];
  40. for (ivIndex = 0; ivIndex < 16; ivIndex++)
  41. iv[ivIndex] = rand() & 0xff;
  42. // Calculate the 16-byte AES block padding
  43. NSInteger dataLength = [self length];
  44. NSInteger paddedLength = dataLength + (32 - (dataLength % 16));
  45. NSInteger totalLength = paddedLength + 16; // Data plus IV
  46. // Allocate enough space for the IV + ciphertext
  47. unsigned char *encryptedBytes = calloc(1, totalLength);
  48. // The first block of the ciphertext buffer is the IV
  49. memcpy(encryptedBytes, iv, 16);
  50. unsigned char *paddedBytes = calloc(1, paddedLength);
  51. memcpy(paddedBytes, [self bytes], dataLength);
  52. // The last 32-bit chunk is the size of the plaintext, which is encrypted with the plaintext
  53. NSInteger bigIntDataLength = NSSwapHostIntToBig((unsigned int)dataLength);
  54. memcpy(paddedBytes + (paddedLength - 4), &bigIntDataLength, 4);
  55. // Create the key from first 128-bits of the 160-bit password hash
  56. unsigned char passwordDigest[20];
  57. SHA1((const unsigned char *)[password UTF8String], strlen([password UTF8String]), passwordDigest);
  58. AES_KEY aesKey;
  59. AES_set_encrypt_key(passwordDigest, 128, &aesKey);
  60. // AES-128-cbc encrypt the data, filling in the buffer after the IV
  61. AES_cbc_encrypt(paddedBytes, encryptedBytes + 16, paddedLength, &aesKey, iv, AES_ENCRYPT);
  62. free(paddedBytes);
  63. return [NSData dataWithBytesNoCopy:encryptedBytes length:totalLength];
  64. }
  65. - (NSData *)dataDecryptedWithPassword:(NSString *)password
  66. {
  67. // Create the key from the password hash
  68. unsigned char passwordDigest[20];
  69. SHA1((const unsigned char *)[password UTF8String], strlen([password UTF8String]), passwordDigest);
  70. // AES-128-cbc decrypt the data
  71. AES_KEY aesKey;
  72. AES_set_decrypt_key(passwordDigest, 128, &aesKey);
  73. // Total length = encrypted length + IV
  74. NSInteger totalLength = [self length];
  75. NSInteger encryptedLength = totalLength - 16;
  76. // Take the IV from the first 128-bit block
  77. unsigned char iv[16];
  78. memcpy(iv, [self bytes], 16);
  79. // Decrypt the data
  80. unsigned char *decryptedBytes = (unsigned char*)malloc(encryptedLength);
  81. AES_cbc_encrypt([self bytes] + 16, decryptedBytes, encryptedLength, &aesKey, iv, AES_DECRYPT);
  82. // If decryption was successful, these blocks will be zeroed
  83. if ( *((UInt32*)decryptedBytes + ((encryptedLength / 4) - 4)) ||
  84. *((UInt32*)decryptedBytes + ((encryptedLength / 4) - 3)) ||
  85. *((UInt32*)decryptedBytes + ((encryptedLength / 4) - 2)) )
  86. {
  87. return nil;
  88. }
  89. // Get the size of the data from the last 32-bit chunk
  90. NSInteger bigIntDataLength = *((UInt32*)decryptedBytes + ((encryptedLength / 4) - 1));
  91. NSInteger dataLength = NSSwapBigIntToHost((unsigned int)bigIntDataLength);
  92. return [NSData dataWithBytesNoCopy:decryptedBytes length:dataLength];
  93. }
  94. - (NSData *)decompress
  95. {
  96. if ([self length] == 0) return self;
  97. NSUInteger full_length = [self length];
  98. NSUInteger half_length = [self length] / 2;
  99. NSMutableData *unzipData = [NSMutableData dataWithLength: full_length + half_length];
  100. BOOL done = NO;
  101. NSInteger status;
  102. z_stream zlibStream;
  103. zlibStream.next_in = (Bytef *)[self bytes];
  104. zlibStream.avail_in = (uInt)[self length];
  105. zlibStream.total_out = 0;
  106. zlibStream.zalloc = Z_NULL;
  107. zlibStream.zfree = Z_NULL;
  108. if(inflateInit(&zlibStream) != Z_OK) return nil;
  109. while(!done)
  110. {
  111. if (zlibStream.total_out >= [unzipData length])
  112. [unzipData increaseLengthBy: half_length];
  113. zlibStream.next_out = [unzipData mutableBytes] + zlibStream.total_out;
  114. zlibStream.avail_out = (uInt)([unzipData length] - zlibStream.total_out);
  115. status = inflate (&zlibStream, Z_SYNC_FLUSH);
  116. if (status == Z_STREAM_END) done = YES;
  117. else if (status != Z_OK) break;
  118. }
  119. if(inflateEnd (&zlibStream) != Z_OK)
  120. return nil;
  121. if(done) {
  122. [unzipData setLength: zlibStream.total_out];
  123. return [NSData dataWithData: unzipData];
  124. }
  125. else
  126. return nil;
  127. }
  128. - (NSData *)compress
  129. {
  130. if ([self length] == 0) return self;
  131. z_stream zlibStream;
  132. zlibStream.zalloc = Z_NULL;
  133. zlibStream.zfree = Z_NULL;
  134. zlibStream.opaque = Z_NULL;
  135. zlibStream.total_out = 0;
  136. zlibStream.next_in=(Bytef *)[self bytes];
  137. zlibStream.avail_in = (uInt)[self length];
  138. if (deflateInit(&zlibStream, Z_DEFAULT_COMPRESSION) != Z_OK) return nil;
  139. NSMutableData *zipData = [NSMutableData dataWithLength:16384];
  140. do{
  141. if (zlibStream.total_out >= [zipData length])
  142. [zipData increaseLengthBy: 16384];
  143. zlibStream.next_out = [zipData mutableBytes] + zlibStream.total_out;
  144. zlibStream.avail_out = (uInt)([zipData length] - zlibStream.total_out);
  145. deflate(&zlibStream, Z_FINISH);
  146. } while(zlibStream.avail_out == 0);
  147. deflateEnd(&zlibStream);
  148. [zipData setLength: zlibStream.total_out];
  149. return [NSData dataWithData: zipData];
  150. }
  151. /**
  152. * Returns the hex representation of the given data.
  153. */
  154. - (NSString *)dataToFormattedHexString
  155. {
  156. NSUInteger i, j;
  157. NSUInteger totalLength = [self length];
  158. NSUInteger bytesPerLine = 16;
  159. NSMutableString *retVal = [NSMutableString string];
  160. // get the length of the longest location
  161. NSUInteger longest = [(NSString *)[NSString stringWithFormat:@"%X", totalLength - ( totalLength % bytesPerLine )] length];
  162. for ( i = 0; i < totalLength; i += bytesPerLine ) {
  163. NSMutableString *hex = [[NSMutableString alloc] initWithCapacity:(3 * bytesPerLine - 1)];
  164. NSMutableString *location = [[NSMutableString alloc] initWithCapacity:(longest + 2)];
  165. unsigned char *buffer;
  166. NSUInteger buffLength = bytesPerLine;
  167. // add hex value of location
  168. [location appendFormat:@"%X", i];
  169. // pad it
  170. while( longest > [location length] ) {
  171. [location insertString:@"0" atIndex:0];
  172. }
  173. // get the chars from the NSData obj
  174. if ( i + buffLength >= totalLength ) {
  175. buffLength = totalLength - i;
  176. }
  177. buffer = (unsigned char*) malloc( sizeof(unsigned char) * buffLength + 1);
  178. [self getBytes:buffer range:NSMakeRange(i, buffLength)];
  179. // build the hex string
  180. for ( j = 0; j < buffLength; j++ ) {
  181. [hex appendFormat:@"%02X ", *(buffer + j)];
  182. // Replace non-displayed bytes by '.'
  183. // non-displayed bytes are all bytes whose hex code is less than 0x20
  184. if(*(buffer + j) < ' ') *(buffer + j) = '.';
  185. }
  186. // Create a NULL-terminated buffer for [NSString stringWithFormat:@"%s"]
  187. *(buffer + j) = '\0';
  188. // add padding to missing hex values.
  189. for ( j = 0; j < bytesPerLine - buffLength; j++ ) {
  190. [hex appendString:@" "];
  191. }
  192. // build line
  193. [retVal appendFormat:@"%@ %@ %s\n", location, hex, buffer];
  194. // clean up
  195. [hex release];
  196. [location release];
  197. free( buffer );
  198. }
  199. return retVal;
  200. }
  201. /**
  202. * Converts data instances to their string representation.
  203. */
  204. - (NSString *)stringRepresentationUsingEncoding:(NSStringEncoding)encoding
  205. {
  206. NSString *string = [[[NSString alloc] initWithData:self encoding:encoding] autorelease];
  207. return !string ? [[[NSString alloc] initWithData:self encoding:NSASCIIStringEncoding] autorelease] : string;
  208. }
  209. /*
  210. * Convert data objects to their string representation (max 255 chars)
  211. * in the current encoding, falling back to ascii. (Mainly used for displaying
  212. * large blob data in a tableView)
  213. */
  214. - (NSString *)shortStringRepresentationUsingEncoding:(NSStringEncoding)encoding
  215. {
  216. NSString *string = [self stringRepresentationUsingEncoding:encoding];
  217. if (!string) {
  218. string = @"-- cannot display --";
  219. }
  220. else if ([string length] > 255) {
  221. string = [string substringToIndex:255];
  222. }
  223. return string;
  224. }
  225. @end