(BitTorrent-related) binary "string" to hexadecimal?

Discussion in 'Ruby' started by Shanti Braford, Oct 31, 2007.

  1. Hello,

    Let's say one were "hypothetically", and that's a big hypothetical
    there, writing a BitTorrent tracker in ruby...


    Quick Synopsis: I've got the SHA1 hexdigest of a .torrent metainfo file
    saved on the server.

    Clients connect to the tracker and send the 'info_hash' param; this is
    the raw SHA1 digest (not stored in hex).

    I'm trying to lookup the hexdigest (of known torrents) with the incoming
    'info_hash' param, which is a binary "String" (ruby class wise).

    So..

    For our example below ('foo' is not a valid bencoded string but it makes
    it easy to demonstrate in this example):
    digest_str = Digest::SHA1.hexdigest('foo')
    # => "0beec7b5ea3f0fdbc95d0dd47f3c5bc275da8a33"

    Next up we're trying to write the /announce portion of the BitTorrent
    tracker.

    The 'info_hash' param comes through as an escaped binary representation
    of the info_hash (not hex).

    To replicate what's going on from the Client end, I've done the
    following:

    digest = Digest::SHA1.digest('foo')
    # => "\v?ǵ????]\r?<[?uڊ3"

    The torrent client then escapes the digest for transmission over http
    wire:

    digest_escaped = CGI::escape(digest)
    # => "%0B%EE%C7%B5%EA%3F%0F%DB%C9%5D%0D%D4%7F%3C%5B%C2u%DA%8A3"

    Back on my end, of course I can first CGI unescape this:

    digest = CGI::unescape(params[:info_hash)
    # => "\v?ǵ????]\r?<[?uڊ3"

    So my $1,000,000 question :) How in ruby do we get from
    "\v?ǵ????]\r?<[?uڊ3" to "0beec7b5ea3f0fdbc95d0dd47f3c5bc275da8a33" ?

    I am aware of a workaround: store the initial SHA1 digest of the torrent
    in binary from in MySQL. I'm more comfortable working with strings, and
    haven't dealt with storing binary data in MySQL... but I'll take a look
    at that option if there's no easy way to go from ruby binary
    representation to hex.

    Anyone have any ideas or pointers?

    - Shanti

    ps. this is written in rails but the question takes place more at the
    ruby level, so I figured this forum would be more fitting to ask in!
    --
    Posted via http://www.ruby-forum.com/.
     
    Shanti Braford, Oct 31, 2007
    #1
    1. Advertising

  2. Shanti Braford, Oct 31, 2007
    #2
    1. Advertising

  3. Hi Shanti,

    > I still have no clue what a "hex nibble" is but it does the trick in a
    > pinch! =)


    A "hex nibble" is half a byte represented in hexadecimal. In other
    words, a byte (8 bits) is made up of two (4 bit) nibbles (a most
    significant and a least significant) and in hexadecimal numbering each
    nibble corresponds to a hexadecimal digit.

    For example, the byte 0xFE (1111 1110) is composed of two nibbles: F
    (1111), the most significant, and E (1110), the least significant.

    The ruby function digest.unpack('H*') unpacks the binary string "digest"
    into a string of hex bytes with the most significant nibble written
    before the least significant.

    Hope that makes things a bit clearer for you.

    Josh
    --
    Posted via http://www.ruby-forum.com/.
     
    Joshua Bassett, Oct 31, 2007
    #3
  4. Shanti Braford

    Konrad Meyer Guest

    --nextPart1419135.RkJO9yV2Cq
    Content-Type: text/plain;
    charset="utf-8"
    Content-Transfer-Encoding: quoted-printable
    Content-Disposition: inline

    Quoth Shanti Braford:
    > Ok in case anyone is curious, this seems to work...
    >=20
    > digest_hex =3D digest.unpack('H*')
    > # =3D> "0beec7b5ea3f0fdbc95d0dd47f3c5bc275da8a33"
    >=20
    > http://www.ruby-doc.org/core/classes/String.html#M000775
    >=20
    > I still have no clue what a "hex nibble" is but it does the trick in a=20
    > pinch! =3D)


    Each character in a string from SHA1.digest() is single byte ranging from=
    0=20
    to 255. What you want to do is take each byte, and break it into the most=20
    significant 4 bits and the least significant 4 bits, and represent each of=
    =20
    these as a hex nibble. Hence, your "0beece..." string will be twice as long=
    ,=20
    but has the benefit of being human readable (or matching the protocol :D).

    #unpack("H*") is doing what you want, and I'd say it is *not* just a quic=
    k=20
    hack, but a valid solution to your problem. Good luck and happy rubying.

    HTH,
    =2D-=20
    Konrad Meyer <> http://konrad.sobertillnoon.com/

    --nextPart1419135.RkJO9yV2Cq
    Content-Type: application/pgp-signature; name=signature.asc
    Content-Description: This is a digitally signed message part.

    -----BEGIN PGP SIGNATURE-----
    Version: GnuPG v1.4.7 (GNU/Linux)

    iD8DBQBHJ+LDCHB0oCiR2cwRAinFAJwLR/jTe3q1HQBOIe6PorPuITBHKgCgoeSI
    wJFBCARgc2iAzHuefBXuxC8=
    =7J93
    -----END PGP SIGNATURE-----

    --nextPart1419135.RkJO9yV2Cq--
     
    Konrad Meyer, Oct 31, 2007
    #4
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Victor Hannak
    Replies:
    0
    Views:
    7,459
    Victor Hannak
    Feb 20, 2004
  2. Eric
    Replies:
    3
    Views:
    1,067
    Bengt Richter
    Apr 22, 2004
  3. lei
    Replies:
    10
    Views:
    778
    Don Roby
    Dec 30, 2006
  4. Replies:
    7
    Views:
    2,907
    Martin Ambuhl
    Dec 27, 2006
  5. Bob Sanders
    Replies:
    5
    Views:
    220
    Ryan Lewis
    May 30, 2008
Loading...

Share This Page