How to convert torrent info hash for scrape? - php

I have a torrent hash from the magnet link. For example: fda164e7af470f83ea699a529845a9353cc26576
When I try to get information about leechers and peers I should request: http://tracker.publicbt.com/scrape?info_hash=???
How should I convert info hash for this request? Is it url encoding or becoding? how? In PHP.

It's a raw hexadecimal representation. Use pack() with H to convert it. Then URL encode it.

Got this python snippet from a colleague,
r = ''
s = 'fda164e7af470f83ea699a529845a9353cc26576'
for n in range(0, len(s), 2):
r += '%%%s' % s[n:n+2].upper()
print r
Output: %FD%A1%64%E7%AF%47%0F%83%EA%69%9A%52%98%45%A9%35%3C%C2%65%76
Works like a charm.
Edit: Works like a charm for getting the tracker to give back status 200 (ok) but still doesn't work for retrieving the torrent details...

In case someone is having trouble and comes across this thread in the future: the trick to this whole issue is to use the bool $raw_output argument of the PHP: sha1 function, setting it to "true".
The BDecode/DEncode classes can be found HERE. This project, called Trackon, also includes many other helpful classes to interact with torrent trackers and files.
So, in PHP, something like this will work to obtain the correct info hash for scraping the tracker for details:
include('./path/to/BDecode.php');
include('./path/to/BEncode.php');
function getHash($torFile){
$tfile = BDecode(file_get_contents($torFile));
$infohash = sha1(BEncode($tfile["info"]), TRUE);
return urlencode($infohash);
}
Then merely call it like so:
$hash = getHash('./path/to/.torrent');
Hope this helps someone out there. I was still scratching my head after reading many posts about how to obtain the correct info hash. I understand why this wasn't mentioned anywhere now though, this argument was added in PHP 5. If you're not running PHP 5, you will have to convert the sha1 hash to raw binary after you calculate it.

Related

LibSodium functions return unreadable characters

I am following along with a tutorial on encryption: https://php.watch/articles/modern-php-encryption-decryption-sodium. In working with the Sodium extension I'm just baffled by a few things. Googling is returning frustratingly little help. (Most of the results are just duplications of the php.net/manual.)
1. In various articles I'm reading, the result of sodium_crypto_*_encrypt() is something familiar:
// ex. DEx9ATXEg/eRq8GWD3NT5BatB3m31WED
Whenever I echo it out myself I get something like:
// ex. 𫦢�2(*���3�CV��Wu��R~�u���H��
which I'm certain won't store correctly on a database. Nowhere in the articles or documentation does it mention anything about charset weirdness. I can throw a header('Content-Type: text/html; charset=ISO-8859-1') in there, but I still get weird characters I'm not certain are right since I'm not finding any threads talking about this:
// ex. ÑAÁ5eŠ…n#±'ýÞÃ1è9ÜÈ̳¬"CžãÚ0ÿÛ
2. I can't find any information about the best practice for storing keys or nonces.
I just figured this obvious-to-security-folks-but-not-to-others bit of information would be a regularly discussed part of articles on keygens and nonces and such. Seeing as both my keygen and nonce functions (at least in the Sodium library) seem to return non-UTF-8 gibberish, what do I do with it? fwrite it out to a file to be referenced later? Pass it directly to my database? Copy/pasting certainly doesn't work right with it being wingdings.
Other than these things, everything else in the encryption/decryption process makes complete sense to me. I'm far from new to PHP development, I just can't figure this out.
Came across https://stackoverflow.com/a/44874239/1128978 answering "PHP random_bytes returns unreadable characters"
random_bytes generates an arbitrary length string of cryptographic random bytes...
And suggests to use bin2hex to get readable characters. So amending my usages:
// Generate $ciphertext
$message = 'This is a secret message';
$key = sodium_crypto_*_keygen();
$nonce = random_bytes(SODIUM_CRYPTO_*BYTES);
$ciphertext = sodium_crypto_*_encrypt($message, '', $nonce, $key);
// Store hexadecimal versions of binary output
$nonce_hex = bin2hex($nonce);
$key_hex = bin2hex($key);
$ciphertext_hex = bin2hex($ciphertext);
// When ready to decrypt, convert hexadecimal values back to binary
$ciphertext_bin = hex2bin($ciphertext_hex);
$nonce_bin = hex2bin($nonce_hex);
$key_bin = hex2bin($key_hex);
$decrypted = sodium_crypto_*_decrypt($ciphertext_bin, '', $nonce_bin, $key_bin);
// "This is a secret message"
So making lots of use of bin2hex and hex2bin, but this now makes sense. Effectively solved, though not confident this is the proper way to work with it. I still have no idea why this isn't pointed out anywhere in php.net/manual nor in any of the articles/comments I've been perusing.

Different results between PHP md5() and Ruby Digest::MD5.hexdigest

I wanted to pass a MD5 hash generated by Ruby program to a PHP program, and found something strange.
Ruby code(result: ad0efdf609e99ec50d9333dc0bd1c11a)
Digest::MD5.hexdigest 'test str1&test str2&test str3&test str4'
PHP code(result: 804160119894a4cc8c376fffbcc21e1c)
PHP online MD5 generator
You can see the results are different... but if I remove the "&" in my string:
Ruby code(result: 45fa91e4c89aa6f3bb501531a5de6bf4)
Digest::MD5.hexdigest 'test str1test str2test str3test str4'
PHP code(result: 45fa91e4c89aa6f3bb501531a5de6bf4)
PHP online MD5 generator
They are the same. Why did this happen? The MD5 algorithm should be same in any language, shouldn't it?
The results of that website are wrong.
Here comes an example (using PHP on the command line):
php -r 'echo md5("test str1&test str2&test str3&test str4");'
Output:
ad0efdf609e99ec50d9333dc0bd1c11a
804160119894a4cc8c376fffbcc21e1c is the MD5 hash for test str1, not test str1&test str2&test str3&test str4.
That on-line generator is obviously corrupting POST data when reading it. According to Firebug, data is already sent corrupted to the server, so the issue is on its client-side form handling. It's easy to find what's wrong:
function sendHttpRequest(w){
var url = "http://www.md5.cz/getmd5.php";
var idWhat = document.getElementById('what');
var params = "what=" + idWhat.value;
^^^^ Pardon???
The correct hash is ad0efdf609e99ec50d9333dc0bd1c11a.

SHA-1 base32 of a file report back to a string

I'm having troubles figuring out how to implement a program that I can generate a base32 sha-1 value of a file. I know it can't be too difficult to figure out as to generate a standard sha1 file is fairly easy.
$file1 = sha1_file('main.jpg');
Any help would be appreciated.
If you want to encode the SHA1 value as Base32, you gonna have to either write that yourself or find a library. PHP does not have it built-in, like it does with base64_encode.
A while ago, I needed a base32_encode function, so I wrote one. I don't know how efficient it is, and I'm sure better ones exist out there, but it does work. It's located here: https://github.com/NTICompass/PHP-Base32
Using that you can do:
<?php
include 'Base32.php';
$base32 = new Base32;
$file1 = sha1_file('main.jpg');
echo $base32->base32_encode($file1);
I have a PHP class, Base2n, which can encode Base32 per RFC 4648. It's actually more flexible than that, allowing you to parametrically define many standard and non-standard encoding schemes with a 2n base.
https://github.com/ademarre/binary-to-text-php
Base32 is demonstrated in the first example of the README file.
Here's what your "main.jpg" example would look like:
// include, require, or autoload Base2n
$file1 = sha1_file('main.jpg', TRUE);
$base32 = new Base2n(5, 'ABCDEFGHIJKLMNOPQRSTUVWXYZ234567', FALSE, TRUE, TRUE);
$base32FileHash = $base32->encode($file1);
Notice that I also set $raw_output=TRUE in the call to sha1_file(). I assume this is what you want because otherwise the Base32 output would be done on the hexadecimal representation of the SHA-1 hash digest, not the raw 160-bit digest itself.

How to make hash in PHP and Node.js have the same value?

In node.js, I have:
var h = crypto.createHash("md5"); // md5
h.update("AAA");
h.digest("hex");
In PHP I have:
md5("AAA");
However, both have different value. How can I make it the same? or else, what other algorithm I should use to make them the same, so that I can use it as signature calculation. Thanks.
Oppss.. actually. my mistake. when I test it, there is a bug.. it will md5 the same thing.
Simple googling I did in the past gave me => http://japhr.blogspot.com/2010/06/md5-in-nodejs-and-fabjs.html
Node.js
Script:
var crypto = require('crypto');
var hash = crypto.createHash('md5').update('AAA').digest("hex");
console.log(hash);
Output:
alfred#alfred-laptop:~/node/hash$ node hash.js
e1faffb3e614e6c2fba74296962386b7
PHP
Code
<?php
echo md5("AAA");
Output:
alfred#alfred-laptop:~/node/hash$ php md5.php
e1faffb3e614e6c2fba74296962386b7
The output for both PHP and node.js are equal.
C extension
Also you might have look at https://github.com/brainfucker/hashlib which uses C implementation which is going to be faster.
Your code creates the same hash value for me, you might doing it wrong at some point
I had the same issue with creating hash for non UTF8 string :
var non_utf8_str = "test_merchant;www.market.ua;DH783023;1415379863;1547.36;UAH;Процессор
Intel Core i5-4670 3.4GHz;Память Kingston DDR3-1600 4096MB
PC3-12800;1;1;1000;547.36";
The results in PHP and NodeJS was different until I used utf8 library.
So following code works equivalent for both PHP and NodeJS :
crypto.createHash('md5').update(utf8.encode(non_utf8_str)).digest('hex');
var hash = crypto.createHash('md5').update(password, 'latin1', 'latin1').digest('hex');
This worked for me. Try different encodings: 'utf8', 'ascii', or 'latin1'.

RSA Decrypted Data Corrupt

My script uses openssl_private_decrypt() to decrypt a string encrypted with RSA in another program. Currently it writes to a file. But when I try to open it up in a text editor, it says it can't detect the encoding. If I try to echo it, nothing appears. If I output it's length, I get 256, instead of the correct 3.
I know the decryption is done right because using the cat terminal command on the output file gives the correct data.
$ cat decrypted.txt
It looks like this is a character encoding problem, a problem I hear can give a lot of pain in PHP. I even tried utf8_encode(). What might the problem be?
Here's the code:
$results = '';
openssl_private_decrypt(
base64_decode(
<<<EOS
QWlG+AZIt9GE0hw0wwcPRtUWueMLBxj3YWpa5zQBoz1ttnt7TvlxDtYWZcvaUL/qr2CJCADE2iTR
G72FhAwew2fhqlqmsxL7Nns3yegflTTMXyilVM3mPU4Cx94ylLfa+ZrqrNEepaRorNJ/js5iTq9i
avegO/kYOv4zhEsZirlk/Mj0vVv6irWo8WyZoCDC2SwfGWeSUI8F4pq4FUkRh9V/0zAUZ+3P0A7Z
SrA80dSa6U/J+poRcmE1vRLQXvM8dBtFRKmb0zfltLUBMcMhcglzAhcpemJ99OCZmUuynFRcRNkj
CkOLsO+lSHntcbmXqsKE+of78gnU3tp5hHSHIg==
EOS
),
$results,
openssl_pkey_get_private(
// load private key
),
OPENSSL_NO_PADDING
);
echo $results;
The fact that you're getting decrypted data exactly the length of a single block instead of the length of your expected data is really, really pointing towards a padding problem.
Make sure you're using the same padding flag on both sides.
I'm not familiar with openssl_private_decrypt, but it seems logical to me that you would provide base64_encode()'d data to openssl_private_encrypt().
In such case, you're mangling your data by running in the wrong order on decrypt.
Seems like you would want to decrypt the string first, then run base64_decode() on the unencrypted string.

Categories