2

I am trying to decrypt data being communicated to our server. Its a certain 8 digit number which is encrypted using a scheme. I have the encryption and integrity keys with me. I have a documentation on how to decrypt it which says -

The value is encrypted using a custom encryption scheme. The encryption scheme uses a keyed HMAC-SHA1 algorithm to generate a secret pad based on the unique event ID. The encrypted value has a fixed length of 28 bytes. It is comprised of a 16-byte initialization vector, 8 bytes of ciphertext, and a 4-byte integrity signature. The encrypted value is web-safe base-64-encoded, according to RFC 3548, with padding characters omitted. Thus, the 28-byte encrypted value is encoded as a 38 character web-safe base-64 string. The value is encrypted as:

value xor HMAC-SHA1(encryption_key, initialization_vector)>

so decryption calculates:

HMAC-SHA1(encryption_key, initialization_vector)

and xor's with the encrypted value to reverse the encryption. The integrity stage takes 4 bytes of

HMAC-SHA1(integrity_key, value||initialization_vector)>

where || is concatenation.

So i wrote the following PHP Code.

$value= "[VALUE]"; //38 character base64
$ekey=hextostr("[ENCRYPTIONKEY]"); //64 byte hex encoded key . 32 byte key
$ikey=hextostr("[INTEGRITYKEY]"); //64 byte hex encoded key . 32 byte key
$value=str_replace("-","+",$value);
$value=str_replace("_","/",$value);
$value=$value."==";
$dvalue=base64_decode($value); //Gets a 28 byte encrypted string.
$initvec=substr($dvalue,0,16);
$ciphertext=substr($dvalue,16,8);
$integritysig=substr($dvalue,24,4);
$pad=hash_hmac("sha1",$initvec,$ekey); //Generates 40 byte pad
$uncipher=$ciphertext^$pad;
print($uncipher); //This is 8 byte binary. Dumps some binary on screen. Result should be a 8 byte number

Unable to get around this problem. Please advice.

asked May 17, 2012 at 1:21
3
  • When you say an "8-byte number", do you mean that? Or do you mean it's an ASCII encoding of the number in decimal? Or something else? Commented May 17, 2012 at 1:26
  • Do you know the unique event ID on your end? Commented May 17, 2012 at 1:37
  • No, We don't now the event ID Commented May 17, 2012 at 9:34

3 Answers 3

1
$pad=hash_hmac("sha1",$initvec,$ekey); // returns a hexstring, but XOR interprets
 // as ASCII string and converts to binary
 // accordingly
$ciphertext=substr($dvalue,16,8); // this is ASCII, converted to binary by XOR
$uncipher=$ciphertext^$pad; // so the XOR operation is confused in interpretation.

try changing it to,

function bin2asc($in)#syntax - bin2asc("binary to convert");
{
 $out = '';
 for ($i = 0, $len = strlen($in); $i < $len; $i += 8)
 {
 $out .= chr(bindec(substr($in,$i,8)));
 }
 return $out; 
}
$pad= hash_hmac("sha1",$initvec,$ekey, true); // now it will return in binary 
$pad = bin2asc($pad);
$uncipher=$ciphertext^$pad;

hope this solve your problem.

answered May 17, 2012 at 10:34
Sign up to request clarification or add additional context in comments.

4 Comments

you are right. Earlier the pad was 40 bytes, now its 20 bytes. Now strlen($uncipher) returns 8 but when i echo it on screen, it shows blank. Not sure why
try it now... I think we need to keep both of them in ASCII or as binary number.
nop .. the strlen($pad) is now 3 . Unciphered is also 3 bytes.
try var_dump() to check on every variable.
1

Your posted code should look like this

$value= "[VALUE]"; //38 character base64
$ekey=hextostr("[ENCRYPTIONKEY]"); //64 byte hex encoded key . 32 byte key
$ikey=hextostr("[INTEGRITYKEY]"); //64 byte hex encoded key . 32 byte key
$value=str_replace("-","+",$value);
$value=str_replace("_","/",$value);
$value=$value."==";
$dvalue=base64_decode($value); //Gets a 28 byte encrypted string.
$initvec=substr($dvalue,0,16);
$ciphertext=substr($dvalue,16,8);
$integritysig=substr($dvalue,24,4);
//here is the change
$pad=hash_hmac("sha1",$initvec,$ekey, true);
$uncipher=$ciphertext^$pad;
print(hexdec(strToHex($uncipher))); //This is 8 byte binary. Dumps some binary on screen. Result should be a 8 byte number
answered May 29, 2012 at 17:03

Comments

1

Try this

function decrypt_google_winning_price($value, $ekey, $ikey, &$reason = '') {
if (strlen($value) != 38)
{
 $reason = "Wrong encrypted value length";
 return false;
}
$ekey = base64_decode($ekey);
$ikey = base64_decode($ikey);
$value = strtr($value, '-_,', '+/=') . "==";
$enc_value = base64_decode($value); //Gets a 28 byte encrypted string.
if (strlen($enc_value) != 28)
{
 $reason = "Wrong encrypted value length after base64_decode()";
 return false;
}
$iv = substr($enc_value, 0, 16);// initialization vector (16 bytes - unique to the impression)
$p = substr($enc_value, 16, 8); // encryption key (32 bytes - provided at account set up)
$sig = substr($enc_value, 24, 4);// integrity signature (4 bytes)
$price_pad = hash_hmac("sha1", $iv, $ekey, true);
$price = $p ^ $price_pad;// XOR
$conf_sig = substr(hex2bin(hash_hmac("sha1", $price . $iv, $ikey)), 0, 4);
if ($sig !== $conf_sig)
{
 $reason = "Signature is not valid";
 return false;
}
return hexdec(bin2hex($price)); //This is 8 byte binary. Dumps some binary on screen. Result should be a 8 byte number
}
$value = "[VALUE]"; //38 character base64
$ekey = "[ENCRYPTIONKEY]"; //64 byte hex encoded key . 32 byte key
$ikey "[INTEGRITYKEY]"; //64 byte hex encoded key . 32 byte key
var_dump(decrypt_google_winning_price($value, $ekey, $ikey));
answered Apr 25, 2016 at 14:33

Comments

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.