Encrypt in Objective-C / Decrypt in Ruby using anything

前端 未结 4 1207
梦如初夏
梦如初夏 2021-01-01 07:26

We are using this code to encrypt in Objective-C on the iPhone:

- (NSMutableData*) EncryptAES: (NSString *) key
{
    char keyPtr[kCCKeySizeAES128+1];
    bz         


        
4条回答
  •  时光说笑
    2021-01-01 07:50

    Your code is leaking the first allocation of output.

    Besides that it looks mostly ok.

    This is a complete end-to-end implementation using a SHA256 hash of the user's passphrase (in this case 'Salamander') and base64'ing the output. There is a PHP test implementation in the source that reconstructs the key then trims the PKCS7 padding before giving final output. A decryptor in Ruby follows, the PKCS7 padding removal happens automatically by the OpenSSL::Cipher.

    Here you go:

    // Crypto categories for iOS
    
    #import 
    #import 
    
    
    @interface NSData( Crypto )
    
    - (NSData *) aesEncryptedDataWithKey:(NSData *) key;
    - (NSString *) base64Encoding;
    
    @end
    
    
    @interface NSString( Crypto )
    
    - (NSData *) sha256;
    
    @end
    
    
    // --------
    
    
    @implementation NSData( Crypto )
    
    - (NSData *) aesEncryptedDataWithKey:(NSData *) key {
        unsigned char               *buffer = nil;
        size_t                      bufferSize;
        CCCryptorStatus             err;
        NSUInteger                  i, keyLength, plainTextLength;
    
        // make sure there's data to encrypt
        err = ( plainTextLength = [self length] ) == 0;
    
        // pass the user's passphrase through SHA256 to obtain 32 bytes
        // of key data.  Use all 32 bytes for an AES256 key or just the
        // first 16 for AES128.
        if ( ! err ) {
            switch ( ( keyLength = [key length] ) ) {
                case kCCKeySizeAES128:
                case kCCKeySizeAES256:                      break;
    
                // invalid key size
                default:                    err = 1;        break;
            }
        }
    
        // create an output buffer with room for pad bytes
        if ( ! err ) {
            bufferSize = kCCBlockSizeAES128 + plainTextLength + kCCBlockSizeAES128;     // iv + cipher + padding
    
            err = ! ( buffer = (unsigned char *) malloc( bufferSize ) );
        }
    
        // encrypt the data
        if ( ! err ) {
            srandomdev();
    
            // generate a random iv and prepend it to the output buffer.  the
            // decryptor needs to be aware of this.
            for ( i = 0; i < kCCBlockSizeAES128; ++i ) buffer[ i ] = random() & 0xff;
    
            err = CCCrypt( kCCEncrypt, kCCAlgorithmAES128, kCCOptionPKCS7Padding,
                [key bytes], keyLength, buffer, [self bytes], plainTextLength,
                buffer + kCCBlockSizeAES128, bufferSize - kCCBlockSizeAES128, &bufferSize );
        }
    
        if ( err ) {
            if ( buffer ) free( buffer );
    
            return nil;
        }
    
        // dataWithBytesNoCopy takes ownership of buffer and will free() it
        // when the NSData object that owns it is released.
        return [NSData dataWithBytesNoCopy: buffer length: bufferSize + kCCBlockSizeAES128];
    }
    
    - (NSString *) base64Encoding {
        char                    *encoded, *r;
        const char              eTable[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
        unsigned                i, l, n, t;
        UInt8                   *p, pad = '=';
        NSString                *result;
    
        p = (UInt8 *) [self bytes];
        if ( ! p || ( l = [self length] ) == 0 ) return @"";
        r = encoded = malloc( 4 * ( ( n = l / 3 ) + ( l % 3 ? 1 : 0 ) ) + 1 );
    
        if ( ! encoded ) return nil;
    
        for ( i = 0; i < n; ++i ) {
            t  = *p++ << 16;
            t |= *p++ << 8;
            t |= *p++;
    
            *r++ = eTable[ t >> 18 ];
            *r++ = eTable[ t >> 12 & 0x3f ];
            *r++ = eTable[ t >>  6 & 0x3f ];
            *r++ = eTable[ t       & 0x3f ];
        }
    
        if ( ( i = n * 3 ) < l ) {
            t = *p++ << 16;
    
            *r++ = eTable[ t >> 18 ];
    
            if ( ++i < l ) {
                t |= *p++ << 8;
    
                *r++ = eTable[ t >> 12 & 0x3f ];
                *r++ = eTable[ t >>  6 & 0x3f ];
            } else {
                *r++ = eTable[ t >> 12 & 0x3f ];
                *r++ = pad;
            }
    
            *r++ = pad;
        }
    
        *r = 0;
    
        result = [NSString stringWithUTF8String: encoded];
    
        free( encoded );
    
        return result;
    }
    
    @end
    
    
    @implementation NSString( Crypto )
    
    - (NSData *) sha256 {
        unsigned char               *buffer;
    
        if ( ! ( buffer = (unsigned char *) malloc( CC_SHA256_DIGEST_LENGTH ) ) ) return nil;
    
        CC_SHA256( [self UTF8String], [self lengthOfBytesUsingEncoding: NSUTF8StringEncoding], buffer );
    
        return [NSData dataWithBytesNoCopy: buffer length: CC_SHA256_DIGEST_LENGTH];
    }
    
    @end
    
    
    // -----------------
    
    
    @implementation AppDelegate
    
    - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {    
        NSData              *plain = [@"This is a test of the emergency broadcast system." dataUsingEncoding: NSUTF8StringEncoding];
        NSData              *key = [NSData dataWithBytes: [[@"Salamander" sha256] bytes] length: kCCKeySizeAES128];
        NSData              *cipher = [plain aesEncryptedDataWithKey: key];
        NSString            *base64 = [cipher base64Encoding];
    
        NSLog( @"cipher: %@", base64 );
    
        // stuff the base64'ed cipher into decrypt.php:
        // http://localhost/~par/decrypt.php?cipher=
    
    /*
    
    */
    
        return YES;
    }
    
    @end
    

    Decryption of the output of the above in Ruby:

    require 'base64'
    require 'openssl'
    
    def decrypt( cipherBase64 )
        cipher = Base64.decode64( cipherBase64 )
    
        aes = OpenSSL::Cipher::Cipher.new( "aes-128-cbc" ).decrypt
        aes.iv = cipher.slice( 0, 16 )
        # don't slice the SHA256 output for AES256
        aes.key = ( Digest::SHA256.digest( 'Salamander' ) ).slice( 0, 16 )
    
        cipher = cipher.slice( 16..-1 )
    
        return aes.update( cipher ) + aes.final
    end
    
    text = '3o4ARWOxwmLEPgq3SJ3A2ws7sUSxMvWSKbbs+oABsOcywk+9qPBoDjhLAfAW/n28pbnsT2w5QMSye6pz3Lz8xmg5BYL8HdfKwbS9EpTbaUc='
    
    print decrypt( text ) + "\n"
    

提交回复
热议问题