AES/CBC/PKCS5Padding in iOS objective c result differs from Android
I am using the AES/CBC/PKCS5Padding in Android application. Code is like-
private static String TRANSFORMATION = "AES/CBC/PKCS5Padding";
private static String ALGORITHM = "AES";
private static String DIGEST = "MD5";
private static Cipher cipher;
private static SecretKey password;
private static IvParameterSpec IVParamSpec;
private final static String pvtkey="GDNBCGDRFSC$%#%=";
//16-byte private key
private static byte[] IV = pvtkey.getBytes();
public PassWordEncryptor() {
try {
//Encode digest
MessageDigest digest;
digest = MessageDigest.getInstance(DIGEST);
password = new SecretKeySpec(digest.digest(pvtkey.getBytes()), ALGORITHM);
//Initialize objects
cipher = Cipher.getInstance(TRANSFORMATION);
IVParamSpec = new IvParameterSpec(IV);
} catch (NoSuchAlgorithmException e) {
Log.i(Lams4gApp.TAG, "No such algorithm " + ALGORITHM);
} catch (NoSuchPaddingException e) {
System.out.println( "No such padding PKCS7"+ e);
}
}
/**
Encryptor.
@text String to be encrypted
@return Base64 encrypted text
*/
public String encrypt(byte[] text) {
byte[] encryptedData;
try {
cipher.init(Cipher.ENCRYPT_MODE, password, IVParamSpec);
encryptedData = cipher.doFinal(text);
} catch (InvalidKeyException e) {
System.out.println( "Invalid key (invalid encoding, wrong length, uninitialized, etc)."+ e);
return null;
} catch (InvalidAlgorithmParameterException e) {
System.out.println( "Invalid or inappropriate algorithm parameters for " + ALGORITHM+ e);
return null;
} catch (IllegalBlockSizeException e) {
System.out.println( "The length of data provided to a block cipher is incorrect"+ e);
return null;
} catch (BadPaddingException e) {
System.out.println( "The input data but the data is not padded properly."+ e);
return null;
}
return Base64.encodeToString(encryptedData,Base64.DEFAULT);
}
I need similar code in iOS Objective C. Encryption and Decryption results should be same in android and iOS. Kindly provide the same algorithm for Objective C.
I am using iOS code as-
- (void)viewDidLoad {
[super viewDidLoad];
NSData *encodingData=[self encrypt:[@"slapkh"
dataUsingEncoding:NSUTF8StringEncoding]];
NSString *encodingResult = [NSString base64StringFromData:encodingData length:[encodingData length]];
}
- (NSData *) encrypt:(NSData *) plainText {
return [self transform:kCCEncrypt data:plainText];
}
- (NSData *) decrypt:(NSData *) cipherText {
return [self transform:kCCDecrypt data:cipherText];
}
- (NSData *) transform:(CCOperation) encryptOrDecrypt data:(NSData *) inputData {
Cipher* cipher = [[Cipher alloc]initWithKey:@"GDNBCGDRFSC$%#%="];
NSString* Key = cipher.cipherKey;
// kCCKeySizeAES128 = 16 bytes
// CC_MD5_DIGEST_LENGTH = 16 bytes
NSData* secretKey = [Cipher md5:Key];
CCCryptorRef cryptor = NULL;
CCCryptorStatus status = kCCSuccess;
uint8_t iv[kCCBlockSizeAES128];
memset((void *) iv, 0x0, (size_t) sizeof(iv));
status = CCCryptorCreate(encryptOrDecrypt,
kCCAlgorithmAES128,kCCOptionPKCS7Padding,
[secretKey bytes], kCCKeySizeAES128, iv, &cryptor);
if (status != kCCSuccess) {
return nil;
}
size_t bufsize = CCCryptorGetOutputLength(cryptor, (size_t)[inputData length],
true);
void * buf = malloc(bufsize * sizeof(uint8_t));
memset(buf, 0x0, bufsize);
size_t bufused = 0;
size_t bytesTotal = 0;
status = CCCryptorUpdate(cryptor, [inputData bytes], (size_t)[inputData length],
buf, bufsize, &bufused);
if (status != kCCSuccess) {
free(buf);
CCCryptorRelease(cryptor);
return nil;
}
bytesTotal += bufused;
status = CCCryptorFinal(cryptor, buf + bufused, bufsize - bufused, &bufused);
if (status != kCCSuccess) {
free(buf);
CCCryptorRelease(cryptor);
return nil;
}
bytesTotal += bufused;
CCCryptorRelease(cryptor);
return [NSData dataWithBytesNoCopy:buf length:bytesTotal];
}
But the results for Android and iOS Differs as- Text to encrypt: slapkh key: GDNBCGDRFSC$%#%=
Android result: jN2p1yAdBJLRmoHq+k9KtA==\n
iOS Resut: tbaSJFv5mGyZ9t/+kOw+gg==
Solution 1:
After spending time dealing with this, I got success in ANDROID(java) and IOS (Objc) using AES with the codes below:
ANDROID CODE
import java.io.IOException;
import java.security.InvalidAlgorithmParameterException;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
public class SecurityUtils {
private static final String ALGORITHM = "AES";
private static final String MODE = "AES";
private static final String IV = "AEE0715D0778A4E4";
private static final String KEY= "9336365521W5F092BB5909E8E033BC69";
public static String encrypt(String value ) throws NoSuchPaddingException, NoSuchAlgorithmException, BadPaddingException, IllegalBlockSizeException, InvalidAlgorithmParameterException, InvalidKeyException {
SecretKeySpec secretKeySpec = new SecretKeySpec(KEY.getBytes(), ALGORITHM);
Cipher cipher = Cipher.getInstance(MODE);
cipher.init(Cipher.ENCRYPT_MODE, secretKeySpec, new IvParameterSpec(IV.getBytes()));
byte[] values = cipher.doFinal(value.getBytes());
return Base64.encodeBytes(values);
}
public static String decrypt(String value) throws IOException, NoSuchPaddingException, NoSuchAlgorithmException, BadPaddingException, IllegalBlockSizeException, InvalidAlgorithmParameterException, InvalidKeyException {
byte[] values = Base64.decode(value);
SecretKeySpec secretKeySpec = new SecretKeySpec(KEY.getBytes(), ALGORITHM);
Cipher cipher = Cipher.getInstance(MODE);
cipher.init(Cipher.DECRYPT_MODE, secretKeySpec, new IvParameterSpec(IV.getBytes()));
return new String(cipher.doFinal(values));
}
}
TESTING ANDROID
try {
String encrypted = SecurityUtils.encrypt("My Secret Text");
String decrypted = SecurityUtils.decrypt(encrypted);
Log.e("encrypted", encrypted);
Log.e("decrypted", decrypted);
}catch(Exception ex){
Log.e("AES", ex.getMessage());
}
IOS CODE
Header file
#import <Foundation/Foundation.h>
#import <CommonCrypto/CommonCryptor.h>
NS_ASSUME_NONNULL_BEGIN
@interface SecurityUtils : NSObject
+ (NSString *)encrypt:(NSString *)plainText error:(NSError **)error;
+ (NSString *)decrypt:(NSString *)plainText error:(NSError **)error;
@end
NS_ASSUME_NONNULL_END
Implementation file
NSString *const IV = @"AEE0515D0B08A4E4";
NSString *const KEY = @"9336565521E5F082BB5929E8E033BC69";
#import "SecurityUtils.h"
@implementation SecurityUtils
+ (NSString *)encrypt:(NSString *)plainText error:(NSError **)error {
NSMutableData *result = [SecurityUtils doAES:[plainText dataUsingEncoding:NSUTF8StringEncoding] context: kCCEncrypt error:error];
return [result base64EncodedStringWithOptions:0];
}
+ (NSString *)decrypt:(NSString *)encryptedBase64String error:(NSError **)error {
NSData *dataToDecrypt = [[NSData alloc] initWithBase64EncodedString:encryptedBase64String options:0];
NSMutableData *result = [SecurityUtils doAES:dataToDecrypt context: kCCDecrypt error:error];
return [[NSString alloc] initWithData:result encoding:NSUTF8StringEncoding];
}
+ (NSMutableData *)doAES:(NSData *)dataIn context:(CCOperation)kCCEncrypt_or_kCCDecrypt error:(NSError **)error {
CCCryptorStatus ccStatus = kCCSuccess;
size_t cryptBytes = 0;
NSMutableData *dataOut = [NSMutableData dataWithLength:dataIn.length + kCCBlockSizeBlowfish];
NSData *key =[KEY dataUsingEncoding:NSUTF8StringEncoding];
NSData *iv = [IV dataUsingEncoding:NSUTF8StringEncoding];
ccStatus = CCCrypt( kCCEncrypt_or_kCCDecrypt,
kCCAlgorithmAES,
kCCOptionPKCS7Padding,
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;
}
@end
IOS TESTING
NSError *error;
NSString *encrypted = [SecurityUtils encrypt:@"My Secret Text" error:&error];
NSLog(@"encrypted: %@",encrypted);
NSLog(@"decrypted: %@",[SecurityUtils decrypt:encrypted error:&error]);
Finally, the outputs of the test:
ANDROID OUTPUT
2019-05-16 21:35:01.215 4920-4920/br.com.my.app E/encrypted: EJ41am5W1k6fA7ygFjTSEw==
2019-05-16 21:35:01.215 4920-4920/br.com.my.app E/decrypted: My Secret Text
IOS OUTPUT
2019-05-16 21:38:02.947043-0300 MyApp[63392:1590665] encrypted: EJ41am5W1k6fA7ygFjTSEw==
2019-05-16 21:38:02.947270-0300 MyApp[63392:1590665] decrypted: My Secret Text
My repo on GitHub with this example.