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 :
- step 1 call the login function to receive a token (i have this)
- 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