Note that there are some explanatory texts on larger screens.

plurals
  1. POAES Encryption for an NSString?
    primarykey
    data
    text
    <p>I am implementing for iOS some decryption code for a message originating on a server over which I have no control. So the decryption requirements are:</p> <pre><code>Cipher Method : AES256 Cipher Mode: ECB Padding: PKCS5Padding </code></pre> <p>Since my initial trials failed to decrypt. So I played around with <a href="http://www.inconteam.com/software-development/41-encryption/55-aes-test-vectors#aes-ecb-256" rel="noreferrer">some test vectors</a> to see the code that i use was right,</p> <p>This is the code that encrypts the data:</p> <pre><code>NSString+AESCrypt.h ------------------- #import &lt;Foundation/Foundation.h&gt; #import "NSData+AESCrypt.h" @interface NSString (AESCrypt) - (NSString *)AES256EncryptWithKey:(NSString *)key; - (NSString *)AES256DecryptWithKey:(NSString *)key; @end NSString+AESCrypt.m ------------------- #import "NSString+AESCrypt.h" @implementation NSString (AESCrypt) - (NSString *)AES256EncryptWithKey:(NSString *)key { NSData *plainData = [self dataUsingEncoding:NSUTF8StringEncoding]; NSData *encryptedData = [plainData AES256EncryptWithKey:key]; NSString *encryptedString = [encryptedData base64Encoding]; return encryptedString; } - (NSString *)AES256DecryptWithKey:(NSString *)key { NSData *encryptedData = [NSData dataWithBase64EncodedString:self]; NSData *plainData = [encryptedData AES256DecryptWithKey:key]; NSString *plainString = [[NSString alloc] initWithData:plainData encoding:NSUTF8StringEncoding]; return [plainString autorelease]; } @end NSData+AESCrypt.h ------------------- #import &lt;Foundation/Foundation.h&gt; @interface NSData (AESCrypt) - (NSData *)AES256EncryptWithKey:(NSString *)key; - (NSData *)AES256DecryptWithKey:(NSString *)key; + (NSData *)dataWithBase64EncodedString:(NSString *)string; - (id)initWithBase64EncodedString:(NSString *)string; - (NSString *)base64Encoding; - (NSString *)base64EncodingWithLineLength:(NSUInteger)lineLength; - (BOOL)hasPrefixBytes:(const void *)prefix length:(NSUInteger)length; - (BOOL)hasSuffixBytes:(const void *)suffix length:(NSUInteger)length; @end NSData+AESCrypt.m ------------------- #import "NSData+AESCrypt.h" #import &lt;CommonCrypto/CommonCryptor.h&gt; static char encodingTable[64] = { 'A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P', 'Q','R','S','T','U','V','W','X','Y','Z','a','b','c','d','e','f', 'g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v', 'w','x','y','z','0','1','2','3','4','5','6','7','8','9','+','/' }; @implementation NSData (AESCrypt) - (NSData *)AES256EncryptWithKey:(NSString *)key { // 'key' should be 32 bytes for AES256, will be null-padded otherwise char keyPtr[kCCKeySizeAES256 + 1]; // room for terminator (unused) bzero( keyPtr, sizeof( keyPtr ) ); // fill with zeroes (for padding) // fetch key data [key getCString:keyPtr maxLength:sizeof( keyPtr ) encoding:NSUTF8StringEncoding]; NSUInteger dataLength = [self length]; //See the doc: For block ciphers, the output size will always be less than or //equal to the input size plus the size of one block. //That's why we need to add the size of one block here size_t bufferSize = dataLength + kCCBlockSizeAES128; void *buffer = malloc( bufferSize ); size_t numBytesEncrypted = 0; CCCryptorStatus cryptStatus = CCCrypt( kCCEncrypt, kCCAlgorithmAES128, kCCOptionECBMode + kCCOptionPKCS7Padding, keyPtr, kCCKeySizeAES256, NULL /* initialization vector (optional) */, [self bytes], dataLength, /* input */ buffer, bufferSize, /* output */ &amp;numBytesEncrypted ); if( cryptStatus == kCCSuccess ) { //the returned NSData takes ownership of the buffer and will free it on deallocation return [NSData dataWithBytesNoCopy:buffer length:numBytesEncrypted]; } free( buffer ); //free the buffer return nil; } - (NSData *)AES256DecryptWithKey:(NSString *)key { // 'key' should be 32 bytes for AES256, will be null-padded otherwise char keyPtr[kCCKeySizeAES256+1]; // room for terminator (unused) bzero( keyPtr, sizeof( keyPtr ) ); // fill with zeroes (for padding) // fetch key data [key getCString:keyPtr maxLength:sizeof( keyPtr ) encoding:NSUTF8StringEncoding]; NSUInteger dataLength = [self length]; //See the doc: For block ciphers, the output size will always be less than or //equal to the input size plus the size of one block. //That's why we need to add the size of one block here size_t bufferSize = dataLength + kCCBlockSizeAES128; void *buffer = malloc( bufferSize ); size_t numBytesDecrypted = 0; CCCryptorStatus cryptStatus = CCCrypt( kCCDecrypt, kCCAlgorithmAES128, kCCOptionECBMode + kCCOptionPKCS7Padding, keyPtr, kCCKeySizeAES256, NULL /* initialization vector (optional) */, [self bytes], dataLength, /* input */ buffer, bufferSize, /* output */ &amp;numBytesDecrypted ); if( cryptStatus == kCCSuccess ) { //the returned NSData takes ownership of the buffer and will free it on deallocation return [NSData dataWithBytesNoCopy:buffer length:numBytesDecrypted]; } free( buffer ); //free the buffer return nil; } #pragma mark - + (NSData *)dataWithBase64EncodedString:(NSString *)string { return [[[NSData allocWithZone:nil] initWithBase64EncodedString:string] autorelease]; } - (id)initWithBase64EncodedString:(NSString *)string { NSMutableData *mutableData = nil; if( string ) { unsigned long ixtext = 0; unsigned long lentext = 0; unsigned char ch = 0; unsigned char inbuf[4], outbuf[3]; short i = 0, ixinbuf = 0; BOOL flignore = NO; BOOL flendtext = NO; NSData *base64Data = nil; const unsigned char *base64Bytes = nil; // Convert the string to ASCII data. base64Data = [string dataUsingEncoding:NSASCIIStringEncoding]; base64Bytes = [base64Data bytes]; mutableData = [NSMutableData dataWithCapacity:base64Data.length]; lentext = base64Data.length; while( YES ) { if( ixtext &gt;= lentext ) break; ch = base64Bytes[ixtext++]; flignore = NO; if( ( ch &gt;= 'A' ) &amp;&amp; ( ch &lt;= 'Z' ) ) ch = ch - 'A'; else if( ( ch &gt;= 'a' ) &amp;&amp; ( ch &lt;= 'z' ) ) ch = ch - 'a' + 26; else if( ( ch &gt;= '0' ) &amp;&amp; ( ch &lt;= '9' ) ) ch = ch - '0' + 52; else if( ch == '+' ) ch = 62; else if( ch == '=' ) flendtext = YES; else if( ch == '/' ) ch = 63; else flignore = YES; if( ! flignore ) { short ctcharsinbuf = 3; BOOL flbreak = NO; if( flendtext ) { if( ! ixinbuf ) break; if( ( ixinbuf == 1 ) || ( ixinbuf == 2 ) ) ctcharsinbuf = 1; else ctcharsinbuf = 2; ixinbuf = 3; flbreak = YES; } inbuf [ixinbuf++] = ch; if( ixinbuf == 4 ) { ixinbuf = 0; outbuf [0] = ( inbuf[0] &lt;&lt; 2 ) | ( ( inbuf[1] &amp; 0x30) &gt;&gt; 4 ); outbuf [1] = ( ( inbuf[1] &amp; 0x0F ) &lt;&lt; 4 ) | ( ( inbuf[2] &amp; 0x3C ) &gt;&gt; 2 ); outbuf [2] = ( ( inbuf[2] &amp; 0x03 ) &lt;&lt; 6 ) | ( inbuf[3] &amp; 0x3F ); for( i = 0; i &lt; ctcharsinbuf; i++ ) [mutableData appendBytes:&amp;outbuf[i] length:1]; } if( flbreak ) break; } } } self = [self initWithData:mutableData]; return self; } #pragma mark - - (NSString *)base64Encoding { return [self base64EncodingWithLineLength:0]; } - (NSString *)base64EncodingWithLineLength:(NSUInteger)lineLength { const unsigned char *bytes = [self bytes]; NSMutableString *result = [NSMutableString stringWithCapacity:self.length]; unsigned long ixtext = 0; unsigned long lentext = self.length; long ctremaining = 0; unsigned char inbuf[3], outbuf[4]; unsigned short i = 0; unsigned short charsonline = 0, ctcopy = 0; unsigned long ix = 0; while( YES ) { ctremaining = lentext - ixtext; if( ctremaining &lt;= 0 ) break; for( i = 0; i &lt; 3; i++ ) { ix = ixtext + i; if( ix &lt; lentext ) inbuf[i] = bytes[ix]; else inbuf [i] = 0; } outbuf [0] = (inbuf [0] &amp; 0xFC) &gt;&gt; 2; outbuf [1] = ((inbuf [0] &amp; 0x03) &lt;&lt; 4) | ((inbuf [1] &amp; 0xF0) &gt;&gt; 4); outbuf [2] = ((inbuf [1] &amp; 0x0F) &lt;&lt; 2) | ((inbuf [2] &amp; 0xC0) &gt;&gt; 6); outbuf [3] = inbuf [2] &amp; 0x3F; ctcopy = 4; switch( ctremaining ) { case 1: ctcopy = 2; break; case 2: ctcopy = 3; break; } for( i = 0; i &lt; ctcopy; i++ ) [result appendFormat:@"%c", encodingTable[outbuf[i]]]; for( i = ctcopy; i &lt; 4; i++ ) [result appendString:@"="]; ixtext += 3; charsonline += 4; if( lineLength &gt; 0 ) { if( charsonline &gt;= lineLength ) { charsonline = 0; [result appendString:@"\n"]; } } } return [NSString stringWithString:result]; } #pragma mark - - (BOOL)hasPrefixBytes:(const void *)prefix length:(NSUInteger)length { if( ! prefix || ! length || self.length &lt; length ) return NO; return ( memcmp( [self bytes], prefix, length ) == 0 ); } - (BOOL)hasSuffixBytes:(const void *)suffix length:(NSUInteger)length { if( ! suffix || ! length || self.length &lt; length ) return NO; return ( memcmp( ((const char *)[self bytes] + (self.length - length)), suffix, length ) == 0 ); } @end </code></pre> <p>I execute above function and write the resulting data to the log with this code:</p> <pre><code>NSString * _secret = @"6bc1bee22e409f96e93d7e117393172a"; NSString * _key = @"603deb1015ca71be2b73aef0857d77811f352c073b6108d72d9810a30914dff4"; NSString *encryptedString = [_secret AES256EncryptWithKey:_key]; NSLog(@"Encrypted ID : %@", encryptedString); NSString *decryptedString = [encryptedString AES256DecryptWithKey:_key]; NSLog(@"Decrypted ID : %@", decryptedString); </code></pre> <p>As from test vector, the encrypted cipher should be this:</p> <blockquote> <p>f3eed1bdb5d2a03c064b5a7e3db181f8</p> </blockquote> <p>Result logs:</p> <pre><code>2011-10-19 13:32:41.640 Ticket[2215:707] Encrypted ID : XWLsnTQvocXNkAqVisEgWTCPdYR6KPoIojezjN3fn/wuytQkpUZnNbzUoT4peeTK 2011-10-19 13:32:41.641 Ticket[2215:707] Decrypted ID : 6bc1bee22e409f96e93d7e117393172a </code></pre> <p>I know that this Encrypted ID is in Base64, but still even if i convert it to HEX, the actual output varies from the result.</p> <p>What option am I forgetting? Is the encoding of the NSData returned something else…?</p> <p>So if someone could direct me on the right path that would be great, Cheers.</p>
    singulars
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    plurals
    1. This table or related slice is empty.
    1. This table or related slice is empty.
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload