Swift AES Encryption throws error while in Android doesn't - android

I tried to do AES encryption in Swift which I do in Android like this:
public static String Encrypt(String text, String key) {
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.ENCRYPT_MODE, keySpec, ivSpec);
byte[] results = cipher.doFinal(text.getBytes("UTF-8"));
return Base64.encodeToString(results, Base64.DEFAULT);
}
catch (Exception ex){return "error"+ex.getMessage();}
}
Below is the equivalent code in Swift 3.2:
func aesEncrypt(key: String, iv: String) throws -> String{
let data = self.data(using: String.Encoding.utf8)
let enc = try AES(key: key.bytes, blockMode: BlockMode.CBC(iv: iv.bytes, padding: Padding.pkcs5).encrypt(data!.bytes)
let encData = NSData(bytes: enc, length: Int(enc.count))
let base64String: String = encData.base64EncodedString(options: NSData.Base64EncodingOptions(rawValue: 0));
let result = String(base64String)
return result!}
In Android it doesn't matter for key: I can fill with any string (no length limitations). But when using Swift I have to use a 32 charachter string for key and a 16 charachter string for IV, otherwise it will throw an error.
Here is the Swift usage:
let data = "this is string which I want to be encrypted"
let key = "bbbb98232-a343-4343f-2111"
let iv = "0000000000000000" // lenght = 16 like android code
let encryptedString = data.aesEncrypt(key: key, iv: iv);
Is there maybe some mistake in my Swift code?

You can try the below Swift code for AES encryption. Its String extension.
import Foundation
import CommonCrypto
extension String {
func aesEncrypt(key: String, initializationVector: String, options: Int = kCCOptionPKCS7Padding) -> String? {
if let keyData = key.data(using: String.Encoding.utf8),
let data = self.data(using: String.Encoding.utf8),
let cryptData = NSMutableData(length: Int((data.count)) + kCCBlockSizeAES128) {
let keyLength = size_t(kCCKeySizeAES128)
let operation: CCOperation = UInt32(kCCEncrypt)
let algoritm: CCAlgorithm = UInt32(kCCAlgorithmAES128)
let options: CCOptions = UInt32(options)
var numBytesEncrypted: size_t = 0
let cryptStatus = CCCrypt(operation,
algoritm,
options,
(keyData as NSData).bytes, keyLength,
initializationVector,
(data as NSData).bytes, data.count,
cryptData.mutableBytes, cryptData.length,
&numBytesEncrypted)
if UInt32(cryptStatus) == UInt32(kCCSuccess) {
cryptData.length = Int(numBytesEncrypted)
let base64cryptString = cryptData.base64EncodedString(options: .lineLength64Characters)
return base64cryptString
} else {
return nil
}
}
return nil
}
}

Related

AES Encryption and decryption for android and iOS gives wrong output

Android code:
private static final String ALGORITHM = "AES/ECB/PKCS5Padding";
private static final String KEY = "SixteenCharacter";
Encryption:
private static byte[] encrypt(final byte[] key, final byte[] originalData) {
try {
Cipher cipher = Cipher.getInstance(ALGORITHM);
SecretKeySpec skeySpec = new SecretKeySpec(key, ALGORITHM);
cipher.init(Cipher.ENCRYPT_MODE, skeySpec);
byte[] encrypted = cipher.doFinal(originalData);
return encrypted;
} catch (Exception ex) {
ex.printStackTrace();
return new byte[0];
}
}
Decryption:
private static byte[] decrypt(final byte[] key, final byte[] encryptedData) {
try {
Cipher cipher = Cipher.getInstance(ALGORITHM);
SecretKeySpec skeySpec = new SecretKeySpec(key, ALGORITHM);
cipher.init(Cipher.DECRYPT_MODE, skeySpec);
byte[] original = cipher.doFinal(encryptedData);
return original;
} catch (Exception ex) {
ex.printStackTrace();
return new byte[0];
}
}
iOS code:
static let KEY = "SixteenCharacter"
private static let iv: Array = [0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00]
Encryption:
static func getEncryptedString(normal: String?, key: String, options: Int = kCCOptionPKCS7Padding) -> String {
guard let normal = normal else { return "" }
if let keyData = key.data(using: String.Encoding.utf8),
let data = normal.data(using: String.Encoding.utf8),
let cryptData = NSMutableData(length: Int((data.count)) + kCCBlockSizeAES128) {
let keyLength = size_t(kCCKeySizeAES128)
let operation: CCOperation = UInt32(kCCEncrypt)
let algoritm: CCAlgorithm = UInt32(kCCAlgorithmAES128)
let options: CCOptions = UInt32(options)
var numBytesEncrypted :size_t = 0
let cryptStatus = CCCrypt(operation,
algoritm,
options,
(keyData as NSData).bytes, keyLength,
iv,
(data as NSData).bytes, data.count,
cryptData.mutableBytes, cryptData.length,
&numBytesEncrypted)
if UInt32(cryptStatus) == UInt32(kCCSuccess) {
cryptData.length = Int(numBytesEncrypted)
var base64cryptString = cryptData.base64EncodedString(options: .lineLength76Characters)
//base64cryptString = base64cryptString.replacingOccurrences(of: "/", with: "_")
.replacingOccurrences(of: "+", with: "-")
return base64cryptString
}
else {
return normal
}
}
return normal
}
Decryption:
static func getDecryptedString(normal: String?, key: String, options: Int = kCCOptionPKCS7Padding) -> String {
guard var normal = normal else { return "" }
//normal = normal.replacingOccurrences(of: "_", with: "/").replacingOccurrences(of: "-", with: "+")
if let keyData = key.data(using: .utf8),
let data = NSData(base64Encoded: normal, options: .ignoreUnknownCharacters),
let cryptData = NSMutableData(length: Int((data.length)) + kCCBlockSizeAES128) {
let keyLength = size_t(kCCKeySizeAES128)
let operation: CCOperation = UInt32(kCCDecrypt)
let algoritm: CCAlgorithm = UInt32(kCCAlgorithmAES128)
let options: CCOptions = UInt32(options)
var numBytesEncrypted :size_t = 0
let cryptStatus = CCCrypt(operation,
algoritm,
options,
(keyData as NSData).bytes, keyLength,
iv,
data.bytes, data.length,
cryptData.mutableBytes, cryptData.length,
&numBytesEncrypted)
if UInt32(cryptStatus) == UInt32(kCCSuccess) {
cryptData.length = Int(numBytesEncrypted)
let unencryptedMessage = String(data: cryptData as Data, encoding:String.Encoding.utf8)
if let unencryptedMessage = unencryptedMessage, !unencryptedMessage.isEmpty {
return unencryptedMessage
}
}
else {
return normal
}
}
return normal
}
As I haven't worked with AES encryption before, I have no idea where am I going wrong
I have seen so many solutions on the internet but no luck yet
Android code is already done and the only way I have is to modify the iOS code!
Thanks in advance!
You are working across two different systems. That means you cannot rely on system defaults, they may be different. You need to specify everything: Key, IV, padding, character encoding, etc. Crypto is designed to fail with even a small mismatch, so you have to check everything to make sure it matches across both systems. For instance, IIRC iOS and Java use different end-of-line characters. Something as simple as that might throw off the decryption.
If there is nothing obvious then look at all the inputs to both sides in binary/hex to make sure everything matches exactly.
You are using ECB mode. This is insecure and shouldn't be used except for very specific and rare situations. Better to use CBC or CTR mode. If you need authentication as well then try GCM mode.

iOS Triple DES encryption generating a different String to Android

I utilised TripleDES encryption in my Android app and it returns the expected string as required. However, when implementing the same feature in iOS using CommonCrypto, the returned string is different than what was expected.
public String encrypt(String message, String secretKey) throws Exception {
MessageDigest md = MessageDigest.getInstance("md5");
byte[] digestOfPassword = md.digest(secretKey.getBytes("utf-8"));
byte[] keyBytes = Arrays.copyOf(digestOfPassword, 24);
for (int j = 0, k = 16; j < 8;) {
keyBytes[k++] = keyBytes[j++];
}
KeySpec keySpec = new DESedeKeySpec(keyBytes);
SecretKey key = SecretKeyFactory.getInstance("DESede").generateSecret(keySpec);
Cipher cipher = Cipher.getInstance("DESede");
cipher.init(Cipher.ENCRYPT_MODE, key);
byte[] plainTextBytes = message.getBytes("utf-8");
byte[] buf = cipher.doFinal(plainTextBytes);
byte[] base64Bytes = Base64.encodeBase64(buf);
String base64EncryptedString = new String(base64Bytes);
return base64EncryptedString;
}
iOS Code
+ (NSData*)transformData:(NSData*)inputData operation:(CCOperation)operation withPassword:(NSString*)password
{
NSData* key = [self keyFromPassword:password];
//NSData* iv = [self ivFromPassword:password];
NSMutableData* outputData = [NSMutableData dataWithLength:(inputData.length + kCCBlockSize3DES)];
size_t outLength;
CCCryptorStatus result = CCCrypt(operation, kCCAlgorithm3DES, kCCAlgorithmDES, key.bytes, key.length, nil, inputData.bytes, inputData.length, outputData.mutableBytes, outputData.length, &outLength);
if (result != kCCSuccess)
return nil;
[outputData setLength:outLength];
return outputData;
}
+ (NSData*)keyFromPassword:(NSString*)password
{
NSString* key = [password copy];
int length = kCCKeySize3DES;
while (key.length < length)
key = [key stringByAppendingString:password];
if (key.length > length)
key = [key substringToIndex:length];
return [key dataUsingEncoding:NSUTF8StringEncoding];
}
+ (NSData*)ivFromPassword:(NSString*)password
{
NSString* key = [password copy];
int length = 8;
while (key.length < length)
key = [key stringByAppendingString:password];
if (key.length > length)
key = [key substringToIndex:length];
return [key dataUsingEncoding:NSUTF8StringEncoding];
}
It may be helpful to note that the key being used is a 20 byte key. I am limited to the 20-byte key. The android app automatically takes care of this limitation with Array.copyOf function, however, despite zero padding and repeating the first characters of the key as the last eight characters, I still cannot replicate the output in iOS.
Any help will be appreciated.

Encryption for iOS 3des not same as android and .net

I'm trying do some encrypt something using 3des on the iOS that must match the results from java and .NET.
Java code is :
public class EncryptionHelper {
// Encrypts string and encode in Base64
public static String encryptText(String plainText,String key, String IV) throws Exception {
// ---- Use specified 3DES key and IV from other source --------------
byte[] plaintext = plainText.getBytes();//input
byte[] tdesKeyData = key.getBytes();// your encryption key
byte[] myIV = IV.getBytes();// initialization vector
Cipher c3des = Cipher.getInstance("DESede/CBC/PKCS5Padding");
SecretKeySpec myKey = new SecretKeySpec(tdesKeyData, "DESede");
IvParameterSpec ivspec = new IvParameterSpec(myIV);
c3des.init(Cipher.ENCRYPT_MODE, myKey, ivspec);
byte[] cipherText = c3des.doFinal(plaintext);
String encryptedString = Base64.encodeToString(cipherText,
Base64.DEFAULT);
// return Base64Coder.encodeString(new String(cipherText));
return encryptedString;
}
}
and iOS code for the same is :
-(NSString*)new3DESwithoperand:(NSString*)plaintext encryptOrDecrypt:(CCOperation)encryptorDecrypt key:(NSString*)key initVec:(NSString*)initVec
{
NSData* data = [plaintext dataUsingEncoding:NSUTF8StringEncoding];
const void *vplainText = [data bytes];;
size_t plainTextBufferSize = [data length];
NSLog(#"%#, Length: %u",[data description],[data length]);
size_t bufferPtrSize = (plainTextBufferSize + kCCBlockSize3DES) & ~(kCCBlockSize3DES - 1);
NSLog(#"%zu, sizof of uint8_t: %zu",bufferPtrSize, sizeof(uint8_t));
size_t movedBytes = 0;
uint8_t *bufferPtr = malloc( bufferPtrSize * sizeof(uint8_t));
NSLog(#"%zu",sizeof(bufferPtr));
memset((void*)bufferPtr, 0x0, bufferPtrSize);
NSLog(#"%zu",sizeof(bufferPtr));
const void * vkey = [[NSData base64DataFromString:key] bytes];
const void *vinitVec = [[NSData base64DataFromString:initVec] bytes];
NSLog(#"vinitvec: %#",[[NSData base64DataFromString:initVec] description]);
CCCryptorStatus ccStatus;
ccStatus = CCCrypt(encryptorDecrypt,
kCCAlgorithm3DES,
kCCOptionPKCS7Padding & kCCModeCBC,
vkey,
kCCKeySize3DES,
vinitVec,
vplainText,
plainTextBufferSize,
(void*)bufferPtr,
bufferPtrSize,
&movedBytes);
NSData* result = [NSData dataWithBytes:(const void*)bufferPtr length:(NSUInteger)movedBytes];
NSString* str = [NSString base64StringFromData:result length:result.length];
NSLog(#"%#",str);
return str;
}
This code successfully encrypts and decrypts a string. However, it does not match the results from .NET and java.
Thank you
Have found a solution for the above problem of encryption value generated different on iOS and .NET or Java.
Solution:
1. In Android and .NET you have to use a key of size 16 Bytes (eg: key="1234567890123456")
In iOS you need to use a key size of 24 bytes but the generation of key makes a little difference.
Use the same key as used in Android or .NET (16 bytes) and append it with the first 8 Bytes of the same key.
key16Byte = "1234567890123456" //Android and .NET key
key24Byte = key16Byte + "12345678" //ios and Java key, Replicated first 8 Bytes of 16Byte key
//new24ByteKey = "123456789012345612345678"
Remove "& kCCModeCBC" from CCypher Mode.
Some values require bytes in CCCrypt function which I have changed in the below mentioned code below. like keyData, encryptData.
Reason for different encryption generated:
Android and .NET - It takes 16Byte key and internally replicates, and generates a 24Byte key.
Java - It throws an Exception "Invalid key length", if you provide a 16Byte key value.
iOS - It generates encryption value with 16Byte and 24Byte both values without throwing any exception, so is the reason we get a different encryption generated in case of 16Byte key.
Java Code
public class EncryptionHelper {
// Encrypts string and encode in Base64
public static String encryptText(String plainText,String key, String IV) throws Exception {
// ---- Use specified 3DES key and IV from other source --------------
byte[] plaintext = plainText.getBytes();//input
byte[] tdesKeyData = key.getBytes();// your encryption key
byte[] myIV = IV.getBytes();// initialization vector
Cipher c3des = Cipher.getInstance("DESede/CBC/PKCS5Padding");
SecretKeySpec myKey = new SecretKeySpec(tdesKeyData, "DESede");
IvParameterSpec ivspec = new IvParameterSpec(myIV);
c3des.init(Cipher.ENCRYPT_MODE, myKey, ivspec);
byte[] cipherText = c3des.doFinal(plaintext);
String encryptedString = Base64.encodeToString(cipherText,
Base64.DEFAULT);
// return Base64Coder.encodeString(new String(cipherText));
return encryptedString;
}
iOS Code:
- (NSString *)encrypt:(NSString *)encryptValue key:(NSString *)key24Byte IV:(NSString *)IV{
// first of all we need to prepare key
if([key length] != 24)
return #"Require 24 byte key, call function generate24ByteKeySameAsAndroidDotNet with a 16Byte key same as used in Android and .NET"; //temporary error message
NSData *keyData = [key24Byte dataUsingEncoding:NSUTF8StringEncoding];
// our key is ready, let's prepare other buffers and moved bytes length
NSData *encryptData = [encryptValue dataUsingEncoding:NSUTF8StringEncoding];
size_t resultBufferSize = [encryptData length] + kCCBlockSize3DES;
unsigned char resultBuffer[resultBufferSize];
size_t moved = 0;
// DES-CBC requires an explicit Initialization Vector (IV)
// IV - second half of md5 key
NSMutableData *ivData = [[IV dataUsingEncoding:NSUTF8StringEncoding]mutableCopy];
NSMutableData *iv = [NSMutableData dataWithData:ivData];
CCCryptorStatus cryptorStatus = CCCrypt(kCCEncrypt, kCCAlgorithm3DES,
kCCOptionPKCS7Padding , [keyData bytes],
kCCKeySize3DES, [iv bytes],
[encryptData bytes], [encryptData length],
resultBuffer, resultBufferSize, &moved);
if (cryptorStatus == kCCSuccess) {
return [[NSData dataWithBytes:resultBuffer length:moved] base64EncodedStringWithOptions:0];
} else {
return nil;
}
}
iOS
-(NSString *)generate24ByteKeySameAsAndroidDotNet:(NSString *)key{
NSString *new24ByteKey = key;
;
new24ByteKey = [new24ByteKey stringByAppendingString:[key substringWithRange:NSMakeRange(0, 8)]];
return new24ByteKey;
}
As #Jugal Desai mentioned, the key difference between iOS and Android/.Net is that the later ones automatically fill the key (with size 16 bytes) with another 8 bytes from the start of the key! You saved me :)
Here I provide the simple fix in Swift 3:
....
YOUR_KEY_SIZE_16 = YOUR_KEY_SIZE_16 + YOUR_KEY_SIZE_16[0...7]
....
Sample complete code (MD5 for key hash + ECB + PKCS7Padding) with base64 result:
func tripleDesEncrypt(keyString: String, pass: String) -> String{
let keyData = keyString.data(using: .utf8)!
var digestData = Data(count: Int(CC_MD5_DIGEST_LENGTH))
_ = digestData.withUnsafeMutableBytes {digestBytes in
keyData.withUnsafeBytes {messageBytes in
CC_MD5(messageBytes, CC_LONG(keyData.count), digestBytes)
}
}
digestData = digestData + digestData[0...7]
let data = pass.data(using: .utf8)!
let dataNS = data as NSData
let cryptData = NSMutableData(length: Int(dataNS.length) + kCCBlockSize3DES)!
let keyLength = size_t(kCCKeySize3DES)
let operation: CCOperation = UInt32(kCCEncrypt)
let algoritm: CCAlgorithm = UInt32(kCCAlgorithm3DES)
let options: CCOptions = UInt32(kCCOptionECBMode + kCCOptionPKCS7Padding)
var numBytesEncrypted :size_t = 0
let cryptStatus = CCCrypt(operation,
algoritm,
options,
(digestData as NSData).bytes,
keyLength,
nil,
dataNS.bytes,
dataNS.length,
cryptData.mutableBytes,
cryptData.length,
&numBytesEncrypted)
if UInt32(cryptStatus) == UInt32(kCCSuccess) {
cryptData.length = Int(numBytesEncrypted)
// Not all data is a UTF-8 string so Base64 is used
let base64cryptString = cryptData.base64EncodedString(options: NSData.Base64EncodingOptions.lineLength76Characters)
return base64cryptString
} else {
print("Error: \(cryptStatus)")
}
return ""
}
How serious in decrypted?
- (NSString *)encrypt:(NSString *)encryptValue key:(NSString *)key24Byte IV:(NSString *)IV{
// first of all we need to prepare key
if([key length] != 24)
return #"Require 24 byte key, call function generate24ByteKeySameAsAndroidDotNet with a 16Byte key same as used in Android and .NET"; //temporary error message
NSData *keyData = [key24Byte dataUsingEncoding:NSUTF8StringEncoding];
// our key is ready, let's prepare other buffers and moved bytes length
NSData *encryptData = [encryptValue dataUsingEncoding:NSUTF8StringEncoding];
size_t resultBufferSize = [encryptData length] + kCCBlockSize3DES;
unsigned char resultBuffer[resultBufferSize];
size_t moved = 0;
// DES-CBC requires an explicit Initialization Vector (IV)
// IV - second half of md5 key
NSMutableData *ivData = [[IV dataUsingEncoding:NSUTF8StringEncoding]mutableCopy];
NSMutableData *iv = [NSMutableData dataWithData:ivData];
CCCryptorStatus cryptorStatus = CCCrypt(kCCEncrypt, kCCAlgorithm3DES,
kCCOptionPKCS7Padding , [keyData bytes],
kCCKeySize3DES, [iv bytes],
[encryptData bytes], [encryptData length],
resultBuffer, resultBufferSize, &moved);
if (cryptorStatus == kCCSuccess) {
return [[NSData dataWithBytes:resultBuffer length:moved] base64EncodedStringWithOptions:0];
} else {
return nil;
}
}

Pad Block Corrupted

I have to do the following operation:
Encryption VB -> Decryption VB
Encryption Android - Decryption Android
Encryption VB -> Decryption Android
Encryption Android -> decryption VB
So far I succedded do encrypt and decrypt on Android.
When I encrypt in VB and try to decrypt on Android, I get the following exception:
E/Exception: pad block corrupted
I also have to mention that when i encrypt short strings in VB and decrypt them also in VB, everything works well. But when i encrypt a larger array of bytes, the decryption works but the result is not the one expected.
Can somebody give me a hint of how to solve the problem?
Thank you !
Here is my code:
.NET functions
Public Function AES_Encrypt2(ByVal byteArray() As Byte, ByVal key As String, Optional ByVal ShortKey As Boolean = False) As String
Try
Dim FirstKeyBytes() As Byte = Encoding.UTF8.GetBytes(key)
If Not FirstKeyBytes Is Nothing Then
If FirstKeyBytes.Length < 32 Then
Array.Resize(FirstKeyBytes, 32)
End If
End If
Dim KeyBytes() As Byte
If ShortKey Then
KeyBytes = New Byte(15) {}
Array.Copy(FirstKeyBytes, KeyBytes, 16)
Else
KeyBytes = New Byte(31) {}
Array.Copy(FirstKeyBytes, KeyBytes, 32)
End If
Dim InitialVectorBytes() As Byte = New Byte() {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} 'Encoding.UTF8.GetBytes("\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0")
Dim SymmetricKey As New RijndaelManaged()
SymmetricKey.Mode = CipherMode.CBC
SymmetricKey.Padding = PaddingMode.PKCS7
Dim Encryptor As ICryptoTransform = SymmetricKey.CreateEncryptor(KeyBytes, InitialVectorBytes)
Dim MemStream As New MemoryStream()
Dim CryptoStream As New CryptoStream(MemStream, Encryptor, CryptoStreamMode.Write)
CryptoStream.Write(byteArray, 0, byteArray.Length)
CryptoStream.FlushFinalBlock()
MemStream.Close()
CryptoStream.Close()
Dim CipherTextBytes As Byte() = MemStream.ToArray()
Dim encryptedString As String = Convert.ToBase64String(CipherTextBytes)
Return encryptedString
Catch ex As Exception
Return String.Empty
End Try
End Function
Public Function AES_Decrypt2(ByVal encryptedString As String, ByVal key As String, Optional ByVal ShortKey As Boolean = False) As String
Try
Dim PlainTextBytes1 As Byte() = Convert.FromBase64String(encryptedString)
Dim FirstKeyBytes() As Byte = Encoding.UTF8.GetBytes(key)
If Not FirstKeyBytes Is Nothing Then
If FirstKeyBytes.Length < 32 Then
Array.Resize(FirstKeyBytes, 32)
End If
End If
Dim KeyBytes() As Byte
If ShortKey Then
KeyBytes = New Byte(15) {}
Array.Copy(FirstKeyBytes, KeyBytes, 16)
Else
KeyBytes = New Byte(31) {}
Array.Copy(FirstKeyBytes, KeyBytes, 32)
End If
Dim SymmetricKey As New RijndaelManaged()
Dim InitialVectorBytes As Byte() = New Byte() {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} 'Encoding.UTF8.GetBytes("\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0")
SymmetricKey.Mode = CipherMode.CBC
SymmetricKey.Padding = PaddingMode.PKCS7
Dim Decryptor As ICryptoTransform = SymmetricKey.CreateDecryptor(KeyBytes, InitialVectorBytes)
Dim MemStream1 As New MemoryStream(PlainTextBytes1)
Dim CryptoStream As New CryptoStream(MemStream1, Decryptor, CryptoStreamMode.Read)
Dim pltxt As Byte() = New Byte(PlainTextBytes1.Length - 1) {}
Dim d As Integer = CryptoStream.Read(pltxt, 0, pltxt.Length)
MemStream1.Close()
CryptoStream.Close()
Dim textConverter As New ASCIIEncoding()
Dim round As String = textConverter.GetString(pltxt, 0, d)
Return round
Catch ex As Exception
Return String.Empty
End Try
End Function
And Android methods:
public static String encrypt(byte[] input, String key) {
try {
byte[] iv = new byte[16];
AlgorithmParameterSpec paramSpec = new IvParameterSpec(iv);
String newKey = "";
if (key.length() >= 32) {
newKey = key.substring(0, 32);
} else {
for (int i = key.length(); i < 32; i++) {
key += "0";
}
newKey = key.substring(0, 32);
}
SecretKeySpec skeySpec = new SecretKeySpec(newKey.getBytes(), "AES");
//skeySpec = new SecretKeySpec(newKey.getBytes(), 0, newKey.length(), "AES");
Cipher fileCipher = Cipher.getInstance("AES/CBC/PKCS7Padding");
fileCipher.init(1, skeySpec, paramSpec);
byte[] decrypted = fileCipher.doFinal(input);
byte[] base64enc = Base64.encode(decrypted, 0);
return new String(base64enc);
} catch (Exception e) {
Log.e("Exception", e.getMessage());
}
return null;
}
public static byte[] decrypt(String input, String key) {
try {
byte[] iv = new byte[16];
AlgorithmParameterSpec paramSpec = new IvParameterSpec(iv);
byte[] base64enc = Base64.decode(input.getBytes(), 0);
String newKey = "";
if (key.length() >= 32) {
newKey = key.substring(0, 32);
} else {
for (int i = key.length(); i < 32; i++) {
key += "0";
}
newKey = key.substring(0, 32);;
}
SecretKeySpec skeySpec = new SecretKeySpec(newKey.getBytes(), "AES");
Cipher fileCipher = Cipher.getInstance("AES/CBC/PKCS7Padding");
fileCipher.init(2, skeySpec, paramSpec);
int x = base64enc.length;
return fileCipher.doFinal(base64enc);
} catch (Exception e) {
Log.e("Exception: ", e.getMessage());
}
return null;
}
I guess the main issue is that the key generation is different in both pieces of code. Passwords are not keys, you should use either binary, randomly generated keys or a good key derivation mechanism like PBKDF2.
Trying to find a well vetted lib. that does use the same protocol for encryption in .NET and Java (/Android) would also be a good idea.
In general, input to cryptographic algorithms need to be binary. Always compare all inputs of your algorithms using hexadecimal encoding right before executing the algorithm.

AES Encryption in iOS and Java

I am a newbie to this encryption. I am creating an application for both android and iOS in which i have to encrypt(using AES Encryprtion) a file at server side and decrypt at client side in both iOS and Android App. I got code in internet to perform AES encryption and decryption for both Android and iOS, they are working fine. Server side they are using java. But the problem is Java Encrypted File cant be decrypted by iOS program, even I got the same filesize, But the file is not in correct format. I posted the code below...
Java Encryption and Decryption:
public static byte[] encrypt(byte[] data, byte[] key, byte[] ivs) {
try {
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
SecretKeySpec secretKeySpec = new SecretKeySpec(key, "AES");
byte[] finalIvs = new byte[16];
int len = ivs.length > 16 ? 16 : ivs.length;
System.arraycopy(ivs, 0, finalIvs, 0, len);
IvParameterSpec ivps = new IvParameterSpec(finalIvs);
cipher.init(Cipher.ENCRYPT_MODE, secretKeySpec, ivps);
return cipher.doFinal(data);
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
public static byte[] decrypt(byte[] data, byte[] key, byte[] ivs) {
try {
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
SecretKeySpec secretKeySpec = new SecretKeySpec(key, "AES");
byte[] finalIvs = new byte[16];
int len = ivs.length > 16 ? 16 : ivs.length;
System.arraycopy(ivs, 0, finalIvs, 0, len);
IvParameterSpec ivps = new IvParameterSpec(finalIvs);
cipher.init(Cipher.DECRYPT_MODE, secretKeySpec, ivps);
return cipher.doFinal(data);
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
iOS Code for Decryption:
- (NSData *) decryptFile:(NSString *)key withData:(NSData *)fileData {
char keyPtr[kCCKeySizeAES128+1];
bzero(keyPtr, sizeof(keyPtr));
NSString* iv = #"12345678";
[key getCString:keyPtr maxLength:sizeof(keyPtr) encoding:NSUTF8StringEncoding];
NSUInteger dataLength = [fileData length];
size_t bufferSize = dataLength + kCCBlockSizeAES128;
void *buffer = malloc(bufferSize);
size_t numBytesDecrypted = 0;
CCCryptorStatus cryptStatus = CCCrypt(kCCDecrypt, kCCAlgorithmAES128, kCCOptionPKCS7Padding,keyPtr, kCCKeySizeAES128,
iv /* initialization vector (optional) */,
[fileData bytes], dataLength, /* input */
buffer, bufferSize, /* output */
&numBytesDecrypted);
if (cryptStatus == kCCSuccess) {
//the returned NSData takes ownership of the buffer and will free it on deallocation
return [NSData dataWithBytesNoCopy:buffer length:numBytesDecrypted];
}
free(buffer); //free the buffer;
return nil;
}
Give me any solution or suggestion for this problem
The issue is with the iv parameter.
1) You are passing a NSString* as iv. You probably want to pass in the actual bytes.
2) The length of iv should be 16 (in this case) as per the api docs of CCCrypt. See link below:
http://www.opensource.apple.com/source/CommonCrypto/CommonCrypto-36064/CommonCrypto/CommonCryptor.h

Categories

Resources