1

Hi I am building a iOS application that communicates with a restful server. This requires my java AES code and Swift AES code to produce the same results currently I am using CryptoSwift, using the tutorial here (AES Encrypt and Decrypt). However this gives me different results compared to my java code.

Here is my java code:

private static final byte[] keyValue = new byte[] { 'T', 'h', 'e', 'B', 'e', 's', 't', 'S', 'e', 'c', 'r','e', 't', 'K', 'e', 'y' };

public static String encrypt(String Data) throws Exception {
    Key key = generateKey();
    Cipher c = Cipher.getInstance("AES");
    c.init(Cipher.ENCRYPT_MODE, key);
    byte[] encVal = c.doFinal(Data.getBytes());
    String encryptedValue = new BASE64Encoder().encode(encVal);
    return encryptedValue;
}

public static String decrypt(String encryptedData) throws Exception {
    Key key = generateKey();
    Cipher c = Cipher.getInstance("AES");
    c.init(Cipher.DECRYPT_MODE, key);
    byte[] decordedValue = new BASE64Decoder().decodeBuffer(encryptedData);
    byte[] decValue = c.doFinal(decordedValue);
    String decryptedValue = new String(decValue);
    return decryptedValue;
}

public static Key generateKey() throws Exception {
    Key key = new SecretKeySpec(keyValue, "AES");
    return key;
}

public static void main(String[] args) {
    try {
        System.out.println(AES.encrypt("test"));
    } catch (Exception e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }
}

This code gives me xGdooY+6V8q1cze7mR9TjQ==

Here is my code in swift

import Foundation
import CryptoSwift

extension String {
func aesEncrypt(key: String, iv: String) throws -> String{                                   
    let data = self.dataUsingEncoding(NSUTF8StringEncoding)
    let enc = try AES(key: key, iv: iv, blockMode:.CBC).encrypt(data!.arrayOfBytes())
    let encData = NSData(bytes: enc, length: Int(enc.count))
    let base64String: String = encData.base64EncodedStringWithOptions(NSDataBase64EncodingOptions(rawValue: 0));
    let result = String(base64String)
    return result
}

func aesDecrypt(key: String, iv: String) throws -> String {
    let data = NSData(base64EncodedString: self, options: NSDataBase64DecodingOptions(rawValue: 0))
    let dec = try AES(key: key, iv: iv, blockMode:.CBC).decrypt(data!.arrayOfBytes())
    let decData = NSData(bytes: dec, length: Int(dec.count))
    let result = NSString(data: decData, encoding: NSUTF8StringEncoding)
    return String(result!)
}
}

    let key = "TheBestSecretKey" // length == 32
    let iv = "gqLOHUioQ0QjhuvI" // length == 16
    let s = "test"
    let enc = try! s.aesEncrypt(key, iv: iv)
    let dec = try! enc.aesDecrypt(key, iv: iv)
    print(s)
    print("enc:\(enc)")
    print("dec:\(dec)")
    print("\(s == dec)")

This code gives me LQu3c4HaOQf7W0CfnMMy1w==

As you may see they do work independently but I need them to be compatible

Community
  • 1
  • 1
Mac Lane
  • 13
  • 1
  • 4

1 Answers1

7

You are doing two different types of encryption.
Your Java code is using the AES cipher which is more accurately AES/ECB/PKCS5Padding while your swift code is doing the equivalent of AES/CBC/PKCS5Padding and is using an IV.
In other words your swift code is doing cipher block chaining and uses a initialization vector. While your java code is doing ECB mode without an IV.
If you don't know what you are doing you shouldn't be implementing encryption schemes, but at a minimum, you should always use a random IV and cipher block chaining.
You should really never use ECB mode.
If you use a random IV, then each time you encrypt something the result will be different.
Rather than checking that the cipher texts are the same you should test that you can encrypt/decrypt messages between each component.

Magnus
  • 7,952
  • 2
  • 26
  • 52
  • Thanks for your help, I think I understood what you are saying. However encryption is not a huge element of my application so I don't need to be perfect I just need it to work, without having to send information back and forth in plain text. Is there any library or exiting code I can use for either swift or java that I can use? – Mac Lane Jun 26 '16 at 11:00
  • 1
    I don't know what your requirements are, but the simplest, least error prone method of sending encrypted data between a client and server would be to use HTTPS. – Magnus Jun 26 '16 at 11:04
  • 1
    A good cross platform solution is to use [RNCryptor](https://github.com/RNCryptor) which has versions for several platforms/languages. Further is provided authenticated encryption and password to key derivation. It covers the various details that are hard to get correct. – zaph Jun 26 '16 at 12:54
  • 1
    @zaph thanks RNCyptor works perfectly for my requirments – Mac Lane Jun 26 '16 at 16:57