New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[php] Convert encrypted data to string? #20

Closed
thehellsoul opened this Issue Jan 29, 2015 · 53 comments

Comments

7 participants
@thehellsoul

I need to send encrypted data as string to server.
I tried :
let encryptedString = NSString(data: encryptedData, encoding: NSUTF8StringEncoding)
println(encryptedString)
but the result is nil
So can you add a function to convert encrypted data to string?

@krzyzanowskim

This comment has been minimized.

Show comment
Hide comment
@krzyzanowskim

krzyzanowskim Jan 29, 2015

Owner

It is not much related to CryptoSwift, more stackoverflow question.

Anyway, depends what format is expected by your server you may expect different result. It may be Base64, or hex representation of bytes.

  • base64:
    let base64String = data.base64EncodedStringWithOptions(NSDataBase64EncodingOptions.allZeros)
  • hex representation by reading hexString property on NSData defined in NSDataExtension.
    let hexString = data.hexString
Owner

krzyzanowskim commented Jan 29, 2015

It is not much related to CryptoSwift, more stackoverflow question.

Anyway, depends what format is expected by your server you may expect different result. It may be Base64, or hex representation of bytes.

  • base64:
    let base64String = data.base64EncodedStringWithOptions(NSDataBase64EncodingOptions.allZeros)
  • hex representation by reading hexString property on NSData defined in NSDataExtension.
    let hexString = data.hexString
@bradleybernard

This comment has been minimized.

Show comment
Hide comment
@bradleybernard

bradleybernard Feb 1, 2015

The format of this

let base64String = data.base64EncodedStringWithOptions(NSDataBase64EncodingOptions.allZeros)

is not the same as PHP's function base64encode()... do you know anything about that? How to match it up to PHP function would be awesome. Would help alot thanks!

The format of this

let base64String = data.base64EncodedStringWithOptions(NSDataBase64EncodingOptions.allZeros)

is not the same as PHP's function base64encode()... do you know anything about that? How to match it up to PHP function would be awesome. Would help alot thanks!

@krzyzanowskim

This comment has been minimized.

Show comment
Hide comment
@krzyzanowskim

krzyzanowskim Feb 1, 2015

Owner

for the same input data, base64 output have to be the same. Are you sure input data is the same?

Owner

krzyzanowskim commented Feb 1, 2015

for the same input data, base64 output have to be the same. Are you sure input data is the same?

@bradleybernard

This comment has been minimized.

Show comment
Hide comment
@bradleybernard

bradleybernard Feb 1, 2015

Yes I am sure the input data is the same. The PHP function always returns two == at the end of the string while iOS produces only one = at the end of the string. It also worries me because iOS has options for base64 encoding while PHP doesn't

Yes I am sure the input data is the same. The PHP function always returns two == at the end of the string while iOS produces only one = at the end of the string. It also worries me because iOS has options for base64 encoding while PHP doesn't

@krzyzanowskim

This comment has been minimized.

Show comment
Hide comment
@krzyzanowskim

krzyzanowskim Feb 1, 2015

Owner

It looks like input to base64 encryption methods are different, but if you say it's not... I don't know. Actually I'm not familiar if there is difference between iOS and PHP in regard of Base64. I would recommend double check encryption output result.

Owner

krzyzanowskim commented Feb 1, 2015

It looks like input to base64 encryption methods are different, but if you say it's not... I don't know. Actually I'm not familiar if there is difference between iOS and PHP in regard of Base64. I would recommend double check encryption output result.

@bradleybernard

This comment has been minimized.

Show comment
Hide comment
@bradleybernard

bradleybernard Feb 1, 2015

Yes I will double check, I have another question though. Is the AES example provided AES-256? It just says aes.encrypt but how do I know its 256? I know nothing about encryption stuff...

Yes I will double check, I have another question though. Is the AES example provided AES-256? It just says aes.encrypt but how do I know its 256? I know nothing about encryption stuff...

@bradleybernard

This comment has been minimized.

Show comment
Hide comment
@bradleybernard

bradleybernard Feb 1, 2015

The PHP side is AES-256 that is why I'm asking.

The PHP side is AES-256 that is why I'm asking.

@krzyzanowskim

This comment has been minimized.

Show comment
Hide comment
@krzyzanowskim

krzyzanowskim Feb 1, 2015

Owner

256 (bits) is length of the key. If you key is 32 bytes long, then it's AES-256.

Owner

krzyzanowskim commented Feb 1, 2015

256 (bits) is length of the key. If you key is 32 bytes long, then it's AES-256.

@bradleybernard

This comment has been minimized.

Show comment
Hide comment
@bradleybernard

bradleybernard Feb 1, 2015

So if PHP and iOS have a 16 character key then they should both still product same output? I have 16 chars instead of 32. I am doing this to create a key:

iOS
var keyStr = String("abcdefghijklmnop")
let keyData = NSData.withBytes(UInt8)

PHP
Crypt::setKey("abcdefghijklmnop");
Crypt::encrypt("data")

So if PHP and iOS have a 16 character key then they should both still product same output? I have 16 chars instead of 32. I am doing this to create a key:

iOS
var keyStr = String("abcdefghijklmnop")
let keyData = NSData.withBytes(UInt8)

PHP
Crypt::setKey("abcdefghijklmnop");
Crypt::encrypt("data")

@krzyzanowskim

This comment has been minimized.

Show comment
Hide comment
@krzyzanowskim

krzyzanowskim Feb 1, 2015

Owner

16 bytes long key is for AES-128. I don't know how "Crypt" class is working, couldn't find it on php documentation site.

Owner

krzyzanowskim commented Feb 1, 2015

16 bytes long key is for AES-128. I don't know how "Crypt" class is working, couldn't find it on php documentation site.

@bradleybernard

This comment has been minimized.

Show comment
Hide comment
@bradleybernard

bradleybernard Feb 1, 2015

Sorry I forgot to include I am using a PHP framework called Laravel. Here is docs on Crypt class:

https://github.com/laravel/framework/blob/4.2/src/Illuminate/Encryption/Encrypter.php

Sorry I forgot to include I am using a PHP framework called Laravel. Here is docs on Crypt class:

https://github.com/laravel/framework/blob/4.2/src/Illuminate/Encryption/Encrypter.php

@bradleybernard

This comment has been minimized.

Show comment
Hide comment
@bradleybernard

bradleybernard Feb 1, 2015

I might be doing something wrong on PHP side

I might be doing something wrong on PHP side

@krzyzanowskim

This comment has been minimized.

Show comment
Hide comment
@krzyzanowskim

krzyzanowskim Feb 1, 2015

Owner

This PHP class doesn't just do AES encryption. It is doing a much more by constructing actual message.
"padAndMcrypt()" (which is protected method) is padding and encryption, while "encrypt()" is doing much more, see https://github.com/laravel/framework/blob/4.2/src/Illuminate/Encryption/Encrypter.php#L53

if you need to replicate this output format you have to handle it on iOS by yourself.

Owner

krzyzanowskim commented Feb 1, 2015

This PHP class doesn't just do AES encryption. It is doing a much more by constructing actual message.
"padAndMcrypt()" (which is protected method) is padding and encryption, while "encrypt()" is doing much more, see https://github.com/laravel/framework/blob/4.2/src/Illuminate/Encryption/Encrypter.php#L53

if you need to replicate this output format you have to handle it on iOS by yourself.

@bradleybernard

This comment has been minimized.

Show comment
Hide comment
@bradleybernard

bradleybernard Feb 1, 2015

But isn't the crypto swift padding too? The option to add padding can be turned on to match that encryption on PHp?

Sent from my iPhone

On Feb 1, 2015, at 1:30 PM, Marcin Krzyzanowski notifications@github.com wrote:

This PHP class doesn't just do AES encryption. It is doing a much more by constructing actual message.
"padAndMcrypt()" (which is protected method) is padding and encryption, while "encrypt()" is doing much more, see https://github.com/laravel/framework/blob/4.2/src/Illuminate/Encryption/Encrypter.php#L53

if you need to replicate this output format you have to handle it on iOS by yourself.


Reply to this email directly or view it on GitHub.

But isn't the crypto swift padding too? The option to add padding can be turned on to match that encryption on PHp?

Sent from my iPhone

On Feb 1, 2015, at 1:30 PM, Marcin Krzyzanowski notifications@github.com wrote:

This PHP class doesn't just do AES encryption. It is doing a much more by constructing actual message.
"padAndMcrypt()" (which is protected method) is padding and encryption, while "encrypt()" is doing much more, see https://github.com/laravel/framework/blob/4.2/src/Illuminate/Encryption/Encrypter.php#L53

if you need to replicate this output format you have to handle it on iOS by yourself.


Reply to this email directly or view it on GitHub.

@krzyzanowskim

This comment has been minimized.

Show comment
Hide comment
@krzyzanowskim

krzyzanowskim Feb 1, 2015

Owner

it is, just php encrypt() is doing much more, is calculating MAC, creating JSON, combine IV and cipher result, then this all is encoded with base64

    public function encrypt($value)
    {
        $iv = mcrypt_create_iv($this->getIvSize(), $this->getRandomizer());
        $value = base64_encode($this->padAndMcrypt($value, $iv));
        // Once we have the encrypted value we will go ahead base64_encode the input
        // vector and create the MAC for the encrypted value so we can verify its
        // authenticity. Then, we'll JSON encode the data in a "payload" array.
        $mac = $this->hash($iv = base64_encode($iv), $value);
        return base64_encode(json_encode(compact('iv', 'value', 'mac')));
    }
Owner

krzyzanowskim commented Feb 1, 2015

it is, just php encrypt() is doing much more, is calculating MAC, creating JSON, combine IV and cipher result, then this all is encoded with base64

    public function encrypt($value)
    {
        $iv = mcrypt_create_iv($this->getIvSize(), $this->getRandomizer());
        $value = base64_encode($this->padAndMcrypt($value, $iv));
        // Once we have the encrypted value we will go ahead base64_encode the input
        // vector and create the MAC for the encrypted value so we can verify its
        // authenticity. Then, we'll JSON encode the data in a "payload" array.
        $mac = $this->hash($iv = base64_encode($iv), $value);
        return base64_encode(json_encode(compact('iv', 'value', 'mac')));
    }
@bradleybernard

This comment has been minimized.

Show comment
Hide comment
@bradleybernard

bradleybernard Feb 1, 2015

I could just avoid the framework for this encryption and create my own function just using php standard encryption library mcrypt. To be able to not do the json payload and Mac stuff. Do you think that would work?

Sent from my iPhone

On Feb 1, 2015, at 1:45 PM, Marcin Krzyzanowski notifications@github.com wrote:

it is, just php encrypt() is doing much more, is calculating MAC, creating JSON, combine IV and cipher result, then this all is encoded with base64

public function encrypt($value)
{
    $iv = mcrypt_create_iv($this->getIvSize(), $this->getRandomizer());
    $value = base64_encode($this->padAndMcrypt($value, $iv));
    // Once we have the encrypted value we will go ahead base64_encode the input
    // vector and create the MAC for the encrypted value so we can verify its
    // authenticity. Then, we'll JSON encode the data in a "payload" array.
    $mac = $this->hash($iv = base64_encode($iv), $value);
    return base64_encode(json_encode(compact('iv', 'value', 'mac')));
}


Reply to this email directly or view it on GitHub.

I could just avoid the framework for this encryption and create my own function just using php standard encryption library mcrypt. To be able to not do the json payload and Mac stuff. Do you think that would work?

Sent from my iPhone

On Feb 1, 2015, at 1:45 PM, Marcin Krzyzanowski notifications@github.com wrote:

it is, just php encrypt() is doing much more, is calculating MAC, creating JSON, combine IV and cipher result, then this all is encoded with base64

public function encrypt($value)
{
    $iv = mcrypt_create_iv($this->getIvSize(), $this->getRandomizer());
    $value = base64_encode($this->padAndMcrypt($value, $iv));
    // Once we have the encrypted value we will go ahead base64_encode the input
    // vector and create the MAC for the encrypted value so we can verify its
    // authenticity. Then, we'll JSON encode the data in a "payload" array.
    $mac = $this->hash($iv = base64_encode($iv), $value);
    return base64_encode(json_encode(compact('iv', 'value', 'mac')));
}


Reply to this email directly or view it on GitHub.

@krzyzanowskim

This comment has been minimized.

Show comment
Hide comment
@krzyzanowskim

krzyzanowskim Feb 1, 2015

Owner

yes, simply do what padAndMcrypt() is doing.

Owner

krzyzanowskim commented Feb 1, 2015

yes, simply do what padAndMcrypt() is doing.

@bradleybernard

This comment has been minimized.

Show comment
Hide comment
@bradleybernard

bradleybernard Feb 1, 2015

So comment out the last two lines where it says

$mac = $this->hash($iv = base64_encode($iv), $value);
return base64_encode(json_encode(compact('iv', 'value', 'mac')));

And just return $value which is
$value = base64_encode($this->padAndMcrypt($value, $iv));

and I would have same output as cryptoswift?

So comment out the last two lines where it says

$mac = $this->hash($iv = base64_encode($iv), $value);
return base64_encode(json_encode(compact('iv', 'value', 'mac')));

And just return $value which is
$value = base64_encode($this->padAndMcrypt($value, $iv));

and I would have same output as cryptoswift?

@bradleybernard

This comment has been minimized.

Show comment
Hide comment
@bradleybernard

bradleybernard Feb 1, 2015

Ok I am using this class now:

class Encryption
{
const CIPHER = MCRYPT_RIJNDAEL_128; // Rijndael-128 is AES
const MODE = MCRYPT_MODE_CBC;

/* Cryptographic key of length 16, 24 or 32. NOT a password! */
private $key;
public function __construct($key) {
    $this->key = $key;
}

public function encrypt($plaintext) {
    $ivSize = mcrypt_get_iv_size(self::CIPHER, self::MODE);
    $iv = mcrypt_create_iv($ivSize, MCRYPT_DEV_RANDOM);
    $ciphertext = mcrypt_encrypt(self::CIPHER, $this->key, $plaintext, self::MODE, $iv);
    return base64_encode($iv.$ciphertext);
}

public function decrypt($ciphertext) {
    $ciphertext = base64_decode($ciphertext);
    $ivSize = mcrypt_get_iv_size(self::CIPHER, self::MODE);
    if (strlen($ciphertext) < $ivSize) {
        throw new Exception('Missing initialization vector');
    }

    $iv = substr($ciphertext, 0, $ivSize);
    $ciphertext = substr($ciphertext, $ivSize);
    $plaintext = mcrypt_decrypt(self::CIPHER, $this->key, $ciphertext, self::MODE, $iv);
    return rtrim($plaintext, "\0");
}

}

And using it like this:

$key = "abcdefghijklmnop";
$crypt = new Encryption($key);
$encrypted_string = $crypt->encrypt('data');
$decrypted_string = $crypt->decrypt($encrypted_string);

Ok I am using this class now:

class Encryption
{
const CIPHER = MCRYPT_RIJNDAEL_128; // Rijndael-128 is AES
const MODE = MCRYPT_MODE_CBC;

/* Cryptographic key of length 16, 24 or 32. NOT a password! */
private $key;
public function __construct($key) {
    $this->key = $key;
}

public function encrypt($plaintext) {
    $ivSize = mcrypt_get_iv_size(self::CIPHER, self::MODE);
    $iv = mcrypt_create_iv($ivSize, MCRYPT_DEV_RANDOM);
    $ciphertext = mcrypt_encrypt(self::CIPHER, $this->key, $plaintext, self::MODE, $iv);
    return base64_encode($iv.$ciphertext);
}

public function decrypt($ciphertext) {
    $ciphertext = base64_decode($ciphertext);
    $ivSize = mcrypt_get_iv_size(self::CIPHER, self::MODE);
    if (strlen($ciphertext) < $ivSize) {
        throw new Exception('Missing initialization vector');
    }

    $iv = substr($ciphertext, 0, $ivSize);
    $ciphertext = substr($ciphertext, $ivSize);
    $plaintext = mcrypt_decrypt(self::CIPHER, $this->key, $ciphertext, self::MODE, $iv);
    return rtrim($plaintext, "\0");
}

}

And using it like this:

$key = "abcdefghijklmnop";
$crypt = new Encryption($key);
$encrypted_string = $crypt->encrypt('data');
$decrypted_string = $crypt->decrypt($encrypted_string);

@bradleybernard

This comment has been minimized.

Show comment
Hide comment
@bradleybernard

bradleybernard Feb 1, 2015

I want to remove padding from this statement

    let plaintextData = PKCS7(data: strTest.dataUsingEncoding(NSUTF8StringEncoding)!).addPadding(AES.blockSizeBytes())

but when I remove .addPadding it won't return the right data type.

I want to remove padding from this statement

    let plaintextData = PKCS7(data: strTest.dataUsingEncoding(NSUTF8StringEncoding)!).addPadding(AES.blockSizeBytes())

but when I remove .addPadding it won't return the right data type.

@krzyzanowskim

This comment has been minimized.

Show comment
Hide comment
@krzyzanowskim

krzyzanowskim Feb 1, 2015

Owner

No. try this:

function encrypt($value, $iv)
{
    $value = $this->addPadding($value);
    return base64_encode(mcrypt_encrypt($this->cipher, $this->key, $value, $this->mode, $iv));
}

I haven't done any php code since years, but this one should work ;)

Owner

krzyzanowskim commented Feb 1, 2015

No. try this:

function encrypt($value, $iv)
{
    $value = $this->addPadding($value);
    return base64_encode(mcrypt_encrypt($this->cipher, $this->key, $value, $this->mode, $iv));
}

I haven't done any php code since years, but this one should work ;)

@bradleybernard

This comment has been minimized.

Show comment
Hide comment
@bradleybernard

bradleybernard Feb 1, 2015

That returned something that looks okay lol. But I would need to change decrypt now...

  public function decrypt($payload)
  {
    $payload = $this->getJsonPayload($payload);

    // We'll go ahead and remove the PKCS7 padding from the encrypted value before
    // we decrypt it. Once we have the de-padded value, we will grab the vector
    // and decrypt the data, passing back the unserialized from of the value.
    $value = base64_decode($payload['value']);

    $iv = base64_decode($payload['iv']);

    return unserialize($this->stripPadding($this->mcryptDecrypt($value, $iv)));
   }

That returned something that looks okay lol. But I would need to change decrypt now...

  public function decrypt($payload)
  {
    $payload = $this->getJsonPayload($payload);

    // We'll go ahead and remove the PKCS7 padding from the encrypted value before
    // we decrypt it. Once we have the de-padded value, we will grab the vector
    // and decrypt the data, passing back the unserialized from of the value.
    $value = base64_decode($payload['value']);

    $iv = base64_decode($payload['iv']);

    return unserialize($this->stripPadding($this->mcryptDecrypt($value, $iv)));
   }
@bradleybernard

This comment has been minimized.

Show comment
Hide comment
@bradleybernard

bradleybernard Feb 1, 2015

You named your function encrypt but passed two parameters $value and $iv. Did you mean to call it padAndMcrypt? That function has two parameters called $value and $iv, compared to the original encrypt function that just has $value.

You named your function encrypt but passed two parameters $value and $iv. Did you mean to call it padAndMcrypt? That function has two parameters called $value and $iv, compared to the original encrypt function that just has $value.

@krzyzanowskim

This comment has been minimized.

Show comment
Hide comment
@krzyzanowskim

krzyzanowskim Feb 1, 2015

Owner

it's slightly different as you can see.

Owner

krzyzanowskim commented Feb 1, 2015

it's slightly different as you can see.

@bradleybernard

This comment has been minimized.

Show comment
Hide comment
@bradleybernard

bradleybernard Feb 1, 2015

I see, however PHP is still returning a string with == on the end and Swift is still returning one with one = on the end... Does this have to do with the padding? On Swift it looks like I am adding padding and on PHP side I don't do padding to encrypt?

I see, however PHP is still returning a string with == on the end and Swift is still returning one with one = on the end... Does this have to do with the padding? On Swift it looks like I am adding padding and on PHP side I don't do padding to encrypt?

@bradleybernard

This comment has been minimized.

Show comment
Hide comment
@bradleybernard

bradleybernard Feb 1, 2015

var strTest = String("data")
        var keyStr = String("abcdefghijklmnop")

        let plaintextData = PKCS7(data: strTest.dataUsingEncoding(NSUTF8StringEncoding)!).addPadding(AES.blockSizeBytes())
        let keyData = NSData.withBytes([UInt8](keyStr.utf8))
        let ivData:NSData = Cipher.randomIV(keyData)

        let encryptedData = Cipher.AES(key: keyData, iv: ivData, blockMode: .CBC).encrypt(plaintextData)
        if let actualData = encryptedData {
            let aes = AES(key: keyData, iv: ivData, blockMode: .CBC) // CBC is default
            //let encryptedData = aes?.encrypt(plaintextData, addPadding: true) // With padding enabled
            let decryptedData = Cipher.AES(key: keyData, iv: ivData, blockMode: .CBC).decrypt(encryptedData!)

            let returnTextData = PKCS7(data: decryptedData!).removePadding()
            let encryptString = NSString(data: encryptedData!, encoding: NSUTF8StringEncoding)
            let resStr = NSString(data: returnTextData, encoding: NSUTF8StringEncoding)
            let encryptKey = NSString(data: keyData, encoding: NSUTF8StringEncoding)
            let base64String = actualData.base64EncodedStringWithOptions(NSDataBase64EncodingOptions.EncodingEndLineWithCarriageReturn)
            println(base64String)
        }
var strTest = String("data")
        var keyStr = String("abcdefghijklmnop")

        let plaintextData = PKCS7(data: strTest.dataUsingEncoding(NSUTF8StringEncoding)!).addPadding(AES.blockSizeBytes())
        let keyData = NSData.withBytes([UInt8](keyStr.utf8))
        let ivData:NSData = Cipher.randomIV(keyData)

        let encryptedData = Cipher.AES(key: keyData, iv: ivData, blockMode: .CBC).encrypt(plaintextData)
        if let actualData = encryptedData {
            let aes = AES(key: keyData, iv: ivData, blockMode: .CBC) // CBC is default
            //let encryptedData = aes?.encrypt(plaintextData, addPadding: true) // With padding enabled
            let decryptedData = Cipher.AES(key: keyData, iv: ivData, blockMode: .CBC).decrypt(encryptedData!)

            let returnTextData = PKCS7(data: decryptedData!).removePadding()
            let encryptString = NSString(data: encryptedData!, encoding: NSUTF8StringEncoding)
            let resStr = NSString(data: returnTextData, encoding: NSUTF8StringEncoding)
            let encryptKey = NSString(data: keyData, encoding: NSUTF8StringEncoding)
            let base64String = actualData.base64EncodedStringWithOptions(NSDataBase64EncodingOptions.EncodingEndLineWithCarriageReturn)
            println(base64String)
        }
@krzyzanowskim

This comment has been minimized.

Show comment
Hide comment
@krzyzanowskim

krzyzanowskim Feb 1, 2015

Owner

Check this PHP code I wrote: gist: How to encrypt data with padding usign AES cipher. Should work fine.

Owner

krzyzanowskim commented Feb 1, 2015

Check this PHP code I wrote: gist: How to encrypt data with padding usign AES cipher. Should work fine.

@bradleybernard

This comment has been minimized.

Show comment
Hide comment
@bradleybernard

bradleybernard Feb 1, 2015

Seems to work great! You are an incredible coder. HOWEVER Swift is still giving me a one = on the end of the base64encoded output. And PHP is giving me two ==

I took my Swift base64 encoded string and ran it in your stripPadding(decrypt("SWIFTRESULT", "abcdefghijklmnop", $IV)); and it returned gibberish. Maybe it is my Swift code that is bad? :(

Seems to work great! You are an incredible coder. HOWEVER Swift is still giving me a one = on the end of the base64encoded output. And PHP is giving me two ==

I took my Swift base64 encoded string and ran it in your stripPadding(decrypt("SWIFTRESULT", "abcdefghijklmnop", $IV)); and it returned gibberish. Maybe it is my Swift code that is bad? :(

@krzyzanowskim

This comment has been minimized.

Show comment
Hide comment
@krzyzanowskim

krzyzanowskim Feb 1, 2015

Owner

here is Swift part. You need the same key and iv on both sides to get the same result. And please update CryproSwift from repository, I just pushed fix for removing padding.

    var strTest = "data"
    var keyStr = "abcdefghijklmnop"
    var ivStr = "abcdefghijklmnop"

    let plaintextData = strTest.dataUsingEncoding(NSUTF8StringEncoding)!
    // KEY and IV
    let keyData = keyStr.dataUsingEncoding(NSUTF8StringEncoding, allowLossyConversion: false)!
    let ivData:NSData = ivStr.dataUsingEncoding(NSUTF8StringEncoding, allowLossyConversion: false)! //Cipher.randomIV(keyData)
    // Encrypt
    let cipherdata = Cipher.AES(key: keyData, iv: ivData, blockMode: .CBC).encrypt(plaintextData)

    if let cipherdata = cipherdata {
        let aes = AES(key: keyData, iv: ivData, blockMode: .CBC) // CBC is default
        let decryptedData = Cipher.AES(key: keyData, iv: ivData, blockMode: .CBC).decrypt(cipherdata)
        let decryptedString = NSString(data: decryptedData!, encoding: NSUTF8StringEncoding)!
        let base64String = cipherdata.base64EncodedStringWithOptions(NSDataBase64EncodingOptions.Encoding64CharacterLineLength)
        println(base64String)
    }
Owner

krzyzanowskim commented Feb 1, 2015

here is Swift part. You need the same key and iv on both sides to get the same result. And please update CryproSwift from repository, I just pushed fix for removing padding.

    var strTest = "data"
    var keyStr = "abcdefghijklmnop"
    var ivStr = "abcdefghijklmnop"

    let plaintextData = strTest.dataUsingEncoding(NSUTF8StringEncoding)!
    // KEY and IV
    let keyData = keyStr.dataUsingEncoding(NSUTF8StringEncoding, allowLossyConversion: false)!
    let ivData:NSData = ivStr.dataUsingEncoding(NSUTF8StringEncoding, allowLossyConversion: false)! //Cipher.randomIV(keyData)
    // Encrypt
    let cipherdata = Cipher.AES(key: keyData, iv: ivData, blockMode: .CBC).encrypt(plaintextData)

    if let cipherdata = cipherdata {
        let aes = AES(key: keyData, iv: ivData, blockMode: .CBC) // CBC is default
        let decryptedData = Cipher.AES(key: keyData, iv: ivData, blockMode: .CBC).decrypt(cipherdata)
        let decryptedString = NSString(data: decryptedData!, encoding: NSUTF8StringEncoding)!
        let base64String = cipherdata.base64EncodedStringWithOptions(NSDataBase64EncodingOptions.Encoding64CharacterLineLength)
        println(base64String)
    }
@bradleybernard

This comment has been minimized.

Show comment
Hide comment
@bradleybernard

bradleybernard Feb 1, 2015

Oh my god. I think I got it to work using your given code. I can't give it a random IV in PHP and Swift, I have to give the IV to be a key that they both share. I thought the IV could be random between the two but I guess not. (I don't know anything about cryptography). Here is my finished code

// Generate IV
   $iv_size = mcrypt_get_iv_size(MCRYPT_RIJNDAEL_128, MCRYPT_MODE_CBC);
   //$iv = mcrypt_create_iv($iv_size, MCRYPT_RAND);
   $iv = "abcdefghijklmnop";
   print $iv."\n";


   // Encrypt
   $ciphertext_base64 = encrypt(addPadding("data"), "abcdefghijklmnop", $iv);
   print $ciphertext_base64."\n";
   // Decrypt
   $plaintext = stripPadding(decrypt($ciphertext_base64, "abcdefghijklmnop", $iv));
   print $plaintext."\n";

   $decryptTry = stripPadding(decrypt("IuV9IYIdL6dQN99vqz8ZjQ==", "abcdefghijklmnop", $iv));
   $decryptSwift = stripPadding(decrypt("gSxZy8HucfGTcrDUsncfiQ==", "abcdefghijklmnop", $iv));
   print $decryptTry."\n";
   print $decryptSwift . "\n";
var strTest = "asdfasdf"
        var keyStr = "abcdefghijklmnop"
        var ivStr = "abcdefghijklmnop"

        let plaintextData = strTest.dataUsingEncoding(NSUTF8StringEncoding)!
        // KEY and IV
        let keyData = keyStr.dataUsingEncoding(NSUTF8StringEncoding, allowLossyConversion: false)!
        let ivData:NSData = ivStr.dataUsingEncoding(NSUTF8StringEncoding, allowLossyConversion: false)! //Cipher.randomIV(keyData)
        // Encrypt
        let cipherdata = Cipher.AES(key: keyData, iv: ivData, blockMode: .CBC).encrypt(plaintextData)

        if let cipherdata = cipherdata {
            let aes = AES(key: keyData, iv: ivData, blockMode: .CBC) // CBC is default
            let decryptedData = Cipher.AES(key: keyData, iv: ivData, blockMode: .CBC).decrypt(cipherdata)
            let decryptedString = NSString(data: decryptedData!, encoding: NSUTF8StringEncoding)!
            let base64String = cipherdata.base64EncodedStringWithOptions(NSDataBase64EncodingOptions.Encoding64CharacterLineLength)
            println(base64String)
        }

I am beyond thankful for your work. Do you have a paypal that I can donate to?

Oh my god. I think I got it to work using your given code. I can't give it a random IV in PHP and Swift, I have to give the IV to be a key that they both share. I thought the IV could be random between the two but I guess not. (I don't know anything about cryptography). Here is my finished code

// Generate IV
   $iv_size = mcrypt_get_iv_size(MCRYPT_RIJNDAEL_128, MCRYPT_MODE_CBC);
   //$iv = mcrypt_create_iv($iv_size, MCRYPT_RAND);
   $iv = "abcdefghijklmnop";
   print $iv."\n";


   // Encrypt
   $ciphertext_base64 = encrypt(addPadding("data"), "abcdefghijklmnop", $iv);
   print $ciphertext_base64."\n";
   // Decrypt
   $plaintext = stripPadding(decrypt($ciphertext_base64, "abcdefghijklmnop", $iv));
   print $plaintext."\n";

   $decryptTry = stripPadding(decrypt("IuV9IYIdL6dQN99vqz8ZjQ==", "abcdefghijklmnop", $iv));
   $decryptSwift = stripPadding(decrypt("gSxZy8HucfGTcrDUsncfiQ==", "abcdefghijklmnop", $iv));
   print $decryptTry."\n";
   print $decryptSwift . "\n";
var strTest = "asdfasdf"
        var keyStr = "abcdefghijklmnop"
        var ivStr = "abcdefghijklmnop"

        let plaintextData = strTest.dataUsingEncoding(NSUTF8StringEncoding)!
        // KEY and IV
        let keyData = keyStr.dataUsingEncoding(NSUTF8StringEncoding, allowLossyConversion: false)!
        let ivData:NSData = ivStr.dataUsingEncoding(NSUTF8StringEncoding, allowLossyConversion: false)! //Cipher.randomIV(keyData)
        // Encrypt
        let cipherdata = Cipher.AES(key: keyData, iv: ivData, blockMode: .CBC).encrypt(plaintextData)

        if let cipherdata = cipherdata {
            let aes = AES(key: keyData, iv: ivData, blockMode: .CBC) // CBC is default
            let decryptedData = Cipher.AES(key: keyData, iv: ivData, blockMode: .CBC).decrypt(cipherdata)
            let decryptedString = NSString(data: decryptedData!, encoding: NSUTF8StringEncoding)!
            let base64String = cipherdata.base64EncodedStringWithOptions(NSDataBase64EncodingOptions.Encoding64CharacterLineLength)
            println(base64String)
        }

I am beyond thankful for your work. Do you have a paypal that I can donate to?

@bradleybernard

This comment has been minimized.

Show comment
Hide comment
@bradleybernard

bradleybernard Feb 2, 2015

One last thing!! If I am trying to decrypt a string that was sent from PHP to Swift, I tried this but getting errors: fatal error: AES 128-bit block exceeded!

var strTest = "asdfasdf"
        var keyStr = "abcdefghijklmnop"
        var ivStr = "abcdefghijklmnop"
        var encryptedStr = "W9yLRGkIpmJQqXN2kI4C3w=="

        let encryptedStrData = encryptedStr.dataUsingEncoding(NSUTF8StringEncoding, allowLossyConversion: false)!
        let plaintextData = strTest.dataUsingEncoding(NSUTF8StringEncoding)!

        let keyData = keyStr.dataUsingEncoding(NSUTF8StringEncoding, allowLossyConversion: false)!
        let ivData:NSData = ivStr.dataUsingEncoding(NSUTF8StringEncoding, allowLossyConversion: false)!
        let cipherdata = Cipher.AES(key: keyData, iv: ivData, blockMode: .CBC).encrypt(plaintextData)

        if let cipherdata = cipherdata {
            let aes = AES(key: keyData, iv: ivData, blockMode: .CBC)
            let decryptedData = Cipher.AES(key: keyData, iv: ivData, blockMode: .CBC).decrypt(cipherdata)
            let decryptedString = NSString(data: decryptedData!, encoding: NSUTF8StringEncoding)!
            let base64String = cipherdata.base64EncodedStringWithOptions(NSDataBase64EncodingOptions.Encoding64CharacterLineLength)
            println(base64String)
        }

        let decryptedTryData = Cipher.AES(key: keyData, iv: ivData, blockMode: .CBC).decrypt(encryptedStrData)
        if let decryptedTryData = decryptedTryData {
            let base64Decrypted = decryptedTryData.base64EncodedStringWithOptions(NSDataBase64EncodingOptions.Encoding64CharacterLineLength)
            println(base64Decrypted)
        }

One last thing!! If I am trying to decrypt a string that was sent from PHP to Swift, I tried this but getting errors: fatal error: AES 128-bit block exceeded!

var strTest = "asdfasdf"
        var keyStr = "abcdefghijklmnop"
        var ivStr = "abcdefghijklmnop"
        var encryptedStr = "W9yLRGkIpmJQqXN2kI4C3w=="

        let encryptedStrData = encryptedStr.dataUsingEncoding(NSUTF8StringEncoding, allowLossyConversion: false)!
        let plaintextData = strTest.dataUsingEncoding(NSUTF8StringEncoding)!

        let keyData = keyStr.dataUsingEncoding(NSUTF8StringEncoding, allowLossyConversion: false)!
        let ivData:NSData = ivStr.dataUsingEncoding(NSUTF8StringEncoding, allowLossyConversion: false)!
        let cipherdata = Cipher.AES(key: keyData, iv: ivData, blockMode: .CBC).encrypt(plaintextData)

        if let cipherdata = cipherdata {
            let aes = AES(key: keyData, iv: ivData, blockMode: .CBC)
            let decryptedData = Cipher.AES(key: keyData, iv: ivData, blockMode: .CBC).decrypt(cipherdata)
            let decryptedString = NSString(data: decryptedData!, encoding: NSUTF8StringEncoding)!
            let base64String = cipherdata.base64EncodedStringWithOptions(NSDataBase64EncodingOptions.Encoding64CharacterLineLength)
            println(base64String)
        }

        let decryptedTryData = Cipher.AES(key: keyData, iv: ivData, blockMode: .CBC).decrypt(encryptedStrData)
        if let decryptedTryData = decryptedTryData {
            let base64Decrypted = decryptedTryData.base64EncodedStringWithOptions(NSDataBase64EncodingOptions.Encoding64CharacterLineLength)
            println(base64Decrypted)
        }
@krzyzanowskim

This comment has been minimized.

Show comment
Hide comment
@krzyzanowskim

krzyzanowskim Feb 2, 2015

Owner

IV should be random, I made it the same just to conveniency here, but you should use random one. The point is that you have to know key and IV to decrypt ciphertext. Known that. It's common to generate IV upon encryption, then transfer IV along with ciphertext, and read it just before decryption (IV is read and used to decrypt rest part of data). This can be archived quite simple like this:

    func decrypt(transferData:NSData, keyData:NSData) -> String {
        let ivData = transferData.subdataWithRange(NSRange(location: 0, length: AES.blockSizeBytes()))
        let encryptedData = transferData.subdataWithRange(NSRange(location: AES.blockSizeBytes(), length: transferData.length - AES.blockSizeBytes()))

        let aes = AES(key: keyData, iv: ivData, blockMode: .CBC) // CBC is default
        let decryptedData = Cipher.AES(key: keyData, iv: ivData, blockMode: .CBC).decrypt(encryptedData)
        let decryptedString = NSString(data: decryptedData!, encoding: NSUTF8StringEncoding)!
        return decryptedString
    }

    func encrypt(plaintextData:NSData, keyData:NSData) -> NSData {
        let ivData:NSData = Cipher.randomIV(keyData)
        let cipherdata = Cipher.AES(key: keyData, iv: ivData, blockMode: .CBC).encrypt(plaintextData)
        let transferData = NSMutableData(data: ivData)
        transferData.appendData(cipherdata!)
        return transferData
    }


    // KEY and IV
    var strTest = "data"
    var keyStr = "abcdefghijklmnop"

    let keyData = keyStr.dataUsingEncoding(NSUTF8StringEncoding, allowLossyConversion: false)!
    let ivData:NSData = Cipher.randomIV(keyData)

    let encrypted = encrypt(strTest.dataUsingEncoding(NSUTF8StringEncoding)!, keyData)
    let decrypted = decrypt(encrypted, keyData)
    println(decrypted)
Owner

krzyzanowskim commented Feb 2, 2015

IV should be random, I made it the same just to conveniency here, but you should use random one. The point is that you have to know key and IV to decrypt ciphertext. Known that. It's common to generate IV upon encryption, then transfer IV along with ciphertext, and read it just before decryption (IV is read and used to decrypt rest part of data). This can be archived quite simple like this:

    func decrypt(transferData:NSData, keyData:NSData) -> String {
        let ivData = transferData.subdataWithRange(NSRange(location: 0, length: AES.blockSizeBytes()))
        let encryptedData = transferData.subdataWithRange(NSRange(location: AES.blockSizeBytes(), length: transferData.length - AES.blockSizeBytes()))

        let aes = AES(key: keyData, iv: ivData, blockMode: .CBC) // CBC is default
        let decryptedData = Cipher.AES(key: keyData, iv: ivData, blockMode: .CBC).decrypt(encryptedData)
        let decryptedString = NSString(data: decryptedData!, encoding: NSUTF8StringEncoding)!
        return decryptedString
    }

    func encrypt(plaintextData:NSData, keyData:NSData) -> NSData {
        let ivData:NSData = Cipher.randomIV(keyData)
        let cipherdata = Cipher.AES(key: keyData, iv: ivData, blockMode: .CBC).encrypt(plaintextData)
        let transferData = NSMutableData(data: ivData)
        transferData.appendData(cipherdata!)
        return transferData
    }


    // KEY and IV
    var strTest = "data"
    var keyStr = "abcdefghijklmnop"

    let keyData = keyStr.dataUsingEncoding(NSUTF8StringEncoding, allowLossyConversion: false)!
    let ivData:NSData = Cipher.randomIV(keyData)

    let encrypted = encrypt(strTest.dataUsingEncoding(NSUTF8StringEncoding)!, keyData)
    let decrypted = decrypt(encrypted, keyData)
    println(decrypted)
@krzyzanowskim

This comment has been minimized.

Show comment
Hide comment
@krzyzanowskim

krzyzanowskim Feb 2, 2015

Owner

You can't decrypt it because you have to decode base64 FIRST, then decrypt ciphertext, not the other way around

    var keyStr = "abcdefghijklmnop"
    var ivStr = "abcdefghijklmnop"
    var encryptedStr = "ip4KS9CpYou3tqDn2PoREA=="

    var encryptedStrData = NSData(base64EncodedString: encryptedStr, options: NSDataBase64DecodingOptions.allZeros)!
    var keyData = keyStr.dataUsingEncoding(NSUTF8StringEncoding, allowLossyConversion: false)!
    var ivData:NSData = ivStr.dataUsingEncoding(NSUTF8StringEncoding, allowLossyConversion: false)!
    let decryptedTryData = Cipher.AES(key: keyData, iv: ivData, blockMode: .CBC).decrypt(encryptedStrData)
    if let decryptedTryData = decryptedTryData {
        let plaintext = NSString(data: decryptedTryData, encoding: NSUTF8StringEncoding)!
        println(plaintext)
    }
Owner

krzyzanowskim commented Feb 2, 2015

You can't decrypt it because you have to decode base64 FIRST, then decrypt ciphertext, not the other way around

    var keyStr = "abcdefghijklmnop"
    var ivStr = "abcdefghijklmnop"
    var encryptedStr = "ip4KS9CpYou3tqDn2PoREA=="

    var encryptedStrData = NSData(base64EncodedString: encryptedStr, options: NSDataBase64DecodingOptions.allZeros)!
    var keyData = keyStr.dataUsingEncoding(NSUTF8StringEncoding, allowLossyConversion: false)!
    var ivData:NSData = ivStr.dataUsingEncoding(NSUTF8StringEncoding, allowLossyConversion: false)!
    let decryptedTryData = Cipher.AES(key: keyData, iv: ivData, blockMode: .CBC).decrypt(encryptedStrData)
    if let decryptedTryData = decryptedTryData {
        let plaintext = NSString(data: decryptedTryData, encoding: NSUTF8StringEncoding)!
        println(plaintext)
    }
@bradleybernard

This comment has been minimized.

Show comment
Hide comment
@bradleybernard

bradleybernard Feb 2, 2015

I get what you are saying about your second post about base64 decode first and then decrypt, but the post above it is a little beyond me... Would I have to change the PHP code to make it read the IV in the cipher text to be able to decrypt the ciphertext?

I get what you are saying about your second post about base64 decode first and then decrypt, but the post above it is a little beyond me... Would I have to change the PHP code to make it read the IV in the cipher text to be able to decrypt the ciphertext?

@bradleybernard

This comment has been minimized.

Show comment
Hide comment
@bradleybernard

bradleybernard Feb 2, 2015

Would I be risking a lot of security if the IV was the same? I have the code working as is, with the IV being static between PHP and Swift. I don't want to mess it up :P and I don't to ask you to redo the PHP code :(

Would I be risking a lot of security if the IV was the same? I have the code working as is, with the IV being static between PHP and Swift. I don't want to mess it up :P and I don't to ask you to redo the PHP code :(

@krzyzanowskim

This comment has been minimized.

Show comment
Hide comment
@krzyzanowskim

krzyzanowskim Feb 2, 2015

Owner

yes, then you need change PHP code accordingly. IV should be random, this is why he exists at all. Basic rule is never use a key and IV pair twice, ever. That's up to you at the end. I'm not going go change PHP code today, but oyu can do it by yourself it's easy to do.

Owner

krzyzanowskim commented Feb 2, 2015

yes, then you need change PHP code accordingly. IV should be random, this is why he exists at all. Basic rule is never use a key and IV pair twice, ever. That's up to you at the end. I'm not going go change PHP code today, but oyu can do it by yourself it's easy to do.

@bradleybernard

This comment has been minimized.

Show comment
Hide comment
@bradleybernard

bradleybernard Feb 2, 2015

Ok thanks for the help! I will attempt what you stated in making the IV random. I am very happy that you showed me how to do all of this.

bradleybernard commented Feb 2, 2015

Ok thanks for the help! I will attempt what you stated in making the IV random. I am very happy that you showed me how to do all of this.

@bradleybernard

This comment has been minimized.

Show comment
Hide comment

Ok good news! I believe I got it :D

Swift: https://gist.github.com/bradbernard/2a7af4c2200cb3794768
PHP: https://gist.github.com/bradbernard/7789c2dd8d17c2d8304b

Sigh of relief! You are awesome.

@krzyzanowskim

This comment has been minimized.

Show comment
Hide comment
@krzyzanowskim

krzyzanowskim Feb 2, 2015

Owner

thats good, you made it! awsome. Have a good week.

Owner

krzyzanowskim commented Feb 2, 2015

thats good, you made it! awsome. Have a good week.

@bradleybernard

This comment has been minimized.

Show comment
Hide comment
@bradleybernard

bradleybernard Feb 2, 2015

Thanks! You too :D

Sent from my iPhone

On Feb 2, 2015, at 1:32 AM, Marcin Krzyzanowski notifications@github.com wrote:

week, not weekend :-)


Reply to this email directly or view it on GitHub.

Thanks! You too :D

Sent from my iPhone

On Feb 2, 2015, at 1:32 AM, Marcin Krzyzanowski notifications@github.com wrote:

week, not weekend :-)


Reply to this email directly or view it on GitHub.

@tlarevo

This comment has been minimized.

Show comment
Hide comment
@tlarevo

tlarevo Jun 25, 2015

@krzyzanowskim and @bradbernard, thanks a lot for the awesome library and providing code samples for php and Swift 👍 .

However I found few issues on the Swift code and using other related resources I found, I've updated the code for latest version of CryptoSwift and made some improvements as well. If you find anything wrong, you are more than welcome to let me know :)

I'm posting it here for anyone who comes here looking for answers.

Swift: PHP compatible Swift AES Encryption using CryptoSwift
PHP: Swift compatible PHP AES Encryption using mcrypt

Thank you

tlarevo commented Jun 25, 2015

@krzyzanowskim and @bradbernard, thanks a lot for the awesome library and providing code samples for php and Swift 👍 .

However I found few issues on the Swift code and using other related resources I found, I've updated the code for latest version of CryptoSwift and made some improvements as well. If you find anything wrong, you are more than welcome to let me know :)

I'm posting it here for anyone who comes here looking for answers.

Swift: PHP compatible Swift AES Encryption using CryptoSwift
PHP: Swift compatible PHP AES Encryption using mcrypt

Thank you

@xhuliohasa

This comment has been minimized.

Show comment
Hide comment
@xhuliohasa

xhuliohasa Apr 8, 2016

Hello,
I am using cryptoSwift and I want to encrypt text using a key with 32 bytes,

this is my encrypt function

public func Encrypt(plainText text:String, plainText key:String)->String{

    let secretKey = utilityClass.cipher(key)
    let kkey:String = secretKey;
    let key = [UInt8] (kkey.utf8);
    let iiv:String = secretKey;
    let iv = [UInt8] (iiv.utf8);


    do {

        let encryptedBytes: [UInt8] = try! text.encrypt(AES(key: key, iv: iv))

        let toBase64 = NSData(bytes: encryptedBytes).base64EncodedStringWithOptions(NSDataBase64EncodingOptions.Encoding64CharacterLineLength)
        return toBase64
    }

}

}

and i get an error like this "Block size and Initialization Vector must be the same length!"

I know there is a problem with the bytes because it requires a key with 16 bytes but please can you help me how to fix this?

Hello,
I am using cryptoSwift and I want to encrypt text using a key with 32 bytes,

this is my encrypt function

public func Encrypt(plainText text:String, plainText key:String)->String{

    let secretKey = utilityClass.cipher(key)
    let kkey:String = secretKey;
    let key = [UInt8] (kkey.utf8);
    let iiv:String = secretKey;
    let iv = [UInt8] (iiv.utf8);


    do {

        let encryptedBytes: [UInt8] = try! text.encrypt(AES(key: key, iv: iv))

        let toBase64 = NSData(bytes: encryptedBytes).base64EncodedStringWithOptions(NSDataBase64EncodingOptions.Encoding64CharacterLineLength)
        return toBase64
    }

}

}

and i get an error like this "Block size and Initialization Vector must be the same length!"

I know there is a problem with the bytes because it requires a key with 16 bytes but please can you help me how to fix this?

@krzyzanowskim

This comment has been minimized.

Show comment
Hide comment
@krzyzanowskim

krzyzanowskim Apr 8, 2016

Owner

@xhuliohasa it may be everything, but you did not show us input data. this is crucial. Please make sure that IV is in the right size of AES.blockSize

Owner

krzyzanowskim commented Apr 8, 2016

@xhuliohasa it may be everything, but you did not show us input data. this is crucial. Please make sure that IV is in the right size of AES.blockSize

@xhuliohasa

This comment has been minimized.

Show comment
Hide comment
@xhuliohasa

xhuliohasa Apr 8, 2016

how do i assign it because i'm new in swift and it's crypting, i know this is a beginner's question but please help me

how do i assign it because i'm new in swift and it's crypting, i know this is a beginner's question but please help me

@teppotk

This comment has been minimized.

Show comment
Hide comment
@teppotk

teppotk Jul 4, 2016

Thank you @krzyzanowskim for these clarifications. However, these examples are from 2015 and now in 2017 I believe much has changed in CryptoSwift and Swift.

For example, from your code on Feb 2, 2015, the following line doesn't work at all anymore:

let decryptedTryData = Cipher.AES(key: keyData, iv: ivData, blockMode: .CBC).decrypt(encryptedStrData)

Xcode claims Cipher.AES is not available or something to that effect.

Could you produce an similar example with BASE64 decoding and all that uses the "try AES()" way of doing this, which I guess is a more current form in CryptoSwift?

Something like this I guess:
let decryptedTryData = try! AES(key: keyDataStr, iv: ivDataStr, blockMode: .CBC, padding: PKCS7()).decrypt(encryptedStrDataNSData)

I tried putting in your code from FEB 2, 2015, but Xcode doesn't accept much of it anymore, force-modifies it and I'm not sure if it's working as planned after all those Xcode syntax modifications. Also thus a clean modern example would be very much appreciated.

Thank you in advance.

teppotk commented Jul 4, 2016

Thank you @krzyzanowskim for these clarifications. However, these examples are from 2015 and now in 2017 I believe much has changed in CryptoSwift and Swift.

For example, from your code on Feb 2, 2015, the following line doesn't work at all anymore:

let decryptedTryData = Cipher.AES(key: keyData, iv: ivData, blockMode: .CBC).decrypt(encryptedStrData)

Xcode claims Cipher.AES is not available or something to that effect.

Could you produce an similar example with BASE64 decoding and all that uses the "try AES()" way of doing this, which I guess is a more current form in CryptoSwift?

Something like this I guess:
let decryptedTryData = try! AES(key: keyDataStr, iv: ivDataStr, blockMode: .CBC, padding: PKCS7()).decrypt(encryptedStrDataNSData)

I tried putting in your code from FEB 2, 2015, but Xcode doesn't accept much of it anymore, force-modifies it and I'm not sure if it's working as planned after all those Xcode syntax modifications. Also thus a clean modern example would be very much appreciated.

Thank you in advance.

@teppotk

This comment has been minimized.

Show comment
Hide comment
@teppotk

teppotk Jul 4, 2016

In particular with live-data and my modifications, I'm getting this error, or nils:

CryptoSwift.AES.Error.DataPaddingRequired

teppotk commented Jul 4, 2016

In particular with live-data and my modifications, I'm getting this error, or nils:

CryptoSwift.AES.Error.DataPaddingRequired

@krzyzanowskim

This comment has been minimized.

Show comment
Hide comment
@krzyzanowskim

krzyzanowskim Jul 5, 2016

Owner

@teppotk look at README, check Playground it's all there.

Owner

krzyzanowskim commented Jul 5, 2016

@teppotk look at README, check Playground it's all there.

@teppotk

This comment has been minimized.

Show comment
Hide comment
@teppotk

teppotk Jul 5, 2016

@krzyzanowskim Thanks, I've actually got things working pretty well in Swift with my own test data, but not with actual data that I have incoming. The problem comes when incoming string has 16 bytes of IV included in the beginning. Once I get that subrange out from the beginning, the rest i.e. the message, doesn't decrypt anymore. CryptoSwift complains about padding error. Since there's no .padding attribute anymore (I believe), I've tried creating my own padding algorithm, but I don't think it works as it should as output is garbled and doesn't decrypt right.

This case is not shown in the current README I believe. Would it be possible to add IV subrange removal + padding handling somewhere in the README?

This particular example below is probably what I'd need. But this old code (again from FEB 2, 2015) goes all red in Xcode and doesn't work anymore:

    func decrypt(transferData:NSData, keyData:NSData) -> String {
        let ivData = transferData.subdataWithRange(NSRange(location: 0, length: AES.blockSizeBytes()))
        let encryptedData = transferData.subdataWithRange(NSRange(location: AES.blockSizeBytes(), length: transferData.length - AES.blockSizeBytes()))

        let aes = AES(key: keyData, iv: ivData, blockMode: .CBC) // CBC is default
        let decryptedData = Cipher.AES(key: keyData, iv: ivData, blockMode: .CBC).decrypt(encryptedData)
        let decryptedString = NSString(data: decryptedData!, encoding: NSUTF8StringEncoding)!
        return decryptedString
    }

    func encrypt(plaintextData:NSData, keyData:NSData) -> NSData {
        let ivData:NSData = Cipher.randomIV(keyData)
        let cipherdata = Cipher.AES(key: keyData, iv: ivData, blockMode: .CBC).encrypt(plaintextData)
        let transferData = NSMutableData(data: ivData)
        transferData.appendData(cipher data!
        return transferData
    }


    // KEY and IV
    var strTest = "data"
    var keyStr = "abcdefghijklmnop"

    let keyData = keyStr.dataUsingEncoding(NSUTF8StringEncoding, allowLossyConversion: false)!
    let ivData:NSData = Cipher.randomIV(keyData)

    let encrypted = encrypt(strTest.dataUsingEncoding(NSUTF8StringEncoding)!, keyData)
    let decrypted = decrypt(encrypted, keyData)
    println(decrypted)

teppotk commented Jul 5, 2016

@krzyzanowskim Thanks, I've actually got things working pretty well in Swift with my own test data, but not with actual data that I have incoming. The problem comes when incoming string has 16 bytes of IV included in the beginning. Once I get that subrange out from the beginning, the rest i.e. the message, doesn't decrypt anymore. CryptoSwift complains about padding error. Since there's no .padding attribute anymore (I believe), I've tried creating my own padding algorithm, but I don't think it works as it should as output is garbled and doesn't decrypt right.

This case is not shown in the current README I believe. Would it be possible to add IV subrange removal + padding handling somewhere in the README?

This particular example below is probably what I'd need. But this old code (again from FEB 2, 2015) goes all red in Xcode and doesn't work anymore:

    func decrypt(transferData:NSData, keyData:NSData) -> String {
        let ivData = transferData.subdataWithRange(NSRange(location: 0, length: AES.blockSizeBytes()))
        let encryptedData = transferData.subdataWithRange(NSRange(location: AES.blockSizeBytes(), length: transferData.length - AES.blockSizeBytes()))

        let aes = AES(key: keyData, iv: ivData, blockMode: .CBC) // CBC is default
        let decryptedData = Cipher.AES(key: keyData, iv: ivData, blockMode: .CBC).decrypt(encryptedData)
        let decryptedString = NSString(data: decryptedData!, encoding: NSUTF8StringEncoding)!
        return decryptedString
    }

    func encrypt(plaintextData:NSData, keyData:NSData) -> NSData {
        let ivData:NSData = Cipher.randomIV(keyData)
        let cipherdata = Cipher.AES(key: keyData, iv: ivData, blockMode: .CBC).encrypt(plaintextData)
        let transferData = NSMutableData(data: ivData)
        transferData.appendData(cipher data!
        return transferData
    }


    // KEY and IV
    var strTest = "data"
    var keyStr = "abcdefghijklmnop"

    let keyData = keyStr.dataUsingEncoding(NSUTF8StringEncoding, allowLossyConversion: false)!
    let ivData:NSData = Cipher.randomIV(keyData)

    let encrypted = encrypt(strTest.dataUsingEncoding(NSUTF8StringEncoding)!, keyData)
    let decrypted = decrypt(encrypted, keyData)
    println(decrypted)

@krzyzanowskim krzyzanowskim changed the title from Convert encrypted data to string? to [php] Convert encrypted data to string? Dec 29, 2017

@ferdinandharmaputra

This comment has been minimized.

Show comment
Hide comment
@ferdinandharmaputra

ferdinandharmaputra Apr 16, 2018

Please help,in my case im not using IV and keyStr just convert string this is my code:

var strTest = "asdfasdf"
var keyStr = ""
var ivStr = ""

    let plaintextData = strTest.data(using: .utf8)!
    // KEY and IV
    let keyData = keyStr.data(using: .utf8)!
    let ivData:NSData = ivStr.data(using: .utf8)! as NSData //Cipher.randomIV(keyData)
    // Encrypt
    let cipherdata = Cipher.AES(key: keyData, iv: ivData, blockMode: .CBC).encrypt(plaintextData)
    
    if let cipherdata = cipherdata {
        let aes = AES(key: keyData, iv: ivData, blockMode: .CBC) // CBC is default
        let decryptedData = Cipher.AES(key: keyData, iv: ivData, blockMode: .CBC).decrypt(cipherdata)
        let decryptedString = NSString(data: decryptedData!, encoding: NSUTF8StringEncoding)!
        let base64String = cipherdata.base64EncodedStringWithOptions(NSDataBase64EncodingOptions.Encoding64CharacterLineLength)
        print(base64String)
    }

but in this line:
let cipherdata = Cipher.AES(key: keyData, iv: ivData, blockMode: .CBC).encrypt(plaintextData)
shown error "Type 'Cipher' has no member 'AES'"

and this line too:
let aes = AES(key: keyData, iv: ivData, blockMode: .CBC) // CBC is default
Shown error "Type of expression is ambiguous without more context"

please help

Please help,in my case im not using IV and keyStr just convert string this is my code:

var strTest = "asdfasdf"
var keyStr = ""
var ivStr = ""

    let plaintextData = strTest.data(using: .utf8)!
    // KEY and IV
    let keyData = keyStr.data(using: .utf8)!
    let ivData:NSData = ivStr.data(using: .utf8)! as NSData //Cipher.randomIV(keyData)
    // Encrypt
    let cipherdata = Cipher.AES(key: keyData, iv: ivData, blockMode: .CBC).encrypt(plaintextData)
    
    if let cipherdata = cipherdata {
        let aes = AES(key: keyData, iv: ivData, blockMode: .CBC) // CBC is default
        let decryptedData = Cipher.AES(key: keyData, iv: ivData, blockMode: .CBC).decrypt(cipherdata)
        let decryptedString = NSString(data: decryptedData!, encoding: NSUTF8StringEncoding)!
        let base64String = cipherdata.base64EncodedStringWithOptions(NSDataBase64EncodingOptions.Encoding64CharacterLineLength)
        print(base64String)
    }

but in this line:
let cipherdata = Cipher.AES(key: keyData, iv: ivData, blockMode: .CBC).encrypt(plaintextData)
shown error "Type 'Cipher' has no member 'AES'"

and this line too:
let aes = AES(key: keyData, iv: ivData, blockMode: .CBC) // CBC is default
Shown error "Type of expression is ambiguous without more context"

please help

@krzyzanowskim

This comment has been minimized.

Show comment
Hide comment
@krzyzanowskim

krzyzanowskim Apr 16, 2018

Owner

@ferdinandharmaputra you cannot "not use IV" in CBC mode.
The code u attached is insecure, you basically expose your key, don't use it.

I believe there is an AES example in README, did you try it?

Owner

krzyzanowskim commented Apr 16, 2018

@ferdinandharmaputra you cannot "not use IV" in CBC mode.
The code u attached is insecure, you basically expose your key, don't use it.

I believe there is an AES example in README, did you try it?

@ferdinandharmaputra

This comment has been minimized.

Show comment
Hide comment
@ferdinandharmaputra

ferdinandharmaputra Apr 16, 2018

I did

this is my code

do {
var encryptor = try AES(key: encryptKeyData, blockMode: .CBC, padding: PKCS7())

        var ciphertext = Array<UInt8>()
        // aggregate partial results
        ciphertext += try encryptor.encrypt(Array(data))
        // finish at the end

// ciphertext += try encryptor.makeEncryptor().finish()

        print(ciphertext.toHexString())
    } catch {
        print(error)
    }

but still difference with what backend and android team expected

my android team use this

private static SecretKeySpec generateMySQLAESKey(String key, String encoding) {
try {
byte[] finalKey = new byte[16];
int i = 0;
for(byte b : key.getBytes(encoding))
finalKey[i++%16] ^= b;
return new SecretKeySpec(finalKey, "AES");
} catch(UnsupportedEncodingException e) {
throw new RuntimeException(e);
}
}

but I get stuck to converted as swift 3.2

I did

this is my code

do {
var encryptor = try AES(key: encryptKeyData, blockMode: .CBC, padding: PKCS7())

        var ciphertext = Array<UInt8>()
        // aggregate partial results
        ciphertext += try encryptor.encrypt(Array(data))
        // finish at the end

// ciphertext += try encryptor.makeEncryptor().finish()

        print(ciphertext.toHexString())
    } catch {
        print(error)
    }

but still difference with what backend and android team expected

my android team use this

private static SecretKeySpec generateMySQLAESKey(String key, String encoding) {
try {
byte[] finalKey = new byte[16];
int i = 0;
for(byte b : key.getBytes(encoding))
finalKey[i++%16] ^= b;
return new SecretKeySpec(finalKey, "AES");
} catch(UnsupportedEncodingException e) {
throw new RuntimeException(e);
}
}

but I get stuck to converted as swift 3.2

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment