Yearly Archives: 2011

Thursday Quote: Michael Lopp

November 17, 2011 » Geek

“The only thing engineers like about a deadline is it’s precision.”

– Michael Lopp
@rands

Fixing Broken Droid2 Root

November 16, 2011 » Consume, Geek

I had previously rooted my Droid2, but it was broken when the OTA Gingerbread came down. I don’t really use root for much now that I don’t really develop for Android anymore, but I found a need today, so I decided to re-root.

I found a nicely packaged exploit on rootzwiki, but when I ran it I hit a snag.

* daemon started successfully *
* Running exploit [part 3 of 3]...
remount succeeded
5524 KB/s (1867568 bytes in 0.330s)
651 KB/s (26264 bytes in 0.039s)
5928 KB/s (196521 bytes in 0.032s)
	pkg: /data/local/tmp/Superuser.apk
Failure [INSTALL_FAILED_ALREADY_EXISTS]
link failed File exists

My old root was blocking my new root. Lame.

Easy to fix after poking around on the file system.

Essentially it boils down to this:

  1. Manually remove old Superuser.apk
  2. Clean up Superuser.apk data files
  3. Install new super user apk
  4. Link up new su

Details below, but as always YMMV.

Manually remove old Superuser.apk

Make sure you know the full namespace before you delete this file, you will need it later (i.e. com.noshufou.android.su)

[email protected]:~/root$ ./adb.linux shell
# cd /system/app
# rm Superuser.apk

Clean up Superuser.apk data files

[email protected]:~/root$ ./adb.linux uninstall com.noshufou.android.su
Success

Install new super user apk

From here on out you are essentially just finishing up the root script that got skipped.

[email protected]:~/root$ ./adb.linux install Superuser.apk 
3217 KB/s (196521 bytes in 0.059s)
	pkg: /data/local/tmp/Superuser.apk
Success

Link up new su

[email protected]:~/root$ ./adb.linux shell
# cd /system/bin
# mv su su.orig
# ln -s /system/xbin/su /system/bin/su

All done! You should be rooted again.

Pushing a row to the end of a sort with MySQL

November 11, 2011 » Geek

Sometimes you have weird requirements to meet. It’s a fact of life.

One of these requirements I came across recently was outputting a result set in alpha order, but with a specific tuple at the end, instead of where it belongs in the sort.

I decided I’d figure out how to do this in SQL instead of gross rendering or a re-sort.

Please note there are other ways to solve this that are less brittle, but this was in a fairly static data set for a one off solution.

Consider this table:

CREATE TABLE `animals` (
  `id` int(11) UNSIGNED NOT NULL AUTO_INCREMENT,
  `name` varchar(64)  NOT NULL,
  `slug` varchar(64)  NOT NULL,
  PRIMARY KEY (`id`),
  UNIQUE KEY `uniq_name`(`name`(64)),
  UNIQUE KEY `uniq_slug`(`slug`(64))
)
ENGINE = InnoDB DEFAULT CHARSET=utf8;

INSERT INTO `animals` ( `id`, `name`, `slug` ) VALUES
  ( NULL, 'Dog', 'dog' ),
  ( NULL, 'Cat', 'cat' ),
  ( NULL, 'Other', 'other' ),
  ( NULL, 'Zebra', 'zebra' );

Now, pull them out in alpha order:

mysql> SELECT * 
    -> FROM `animals` 
    -> ORDER BY slug ASC;
+----+-------+-------+
| id | name  | slug  |
+----+-------+-------+
|  2 | Cat   | cat   |
|  1 | Dog   | dog   |
|  3 | Other | other |
|  4 | Zebra | zebra |
+----+-------+-------+
4 rows in set (0.00 sec)

But what if we always want “Other” at the end?

Well, our unique indices allow us to guarantee a conditional sort on the slug (or name).

To do this, we will use the CASE statement.

mysql> SELECT * 
    -> FROM `animals` 
    -> ORDER BY CASE 
    -> WHEN `slug` = 'other' 
    -> THEN 0 
    -> ELSE 1 
    -> END DESC, `slug` ASC;
+----+-------+-------+
| id | name  | slug  |
+----+-------+-------+
|  2 | Cat   | cat   |
|  1 | Dog   | dog   |
|  4 | Zebra | zebra |
|  3 | Other | other |
+----+-------+-------+
4 rows in set (0.00 sec)

Here we have two ORDER BY clauses. We first use CASE to return 1 whenever the slug is “other”, and sort on that. Then we sort the sub-groups (“other” and “non-other”) by slug.

CASE is handy for other stuff too, and can handle complex expressions.

mysql> SELECT *, CASE 
    -> WHEN `slug` IN ( 'cat', 'dog' ) 
    -> THEN 'yes' 
    -> ELSE 'no' 
    -> END AS 'is_good_pet' 
    -> FROM `animals`;
+----+-------+-------+-------------+
| id | name  | slug  | is_good_pet |
+----+-------+-------+-------------+
|  1 | Dog   | dog   | yes         |
|  2 | Cat   | cat   | yes         |
|  3 | Other | other | no          |
|  4 | Zebra | zebra | no          |
+----+-------+-------+-------------+
4 rows in set (0.00 sec)

Do you ever use CASE?

Thursday Quote: Juan Reyero

November 10, 2011 » Geek

“It is the curse of the engineer: if it can be done, tadalafil it will be done.”

– Juan Reyero
23 visits a day

Replacing Kohana 3 Auth module hashing

November 9, 2011 » Geek

The password hashing in the Auth module provided with Kohana 3.1 is not very good. By default it is a simple sha256 hmac with a global salt.

modules/auth/classes/kohana/auth.php

public function hash($str)
{
  if ( ! $this->_config['hash_key'])
    throw new Kohana_Exception('A valid hash key must be set in your auth config.');

  return hash_hmac($this->_config['hash_method'], $str, $this->_config['hash_key']);
}

This isn’t strong. If you loose the hashes and the salt it’s just a matter of winding up a GPU.

So how can we fix this? Well, thanks to Kohana’s structure we can easily override the Auth class and tweak it. However, due to Auth’s structure, we can’t drop the global salt. The hash function has to stand alone, so no passing in salts from the database.

That leaves us with key stretching.

Now, I don’t want to deal with a custom key stretching implementation, I’m not a cryptographer. So, let’s find an existing algorithm.

One that pops to mind is PBKDF2. This is a pretty simple algorithm, so it was easy to find and spot check a PHP implementation

We just take some test vectors from RFC 3962 and run them against the code we found.

 1,
      'bits' => 128,
      'expected' => "cd ed b5 28 1b b2 f8 01 56 5a 11 22 b2 56 35 15"
    ),
    array(
      'rounds' => 1,
      'bits' => 256,
      'expected' => "cd ed b5 28 1b b2 f8 01 56 5a 11 22 b2 56 35 15 0a d1 f7 a0 4b b9 f3 a3 33 ec c0 e2 e1 f7 08 37"
    ),
    array(
      'rounds' => 2,
      'bits' => 128,
      'expected' => "01 db ee 7f 4a 9e 24 3e 98 8b 62 c7 3c da 93 5d"
    ),
    array(
      'rounds' => 2,
      'bits' => 256,
      'expected' => "01 db ee 7f 4a 9e 24 3e 98 8b 62 c7 3c da 93 5d a0 53 78 b9 32 44 ec 8f 48 a9 9e 61 ad 79 9d 86"
    ),
    array(
      'rounds' => 1200,
      'bits' => 128,
      'expected' => "5c 08 eb 61 fd f7 1e 4e 4e c3 cf 6b a1 f5 51 2b"
    ),
    array(
      'rounds' => 1200,
      'bits' => 256,
      'expected' => "5c 08 eb 61 fd f7 1e 4e 4e c3 cf 6b a1 f5 51 2b a7 e5 2d db c5 e5 14 2f 70 8a 31 e2 e6 2b 1e 13"
    ),
  );

  foreach( $tests as $test ) {
    print $test['rounds'] . ' rounds at ' . $test['bits'] . ' bits ' . "\n";
    $start = microtime( TRUE );
    $result = trim( preg_replace( '/(..)/', '\1 ', bin2hex( pbkdf2( 'password', 'ATHENA.MIT.EDUraeburn', $test['rounds'], $test['bits']/8, 'sha1' ) ) ) );
    $diff = microtime( TRUE ) - $start;
    print 'Expected: ' . $test['expected'] . "\n";
    print '     Got: ' . $result . "\n";
    if( $result == $test['expected'] ) {
      print "MATCH\n";
    }
    else { 
      print "NO MATCH\n";
    }
    print 'Took ' . number_format( $diff, 10 ) . "\n\n";
  }

Run it, and everything checks out:

1 rounds at 128 bits 
Expected: cd ed b5 28 1b b2 f8 01 56 5a 11 22 b2 56 35 15
     Got: cd ed b5 28 1b b2 f8 01 56 5a 11 22 b2 56 35 15
MATCH
Took 0.0000329018

1 rounds at 256 bits 
Expected: cd ed b5 28 1b b2 f8 01 56 5a 11 22 b2 56 35 15 0a d1 f7 a0 4b b9 f3 a3 33 ec c0 e2 e1 f7 08 37
     Got: cd ed b5 28 1b b2 f8 01 56 5a 11 22 b2 56 35 15 0a d1 f7 a0 4b b9 f3 a3 33 ec c0 e2 e1 f7 08 37
MATCH
Took 0.0000190735

2 rounds at 128 bits 
Expected: 01 db ee 7f 4a 9e 24 3e 98 8b 62 c7 3c da 93 5d
     Got: 01 db ee 7f 4a 9e 24 3e 98 8b 62 c7 3c da 93 5d
MATCH
Took 0.0000147820

2 rounds at 256 bits 
Expected: 01 db ee 7f 4a 9e 24 3e 98 8b 62 c7 3c da 93 5d a0 53 78 b9 32 44 ec 8f 48 a9 9e 61 ad 79 9d 86
     Got: 01 db ee 7f 4a 9e 24 3e 98 8b 62 c7 3c da 93 5d a0 53 78 b9 32 44 ec 8f 48 a9 9e 61 ad 79 9d 86
MATCH
Took 0.0000200272

1200 rounds at 128 bits 
Expected: 5c 08 eb 61 fd f7 1e 4e 4e c3 cf 6b a1 f5 51 2b
     Got: 5c 08 eb 61 fd f7 1e 4e 4e c3 cf 6b a1 f5 51 2b
MATCH
Took 0.0019500256

1200 rounds at 256 bits 
Expected: 5c 08 eb 61 fd f7 1e 4e 4e c3 cf 6b a1 f5 51 2b a7 e5 2d db c5 e5 14 2f 70 8a 31 e2 e6 2b 1e 13
     Got: 5c 08 eb 61 fd f7 1e 4e 4e c3 cf 6b a1 f5 51 2b a7 e5 2d db c5 e5 14 2f 70 8a 31 e2 e6 2b 1e 13
MATCH
Took 0.0144000053

So now all that’s left is to drop it in, which is pretty simple. One thing to note is that I wanted this to stay compatible with the default auth config file, so I just extended that a little bit.

application/classes/auth.php

_config['hash_key'] )
        throw new Kohana_Exception( 'A valid hash key must be set in your auth config.' );

      if ( 'pbkdf2' == $this->_config['hash_method'] ) {
        return base64_encode( self::pbkdf2( 
          $str, 
          $this->_config['hash_key'], 
          Arr::get( $this->_config['pbkdf2'], 'rounds', 1000 ),
          Arr::get( $this->_config['pbkdf2'], 'length', 45 ),
          Arr::get( $this->_config['pbkdf2'], 'method', 'sha256' )
        ) );
      }
      else {
        return parent::hash( $str );
      }
    }

    /** PBKDF2 Implementation (described in RFC 2898)
     *
     *  @param string p password
     *  @param string s salt
     *  @param int c iteration count (use 1000 or higher)
     *  @param int kl derived key length
     *  @param string a hash algorithm
     *
     *  @return string derived key
     *
     *  @url http://www.itnewb.com/tutorial/Encrypting-Passwords-with-PHP-for-Storage-Using-the-RSA-PBKDF2-StandardL
    */
    public static function pbkdf2 ( $p, $s, $c, $kl, $a = 'sha256' ) {

        $hl = strlen(hash($a, null, true)); # Hash length
        $kb = ceil($kl / $hl);              # Key blocks to compute
        $dk = '';                           # Derived key

        # Create key
        for ( $block = 1; $block <= $kb; $block ++ ) {

            # Initial hash for this block
            $ib = $b = hash_hmac($a, $s . pack('N', $block), $p, true);

            # Perform block iterations
            for ( $i = 1; $i < $c; $i ++ )

                # XOR each iterate
                $ib ^= ($b = hash_hmac($a, $b, $p, true));

            $dk .= $ib; # Append iterated block
        }

        # Return derived key of correct length
        return substr($dk, 0, $kl);
    }

  }

application/config/auth.php

 'orm',
    'hash_method'  => 'pbkdf2',
    'hash_key'     => 'zomg',
    'lifetime'     => 1209600,
    'session_key'  => 'auth_user',
    'pbkdf2'       => array(
      'method'  => 'sha256',
      'rounds'  => 1000,
      'length'  => 45,
    )
  );

One item to note is that I am packing these with base64_encode. This is to fit into the default field type for the ORM driver. That is also why my length is stunted to 45. If you really want to go all out, alter your table to use a TINYBLOB, up the length to 256 bit and up the rounds.

So that is how I replace weak hashing in K3 with something a bit better.

How do you do it?