Search code examples
iphoneiosxcodeipadblowfish

How to implement Blowfish algorithm in iOS


What is the best way to implement BlowFish ECB encryption in iOS??? I have been googling a lot and found the library here. But there are no documentation of this library. Not sure how to use it.


Solution

  • 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