2

hey thanks for reading in advance.

I am facing some issue in encrypting something in 3des, it is working but doesn't seem to out the proper values

purpose: i need to authenticate to a rest API from php to be able to retrieve info, their documentation states this :

  1. step 1 call the login function to receive a token (i have this)
  2. step 2, call the authorize function using a string generated from the token

I have implemented the below code, but not sure if am doing something wrong, here's some info from the docs

The process to generate key is as follows:
1. The internal value 99991231 defined by Huawei is added in the plain text to be encrypted. Result A is generated.
2. The standard MD5 algorithm is executed on result A. Result B is generated.
3. Result B is converted into a hexadecimal number. Result C is generated.
If the first character is 0 in the hexadecimal string, ignore it. If another character is 0, retain it. For example, 0x0100101F3B is converted into 100101F3B.
4. The first eight characters in result C are obtained. Result D is generated.
5. The characters in result D are converted into lowercase characters. The encrypted text is generated.

this is the example code they have provided to generate md5 huawei (i think it's java? need it's php equivalent)

byte[] id = plainPwd.getBytes();

MessageDigest md = MessageDigest.getInstance("MD5");
md.update(id);
md.update("99991231".getBytes());           // “99991231” mentioned in XML-API DOC

byte[] buffer = md.digest();
StringBuffer sb = new StringBuffer();
for (int i = 0; i <buffer.length; i++) {
    sb.append(Integer.toHexString((int) buffer[i] & 0xff));
}
String md5Pwd = sb.substring(0, 8);         // only use first 8 characters

this is what is required:

The 3DES encryption algorithm is used to generate an authenticator. The format of a plain text to be encrypted is as follows: Random+"$"+EncryToken+"$"+userid+"$"+terminalid+"$"+terminalip+"$"+mac+"$"+Reserved+"$"+"CTC"

they key is generated based on this:

The 3DES encryption result is converted into a hexadecimal string in
ASCII mode, in which letters A to F are in uppercase. For example, if
the 3DES encryption result is 0x0123456789ABCDEF, the value of
Authenticator is 0123456789ABCDEF. The process of generating an
authenticator is as follows:
1. A client sends a subscriber authentication request to the EPG server. Request URL: http.../XML/Authenticate
 UserID: 10086  Mac address: ABCDEFGH
2. The EPG server returns enctytoken (for example, AD75B1697FB5EB6345B2D412124030D2) and encryptiontype (for example, MD5) to the client.
3. The client encrypts the subscriber's password (for example, 0 in plain text) using the MD5 algorithm to generate a key, for example, db90e7eb.
4. The client generates a string randomly, for example, 20926330.
5. The client generates a string of plain text to be encrypted based on each parameter. The following is an example:
20926330$AD75B1697FB5EB6345B2D412124030D2$10086$10086$10.164.111$ABCDEFGH$Reserved$CTC
6. The client uses the 3DES algorithm to encrypt the string to generate an authenticator. The following is a code example:
567A7A72AE33C8867936AB0190EC9F2405B20D4A4808D2A8E8CBC0D7D5482E4F53454EA4F37A29B81A63ECB0BF717E96505EE59476799D932F16AEBFECE097171159095DC57DA84D91930AF92EF96E75486DEA0DEA781D51

they also have this code(I think java) example which also i need its equivalent in php:

public class DESUtil
{
    private static final String Algorithm = "DESede/ECB/PKCS5Padding";// DESede/ECB/PKCS5Padding;DESede

    private static final String DESede = "DESede";

    public static byte[] encrypt(byte[] keybyte, byte[] src)
    throws NoSuchAlgorithmException, NoSuchPaddingException, Exception
    {
        SecretKey deskey = new SecretKeySpec(keybyte, DESede);
        Cipher c1 = Cipher.getInstance(Algorithm);
        c1.init(Cipher.ENCRYPT_MODE, deskey);
        return c1.doFinal(src);
    }

    public static byte[] decrypt(byte[] keybyte, byte[] src)
        throws NoSuchAlgorithmException, NoSuchPaddingException, Exception
    {
        SecretKey deskey = new SecretKeySpec(keybyte, DESede);
        Cipher c1 = Cipher.getInstance(Algorithm);
        c1.init(Cipher.DECRYPT_MODE, deskey);
        return c1.doFinal(src);
    }

    public static String byte2hex(byte[] b)
    {
        StringBuffer hs = new StringBuffer();
        String stmp = "";
        for (int n = 0; n <b.length; n++)
        {
            stmp = (java.lang.Integer.toHexString(b[n] & 0XFF));
            if (stmp.length() == 1)
                hs.append("0").append(stmp);
            else
                hs.append(stmp);
        }
        return hs.toString().toUpperCase(Locale.getDefault());
    }

    public static byte[] hex2byte(String hexStr)
    {
        if (hexStr.length() % 2 != 0)
        {
            AppLogger.error("hex2bytes's hexStr length is not even.");
            return null;
        }

        byte[] toBytes = new byte[hexStr.length() / 2];
        for (int i = 0, j = 0; i <hexStr.length(); j++, i = i + 2)
        {
            int tmpa = Integer.decode(
                "0X" + hexStr.charAt(i) + hexStr.charAt(i + 1)).intValue();
            toBytes[j] = (byte) (tmpa & 0XFF);
        }
        return toBytes;
    }


    public static void main(String[] args)
    {
        Security.addProvider(new com.sun.crypto.provider.SunJCE());
        final byte[] rawKey = "db90e7eb".getBytes();
        final byte[] keyBytes = new byte[24];

        for (int i = 0; i <rawKey.length; i++)
        {
            keyBytes[i] = rawKey[i];
        }

        for (int i = rawKey.length; i <keyBytes.length; i++)
        {
            keyBytes[i] = (byte)0;
        }

        String szSrc = "20926330$AD75B1697FB5EB6345B2D412124030D2$10086$10086$10.164.111$ABCDEFGH$Reserved$CTC";
        System.out.println("string before encrypt:" + szSrc);
        byte[] encoded = null;

        try
        {
            encoded = encrypt(keyBytes, szSrc.getBytes());
        }
        catch (Exception e)
        {
            e.printStackTrace();
        }
        System.out.println("string after encrypt::" + byte2hex(encoded));

        byte[] srcBytes = null;

        try
        {
            srcBytes = decrypt(keyBytes, encoded);
        }
        catch (Exception e)
        {
            e.printStackTrace();
        }
        System.out.println("string before decode: :" + (new String(srcBytes)));
    }
}

the php code i did based on some online references is below, but api doesnt seem to like it and the encrypted code length seems too long, this is the result of my code + the api's response:

encrypted: y8V17%2BEImP88UyoQRfGbjldYjfGzsR4r%2B04sE1kPOwPdQNeH1jEhZMYTAgdgeinT6A%2BUfXCFI5KN9QDCTq2oz7AZqTlFEfztQRdgW2ij6YvwQVbRsblJwA%3D%3D

Decrypt 15173232$BCE723AE4BC97FAD6293D73B2266361D$20140409$20140409$$ABCDEFGH$Reserved$CTC

encrypted hex: 793856313725324245496D50383855796F51526647626A6C64596A66477A7352347225324230347345316B504F775064514E6548316A45685A4D59544167646765696E543641253242556658434649354B4E395144435471326F7A37415A71546C4645667A74515264675732696A365976775156625273626C4A7741253344253344

3des authenticator: y8V17%2BEImP88UyoQRfGbjldYjfGzsR4r%2B04sE1kPOwPdQNeH1jEhZMYTAgdgeinT6A%2BUfXCFI5KN9QDCTq2oz7AZqTlFEfztQRdgW2ij6YvwQVbRsblJwA%3D%3D

SimpleXMLElement Object (

[retmsg] => 3DES decrypt error second time(0x30), please check epg's encrytMode and acs's encryMode.

my PHP code to be checked for any wrong details:

$userid = '123';
$terminalip = '';
$mac = 'ABCDEFGH';
$terminalid = $userid;
$pin = '123';
$encToken = 'testtest';

$encryption_key = $pin;
$authenticator = rand(0,99999999).'$'.$encToken.'$'.$userid.'$'.$terminalid.'$'.$terminalip.'$'.$mac.'$'.'Reserved'.'$'.'CTC';

$desEncryptedData = encrypt($authenticator, $encryption_key);
echo "encrypted: <br>".$desEncryptedData;
echo"<br><br><br><b>Decrypt</b><br>";
$d = decrypt($desEncryptedData,$encryption_key);
echo $d;

echo "<BR><BR>encrypted hex: <br>". strToHex($desEncryptedData);

echo "<br><br>3des authenticator: <br>".$desEncryptedData."<br />";


$req = "<?xml version='1.0' encoding='UTF-8'?>
<AuthenticateReq>
<userid>$userid</userid>
<authenticator>$desEncryptedData</authenticator>
</AuthenticateReq>
";

// the functions to use to login
$context = stream_context_create(array('http'=>array(
    'method' => 'POST',
    'header'  => "Content-Type: text/xml\r\n",
    'content' => $req
)));


function encrypt($input,$ky)
{
    $key = $ky;
    $size = mcrypt_get_block_size(MCRYPT_TRIPLEDES, 'ecb');
    $input = pkcs5_pad($input, $size);
    $td = mcrypt_module_open(MCRYPT_TRIPLEDES, '', 'ecb', '');
    $iv = mcrypt_create_iv (mcrypt_enc_get_iv_size($td), MCRYPT_RAND);
    mcrypt_generic_init($td, $key, $iv);
    $data = mcrypt_generic($td, $input);
    mcrypt_generic_deinit($td);
    mcrypt_module_close($td);
    $data = base64_encode($data);
    $data = urlencode($data); //push it out so i can check it works
    return $data;
}

function decrypt($crypt,$ky)
{

    $crypt = urldecode($crypt);
    $crypt = base64_decode($crypt);
    $key = $ky;
    $td = mcrypt_module_open (MCRYPT_TRIPLEDES, '', 'ecb', '');
    $iv = mcrypt_create_iv (mcrypt_enc_get_iv_size($td), MCRYPT_RAND);
    mcrypt_generic_init($td, $key, $iv);
    $decrypted_data = mdecrypt_generic ($td, $crypt);
    mcrypt_generic_deinit ($td);
    mcrypt_module_close ($td);
    $decrypted_data = pkcs5_unpad($decrypted_data);
    $decrypted_data = rtrim($decrypted_data);
    return $decrypted_data;
}

function pkcs5_pad($text, $blocksize)
{
    $pad = $blocksize - (strlen($text) % $blocksize);
    return $text . str_repeat(chr($pad), $pad);
}

function pkcs5_unpad($text)
{
    $pad = ord($text{strlen($text)-1});
    if ($pad > strlen($text)) return false;
    return substr($text, 0, -1 * $pad);
}

function strToHex($string){
    $hex = '';
    for ($i=0; $i<strlen($string); $i++){
        $ord = ord($string[$i]);
        $hexCode = dechex($ord);
        $hex .= substr('0'.$hexCode, -2);
    }
    return strToUpper($hex);
}

thanks alot for your time in advance

Maarten Bodewes
  • 90,524
  • 13
  • 150
  • 263
roy naufal
  • 379
  • 1
  • 8
  • 19
  • Such a complicated authentication scheme and they did not provide code examples in PHP? – Eric J. May 07 '14 at 22:43
  • unfortunately not, and when we call them we're directed to a 3rd party IT team who provide no help at all! no sample codes or anything – roy naufal May 07 '14 at 23:28
  • 1
    What a bunch of absolute trap. Their hex encoding is not according to their own specs, and they are using 3DES - in ECB mode - using a key of 8 bytes, repeated 3 times. So they do E(K, D(K0, E(K0, M))) which is obviously the same as E(K, M) - single DES in other words. – Maarten Bodewes May 08 '14 at 00:48
  • ah i see...not my field of expertise...how do you suggest to make the above work ? any ideas – roy naufal May 08 '14 at 06:50
  • 1
    Hard to say, I don't know the requirements. Using AES/GCM (*correctly*) instead of single DES in ECB mode would go a long way of securing the use of the symmetric cipher. Not relying on strings for places where they have no reason to be would help too. And if strings are required, use well defined (character) encodings schemes. Hire somebody who understands Java (e.g. knowing that arrays are automatically initialized to zero would be helpful). – Maarten Bodewes May 08 '14 at 20:15

0 Answers0