RSA Encryption-Decryption in iphone - iphone

I am developing Iphone application. I have used SecKeyGeneratePair method of Security/Security.h framework. I am getting public & private keys as SecKeyRef objects. Can I access the key or print its value to console? Can I get NSString or NSData object from it ? When i print the key to console using NSLog I am getting . Can we pass these key objects over network to other application which might be in java? Can we encrypt some text in iphone application, send it to server, using the key sent decrypt the text on server side ?
Edited to add
Thanks Alex Reynolds for your quick response. In case of RSA Encryption first I have to generate a key pair which is in the form of SecKeyRef objects. Then we will pass that reference to SecKeyEncrypt & SecKeyDecrypt methods. when i encrypt & decrypt locally it is working perfect but if i try to send the key & encrypted data to server & decrypt at server(java implementation) side, I am not able to pass the SecKeyRef object to server as a key value. In java we have to get the string in string or byte array format to pass to the encryption method. Can we get the access to the data stored in object SecKeyRef (which is NSCFType object)? which is a struct __SecKey.

Consider using NSData to get the string value, and perhaps use Base64 or some other form of encoding when passing over the network (and then decoding from Base64 to whatever in Java).
Here's an example of some code that might help you get started. I'm doing a HMAC-SHA1 signature ('digest') here, but the general idea is the same for your RSA case:
#import <Foundation/NSString.h>
#import <CommonCrypto/CommonHMAC.h>
#import <CommonCrypto/CommonDigest.h>
#interface NSString (NSStringAdditions)
+ (NSString *) base64StringFromData:(NSData *)data length:(int)length;
- (NSString *) base64StringWithHMACSHA1Digest:(NSString *)secretKey;
#end
-------------------------------------------
#import "NSStringAdditions.h"
static char base64EncodingTable[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 NSString (NSStringAdditions)
- (NSString *) base64StringWithHMACSHA1Digest:(NSString *)secretKey {
unsigned char digest[CC_SHA1_DIGEST_LENGTH];
char *keyCharPtr = strdup([secretKey UTF8String]);
char *dataCharPtr = strdup([self UTF8String]);
CCHmacContext hctx;
CCHmacInit(&hctx, kCCHmacAlgSHA1, keyCharPtr, strlen(keyCharPtr));
CCHmacUpdate(&hctx, dataCharPtr, strlen(dataCharPtr));
CCHmacFinal(&hctx, digest);
NSData *encryptedStringData = [NSData dataWithBytes:digest length:CC_SHA1_DIGEST_LENGTH];
free(keyCharPtr);
free(dataCharPtr);
return [NSString base64StringFromData:encryptedStringData length:[encryptedStringData length]];
}
+ (NSString *) base64StringFromData: (NSData *)data length: (int)length {
unsigned long ixtext, lentext;
long ctremaining;
unsigned char input[3], output[4];
short i, charsonline = 0, ctcopy;
const unsigned char *raw;
NSMutableString *result;
lentext = [data length];
if (lentext < 1)
return #"";
result = [NSMutableString stringWithCapacity: lentext];
raw = [data bytes];
ixtext = 0;
while (true) {
ctremaining = lentext - ixtext;
if (ctremaining <= 0)
break;
for (i = 0; i < 3; i++) {
unsigned long ix = ixtext + i;
if (ix < lentext)
input[i] = raw[ix];
else
input[i] = 0;
}
output[0] = (input[0] & 0xFC) >> 2;
output[1] = ((input[0] & 0x03) << 4) | ((input[1] & 0xF0) >> 4);
output[2] = ((input[1] & 0x0F) << 2) | ((input[2] & 0xC0) >> 6);
output[3] = input[2] & 0x3F;
ctcopy = 4;
switch (ctremaining) {
case 1:
ctcopy = 2;
break;
case 2:
ctcopy = 3;
break;
}
for (i = 0; i < ctcopy; i++)
[result appendString: [NSString stringWithFormat: #"%c", base64EncodingTable[output[i]]]];
for (i = ctcopy; i < 4; i++)
[result appendString: #"="];
ixtext += 3;
charsonline += 4;
if ((length > 0) && (charsonline >= length))
charsonline = 0;
return result;
}
#end

Related

LateInitializationError: Local 'res' has not been initialized

I am making a program for encrypting text relative to a keyword. Initially, the algorithm was written in Python, everything worked correctly. I decided to translate it into a mobile application in Flutter, so I had to rewrite it in Dart.
List symbols = ['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', '.', ',', ';', ':', '-',
'_', ' ', '!', '#', '#', '\$', '%', '^', '&', '*', '(', ')', '+', '=', '\"', '№', '~', '?',
'\\', '/', '|', '[', ']', '{', '}', '`', '\'', '<', '>'];
late dynamic keyWord = ' ';
late dynamic text = ' ';
late dynamic res;
late dynamic a4;
late dynamic m;
late dynamic n;
late dynamic f;
var d = 0;
var k = 0;
var z = 0;
var operation = 0;
var m1 = 0;
var c = 0;
encode(keyWord, text){
late dynamic res;
var l = (text.length) as int;
for( var i = l ; i >= 1; i-- ){
if(symbols.contains(text[d])) {
var f = symbols.indexOf(text[d]);
a4 = '';
if(f == 0){
a4 = '0';
while(f > 0){
a4 = (f % 4).toString() + a4.toString();
f = f ~/ 4;
}
a4 = '$a4';
}
}
else{
a4 += '1123';
}
while(a4.length != 4) {
a4 = '0' + a4;
}
for( var j = 4 ; j >= 1; j-- ){
res += (keyWord[(a4[z]) as int]);
res.whenComplete((){
setState(() {});
});
z += 1;
}
z = 0;
d += 1;
}
return(res);
}
The encode function does not work due to LateInitializationError: Local 'res' has not been initialized.
The rest of the code works correctly, the res
variable was not called anywhere except for this function. Maybe someone faced the same problem or knows how to solve it? I would be grateful for your help.
Exception is pretty self-explanatory. You access res in res += (keyWord[(a4[z]) as int]);, when it's not yet initialized. You should remove late and do dynamic res = '' for example.
P.S. 'res += value' is basically 'res = res + value'. That's why you get the error
P.S.S Why not to use some typing? Your code's res.whenComplete will fail, because it's not a Future. Seems, that you don't use any code completion at all.

In ios 3des encryption contain lots of null termination.when i convert NSData to NSString , it will endup to first null termination?

i have used this function for 3des encryption.
ccStatus = CCCrypt(kCCEncrypt, // CCoperation op
kCCAlgorithm3DES, // CCAlgorithm alg
kCCOptionPKCS7Padding, // kCCOptionPKCS7Padding, //kCCModeECB, // CCOptions
[_keyData bytes], // const void *key
kCCKeySize3DES, // 3DES key size length 24 bit
vinitVec, //iv, // const void *iv,
[dTextIn bytes], // const void *dataIn
[dTextIn length], // size_t dataInLength
bufferPtr, // void *dataOut
bufferPtrSize, // size_t dataOutAvailable
&movedBytes); // size_t *dataOutMoved
NSData *myData = [NSData dataWithBytes:(const void *)bufferPtr length:(NSUInteger)movedBytes];'
Although it is working. but when i convert convert this NSData to NSString , because the NSString contain lots of null termination,NSString end up on first null termination, the variable is not able to contain the whole data. but i have to send encrypted string on the server. what can i do to convert NSData to NSString. string that contain all data means(if the data contain null termination. the string will not end up in that case)?
Please help
Thanks in advance.
thanks for reply ,
look if the encrypted byte contain
char bytes[] = { 'H', 'e', 'l', 'l', 'o', \0, 'W', 'o', 'r', 'l', 'd', \0 };
NSData *data = [NSData dataWithBytes:bytes length:sizeof(bytes)];
NSString *str = [[NSString alloc] initWithData:data encoding:NSASCIIStringEncoding];
NSLog(#"%#", str);
NSString *sendtoserver=[NSString stringwithformat:#"<request>%#</request>",str];
when we convert these NSData to NSString. it will end on first \0 ( null termination)
because we have to send encrypted NSString.so it is making problem. and i can't send the base64string because server side don't want that.they were asking for encrypting string.
so what i do now , please help
and thanks again for reply sir,
Converting NSData to NSString does not stop at null bytes. A NSString can contain arbitrary Unicode characters, including embedded "NULL" characters.
Example:
char bytes[] = { 'H', 'e', 'l', 'l', 'o', 0, 'W', 'o', 'r', 'l', 'd', 0 };
NSData *data = [NSData dataWithBytes:bytes length:sizeof(bytes)];
NSString *str = [[NSString alloc] initWithData:data encoding:NSASCIIStringEncoding];
NSLog(#"%#", str);
Output:
Hello
So it looks as if the string contains only 5 characters and the conversion stopped at the first null byte. But that is only the NSLog output, in fact nothing is lost:
for (int i = 0; i < [str length]; i++) {
unichar c = [str characterAtIndex:i];
NSLog(#"%2d, %3d, %c", i, c, c);
}
Output:
0, 72, H
1, 101, e
2, 108, l
3, 108, l
4, 111, o
5, 0,
6, 87, W
7, 111, o
8, 114, r
9, 108, l
10, 100, d
11, 0,
So the string contains all data and nothing is lost. Probably the string is truncated later, when you send it to the server.
REMARK: Converting the encrypted data to a string seems problematic to me, because the data is interpreted in some character encoding. I have chosen NSASCIIStringEncoding in this example, but according to the documentation this encoding is only valid for ASCII values 0…127.
If you add more information on how and in which format the encrypted data is sent to the server, we might be able to make suggestions how so solve this better.

Send image to web service

I want send an image from my App to web service, to do it, im send the data like an NSData, but it do nothing:
NSData *imagen= UIImagePNGRepresentation(windowImage);
The Web Service wait the data like: base64Binary
To send this type of data, i know that i need convert the NSData to NSString using the famous method "base64Encoding"
NSData *imagen=UIImagePNGRepresentation(windowImage);
NSString *encoded= [imagen base64Encoding];
And i Send the data like SOAP:
NSString *soapMsg= [NSString stringWithFormat:............<imagenBase64>%#<imagenBase64>,encoded];
Where is the error? I need to do other conversion?
See the following answers. Do like this.
NSData *imagen=UIImagePNGRepresentation(windowImage);
NSString *base64String = [self base64StringFromData:imagen length:[imagen length]];
Now, send this base64string to your web service.
static char base64EncodingTable[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', '+', '/'
};
+ (NSString *) base64StringFromData: (NSData *)data length: (int)length {
unsigned long ixtext, lentext;
long ctremaining;
unsigned char input[3], output[4];
short i, charsonline = 0, ctcopy;
const unsigned char *raw;
NSMutableString *result;
lentext = [data length];
if (lentext < 1)
return #"";
result = [NSMutableString stringWithCapacity: lentext];
raw = [data bytes];
ixtext = 0;
while (true) {
ctremaining = lentext - ixtext;
if (ctremaining <= 0)
break;
for (i = 0; i < 3; i++) {
unsigned long ix = ixtext + i;
if (ix < lentext)
input[i] = raw[ix];
else
input[i] = 0;
}
output[0] = (input[0] & 0xFC) >> 2;
output[1] = ((input[0] & 0x03) << 4) | ((input[1] & 0xF0) >> 4);
output[2] = ((input[1] & 0x0F) << 2) | ((input[2] & 0xC0) >> 6);
output[3] = input[2] & 0x3F;
ctcopy = 4;
switch (ctremaining) {
case 1:
ctcopy = 2;
break;
case 2:
ctcopy = 3;
break;
}
for (i = 0; i < ctcopy; i++)
[result appendString: [NSString stringWithFormat: #"%c", base64EncodingTable[output[i]]]];
for (i = ctcopy; i < 4; i++)
[result appendString: #"="];
ixtext += 3;
charsonline += 4;
if ((length > 0) && (charsonline >= length))
charsonline = 0;
}
return result;
}
I tried the code which Raj posted as an answer, and worked perfectly for my iPhone app.
But then I realised that you can do the same thing using one line of code:
NSString* base64string = [imageData base64EncodedStringWithOptions:NSDataBase64Encoding76CharacterLineLength];
And to convert your base64 string back into a binary:
NSData* imageData = [[NSData alloc] initWithBase64EncodedString:base64string options:0];
Blimey.
For once, with Objective-C, that was easier than expected...!

(iphone) base64 encoding

I get KERN_PROTECTION_FAILURE somewhere (stack trace shows it's happening in main loop but won't give me more details because it seems that memory got corrupted in previous loop. I have all the settings to see debug output correctly)
When I remove calling the following code, the symptom goes away.
(Verify receipt for in App purchasee)
- (NSString *)encode:(const uint8_t *)input length:(NSInteger)length {
static char table[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";
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] = table[(value >> 18) & 0x3F];
output[index + 1] = table[(value >> 12) & 0x3F];
output[index + 2] = (i + 1) < length ? table[(value >> 6) & 0x3F] : '=';
output[index + 3] = (i + 2) < length ? table[(value >> 0) & 0x3F] : '=';
}
return [[[NSString alloc] initWithData:data encoding:NSASCIIStringEncoding] autorelease];
}
I see there are other ways of getting base64 encoding, How do I do base64 encoding on iphone-sdk?
What I find weird is that the 'length' is computed differently.
((length +2 /3) * 4 above, and lentext*4/3+4 below.
Can anyone tell what is going on?
Beside, using the below code, I get 'receipt data-malformed' error when I pass the encoded data to apple server.
+ (NSString *) base64StringFromData: (NSData *)data length: (int)length {
int lentext = [data length];
if (lentext < 1) return #"";
char *outbuf = malloc(lentext*4/3+4); // add 4 to be sure
if ( !outbuf ) return nil;
const unsigned char *raw = [data bytes];
int inp = 0;
int outp = 0;
int do_now = lentext - (lentext%3);
for ( outp = 0, inp = 0; inp < do_now; inp += 3 )
{
outbuf[outp++] = base64EncodingTable[(raw[inp] & 0xFC) >> 2];
outbuf[outp++] = base64EncodingTable[((raw[inp] & 0x03) << 4) | ((raw[inp+1] & 0xF0) >> 4)];
outbuf[outp++] = base64EncodingTable[((raw[inp+1] & 0x0F) << 2) | ((raw[inp+2] & 0xC0) >> 6)];
outbuf[outp++] = base64EncodingTable[raw[inp+2] & 0x3F];
}
if ( do_now < lentext )
{
char tmpbuf[2] = {0,0};
int left = lentext%3;
for ( int i=0; i < left; i++ )
{
tmpbuf[i] = raw[do_now+i];
}
raw = tmpbuf;
outbuf[outp++] = base64EncodingTable[(raw[inp] & 0xFC) >> 2];
outbuf[outp++] = base64EncodingTable[((raw[inp] & 0x03) << 4) | ((raw[inp+1] & 0xF0) >> 4)];
if ( left == 2 ) outbuf[outp++] = base64EncodingTable[((raw[inp+1] & 0x0F) << 2) | ((raw[inp+2] & 0xC0) >> 6)];
}
NSString *ret = [[[NSString alloc] initWithBytes:outbuf length:outp encoding:NSASCIIStringEncoding] autorelease];
free(outbuf);
return ret;
}
I’m using this very small library for encode/decode Base64: http://imthi.com/blog/programming/iphone-sdk-base64-encode-decode.php
It does its work and I assume you use a similar version of it. Did you try to call +initialize before the first usage?

Inserting NSData into SQLite on the iPhone

So far I've managed to create this method for inserting into a SQLite database on the iPhone:
- (void) insertToDB :(NSString *)Identifier :(NSString *)Name
{
sqlite3 *database;
if(sqlite3_open([databasePath UTF8String], &database) == SQLITE_OK)
{
char *sql1 = "INSERT INTO table VALUES ('";
const char *sql2 = [Identifier cStringUsingEncoding:[NSString defaultCStringEncoding]];
char *sql3 = "', '";
const char *sql4 = [Name cStringUsingEncoding:[NSString defaultCStringEncoding]];
char *sql5 = "')";
char *sqlStatement[255];
strcpy(sqlStatement, sql1);
strcat(sqlStatement, sql2);
strcat(sqlStatement, sql3);
strcat(sqlStatement, sql4);
strcat(sqlStatement, sql5);
sqlite3_stmt *compiledStatement;
if(sqlite3_prepare_v2(database, sqlStatement, -1, &compiledStatement, NULL) == SQLITE_OK)
{
sqlite3_last_insert_rowid(database);
sqlite3_reset(compiledStatement);
}
sqlite3_finalize(compiledStatment);
}
sqlite3_close(database);
}
Now I'm looking at storing an image in the database. So far I've found this:
UIImage *cachedImage = [UIImage imageNamed:#"Icon.png"];
NSData *dataForImage = UIImagePNGRepresentation(cachedImage);
But i'm having trouble trying to insert this NSData into the char array which makes the sqlStatement. Anyone got an idea how to do this?
(I have a field in the database of type blob for this).
Thanks
I would use sqlite3_stmt instead of a string. Then, you could use sqlite3_bind_blob to bind the blob to the prepared statement.
sqlite3_stmt *insert_statement;
char *sql = "INSERT INTO table (blobcolumn, column2, column3) VALUES (? , ?, ?)" ;
if(sqlite3_prepare_v2(database, sql, -1, &insert_statement, NULL) != SQLITE_OK)
{
//handle error
}
sqlite3_bind_blob(insert_statement, 1, [dataForImage bytes], [dataForImage length], NULL);
But, really, it would be best for performance to store the image on disk and the path in the database.
Another way to do it, one that I use to send image data in XML, is to base 64 encode the data. I have it here as a category on NSString:
static char base64EncodingTable[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 NSString (NSStringCategories)
+ (NSString *) base64StringFromData: (NSData *)data length: (int)length {
unsigned long ixtext, lentext;
long ctremaining;
unsigned char input[3], output[4];
short i, charsonline = 0, ctcopy;
const unsigned char *raw;
NSMutableString *result;
lentext = [data length];
if (lentext < 1)
return #"";
result = [NSMutableString stringWithCapacity: lentext];
raw = [data bytes];
ixtext = 0;
while (true) {
ctremaining = lentext - ixtext;
if (ctremaining <= 0)
break;
for (i = 0; i < 3; i++) {
unsigned long ix = ixtext + i;
if (ix < lentext)
input[i] = raw[ix];
else
input[i] = 0;
}
output[0] = (input[0] & 0xFC) >> 2;
output[1] = ((input[0] & 0x03) << 4) | ((input[1] & 0xF0) >> 4);
output[2] = ((input[1] & 0x0F) << 2) | ((input[2] & 0xC0) >> 6);
output[3] = input[2] & 0x3F;
ctcopy = 4;
switch (ctremaining) {
case 1:
ctcopy = 2;
break;
case 2:
ctcopy = 3;
break;
}
for (i = 0; i < ctcopy; i++)
[result appendString: [NSString stringWithFormat: #"%c", base64EncodingTable[output[i]]]];
for (i = ctcopy; i < 4; i++)
[result appendString: #"="];
ixtext += 3;
charsonline += 4;
if ((length > 0) && (charsonline >= length))
charsonline = 0;
}
return result;
}