Search code examples
javaencryptiontelegram

Telegram hash validation in Java


For the sake of me, I can't get to validate a Telegram hash in Java.

I have a working JS example compiled from different sources that I've reduced to barebones to illustrate this question.

function main() {
  var k = CryptoJS.HmacSHA256('k', 'WebAppData');
  console.log("k: " + k);

  var h = CryptoJS.HmacSHA256('data', k);
  console.log("h: " + h);
}

main();
<script src="https://cdnjs.cloudflare.com/ajax/libs/crypto-js/4.1.1/crypto-js.min.js"></script>

The response of the complete example matches the expected hash

"k: 3db03151d3fb2678c9fc0f24ee15817bfd1ff922a712a055f63066f875e43fc1"
"h: 9158b0aeb1e882c075ea46a0d5302cffba1a9b66b0df40f5f01eef614f7d9f94"

Trying to do the same thing using Apache commons' Hmac method

var secretKey = new HmacUtils("HmacSHA256", "WebAppData").hmacHex("k");
var hash = new HmacUtils("HmacSHA256", secretKey).hmacHex("data");

I end up with the first one being correct but not the second one, that differs from the other implementation.

secretKey: 3db03151d3fb2678c9fc0f24ee15817bfd1ff922a712a055f63066f875e43fc1
hash: 2c73ad3290e04a382b29edea6cb0ef4b1454592429336c32e98ad611452581b2

what am I failing to see?

Isn't there a method to handle this validation in the Telegram SDK I missed to avoid doing this by hand?


Solution

  • The problem is that you take the hex-encoded form of the secret key as the key of the hash. The HmacUtils(String, String) constructor will encode the string to bytes using UTF-8, which is not what you want here, so you need to use the HmacUtils(String, byte[]) constructor.

    So, you need to use the raw byte form:

    byte[] secretKey = new HmacUtils("HmacSHA256", "WebAppData").hmac("k");
    String hash = new HmacUtils("HmacSHA256", secretKey).hmacHex("data");
    
    System.out.println(HexFormat.of().formatHex(secretKey));
    System.out.println(hash);
    

    Output:

    3db03151d3fb2678c9fc0f24ee15817bfd1ff922a712a055f63066f875e43fc1
    9158b0aeb1e882c075ea46a0d5302cffba1a9b66b0df40f5f01eef614f7d9f94
    

    This matches the hash from the JavaScript code.