#!/usr/bin/perl # usage: encrypt.pl aa:bb:cc:dd:ee:ff filename # (giving the MAC address of the target phone) use strict; use warnings; use Crypt::Rijndael qw{MODE_CBC}; my $mac = shift; my @macbytes = map {hex($_)} split /[:-]/, $mac; die "Invalid mac address $mac\n" unless scalar @macbytes == 6; my @cfgdata; while (<>) { next unless /^P(\d+)\s*=\s*(.*?)\s*$/; my ($key, $value) = ($1, $2); $value =~ s/([^A-Za-z0-9.*_-])/$1 eq ' ' ? '+' : sprintf('%%%02x', ord($1))/eg; push @cfgdata, "P$key=$value"; } push @cfgdata, 'gnkey=0b82'; my $cfgdata = join('&', @cfgdata); # Round up to the nearest 16 bytes my $outlength = length($cfgdata) + 15; $outlength -= $outlength % 16; # Pad out $cfgdata to that length my $cleartext = $cfgdata . (chr(0) x ($outlength - length($cfgdata))); die if length($cleartext) % 16; # Then add 16 for @initbytes $outlength += 16; my $salt = int(rand(0x10000)); my @cleartext_checksum = checksum($cleartext); my @initbytes = (0, 0, (($outlength / 2) >> 8) & 0xff, ($outlength / 2) & 0xff, 0, 0, 0xff, 1, ($salt >> 8) & 0xff, $salt & 0xff, @cleartext_checksum, 13, 10, 13, 10); my @iv1 = unpack('C*', 'lixiabingweixian'); my @iv2 = unpack('C*', 'gweiningzhangwei'); my $iv = pack('C16', map {$iv1[$_] ^ $iv2[$_]} 0..$#iv1); my $l1 = ($macbytes[2] << 24) + ($macbytes[3] << 16) + ($macbytes[4] << 8) + $macbytes[5]; my $l2 = ($initbytes[8] << 8) + $initbytes[9]; my $l = $l1 % $l2; my @keybytes = (@initbytes[2..3], @macbytes, @initbytes[6..11], ($l >> 8) & 0xff, $l & 0xff); my $key = pack('C16', @keybytes); my $cipher = Crypt::Rijndael->new($key, Crypt::Rijndael::MODE_CBC); $cipher->set_iv($iv); my $ciphertext = $cipher->encrypt($cleartext); my $checktext = pack('C16', @initbytes) . $ciphertext; @initbytes[4,5] = checksum($checktext); print pack('C16', @initbytes) . $ciphertext; sub checksum { my $str = shift; my $sum = 0; foreach my $i (0..((length($str) - 1) / 2)) { $sum += ord(substr($str, 2 * $i, 1)) << 8; $sum += ord(substr($str, (2 * $i) + 1, 1)); $sum &= 0xffff; } $sum = 0x10000 - $sum; return (($sum >> 8) & 0xff, $sum & 0xff); }