DES encrypted value mismatching android and ios - ios

IOS code is
#import "DESCodec.h"
#import <CommonCrypto/CommonCryptor.h>
#implementation DESCodec
{
NSString *key;
}
-(id) init{
self=[super init];
if(self){
key=#"12345678";
}
return self;
}
-(NSString *) decode:(NSString *)encoded{
NSData *inputData = [[NSData alloc] initWithBase64EncodedString:encoded options:0];
NSData *keyData = [key dataUsingEncoding:NSUTF8StringEncoding];
size_t outLength;
NSMutableData *outputData = [NSMutableData dataWithLength:(inputData.length +
kCCBlockSizeDES)];
CCCryptorStatus
result = CCCrypt(kCCDecrypt, // operation
kCCAlgorithmDES, // Algorithm
kCCOptionPKCS7Padding , // options
keyData.bytes, // key
keyData.length, // keylength
nil,// iv
inputData.bytes, // dataIn
inputData.length, // dataInLength,
outputData.mutableBytes, // dataOut
outputData.length, // dataOutAvailable
&outLength); // dataOutMoved
if (result != kCCSuccess) {
return nil;
}
[outputData setLength:outLength];
return [[NSString alloc] initWithData:outputData `encoding:NSUTF8StringEncoding];`
}
-(NSString *) encode:(NSString *)decoded{
NSData *inputData = [decoded dataUsingEncoding:NSUTF8StringEncoding];
NSData *keyData = [key dataUsingEncoding:NSUTF8StringEncoding];
size_t outLength;
NSMutableData *outputData = [NSMutableData dataWithLength:(inputData.length + kCCBlockSizeDES)];
CCCryptorStatus result = CCCrypt(kCCEncrypt, // operation
kCCAlgorithmDES, // Algorithm
kCCOptionPKCS7Padding, // options
keyData.bytes, // key
keyData.length, // keylength
nil,// iv
inputData.bytes, // dataIn
inputData.length, // dataInLength,
outputData.mutableBytes, // dataOut
outputData.length, // dataOutAvailable
&outLength); // dataOutMoved
if (result != kCCSuccess) {
return nil;
}
[outputData setLength:outLength];
NSString *r = [outputData base64EncodedStringWithOptions:0];
return r;
}
#end
DESCodec *codec=[[DESCodec alloc] init];
NSString *encoded=[codec encode:#"12345678"];
NSString decoded=[codec decode:encoded];
NSLog(#" %# %#",encoded,decoded);
value is ltACiHjVjImOJQ1fTHZkSw== and 12345678
but in java encypted text is "ltACiHjVjIn+uVm31GQvyw=="
I not good in Objective C and I can't able to trigger out the problem.
can anybody please help me. Thanks and regards
Java code is
public class DESCodec {
/**
* Secret key that shall be used for encryption and decryption.
*/
private String strSecretKey = "12345678";
private static final String UNICODE_FORMAT = "UTF-8";
private static final String DES_ENCRYPTION_SCHEME = "DES";
private static final String TAG = "DESCodec";
private Cipher cipher;
private SecretKey key;
public DESCodec() {
try {
this.strSecretKey = strSecretKey;
String myEncryptionScheme = DES_ENCRYPTION_SCHEME;
byte[] keyAsBytes = strSecretKey.getBytes(UNICODE_FORMAT);
DESKeySpec myKeySpec = new DESKeySpec(keyAsBytes);
SecretKeyFactory mySecretKeyFactory = SecretKeyFactory.getInstance(myEncryptionScheme);
cipher = Cipher.getInstance(myEncryptionScheme);
key = mySecretKeyFactory.generateSecret(myKeySpec);
} catch (Exception e) {
e.printStackTrace();
}
}
public String desEncrypt(String message) {
String encryptedString = null;
try {
cipher.init(Cipher.ENCRYPT_MODE, key);
byte[] plainText = message.getBytes(UNICODE_FORMAT);
byte[] encryptedText = cipher.doFinal(plainText);
encryptedString = Base64.encodeToString(encryptedText, Base64.DEFAULT);
} catch (Exception e) {
e.printStackTrace();
}
return encryptedString;
}
public String desDecrypt(String message) {
String decryptedText = null;
try {
cipher.init(Cipher.DECRYPT_MODE, key);
byte[] encryptedText = Base64.decode(message, Base64.DEFAULT);
byte[] plainText = cipher.doFinal(encryptedText);
decryptedText = bytes2String(plainText);
} catch (Exception e) {
e.printStackTrace();
}
return decryptedText;
}
private String bytes2String(byte[] bytes) {
try {
return new String(bytes, UNICODE_FORMAT);
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
return null;
}
}

It's obviously only a problem with the mode of operation, because the first block matches. In Java you're using ECB mode, because "DES" defaults to "DES/ECB/PKCS5Padding". I think that CCCryptor defaults to CBC.
Don't ever use ECB mode. It's not semantically secure. You need to use at least CBC mode with a random IV. The IV doesn't have to be secret, so you can prepend it to the ciphertext. Please look at RNCryptor that has additional security features like authentication of ciphertext. It also has a Java implementation.
Don't use DES anymore. It's not secure anymore. You should use AES. Triple DES is also not that bad.

I hava the same problem when i develop an iOS app.And the android client is used by many people, so i couldn't change the algorithm to AES or others.As Artjom B. said in Java 'DES' defaults to 'DES/ECB/PKCS5Padding', in the source you can find that
Cipher c1 = Cipher.getInstance("DES/ECB/PKCS5Padding");
but unfortunately in iOS you just find that
enum {
kCCOptionPKCS7Padding = 0x0001,
kCCOptionECBMode = 0x0002
}
But finally i find a solution like this
CCCryptorStatus cryptStatus = CCCrypt(kCCDecrypt,
kCCAlgorithmDES,
kCCOptionPKCS7Padding | kCCOptionECBMode,
[key UTF8String],
kCCKeySizeDES,
nil,
[cipherData bytes],
[cipherData length],
buffer,
1024,
&numBytesDecrypted);
The importance is kCCOptionPKCS7Padding | kCCOptionECBMode, you can try this method.

Related

Objective C - Encryption with AES256 GCM

Currently I'm using the below method for Encryption
+ (NSData*) encrypt:(NSData*)plainText key:(NSData*)key iv:(NSData*)iv {
NSUInteger dataLength = [plainText length];
size_t buffSize = dataLength + kCCBlockSizeAES128;
void *buff = malloc(buffSize);
size_t numBytesEncrypted = 0;
CCCryptorStatus status = CCCrypt(kCCEncrypt, /* kCCEncrypt, etc. */
kCCAlgorithmAES128, /* kCCAlgorithmAES128, etc. */
kCCOptionPKCS7Padding, /* kCCOptionPKCS7Padding, etc. */
key.bytes, kCCKeySizeAES256, /* key and its length */
iv.bytes, /* initialization vector - use random IV everytime */
[plainText bytes], [plainText length], /* input */
buff, buffSize,/* data RETURNED */
&numBytesEncrypted);
if (status == kCCSuccess) {
return [NSData dataWithBytesNoCopy:buff length:numBytesEncrypted];
} else {
// Encryption Failed
}
free(buff);
return nil;
}
I need to use now AES256 GCM for encrypting, I don't see kCCAlgorithmAES256 in CCCrypt. Someone please guide me, I'm using the framework pod 'RNCryptor-objc'.
Below is the decrypt logic handled in backend.
public static byte[] decrypt(byte[] key, byte[] data) {
// TODO utilize GCMAES#decrypt method
try {
if (data.length < NONCE_LENGTH + TAG_LENGTH) {
throw new IllegalArgumentException("data packet too short");
}
int cipherTextLength = data.length - NONCE_LENGTH - TAG_LENGTH;
byte[] nonce = Arrays.copyOf(data, NONCE_LENGTH);
GCMBlockCipher cipher = new GCMBlockCipher(new AESFastEngine());
AEADParameters parameters = new AEADParameters(new KeyParameter(key), TAG_LENGTH * 8, nonce);
cipher.init(false, parameters);
byte[] out = new byte[cipher.getOutputSize(cipherTextLength + TAG_LENGTH)];
int pos = cipher.processBytes(data, NONCE_LENGTH, data.length - NONCE_LENGTH, out, 0);
pos += cipher.doFinal(out, pos);
return Arrays.copyOf(out, pos);
} catch (IllegalStateException | InvalidCipherTextException ex) {
throw new IllegalArgumentException(ex);
}}}

AES Decryption in objective c where encryption in .net

Hello friends I stuck in decryption of data. Server side data is encrypted by .net, i tried many codes but unable to decrypt.
In android data is decrypted by this function
public static String doDecrypt(String data, String key){
String decryptedData = null;
try {
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
byte[] keyBytes = new byte[16];
byte[] b = key.getBytes("UTF-8");
int len = b.length;
if (len > keyBytes.length)
len = keyBytes.length;
System.arraycopy(b, 0, keyBytes, 0, len);
SecretKeySpec keySpec = new SecretKeySpec(keyBytes, "AES");
IvParameterSpec ivSpec = new IvParameterSpec(keyBytes);
cipher.init(Cipher.DECRYPT_MODE, keySpec, ivSpec);
byte[] results = new byte[data.length()];
try {
results = cipher.doFinal(Base64.decode(data,Base64.DEFAULT));
} catch (Exception e) {
Log.i("Erron in Decryption", e.toString());
}
Log.i("Data", new String(results, "UTF-8"));
decryptedData = new String(results, "UTF-8");
}
catch (Exception e) {
e.printStackTrace();
return null;
}
return decryptedData;
}
its working fine in android, but while decrypting in objective c its gives only null.
I used some link that are below:-
nsdata , fwencryption , RNCryptor
But it only gives null value when decrypting in NSString.
For example you can check a demo for decryption
data:-1YbDEEZGnc5EtZY040AaSP233AXZHJVAZb74sCQHm+BX72N5nM81ygDsRHhF8KMk
key- test#123456789
I used this code in Objective c
#import "ViewController.h"
#import "NSData+AES.h"
#interface ViewController ()
#end
#implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
NSString *testData = [self decode:#"1YbDEEZGnc5EtZY040AaSP233AXZHJVAZb74sCQHm+BX72N5nM81ygDsRHhF8KMk"];
NSLog(#"Dtata%#",testData);
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
-(NSString*)encode:(NSString*)plainString {
//convert 'plainString' to NSData using NSUTF8StringEncoding
NSData *plainData = [plainString dataUsingEncoding:NSUTF8StringEncoding];
//encrypt data with AES encryption
NSData *AESData = [plainData AES128EncryptedDataWithKey:#"test#123456789"];
//return base64 encoded string
return [AESData base64EncodedStringWithOptions:0];
}
-(NSString*)decode:(NSString*)encodedString {
//convert 'encodedString' to base64 decoded data
NSData *base64Data = [[NSData alloc] initWithBase64EncodedString:encodedString options:0];
//decode using AES encryption
NSData *AESData = [base64Data AES128DecryptedDataWithKey:#"test#123456789"];
//return string from AES decoded data
return [[NSString alloc] initWithData:AESData encoding:NSUTF8StringEncoding];
}
Please anyone can help me out. I am stuck in this.Thanks in advance.

AES encryption on iOS and android, output and buffer size is different

Implementing AES256 on iOS using CCCrypt function. But output and output buffer length is different than Android.
Cipher class in Android produces 48 bytes data where in iOS we get 80 bytes data.
In IOS using kCCAlgorithmAES, kCCOptionPKCS7Padding and in android using AES/CBC/PKCS5Padding.
in IOS IV is NULL and in android creating iv as new 16 bytes array.
Please help.
please find input and code for reference.
- (void)viewDidLoad {
[super viewDidLoad];
NSString *message = [NSString stringWithFormat:#"com.myapp.com|355004059196637|911111111111|11341e5e-9643-4559-bbb7-34d40555e96c"];
NSString *key = [NSString stringWithFormat:#"4f28d5901b4b7b80d33fda76ca372c2a20bd1a6c2aad7fa215dc79d507330678"];
NSString *shaEncryptMessage = [self sha256:message length:0];
NSData *aesEncryptData = [self aesEncrypt:[shaEncryptMessage dataUsingEncoding:NSUTF8StringEncoding] key:key iv:nil];
NSString *hMac = [aesEncryptData base64EncodedStringWithOptions:NSDataBase64Encoding64CharacterLineLength];
NSLog(#"hMac = %#",hMac);
// IOS output : Can+oQR79D3/lsQGctzY/d2VBNZbWWtJxGI8iRIu80R2yTskn9gf2oKHaRESX73u
// LpJHLx1Xr6iH11jFPlmqwW7mQz0xAW4uACNAMEoZ0kY=
// Android output : MiMDkdo5cGsPMj2qCnNobgp7dr5KMvBhGuKTonrqr1lCYte/kKegGMtI/4TPhUNI
}
- (NSString*) sha256:(NSString *)key length:(NSInteger) length{
const char *s=[key cStringUsingEncoding:NSASCIIStringEncoding];
NSData *keyData=[NSData dataWithBytes:s length:strlen(s)];
uint8_t digest[CC_SHA256_DIGEST_LENGTH]={0};
CC_SHA256(keyData.bytes, (unsigned int)keyData.length, digest);
NSData *out=[NSData dataWithBytes:digest length:CC_SHA256_DIGEST_LENGTH];
NSString *hash=[out description];
hash = [hash stringByReplacingOccurrencesOfString:#" " withString:#""];
hash = [hash stringByReplacingOccurrencesOfString:#"<" withString:#""];
hash = [hash stringByReplacingOccurrencesOfString:#">" withString:#""];
return hash;
}
- (NSData *)aesEncrypt:(NSData *)plainText key:(NSString *)key iv:(NSString *)iv {
char keyPointer[kCCKeySizeAES256+2],// room for terminator (unused) ref: https://devforums.apple.com/message/876053#876053
ivPointer[kCCBlockSizeAES128];
BOOL patchNeeded;
bzero(keyPointer, sizeof(keyPointer)); // fill with zeroes for padding
//key = [[StringEncryption alloc] md5:key];
key = [self stringFromHex:key];
patchNeeded= ([key length] > kCCKeySizeAES256+1);
if(patchNeeded)
{
key = [key substringToIndex:kCCKeySizeAES256]; // Ensure that the key isn't longer than what's needed (kCCKeySizeAES256)
}
[key getCString:keyPointer maxLength:sizeof(keyPointer) encoding:NSUTF8StringEncoding];
[iv getCString:ivPointer maxLength:sizeof(ivPointer) encoding:NSUTF8StringEncoding];
// if (patchNeeded) {
// keyPointer[0] = '\0'; // Previous iOS version than iOS7 set the first char to '\0' if the key was longer than kCCKeySizeAES256
// }
NSUInteger dataLength = [plainText length];
// For block ciphers, the output size will always be less than or equal to the input size plus the size of one block.
size_t buffSize = dataLength + kCCBlockSizeAES128;
void *buff = malloc(buffSize);
size_t numBytesEncrypted = 0;
CCCryptorStatus status = CCCrypt(kCCEncrypt, /* kCCEncrypt, etc. */
kCCAlgorithmAES128, /* kCCAlgorithmAES128, etc. */
kCCOptionPKCS7Padding, /* kCCOptionPKCS7Padding, etc. */
keyPointer, kCCKeySizeAES256, /* key and its length */
NULL, /* initialization vector - use random IV everytime */
[plainText bytes], [plainText length], /* input */
buff, buffSize,/* data RETURNED here */
&numBytesEncrypted);
if (status == kCCSuccess) {
return [NSData dataWithBytesNoCopy:buff length:numBytesEncrypted];
}
free(buff);
return nil;
}
- (NSString *) stringFromHex:(NSString *)str
{
NSMutableData *stringData = [[NSMutableData alloc] init];
unsigned char whole_byte;
char byte_chars[3] = {'\0','\0','\0'};
int i;
for (i=0; i < [str length] / 2; i++) {
byte_chars[0] = [str characterAtIndex:i*2];
byte_chars[1] = [str characterAtIndex:i*2+1];
whole_byte = strtol(byte_chars, NULL, 16);
[stringData appendBytes:&whole_byte length:1];
}
return [[NSString alloc] initWithData:stringData encoding:NSASCIIStringEncoding];
}
Please find android code also,
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
generateHMAC();
}
String K0 = "4f28d5901b4b7b80d33fda76ca372c2a20bd1a6c2aad7fa215dc79d507330678";
String generatedString = "com.myapp.com|355004059196637|911111111111|11341e5e-9643-4559-bbb7-34d40555e96c";
private void generateHMAC() {
Log.d("Message of Hash", generatedString);
byte[] var14 = new byte[0];
try {
var14 = SHA256(generatedString);
byte[] var15 = new byte[0];
var15 = encrypt(var14, hexStringToByteArray(K0));
String var4 = Base64.encodeToString(var15, 2);
Log.d("Existing K0", K0);
Log.d("HMAC", var4);
} catch (Exception e) {
e.printStackTrace();
}
}
public byte[] SHA256(String paramString) throws Exception {
MessageDigest md = MessageDigest.getInstance("SHA-256");
md.update(paramString.getBytes("UTF-8"));
byte[] digest = md.digest();
return digest;
}
public byte[] encrypt(byte[] var1, byte[] var2) throws Exception {
SecretKeySpec var3 = new SecretKeySpec(var2, "AES");
byte[] var4 = new byte[16];
IvParameterSpec var5 = new IvParameterSpec(var4);
Cipher var6 = Cipher.getInstance("AES/CBC/PKCS5Padding");
var6.init(1, var3, var5);
byte[] var7 = var6.doFinal(var1);
return var7;
}
public byte[] hexStringToByteArray(String var1) {
byte[] var2 = new byte[var1.length() / 2];
for (int var3 = 0; var3 < var2.length; ++var3) {
int var4 = var3 * 2;
int var5 = Integer.parseInt(var1.substring(var4, var4 + 2), 16);
var2[var3] = (byte) var5;
}
return var2;
}
Updates after you provided iOS code:
The aesEncryptData should be your output. Get rid of the hmac, that has nothing to do with AES encryption (instead, it is for message integrity).
The only way you are going to match your Android code is if you are using the same IV that the Android code is using.
Earlier reply:
How long is the input? Providing source code and sample data may help us solve the problem quicker.
Without the requested information, I don't have your answer, but I have a few pointers that might help you get to the bottom of it:
Your padding is okay. PKCS5Padding in Java is wrongly named implementation of PKCS#7, so it should be compatible with Apple's kCCOptionPKCS7Padding.
Apple by default uses CBC mode under the hood if no mode is specified, so that agrees with the Android code. So that cannot be the problem either.
When you encrypt, the ciphertext will be a multiple of 16 bytes (because AES has N=16 bytes block size and according to defn of PKCS #7). Specifically:
If the input is a multiple of 16 bytes, then the output should be exactly 16 bytes more than the input.
If the input is not a multiple of 16 bytes, then the output should be 16*Ceiling(Input length/16). Example: 47 byte input should be 16*Ceiling(17/16) = 16*3 = 48 byte output.
It is possible that one of the implementations is outputting the IV as part of the ciphertext. If this is happening, it should be at the beginning of the ciphertext. You should be able to test to see if this is happening. (Let me know if that is happening please)
Having said that, something is weird and likely implemented wrong, and we need the code to get to the bottom of it. It makes no sense that the Android code results in 3 blocks of 16 whereas the Apple code results in 5 blocks of 16.
Also, as I commented above, even though Apple tells you that the IV is optional, they mean that it is optional in terms of getting the code to work. It is not optional for security. IVs are required and must be unpredictable for CBC mode of operation, and they should never be repeated. If you ignore that, you leak information about your data, and in some situations, an attacker may be able to decrypt the data (padding oracle attacks).

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==
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.

AES Encryption not the same result iOS and Android

I've been struggling for many days now finding out how to achieve a same result when encrypting plaintext password using AES.
I have codes below in Java (Android) and Objective-C (iOS). Honestly, the ideal result is the one produced by Java because our existing passwords are encrypted with this implementation.
Hopefully someone can pin-point my error for Objective-C. I am a super newbie on this programming language, so please bear with and don't be so hard on me. :)
Many thanks!
The plain text password is:
12345abc
The Java code:
Encrypted text result is:
BS/WyqmZ6AD68YbmFERn9w==
private static String encryptionKey="ERVwiiYMFlDcZ0wp";
private static String decryptionKey="ERVwiiYMFlDcZ0wp";
JSONObject resultJSON=new JSONObject();
private static byte[] initializationVector = new byte[] { 0x01, 0x02, 0x03,
0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e,
0x0f, 0x10 };
public JSONObject encryptMethod(JSONObject jObject)
{
try {
textToEncrypt = jObject.getString("text");
textToEncrypt = replaceSlashes(textToEncrypt);
Log.d("STATE", "textToEncrypt: "+textToEncrypt);
try {
cipherText = encryptData(textToEncrypt);
Log.d("STATE", "cipherText: "+cipherText);
resultType=true;
resultData=cipherText;
resultMessage="Encryption success";
}
catch(Exception e)
{
e.printStackTrace();
resultMessage="Encryption is Not Possible, Please try some other text";
}
}
catch(Exception e)
{
e.printStackTrace();
resultMessage="Wrong Text Input, Please try again";
}
try {
resultJSON.put("type", resultType);
resultJSON.put("message", resultMessage);
resultJSON.put("data", resultData);
} catch (JSONException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return resultJSON;
}
public static String encryptData(String plainText) {
String cipherText = null;
byte[] encryptedBytes = null;
String skeySpecString = null;
if (plainText == null || "".equals(plainText)) {
return null;
}
try {
if(encryptionKey==null || encryptionKey.equals("")) {
return null;
}
SecretKeySpec skeySpec = new SecretKeySpec(encryptionKey.getBytes(), "AES");
IvParameterSpec ivps = new IvParameterSpec(initializationVector);
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS7Padding");
cipher.init(Cipher.ENCRYPT_MODE, skeySpec, ivps);
encryptedBytes = cipher.doFinal(plainText.getBytes());
encryptedBytes = Base64.encode(encryptedBytes, 0);
cipherText = new String(encryptedBytes);
} catch (BadPaddingException bpe) {
Log.e("Plain", "<===== BadPaddingException =====>", bpe);
return null;
} catch (IllegalBlockSizeException ibse) {
Log.e("Plain", "<===== BadPaddingException =====>", ibse);
return null;
} catch (InvalidAlgorithmParameterException iape) {
Log.e("Plain", "<===== InvalidAlgorithmParameterException =====>",
iape);
return null;
} catch (InvalidKeyException ike) {
Log.e("Plain", "<===== InvalidKeyException =====>", ike);
return null;
} catch (NoSuchAlgorithmException nae) {
Log.e("Plain", "<===== NoSuchAlgorithmException =====>", nae);
return null;
} catch (NoSuchPaddingException nspe) {
Log.e("Plain", "<===== NoSuchPaddingException =====>", nspe);
return null;
} catch (Exception ex) {
Log.e("Plain", "<===== Exception: {0} =====>", ex);
return null;
}
return cipherText;
}
The Objective-C code:
Encrypted text result is:
V+RZjcXVE+J1aG9kwt7CTA==
Encrypt.m file
-(NSString *) encryptData:(NSString *)plainText
{
NSString *passphrase = #"ERVwiiYMFlDcZ0wp";
NSData *key=[passphrase dataUsingEncoding:NSUTF8StringEncoding];
NSData *password = [plainText dataUsingEncoding:NSUTF8StringEncoding];
StringEncryption *crypt = [[StringEncryption alloc] init];
NSData *encryptedData = [crypt AES256EncryptWithKey:passphrase password:plainText];
NSString *ciphertext =[encryptedData base64EncodingWithLineLength:0];
return ciphertext;
}
Crypt.m file
- (NSData *)AES256EncryptWithKey:(NSString *)key password:(NSString *)plainText {
char keyPtr[kCCKeySizeAES128+1]; // room for terminator (unused)
bzero(keyPtr, sizeof(keyPtr)); // fill with zeroes (for padding)
[key getCString:keyPtr maxLength:sizeof(keyPtr) encoding:NSUTF8StringEncoding];
NSUInteger dataLength = [plainText length];
NSData *myData = [plainText dataUsingEncoding:NSUTF8StringEncoding];
const char myByteArray[] = {
0x01,0x02,0x03,0x04,
0x05,0x06,0x07,0x08,
0x09,0x0a,0x0b,0x0c,
0x0d,0x0e,0x0f,0x10 };
NSData *vector = [NSData dataWithBytes: myByteArray length:16];
size_t bufferSize = dataLength + kCCBlockSizeAES128;
void *buffer = malloc(bufferSize);
size_t numBytesEncrypted = 0;
CCCryptorStatus cryptStatus = CCCrypt(kCCEncrypt, kCCAlgorithmAES128, kCCOptionPKCS7Padding,
keyPtr, kCCKeySizeAES128,
(__bridge const void *)(vector),
myData.bytes, dataLength,
buffer, bufferSize,
&numBytesEncrypted);
if (cryptStatus == kCCSuccess) {
return [NSData dataWithBytesNoCopy:buffer length:numBytesEncrypted];
}
free(buffer);
return nil;
}

Resources