How to Base64 encoding on the iPhone - objective-c

How do I do Base64 encoding on the iPhone?
I have found a few examples that looked promising, but could never get any of them to work on the phone.

You can see an example here.
This is for iOS7+.
I copy the code here, just in case:
// Create NSData object
NSData *nsdata = [#"iOS Developer Tips encoded in Base64"
dataUsingEncoding:NSUTF8StringEncoding];
// Get NSString from NSData object in Base64
NSString *base64Encoded = [nsdata base64EncodedStringWithOptions:0];
// Print the Base64 encoded string
NSLog(#"Encoded: %#", base64Encoded);
// Let's go the other way...
// NSData from the Base64 encoded str
NSData *nsdataFromBase64String = [[NSData alloc]
initWithBase64EncodedString:base64Encoded options:0];
// Decoded NSString from the NSData
NSString *base64Decoded = [[NSString alloc]
initWithData:nsdataFromBase64String encoding:NSUTF8StringEncoding];
NSLog(#"Decoded: %#", base64Decoded);

Use this library to encode Base64.
It also supports ARC

I also had trouble finding working code for the iPhone that I could understand.
I finally wrote this.
-(NSString *)Base64Encode:(NSData *)data;
-(NSString *)Base64Encode:(NSData *)data{
//Point to start of the data and set buffer sizes
int inLength = [data length];
int outLength = ((((inLength * 4)/3)/4)*4) + (((inLength * 4)/3)%4 ? 4 : 0);
const char *inputBuffer = [data bytes];
char *outputBuffer = malloc(outLength+1);
outputBuffer[outLength] = 0;
//64 digit code
static char Encode[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
//Start the count
int cycle = 0;
int inpos = 0;
int outpos = 0;
char temp;
//Pad the last to bytes, the outbuffer must always be a multiple of 4.
outputBuffer[outLength-1] = '=';
outputBuffer[outLength-2] = '=';
/* http://en.wikipedia.org/wiki/Base64
Text content M a n
ASCII 77 97 110
8 Bit pattern 01001101 01100001 01101110
6 Bit pattern 010011 010110 000101 101110
Index 19 22 5 46
Base64-encoded T W F u
*/
while (inpos < inLength){
switch (cycle) {
case 0:
outputBuffer[outpos++] = Encode[(inputBuffer[inpos] & 0xFC) >> 2];
cycle = 1;
break;
case 1:
temp = (inputBuffer[inpos++] & 0x03) << 4;
outputBuffer[outpos] = Encode[temp];
cycle = 2;
break;
case 2:
outputBuffer[outpos++] = Encode[temp|(inputBuffer[inpos]&0xF0) >> 4];
temp = (inputBuffer[inpos++] & 0x0F) << 2;
outputBuffer[outpos] = Encode[temp];
cycle = 3;
break;
case 3:
outputBuffer[outpos++] = Encode[temp|(inputBuffer[inpos]&0xC0) >> 6];
cycle = 4;
break;
case 4:
outputBuffer[outpos++] = Encode[inputBuffer[inpos++] & 0x3f];
cycle = 0;
break;
default:
cycle = 0;
break;
}
}
NSString *pictemp = [NSString stringWithUTF8String:outputBuffer];
free(outputBuffer);
return pictemp;
}

Download following two files from GitHub
Base64.h
Base64.m
Add these files to your project
Import header file in desired file
#import "Base64.h"
And use as to encode
NSString *plainText = #"Your String";
NSString *base64String = [plainText base64EncodedStringWithWrapWidth:0];
Also you can decode it as
NSString *plainText = [base64String base64DecodedString];

Try this out...this worked perfectly for me.create a category Base64.h and Base 64.m,Import to any class you want to use and call it using single line for base 64 encoding to happen.
//
// Base64.h
// CryptTest
// Created by SURAJ K THOMAS on 02/05/2013.
#import <Foundation/Foundation.h>
#interface Base64 : NSObject {
}
+ (void) initialize;
+ (NSString*) encode:(const uint8_t*) input length:(NSInteger) length;
+ (NSString*) encode:(NSData*) rawBytes;
+ (NSData*) decode:(const char*) string length:(NSInteger) inputLength;
+ (NSData*) decode:(NSString*) string;
#end
#import "Base64.h"
#implementation Base64
#define ArrayLength(x) (sizeof(x)/sizeof(*(x)))
static char encodingTable[] =
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
static char decodingTable[128];
+ (void) initialize {
if (self == [Base64 class]) {
memset(decodingTable, 0, ArrayLength(decodingTable));
for (NSInteger i = 0; i < ArrayLength(encodingTable); i++) {
decodingTable[encodingTable[i]] = i;
}
}
}
+ (NSString*) encode:(const uint8_t*) input length:(NSInteger) length {
NSMutableData* data = [NSMutableData dataWithLength:((length + 2) / 3) * 4];
uint8_t* output = (uint8_t*)data.mutableBytes;
for (NSInteger i = 0; i < length; i += 3) {
NSInteger value = 0;
for (NSInteger j = i; j < (i + 3); j++) {
value <<= 8;
if (j < length) {
value |= (0xFF & input[j]);
}
}
NSInteger index = (i / 3) * 4;
output[index + 0] = encodingTable[(value >> 18) & 0x3F];
output[index + 1] = encodingTable[(value >> 12) & 0x3F];
output[index + 2] = (i + 1) < length ? encodingTable[(value >> 6) & 0x3F] : '=';
output[index + 3] = (i + 2) < length ? encodingTable[(value >> 0) & 0x3F] : '=';
}
return [[NSString alloc] initWithData:data
encoding:NSASCIIStringEncoding];
}
+ (NSString*) encode:(NSData*) rawBytes {
return [self encode:(const uint8_t*) rawBytes.bytes length:rawBytes.length];
}
+ (NSData*) decode:(const char*) string length:(NSInteger) inputLength {
if ((string == NULL) || (inputLength % 4 != 0)) {
return nil;
}
while (inputLength > 0 && string[inputLength - 1] == '=') {
inputLength--;
}
NSInteger outputLength = inputLength * 3 / 4;
NSMutableData* data = [NSMutableData dataWithLength:outputLength];
uint8_t* output = data.mutableBytes;
NSInteger inputPoint = 0;
NSInteger outputPoint = 0;
while (inputPoint < inputLength) {
char i0 = string[inputPoint++];
char i1 = string[inputPoint++];
char i2 = inputPoint < inputLength ? string[inputPoint++] : 'A'; /* 'A' will
decode to \0 */
char i3 = inputPoint < inputLength ? string[inputPoint++] : 'A';
output[outputPoint++] = (decodingTable[i0] << 2) | (decodingTable[i1] >> 4);
if (outputPoint < outputLength) {
output[outputPoint++] = ((decodingTable[i1] & 0xf) << 4) |
(decodingTable[i2] >> 2);
}
if (outputPoint < outputLength) {
output[outputPoint++] = ((decodingTable[i2] & 0x3) << 6) |
decodingTable[i3];
}
}
return data;
}
+ (NSData*) decode:(NSString*) string {
return [self decode:[string cStringUsingEncoding:NSASCIIStringEncoding]
length:string.length];
}
#end
now import the above category to any class and convert the string like below
NSString *authString = [[NSString stringWithFormat:#"OD0EK819OJFIFT6OJZZXT09Y1YUT1EJ2"]
stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
NSData *inputData = [authString dataUsingEncoding:NSUTF8StringEncoding];
NSString *finalAuth =[Base64 encode:inputData];
NSLog(#"Encoded string =%#", finalAuth);

reference
NSString *plainString = #"foo";
Encoding
NSData *plainData = [plainString dataUsingEncoding:NSUTF8StringEncoding];
NSString *base64String = [plainData base64EncodedStringWithOptions:0];
NSLog(#"%#", base64String); // Zm9v
Decoding
NSData *decodedData = [[NSData alloc] initWithBase64EncodedString:base64String options:0];
NSString *decodedString = [[NSString alloc] initWithData:decodedData encoding:NSUTF8StringEncoding];
NSLog(#"%#", decodedString); // foo

Seems as of iOS 7 you no longer need any libraries to encode in Base64. Following methods on NSData can be used to Base64 encode:
base64EncodedDataWithOptions:
– base64EncodedStringWithOptions:

I did my own implementation, where has been removed all checks inside the loop. So on big amount of data, it works faster. You can take it as a basis for own solution.
static char *alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
+ (NSString *)encodeString:(NSString *)data
{
const char *input = [data cStringUsingEncoding:NSUTF8StringEncoding];
unsigned long inputLength = [data length];
unsigned long modulo = inputLength % 3;
unsigned long outputLength = (inputLength / 3) * 4 + (modulo ? 4 : 0);
unsigned long j = 0;
// Do not forget about trailing zero
unsigned char *output = malloc(outputLength + 1);
output[outputLength] = 0;
// Here are no checks inside the loop, so it works much faster than other implementations
for (unsigned long i = 0; i < inputLength; i += 3) {
output[j++] = alphabet[ (input[i] & 0xFC) >> 2 ];
output[j++] = alphabet[ ((input[i] & 0x03) << 4) | ((input[i + 1] & 0xF0) >> 4) ];
output[j++] = alphabet[ ((input[i + 1] & 0x0F)) << 2 | ((input[i + 2] & 0xC0) >> 6) ];
output[j++] = alphabet[ (input[i + 2] & 0x3F) ];
}
// Padding in the end of encoded string directly depends of modulo
if (modulo > 0) {
output[outputLength - 1] = '=';
if (modulo == 1)
output[outputLength - 2] = '=';
}
NSString *s = [NSString stringWithUTF8String:(const char *)output];
free(output);
return s;
}

This answer is outdated, use https://stackoverflow.com/a/24468530/669586 since iOS 7.
A method in a NSData category
- (NSString*)encodeBase64 {
static char* alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";
unsigned int length = self.length;
unsigned const char* rawData = self.bytes;
//empty data = empty output
if (length == 0) {
return #"";
}
unsigned int outputLength = (((length + 2) / 3) * 4);
//let's allocate buffer for the output
char* rawOutput = malloc(outputLength + 1);
//with each step we get 3 bytes from the input and write 4 bytes to the output
for (unsigned int i = 0, outputIndex = 0; i < length; i += 3, outputIndex += 4) {
BOOL triple = NO;
BOOL quad = NO;
//get 3 bytes (or only 1 or 2 when we have reached the end of input)
unsigned int value = rawData[i];
value <<= 8;
if (i + 1 < length) {
value |= rawData[i + 1];
triple = YES;
}
value <<= 8;
if (i + 2 < length) {
value |= rawData[i + 2];
quad = YES;
}
//3 * 8 bits written as 4 * 6 bits (indexing the 64 chars of the alphabet)
//write = if end of input reached
rawOutput[outputIndex + 3] = (quad) ? alphabet[value & 0x3F] : '=';
value >>= 6;
rawOutput[outputIndex + 2] = (triple) ? alphabet[value & 0x3F] : '=';
value >>= 6;
rawOutput[outputIndex + 1] = alphabet[value & 0x3F];
value >>= 6;
rawOutput[outputIndex] = alphabet[value & 0x3F];
}
rawOutput[outputLength] = 0;
NSString* output = [NSString stringWithCString:rawOutput encoding:NSASCIIStringEncoding];
free(rawOutput);
return output;
}

Related

Objective - C : unsigned int to base64

My server devs ask me to send them some data encoded with base64 with this rules:
big-endian byte order
no extra zero bytes
base64 string
for example:
10005000 → «mKol»
1234567890 → «SZYC0g»
I did some spaghetti code, and it's work. But maybe somebody have more elegant solution?
+ (NSString*)encodeBigEndianBase64:(uint32_t)value {
char *bytes = (char*) &value;
int len = sizeof(uint32_t);
char *reverseBytes = malloc(sizeof(char) * len);
unsigned long index = len - 1;
for (int i = 0; i < len; i++)
reverseBytes[index--] = bytes[i];
int offset = 0;
while (reverseBytes[offset] == 0) {
offset++;
}
NSData *resultData;
if (offset > 0) {
int truncatedLen = (len - offset);
char *truncateBytes = malloc(sizeof(char) * truncatedLen);
for (int i = 0; i < truncatedLen ; i++)
truncateBytes[i] = reverseBytes[i + offset];
resultData = [NSData dataWithBytes:truncateBytes length:truncatedLen];
free(truncateBytes);
} else {
resultData = [NSData dataWithBytes:reverseBytes length:len];
}
free(reverseBytes);
return [[resultData base64EncodedStringWithOptions:NSDataBase64Encoding64CharacterLineLength] stringByReplacingOccurrencesOfString:#"=" withString:#""];
}
Little bit improved solution (thanks to zaph):
+ (NSString*)encodeBigEndianBase64:(uint32_t)value {
uint32_t swappedValue = CFSwapInt32HostToBig(value);
char *swappedBytes = (char*) &swappedValue;
int len = sizeof(uint32_t);
int offset = 0;
while (swappedBytes[offset] == 0) {
offset++;
}
NSData *resultData;
if (offset > 0) {
int truncatedLen = (len - offset);
char *truncateBytes = malloc(sizeof(char) * truncatedLen);
for (int i = 0; i < truncatedLen ; i++)
truncateBytes[i] = swappedBytes[i + offset];
resultData = [NSData dataWithBytes:truncateBytes length:truncatedLen];
free(truncateBytes);
} else {
resultData = [NSData dataWithBytes:swappedBytes length:len];
}
return [[resultData base64EncodedStringWithOptions:NSDataBase64Encoding64CharacterLineLength] stringByReplacingOccurrencesOfString:#"=" withString:#""];
}
For endian conversions use htons(), htonl(), ntohs(), ntohl()
network byte order is bigendian
`htons()` // host to network short
`htonl()` // host to network ling
`ntohs()` // network to host long
`ntohl()` // network to host long
These are defined in endan.h
Also see Byte-Order Utilities Reference

Calculate LRC in Objective c

I want to calculate the LRC of a message that I send via Bluetooth. Here is for example a message :
(The message structure is STX MESSAGE FS EXT LRC)
02 1212004123422826E0B8C0F000F0A00182620000THYRON SYSTEMS WATFORD UKR 1C 03 60
STX = 02
MESSAGE = 1212004123422826E0B8C0F000F0A00182620000THYRON SYSTEMS WATFORD UKR
FS = 1C
EXT = 03
LRC = 60
What I have to do is calculate the LRC by performing a modulo 2 binary sum of every character in the communication message excluding the STX character but including the EXT characterr.
Before to calculate the LRC, I have to convert this NSString in HexaString :
31323132 30303431 32333432 32383236 45304238 43304630 30304630 41303031 38323632 30303030 54485952 4f4e2053 59535445 4d532057 4154464f 52442055 4b521c03
Method used :
- (NSString *) stringToHex:(NSString *)str
{
NSUInteger len = [str length];
unichar *chars = malloc(len * sizeof(unichar));
[str getCharacters:chars];
NSMutableString *hexString = [[NSMutableString alloc] init];
for(NSUInteger i = 0; i < len; i++ )
{
[hexString appendFormat:#"%02x", chars[i]];
}
free(chars);
return [hexString autorelease];
}
And then I have to convert it in Byte Array.
Method used :
- (NSData*) hexToBytes:(NSString *) hexaStr {
NSMutableData* data = [NSMutableData data];
int idx;
for (idx = 0; idx+2 <= hexaStr.length; idx+=2) {
NSRange range = NSMakeRange(idx, 2);
NSString * hexStrTmp = [hexaStr substringWithRange:range];
NSScanner* scanner = [NSScanner scannerWithString:hexStrTmp];
unsigned int intValue;
[scanner scanHexInt:&intValue];
[data appendBytes:&intValue length:1];
}
return data;
}
And then I try to do calculate my LRC, that should be 60, with the following :
- (void) calculateLRC:(NSString *) text {
NSData * data = [self hexToBytes:text];
NSUInteger size = [data length] / sizeof(const char);
const char * array = (const char*) [data bytes];
char checksum = 0;
for( uint32_t i = 0 ; i < size; i++) {
checksum += * array++;
}
NSLog(#"Checksum = %c", checksum);
self.LRC_Check = checksum;
}
The problem is that "checksum" has not the value "60" in it. Can someone help me with that please ?
Thanx in advance !
I have the answer !
In the method - (void) calculateLRC:(NSString *) text I have to replace :
checksum += * array++;
with :
checksum ^= * array++;
I thougt the Modulo character was "%" in Objective C...
I needed to do this in swift
this seems to work . .need to do some rigorous testing though..
var str = computeLRC(hexString:"373203")
print(str)
// returns 06
func computeLRC (hexString: String ) -> String {
var checksum : UInt16 = 0
var my = ""
for i in stride(from: 0, to: hexString.count, by: 2) {
let indexStartOfText = hexString.index( hexString.startIndex, offsetBy: i)
let indexEndOfText = hexString.index( indexStartOfText, offsetBy: 2)
let substring3 = hexString[indexStartOfText..<indexEndOfText]
let intResult = Int(String(substring3) , radix: 16)
guard let myUnicodeScalar = UnicodeScalar(intResult!) else {
return ""
}
// convert UnicodeScalar to Character
let myCharacter = Character(myUnicodeScalar)
my += String(myCharacter)
}
for myChar in my {
var byte: UInt16 = Array(String(myChar).utf16)[0]
checksum ^= byte
}
return String(format:"%02X", checksum)
}

decode route from google API

i am desperately trying to find a way on how to get an Array of all the Coordinates (or a Polyline) from the google API so that I can draw my route on the MKMapView.
( By the way, I don´t want to use the RegexKitLite)
As I found elsewhere, this should be the right way to call for the API.
NSString* apiUrlStr = [NSString stringWithFormat:#"http://maps.google.com/maps?output=dragdir&saddr=%#&daddr=%#", saddr, daddr];
NSURL* apiUrl = [NSURL URLWithString:apiUrlStr];
encodedString = ..... ???? // here i need some code before i can call the following Method
[self polylineWithEncodedString:encodedString];
and here is a method i found, to get a polyline.
+ (MKPolyline *)polylineWithEncodedString:(NSString *)encodedString {
const char *bytes = [encodedString UTF8String];
NSUInteger length = [encodedString lengthOfBytesUsingEncoding:NSUTF8StringEncoding];
NSUInteger idx = 0;
NSUInteger count = length / 4;
CLLocationCoordinate2D *coords = calloc(count, sizeof(CLLocationCoordinate2D));
NSUInteger coordIdx = 0;
float latitude = 0;
float longitude = 0;
while (idx < length) {
char byte = 0;
int res = 0;
char shift = 0;
do {
byte = bytes[idx++] - 63;
res |= (byte & 0x1F) << shift;
shift += 5;
} while (byte >= 0x20);
float deltaLat = ((res & 1) ? ~(res >> 1) : (res >> 1));
latitude += deltaLat;
shift = 0;
res = 0;
do {
byte = bytes[idx++] - 0x3F;
res |= (byte & 0x1F) << shift;
shift += 5;
} while (byte >= 0x20);
float deltaLon = ((res & 1) ? ~(res >> 1) : (res >> 1));
longitude += deltaLon;
float finalLat = latitude * 1E-5;
float finalLon = longitude * 1E-5;
CLLocationCoordinate2D coord = CLLocationCoordinate2DMake(finalLat, finalLon);
coords[coordIdx++] = coord;
if (coordIdx == count) {
NSUInteger newCount = count + 10;
coords = realloc(coords, newCount * sizeof(CLLocationCoordinate2D));
count = newCount;
}
}
MKPolyline *polyline = [MKPolyline polylineWithCoordinates:coords count:coordIdx];
free(coords);
return polyline;
}
Code from here works perfectly well:
https://gist.github.com/Muximize/3770235
+ (MKPolyline *)polylineWithGMEncodedString:(NSString *)encodedString {
const char *bytes = [encodedString UTF8String];
NSUInteger length = [encodedString lengthOfBytesUsingEncoding:NSUTF8StringEncoding];
NSUInteger idx = 0;
NSUInteger count = length / 4;
CLLocationCoordinate2D *coords = calloc(count, sizeof(CLLocationCoordinate2D));
NSUInteger coordIdx = 0;
float latitude = 0;
float longitude = 0;
while (idx < length) {
char byte = 0;
int res = 0;
char shift = 0;
do {
byte = bytes[idx++] - 63;
res |= (byte & 0x1F) << shift;
shift += 5;
} while (byte >= 0x20);
float deltaLat = ((res & 1) ? ~(res >> 1) : (res >> 1));
latitude += deltaLat;
shift = 0;
res = 0;
do {
byte = bytes[idx++] - 0x3F;
res |= (byte & 0x1F) << shift;
shift += 5;
} while (byte >= 0x20);
float deltaLon = ((res & 1) ? ~(res >> 1) : (res >> 1));
longitude += deltaLon;
float finalLat = latitude * 1E-5;
float finalLon = longitude * 1E-5;
CLLocationCoordinate2D coord = CLLocationCoordinate2DMake(finalLat, finalLon);
coords[coordIdx++] = coord;
if (coordIdx == count) {
NSUInteger newCount = count + 10;
coords = realloc(coords, newCount * sizeof(CLLocationCoordinate2D));
count = newCount;
}
}
MKPolyline *polyline = [MKPolyline polylineWithCoordinates:coords count:coordIdx];
free(coords);
return polyline;
}
Calling...
NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:[NSString stringWithFormat:#"http://maps.googleapis.com/maps/api/directions/json?origin=%#,%#&destination=%f,%f&mode=driving&sensor=false",smAppDelegate.currPosition.latitude, smAppDelegate.currPosition.longitude, ((LocationItem*)selectedAnno).coordinate.latitude, ((LocationItem*)selectedAnno).coordinate.longitude]]];
[[NSURLConnection alloc] initWithRequest:request delegate:self];
Response...
-(void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response{
[self.responseDirectionData setLength:0];
}
-(void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data{
[self.responseDirectionData appendData:data];
}
-(void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error{
[connection release];
self.responseDirectionData =nil;
}
-(void)connectionDidFinishLoading:(NSURLConnection *)connection{
NSLog(#"connection established");
[connection release];
NSError *error = nil;
NSString *responseString=[[NSString alloc]initWithData:responseDirectionData encoding:NSUTF8StringEncoding];
SBJsonParser *jsonParser = [[SBJsonParser alloc] init];
NSDictionary *jsonObjects = [jsonParser objectWithString:responseString error:&error];
NSLog(#"responce = %#",jsonObjects);
NSMutableArray *ad = [jsonObjects objectForKey:#"routes"];
NSMutableArray *data2 = [[ad objectAtIndex:0] objectForKey:#"legs"];
NSMutableArray *data3 = [[data2 objectAtIndex:0] objectForKey:#"steps"];
NSLog(#"Data3 %#", data3);
NSMutableArray *polyLinesArray = [[NSMutableArray alloc] init];
for (int i = 0; i < [data3 count]; i++)
{
NSString* encodedPoints = [[[data3 objectAtIndex:i] objectForKey:#"polyline"] valueForKey:#"points"];
MKPolyline *route = [self polylineWithEncodedString:encodedPoints];
[polyLinesArray addObject:route];
}
[self.mapView addOverlays:polyLinesArray];
[polyLinesArray release];
}

AES Encryption for an NSString?

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:
Cipher Method : AES256
Cipher Mode: ECB
Padding: PKCS5Padding
Since my initial trials failed to decrypt. So I played around with some test vectors to see the code that i use was right,
This is the code that encrypts the data:
NSString+AESCrypt.h
-------------------
#import <Foundation/Foundation.h>
#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 <Foundation/Foundation.h>
#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 <CommonCrypto/CommonCryptor.h>
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 */
&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 */
&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 >= lentext ) break;
ch = base64Bytes[ixtext++];
flignore = NO;
if( ( ch >= 'A' ) && ( ch <= 'Z' ) ) ch = ch - 'A';
else if( ( ch >= 'a' ) && ( ch <= 'z' ) ) ch = ch - 'a' + 26;
else if( ( ch >= '0' ) && ( ch <= '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] << 2 ) | ( ( inbuf[1] & 0x30) >> 4 );
outbuf [1] = ( ( inbuf[1] & 0x0F ) << 4 ) | ( ( inbuf[2] & 0x3C ) >> 2 );
outbuf [2] = ( ( inbuf[2] & 0x03 ) << 6 ) | ( inbuf[3] & 0x3F );
for( i = 0; i < ctcharsinbuf; i++ )
[mutableData appendBytes:&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 <= 0 ) break;
for( i = 0; i < 3; i++ )
{
ix = ixtext + i;
if( ix < lentext ) inbuf[i] = bytes[ix];
else inbuf [i] = 0;
}
outbuf [0] = (inbuf [0] & 0xFC) >> 2;
outbuf [1] = ((inbuf [0] & 0x03) << 4) | ((inbuf [1] & 0xF0) >> 4);
outbuf [2] = ((inbuf [1] & 0x0F) << 2) | ((inbuf [2] & 0xC0) >> 6);
outbuf [3] = inbuf [2] & 0x3F;
ctcopy = 4;
switch( ctremaining )
{
case 1:
ctcopy = 2;
break;
case 2:
ctcopy = 3;
break;
}
for( i = 0; i < ctcopy; i++ )
[result appendFormat:#"%c", encodingTable[outbuf[i]]];
for( i = ctcopy; i < 4; i++ )
[result appendString:#"="];
ixtext += 3;
charsonline += 4;
if( lineLength > 0 )
{
if( charsonline >= 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 < length ) return NO;
return ( memcmp( [self bytes], prefix, length ) == 0 );
}
- (BOOL)hasSuffixBytes:(const void *)suffix length:(NSUInteger)length
{
if( ! suffix || ! length || self.length < length ) return NO;
return ( memcmp( ((const char *)[self bytes] + (self.length - length)), suffix, length ) == 0 );
}
#end
I execute above function and write the resulting data to the log with this 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);
As from test vector, the encrypted cipher should be this:
f3eed1bdb5d2a03c064b5a7e3db181f8
Result logs:
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
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.
What option am I forgetting? Is the encoding of the NSData returned something else…?
So if someone could direct me on the right path that would be great, Cheers.
I htink the problem is that the test-vector-page assumes that these printed hex-values are binaries and not text: The string "6b" does look utf-8 encoded like this: 0x3662.
for getting the correct test-string you have to encode it first. your string should start with this: #"kÁ¾â....". That String will result in the right hexa-representation if it will be ecnoded with utf-8.
You should either test your aes-encryption with NSData initialized with an hex-string or you have to decode utf-8 first to pack all that into a string. But take care: there are often symbols which cannot be represented/printed and even worse: if your tesdata or the cypher contains the Zero-Byte then this will cause some problems because it is often used as a termination-symbol in strings which normally contains only readable charachters. (dont know how this interacts with NSString)
or use the first variant to create an NSData out of a hex-string and then convert that data to an NSString

Insert a #"\n" in NSString

For example, if I start with this string:
NSString * labeltext = #"abcdefghijk";
I want this string change to #"abc\n def\n ghi \n jk".
I want #"\n" to be inserted at an interval of 3.
How can I accomplish this?
Use a NSMutableString and then for loop through the original NSString.
NSMutableString *buffer = [[NSMutableString alloc] init];
int len = [labelText length];
for (i = 0; i < len; i++) {
NSRange charAt = NSMakeRange(i,1);
[buffer appendString: [labelText substringWithRange: charAt]];
if ((i % 3) == 2) {
[buffer appendString: #"\n"];
}
}
labelText = (NSString *)buffer;
The above example is pure Objective-C. This can also be accomplished using C. Convert the NSString into a cstring and then loop through the array. For instance,
const char *str = [labelText UTF8String];
int len = strlen(str) - 1;
int pos = 0;
char buffer[(len * 2) + 1];
for (i = 0; i < len; i++) {
char ch = str[i];
buffer[pos] = ch;
pos++;
if ((i % 3) == 2) {
buffer[pos] = '\n';
pos++;
}
}
buffer[pos] = '\0';
labelText = [NSString stringWithFormat: #"%s", buffer];