Decrypt Value from Blowfish in Objective-C Code

decrypt value from blowfish in Objective-C code

1) Source of Blowfish routines from David Madore: ftp://quatramaran.ens.fr/pub/madore/misc/blowfish.c

Pls note that in this source .h part should be separated from the .c file.

2) To use Pandora API we have to use the passwords given by its wiki page here:
http://pan-do-ra-api.wikia.com/wiki/Json/5/partners

Currently decrypt password is: 20zE1E47BE57$51

3) Use this code snippet (standing on great programmers' shoulders) - original Pandora API implementation is here: https://github.com/alexcrichton/hermes

In AppDelegate.h (for simplicity)

#define PARTNER_DECRYPT  "20zE1E47BE57$51"
...
-(NSData*) PandoraDecrypt:(NSString*) string;

In AppDelegate.m

static char h2i[256] = {
['0'] = 0, ['1'] = 1, ['2'] = 2, ['3'] = 3, ['4'] = 4, ['5'] = 5, ['6'] = 6,
['7'] = 7, ['8'] = 8, ['9'] = 9, ['a'] = 10, ['b'] = 11, ['c'] = 12,
['d'] = 13, ['e'] = 14, ['f'] = 15
};

static void appendByte(unsigned char byte, void *_data) {
NSMutableData *data = (__bridge NSMutableData*) _data;
NSLog(@"pre: %@", data);
[data appendBytes:&byte length:1];
NSLog(@"post: %@", data);
}

-(NSData*) PandoraDecrypt:(NSString*) string {
struct blf_ecb_ctx ctx;
NSMutableData *mut = [[NSMutableData alloc] init];

Blowfish_ecb_start(&ctx, FALSE, (unsigned char*) PARTNER_DECRYPT,
sizeof(PARTNER_DECRYPT) - 1, appendByte,
(__bridge void*) mut);

const char *bytes = [string cStringUsingEncoding:NSASCIIStringEncoding];
int len = [string lengthOfBytesUsingEncoding:NSASCIIStringEncoding];
int i;
for (i = 0; i < len; i += 2) {
NSLog(@"%c, %c, %d, %d", bytes[i], bytes[i+1], h2i[(int) bytes[i]] * 16, h2i[(int) bytes[i + 1]]);
Blowfish_ecb_feed(&ctx, h2i[(int) bytes[i]] * 16 + h2i[(int) bytes[i + 1]]);
}
Blowfish_ecb_stop(&ctx);

return mut;
}

And you can use this like:

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
NSLog(@"%@", [NSString stringWithCString:[
[self PandoraDecrypt:@"aed5c110d793f850521a4dd3a56a70d9"] bytes]
encoding:NSASCIIStringEncoding]);
return YES;
}

So it was mainly a research from my side, pls give credit to implementers of the Blowfish api and the pandora api ;-)
Also my NSLogs are for research purpose, it highlights how the decryption works.

blowfish algorithm objective c

HINT#1 //general answer

NSString provides an initializer for this purpose. You can see more info using the docs here.

NSString * dSync = [[NSString alloc] initWithData: dycryptData 
encoding:NSUTF8StringEncoding];

Assuming you use ARC.

HINT#2 // the answer for this particular question

I tried your code and confirm the above NSString conversion returns null. So why it is not working? dycryptData is stream of bytes represented as hex, so I tried the following and received the desired result:

int dycryptData_len = [dycryptData length];
NSMutableString *dSync_hex = [NSMutableString stringWithCapacity:dycryptData_len*2];
const unsigned char *dycryptData_bytes = [dycryptData bytes];
for (int i = 0; i < dycryptData_len; ++i) {
[dSync_hex appendFormat:@"%02x", dycryptData_bytes[i]];
}

NSLog(@"dSync_hex=%@",dSync_hex);

I can see this result in log output:

dSync_hex=0eec37b62b76c2dfcdf723560f033ed8d6bd37dd5223bf665c318ebe07f3cf71

PHP and Objective C Blowfish Encryption Encoding different

Well,

After re-reading my post to see if I forgot any piece of information, it came to me that if the problem is the encoding, then the iOS library maybe using a NSEncoding different then it should be.

So I opened the FclBlowfish code and saw that they were using the NSISOLatin1StringEncoding and NSASCIIStringEncoding Encoding in the Encryption and Decryption methods, then I decided to try a few others and found out that using NSWindowsCP1252StringEncoding actually returns the correct encoding as the PHP one and decryption works like a charm!

Hope this helps someone with the same problem!

How to implement Blowfish ECB algorithm PKCS5 Padding in iOS

Example code:

Add Security.framework

#import <CommonCrypto/CommonCryptor.h>

+ (NSData *)doBlowfish:(NSData *)dataIn
context:(CCOperation)kCCEncrypt_or_kCCDecrypt
key:(NSData *)key
options:(CCOptions)options
iv:(NSData *)iv
error:(NSError **)error
{
CCCryptorStatus ccStatus = kCCSuccess;
size_t cryptBytes = 0;
NSMutableData *dataOut = [NSMutableData dataWithLength:dataIn.length + kCCBlockSizeBlowfish];

ccStatus = CCCrypt( kCCEncrypt_or_kCCDecrypt,
kCCAlgorithmBlowfish,
options,
key.bytes,
key.length,
(iv)?nil:iv.bytes,
dataIn.bytes,
dataIn.length,
dataOut.mutableBytes,
dataOut.length,
&cryptBytes);

if (ccStatus == kCCSuccess) {
dataOut.length = cryptBytes;
}
else {
if (error) {
*error = [NSError errorWithDomain:@"kEncryptionError"
code:ccStatus
userInfo:nil];
}
dataOut = nil;
}

return dataOut;
}

Test:

NSError *error;
NSData *key = [@"Blowfish" dataUsingEncoding:NSUTF8StringEncoding];
NSString *stringOriginal = @"TestData";
NSData *dataOriginal = [stringOriginal dataUsingEncoding:NSUTF8StringEncoding];;

NSLog(@"key %@", key);
NSLog(@"stringOriginal %@", stringOriginal);
NSLog(@"dataOriginal %@", dataOriginal);

NSData *dataEncrypted = [Test doBlowfish:dataOriginal
context:kCCEncrypt
key:key
options:kCCOptionPKCS7Padding | kCCOptionECBMode
iv:nil
error:&error];
NSLog(@"dataEncrypted %@", dataEncrypted);

NSString *encryptedBase64String = [dataEncrypted base64EncodedStringWithOptions:0];
NSLog(@"encryptedBase64String %@", encryptedBase64String);

NSData *dataToDecrypt = [[NSData alloc] initWithBase64EncodedString:encryptedBase64String options:0];
NSData *dataDecrypted = [Test doBlowfish:dataToDecrypt
context:kCCDecrypt
key:key
options:kCCOptionPKCS7Padding | kCCOptionECBMode
iv:nil
error:&error];
NSLog(@"dataDecrypted %@", dataDecrypted);

NSString *stringDecrypted = [[NSString alloc] initWithData:dataDecrypted encoding:NSUTF8StringEncoding];
NSLog(@"stringDecrypted %@", stringDecrypted);

Output:


key 426c6f77 66697368
stringOriginal TestData
dataOriginal 54657374 44617461
dataEncrypted ba5eb956 7e73ae1a b5513ea1 75a14019
encryptedBase64String ul65Vn5zrhrdmeYV9B5rQA==
dataDecrypted 54657374 44617461
stringDecrypted TestData

Blowfish encryption with c++ code in cocoa project

You're using a block cipher with padding (look at the source code to CBlowFish::Encode) to encrypt a stream. You can't do that because the decryption operation will have no way to know what constitutes a padded chunk that it should decrypt.

For example, say you're encrypting "FOOBAR", but you read "FOO" the first time and this encrypts to "XYZZY". Then you encrypt "BAR" to "ABCDE". Your written file will contain "XYZZYABCDE". But is that "XY" "ZZYA" "BCDE"? Or one block, "XYZZYABCDE" or what?

If you want to encrypt a stream, use a stream cipher. Or if you want to cut it into arbitrary blocks, you have to preserve the output block boundaries so you can decrypt the blocks.

Blowfish Encryption Decryption

NSData+Base64Utilities.h looks like the header file for a category that adds Base64 support to NSData.

The error is telling you that the compiler cannot find the files for the category. You need to add them to your project.

Edited to add

If you are targeting iOS7, then you can use the new NSData methods that handle base64 encodings. You don't need to use the category that you are trying to find.

How to implement Blowfish algorithm in iOS

I got Paul Kocher implementation from Bruce Schneier's website. And here is how an encryption method may look like:

#define PADDING_PHRASE @"       "

#import "CryptoUtilities.h"
#import "blowfish.h"
#import "NSData+Base64Utilities.h"

@implementation CryptoUtilities

+ (NSString *)blowfishEncrypt:(NSData *)messageData usingKey:(NSData *)secretKey
{
NSMutableData *dataToEncrypt = [messageData mutableCopy];

if ([dataToEncrypt length] % 8) {
NSMutableData *emptyData = [[PADDING_PHRASE dataUsingEncoding:NSUTF8StringEncoding] mutableCopy];

emptyData.length = 8 - [dataToEncrypt length] % 8;
[dataToEncrypt appendData:emptyData];
}

// Here we have data ready to encipher
BLOWFISH_CTX ctx;
Blowfish_Init (&ctx, (unsigned char*)[secretKey bytes], [secretKey length]);

NSRange aLeftRange, aRightRange;
NSData *aLeftBox, *aRightBox;
unsigned long dl = 0, dr = 0;

for (int i = 0; i < [dataToEncrypt length]; i += 8) { // Divide data into octets...
// …and then into quartets
aLeftRange = NSMakeRange(i, 4);
aRightRange = NSMakeRange(i + 4, 4);

aLeftBox = [dataToEncrypt subdataWithRange:aLeftRange];
aRightBox = [dataToEncrypt subdataWithRange:aRightRange];

// Convert bytes into unsigned long
[aLeftBox getBytes:&dl length:sizeof(unsigned long)];
[aRightBox getBytes:&dr length:sizeof(unsigned long)];

// Encipher
Blowfish_Encrypt(&ctx, &dl, &dr);

// Put bytes back
[dataToEncrypt replaceBytesInRange:aLeftRange withBytes:&dl];
[dataToEncrypt replaceBytesInRange:aRightRange withBytes:&dr];
}

return [dataToEncrypt getBase64String];
}

I am not really good in C, but it seems that my implementation works correctly. To decrypt you need just repeat same steps, but instead of Blowfish_Encrypt you need to call Blowfish_Decrypt.

Here is a source code for that (I assume that you just decrypt the cipher text, but don't deal with padding here):

+ (NSData *)blowfishDecrypt:(NSData *)messageData usingKey:(NSData *)secretKeyData
{
NSMutableData *decryptedData = [messageData mutableCopy];

BLOWFISH_CTX ctx;
Blowfish_Init (&ctx, (unsigned char*)[secretKeyData bytes], [secretKeyData length]);

NSRange aLeftRange, aRightRange;
NSData *aLeftBox, *aRightBox;
unsigned long dl = 0, dr = 0;

for (int i = 0; i< [decryptedData length]; i += 8) { // Divide data into octets...
// …and then into quartets
aLeftRange = NSMakeRange(i, 4);
aRightRange = NSMakeRange(i + 4, 4);

aLeftBox = [decryptedData subdataWithRange:aLeftRange];
aRightBox = [decryptedData subdataWithRange:aRightRange];

// Convert bytes into unsigned long
[aLeftBox getBytes:&dl length:sizeof(unsigned long)];
[aRightBox getBytes:&dr length:sizeof(unsigned long)];

// Decipher
Blowfish_Decrypt(&ctx, &dl, &dr);

// Put bytes back
[decryptedData replaceBytesInRange:aLeftRange withBytes:&dl];
[decryptedData replaceBytesInRange:aRightRange withBytes:&dr];
}

return decryptedData;
}

You might want to return pure bytes or Base64 string. For the last case I have a category, which adds an initialiser, which initialises NSData object with Base64 string and a method, which allows to get Base64 string from NSData.

You should also think about playing with PADDING_PHRASE, for example, what if you want to add not just several spaces, but some random bytes? In this case you should send a padding length somehow.

Update: Actually, you should not use PADDING_PRASE in your process. Instead, you should use one of the standard algorithms for block ciphers described on Wikipedia page

How does blowfish algorithm work in C++?

can you guys tell me if the other end knows what algorithm I am using can they not extract the key and decrypt it ?

No. The whole point of standardized encryption algorithms (as opposed to those that rely on obscurity) is that even though everyone knows all details of it, one cannot decrypt it unless one has the key.

This approach works because the only way to crack the encryption is to try all possible keys, of which there are too many. As computation power increases, formerly "secure" algorithms do become "unsecure". With some algorithms there may also be flaws that allow other forms of deductions to take place that significantly reduce the possible key-space and hence speed up these brute-force attacks. But (as far as we know) Blowfish is safe here.

Keeping the key secret is essential of course. If your program also includes the key (as opposed to asking the user or some device for it, or using random session keys that are themselves encrypted using public-key crypto), then a reverse-engineer can probably find it and break your scheme.

An important part of keeping the key secret is to keep it "non-guessable" and to not reuse it for different purposes. Randomly generated keys are the best.

Also, by "the other end" you mean an attacker, right? Usually, "the other end" refers to Bob The Intended Recipient, and he of course needs to be able to decrypt the message.

BlowFish decrypt - nCFB mode

CFB (Cypher Feed Back) mode feeds back part or all of the cyphertext when decrypting. the "n" in nCFB tells you how much to feed back. The default is the entire block. You will need to read the documentation to find out what value of n is being used to encrypt, and how to add that parameter to your decryption algorithm. Given that the first three characters are decrypting correctly, it might be that n is 24 bits, though I am not sure of that.

Normally CTR mode is less trouble than CFB.



Related Topics



Leave a reply



Submit