Jump to content

AES 256 Autoit vs PHP?


Recommended Posts

I am currently encrypting data in my code using AES256 with a passkey.  Example passkey: "123456"

It works fine in my autoit code.  But my php developer insists the passkey for AES256 must be 32 bytes.  So I am assuming that even though my passkey in autoit is not currently 32 bytes it is somehow converting my passkey into a 32 byte passkey?  If that is true... how can I find out the 32 byte passkey that my current code is using... so that I can give that to my php developer?

Thanks!

 

Edited by Proph
Link to post
Share on other sites

My web developer is having a hard time getting AES 256 encryption to output the exact same data as Autoit does with AES encryption (and using the same passkey).

Is there someone here that has experience with this? Can you give me some php code that will output the same AES 256 Encryption and be able to decrypt data that was Encrypted by Autoit AES 256 as well?  I'm sure I cannot be the only one who is having this problem. I know someone else here must have defeated this. ;)  Is this an issue with Autoit's method?  Or is it the default methods in php that are incorrect?  I'm new to AES encryption.  So I'd like to understand why php and autoit don't seem to be outputting the same data.

Edited by Proph
Link to post
Share on other sites
  • Moderators

Proph,

Just the one thread at a time please.

M23

Public_Domain.png.2d871819fcb9957cf44f4514551a2935.png Any of my own code posted anywhere on the forum is available for use by others without any restriction of any kind

Open spoiler to see my UDFs:

Spoiler

ArrayMultiColSort ---- Sort arrays on multiple columns
ChooseFileFolder ---- Single and multiple selections from specified path treeview listing
Date_Time_Convert -- Easily convert date/time formats, including the language used
ExtMsgBox --------- A highly customisable replacement for MsgBox
GUIExtender -------- Extend and retract multiple sections within a GUI
GUIFrame ---------- Subdivide GUIs into many adjustable frames
GUIListViewEx ------- Insert, delete, move, drag, sort, edit and colour ListView items
GUITreeViewEx ------ Check/clear parent and child checkboxes in a TreeView
Marquee ----------- Scrolling tickertape GUIs
NoFocusLines ------- Remove the dotted focus lines from buttons, sliders, radios and checkboxes
Notify ------------- Small notifications on the edge of the display
Scrollbars ----------Automatically sized scrollbars with a single command
StringSize ---------- Automatically size controls to fit text
Toast -------------- Small GUIs which pop out of the notification area

 

Link to post
Share on other sites

Thanks for the reply Deye, but I have tried that example.  It does not seem to work for me.  It Encrypts the data... but it never does the decryption on the php side.  It just returns blank.  

Edited by Proph
Link to post
Share on other sites
  • 3 weeks later...
  • 2 years later...
  • 1 year later...
On 8/24/2019 at 2:43 PM, Inververs said:

Not sure if this still works, but you can check 😉

CryptPhp.au3 15.83 kB · 59 downloads

Thank you so much for this file. After having searched some while this is the only piece of code I could find working for php and autoit.

However, I had to update some functions now being deprecated in recent versions, adapt the code to my needs, add support for Javascript as well as hmac for security reasons (e.g. AES-256 in cbc mode is quite vulnerable for certain type of attacks without hmac).

In case someone is interested, I attached the files for PHP, AutoIt and JS.

I added a function to CryptPhp class creating values for $keys (one key for encryption and one for creating the hmac). These values need to be the same in CryptPhp.au3, cryptphp.au3 and cryptphp.js in case you'd like to exchange data between those.
 

test.au3

#include <CryptPhp.au3>

$key1 = _CryptPhp_CreateKey()
$key2 = _CryptPhp_CreateKey()

ConsoleWrite( _
    'key1: ' & $key1  & @CRLF & _
    'key2: ' & $key2 & @CRLF & @CRLF)

$data = '123'
$encrypted = _CryptPhp_Encrypt($data)
$decrypted = _CryptPhp_Decrypt($encrypted)

ConsoleWrite( _
    $encrypted  & @CRLF & _
    $decrypted & @CRLF)

CryptoNG.au3

https://www.autoitscript.com/forum/topic/201002-cryptong-udf-cryptography-api-next-gen/#comments
 

CryptPhp.au3

#include <CryptoNG.au3>
Local const $keys = [ _
    'oeHHADBHRY2fDFfvA6AwHL8QneBVUzdu45REGmgxPQw=', _
    'HIZ7+30WFI3T2TWAipYbEIo7g7iDPYxiGQaUtEzNvvI=' _
]

Func _CryptPhp_CreateKey()
    Local $keyBinary = _CryptoNG_GenerateRandom($CNG_BCRYPT_RNG_ALGORITHM, 32)
    return _CryptoNG_CryptBinaryToString($keyBinary, BitOr($CNG_CRYPT_STRING_BASE64, $CNG_CRYPT_STRING_NOCRLF))
EndFunc

Func _CryptPhp_Encrypt($data, $urlSafe = true)
    Local $iv = _CryptoNG_GenerateRandom($CNG_BCRYPT_RNG_ALGORITHM, 16)
    Local $encryptionKey = _CryptoNG_CryptStringToBinary($keys[0], $CNG_CRYPT_STRING_BASE64)
    Local $encrypted = _CryptoNG_AES_CBC_EncryptData($data, $encryptionKey, $iv)
    Local $hmacKey = _CryptoNG_CryptStringToBinary($keys[1], $CNG_CRYPT_STRING_BASE64)
    Local $hmac = _CryptoNG_HashData($CNG_BCRYPT_SHA256_ALGORITHM, $iv & $encrypted, True, $hmacKey)
    Local $encoded = _CryptoNG_CryptBinaryToString($iv & $encrypted & $hmac, BitOr($CNG_CRYPT_STRING_BASE64, $CNG_CRYPT_STRING_NOCRLF))

    return ($urlSafe) _
                ? TurnUrlSafe($encoded) _
                : $encoded
EndFunc

Func _CryptPhp_Decrypt($data)
    $data = TurnUrlSafe($data, false)
    Local $raw = _CryptoNG_CryptStringToBinary($data, $CNG_CRYPT_STRING_BASE64)
    Local $iv = BinaryMid($raw, 1, 16)
    Local $encrypted = BinaryMid($raw, 16 + 1, BinaryLen($raw) - (16 + 32))

    Local $hmacIs = BinaryMid($raw, 16 + BinaryLen($encrypted) + 1)
    Local $hmacKey = _CryptoNG_CryptStringToBinary($keys[1], $CNG_CRYPT_STRING_BASE64)
    Local $hmacShould = _CryptoNG_HashData($CNG_BCRYPT_SHA256_ALGORITHM, $iv & $encrypted, True, $hmacKey)
    Local $hashMatch = CTstrcmp($hmacShould, $hmacIs) == 0
    if not $hashMatch then _
        return false

    Local $encryptionKey = _CryptoNG_CryptStringToBinary($keys[0], $CNG_CRYPT_STRING_BASE64)
    return _CryptoNG_AES_CBC_DecryptData($encrypted, $encryptionKey, $iv)
EndFunc

func ord($str)
    return Asc(StringLeft($str, 1))
EndFunc

;source: https://www.php.net/manual/en/function.hash-equals.php#125034
func CTstrcmp($should, $is)
    Local $shouldLength = StringLen($should)
    Local $isLength = StringLen($is)
    Local $deltaLength = $shouldLength - $isLength

    Local $shouldPos = 0
    for $isPos = 0 to $isLength - 1
        Local $isChar = StringMid($is, $isPos + 1, 1)
        Local $shouldChar = StringMid($should, $shouldPos + 1, 1)

        $deltaLength = BitXOR(BitOR($deltaLength, ord($isChar)), ord($shouldChar))
        $shouldPos = Mod($shouldPos + 1, $shouldLength)
    Next

    return $deltaLength
EndFunc

Func TurnUrlSafe($data, $toSafe = true)
    return ($toSafe) _
                ? StringReplace( _
                    StringReplace( _
                        StringReplace($data, _
                            '+', '-'), _
                            '/', '_'), _
                            '=', '') _
                : StringReplace( _
                    StringReplace($data, _
                            '-', '+'), _
                            '_', '/')
EndFunc

test.php

<?php
    include_once 'cryptphp.php';

    $key1 = CryptPhp::create_key();
    $key2 = CryptPhp::create_key();
    echo    'key1: '.$key1.'<br>'.
            'key2: '.$key2.'<br><br>';

    $data = '123';
    $encrypted = CryptPhp::encrypt($data);
    $decrypted = CryptPhp::decrypt($encrypted);

    echo    $encrypted.'<br>'.
            $decrypted.'<br><br>';
?>
<html>
    <script src="crypto-js.min.js"></script>
    <script src="cryptphp.js"></script>
    <script>
        let key1 = CryptPhp.createKey();
        let key2 = CryptPhp.createKey();
        document.write(
            'key1: '+key1+'<br>'+
            'key2: '+key2+'<br><br>');

        let data = '123';
        let encrypted = CryptPhp.encrypt(data);
        let decrypted = CryptPhp.decrypt(encrypted);

        document.write(
            encrypted+'<br>'+
            decrypted);
    </script>
</html>

cryptphp.php

<?php
    class CryptPhp {
        private static $cipherAlgorithm = 'aes-256-cbc';
        private static $hashAlgorithm = 'sha256';
        private static $ivNumBytes = 16;
        private static $hashNumBytes = 32;
        private static $keys = [
            'oeHHADBHRY2fDFfvA6AwHL8QneBVUzdu45REGmgxPQw=',
            'HIZ7+30WFI3T2TWAipYbEIo7g7iDPYxiGQaUtEzNvvI='
        ];

        public static function create_key() {
            return base64_encode(random_bytes(self::$hashNumBytes));
        }

        public static function encrypt($data, $urlSafe = true) {
            $iv = random_bytes(self::$ivNumBytes);
            $encryptionKey = base64_decode(self::$keys[0]);
            $encrypted = openssl_encrypt($data, self::$cipherAlgorithm, $encryptionKey, OPENSSL_RAW_DATA, $iv);
            $hmacKey = base64_decode(self::$keys[1]);
            $hmac = hash_hmac(self::$hashAlgorithm, $iv . $encrypted, $hmacKey, true);

            $result = $iv.$encrypted.$hmac;
            return ($urlSafe)
                        ? base64url_encode($result)
                        : base64_encode($result);
        }

        //source: https://www.php.net/manual/en/function.hash-equals.php#125034
        private static function CTstrcmp($should, $is) {
            $shouldLength = strlen($should);
            $isLength = strlen($is);
            $deltaLength = $shouldLength - $isLength;

            $shouldPos = 0;
            for ($isPos = 0; $isPos < $isLength; $isPos++) {
                $deltaLength |= ord($is[$isPos]) ^ ord($should[$shouldPos]);
                $shouldPos = ($shouldPos + 1) % $shouldLength;
            }

            return $deltaLength;
        }

        public static function decrypt($data) {
            $raw = base64url_decode($data);
            $iv = substr($raw, 0, self::$ivNumBytes);
            $encrypted = substr($raw, self::$ivNumBytes, strlen($raw) - (self::$ivNumBytes + self::$hashNumBytes));

            $hmacIs = substr($raw, -self::$hashNumBytes);
            $hmacKey = base64_decode(self::$keys[1]);
            $hmacShould = hash_hmac(self::$hashAlgorithm, $iv.$encrypted, $hmacKey, true);
            $hashMatch = self::CTstrcmp($hmacShould, $hmacIs) === 0;
            if(!$hashMatch)
                return false;

            $encryptionKey = base64_decode(self::$keys[0]);
            return openssl_decrypt($encrypted, self::$cipherAlgorithm, $encryptionKey, OPENSSL_RAW_DATA, $iv);
        }
    }

    function base64url_decode($data) {
        return base64_decode(str_pad(strtr($data, '-_', '+/'), strlen($data) % 4, '=', STR_PAD_RIGHT));
    }

    function base64url_encode($data) {
        return rtrim(strtr(base64_encode($data), '+/', '-_'), '=');
    }
?>

cryptphp.js

class CryptPhp {
    static cipherAlgorithm = 'aes-256-cbc';
    static hashAlgorithm = 'sha256';
    static iv_num_bytes = 16;
    static hash_num_bytes = 32;
    static keys = [
        'oeHHADBHRY2fDFfvA6AwHL8QneBVUzdu45REGmgxPQw=',
        'HIZ7+30WFI3T2TWAipYbEIo7g7iDPYxiGQaUtEzNvvI='
    ];

    static createKey() {
        let keyBytes = crypto.getRandomValues(new Uint8Array(this.hash_num_bytes));
        let key = CryptoJS.enc.Hex.parse(this.toHexString(keyBytes));

        return CryptoJS.enc.Base64.stringify(key);
    }

    static encrypt(data, urlSafe = true) {
        let ivBytes = crypto.getRandomValues(new Uint8Array(this.iv_num_bytes));
        let iv = CryptoJS.enc.Hex.parse(this.toHexString(ivBytes));
        let encryptionKey = CryptoJS.enc.Base64.parse(this.keys[0]);
        let encrypted = CryptoJS.AES.encrypt(data, encryptionKey, {
            'mode': CryptoJS.mode.CBC,
            iv: iv
        });

        let hmacContent = CryptoJS.enc.Hex.parse(iv + encrypted.ciphertext);
        let hmacKey = CryptoJS.enc.Base64.parse(this.keys[1]);
        let hmac = CryptoJS.HmacSHA256(hmacContent, hmacKey);

        let output = CryptoJS.enc.Hex.parse(iv + encrypted.ciphertext + hmac);
        let result = CryptoJS.enc.Base64.stringify(output);

        return (urlSafe)
                    ? this.turnUrlSafe(result)
                    : result;
    }

    static decrypt(data) {
        data = this.turnUrlSafe(String(data), false);
        let raw = CryptoJS.enc.Base64.parse(data).toString();

        let iv = raw.substr(0, this.iv_num_bytes*2);
        let encrypted = raw.substr(this.hash_num_bytes, raw.length - 2*(this.iv_num_bytes + this.hash_num_bytes));
        let hmacIs = raw.substr(-this.hash_num_bytes*2);
        let hmacKey = CryptoJS.enc.Base64.parse(this.keys[1]);
        let hmacContent = CryptoJS.enc.Hex.parse(iv + encrypted);
        let hmacShould = CryptoJS.HmacSHA256(hmacContent, hmacKey).toString();

        let hashMatch = this.CTstrcmp(hmacShould, hmacIs) === 0;
        if(!hashMatch)
            return false;

        let encryptionKey = CryptoJS.enc.Base64.parse(this.keys[0]);
        let decrypted = CryptoJS.AES.decrypt(CryptoJS.enc.Base64.stringify(CryptoJS.enc.Hex.parse(encrypted)), encryptionKey, {
            'mode': CryptoJS.mode.CBC,
            iv: CryptoJS.enc.Hex.parse(iv)
        });

        let decryptedString = decrypted.toString(CryptoJS.enc.Utf8);
        return decryptedString;
    }

    static turnUrlSafe(data, toSafe = true) {
        return (toSafe)
                    ? data
                        .replaceAll('+', '-')
                        .replaceAll('/', '_')
                        .replaceAll('=', '' )
                    : data
                        .replaceAll('-', '+')
                        .replaceAll('_', '/');
    }

    static ord(str) {
        return str.charCodeAt(0);
    }

    //source: https://www.php.net/manual/en/function.hash-equals.php#125034
    static CTstrcmp(should, is) {
        let shouldLength = should.length;
        let isLength = is.length;
        let deltaLength = should.length - is.length;

        let shouldPos = 0;
        for (let isPos = 0; isPos < isLength; isPos++) {
            deltaLength |= this.ord(is[isPos]) ^ this.ord(should[shouldPos]);
            shouldPos = (shouldPos + 1) % shouldLength;
        }

        return deltaLength;
    }

    static toHexString(byteArray) {
        return byteArray.reduce((output, elem) =>
                (output + ('0' + elem.toString(16)).slice(-2)), '');
    }
}


crypto-js.min.js

https://cdnjs.cloudflare.com/ajax/libs/crypto-js/4.0.0/crypto-js.min.js

 

 

 

 

CryptPhp.zip

Edited by moldevort
Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
  • Recently Browsing   0 members

    No registered users viewing this page.

×
×
  • Create New...