Skip to content

Instantly share code, notes, and snippets.

@philsmd
Created May 14, 2020 16:17
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save philsmd/ff18b8ef76dfaad07b623ef829298257 to your computer and use it in GitHub Desktop.
Save philsmd/ff18b8ef76dfaad07b623ef829298257 to your computer and use it in GitHub Desktop.
rar3_hp_V2.pl
#!/usr/bin/env perl
# Author: philsmd
# Date: May 2020
# License: public domain, credits go to philsmd and hashcat and JTR (Jim Fougeron & magnum)
# Version: V2, with little speed-up, updated 2020-05-14
use warnings;
use strict;
use Digest::SHA;
use Crypt::CBC;
use Encode;
#
# Constants
#
my $ITERATIONS = 0x40000;
my $FIXED_RAW_STRING = pack ("H*", "c43d7b00400700000000000000000000");
my $SHA1C00 = 0x5a827999;
my $SHA1C01 = 0x6ed9eba1;
my $SHA1C02 = 0x8f1bbcdc;
my $SHA1C03 = 0xca62c1d6;
my $SHA1M_A = 0x67452301;
my $SHA1M_B = 0xefcdab89;
my $SHA1M_C = 0x98badcfe;
my $SHA1M_D = 0x10325476;
my $SHA1M_E = 0xc3d2e1f0;
#
# Examples
#
# Example 1 (working w/ hashcat, pass length 28):
# $RAR3$*0*bee9b30f9b6aec26*e1dd6d86bd39c1dc263dc90cd2d6160a
# my $pass = "abcdefghijklmnopqrstuvwxyzab";
# my $salt = pack ("H*", "bee9b30f9b6aec26");
# Example 2 (NOT working w/ hashcat, pass length 29):
# $RAR3$*0*2b5bac3fd11901be*05bcf376571d699b96b15a814156611c
# my $pass = "abcdefghijklmnopqrstuvwxyzabc";
# my $salt = pack ("H*", "2b5bac3fd11901be");
# Example 3 (NOT working w/ hashcat, pass length 29):
# $RAR3$*0*702e4790a25df0dc*b402b39f1823808068cfe930395e05b5
# rar file in hex: 526172211a0700ce997380000d00000000000000702e4790a25df0dc1338f1f00977f8db19ed4d0e4843a341a0887f12c6f076256eb52edfe8c3c9f8a98871a03bd3c27be105474c34d445cf47b36b4dc64b21ba0b7e23c201c59865caa86c4843f18208db5957c44b6c37dbe231de9553b300a8e6ceeef77f3c2d58702e4790a25df0dcb402b39f1823808068cfe930395e05b5
my $pass = "abcdefghijklmnopqrstuvwxyzabc";
my $salt = pack ("H*", "702e4790a25df0dc");
# Example 4 (working w/ hashcat, pass length 28):
# $RAR3$*0*e15a13d318ef2de8*c80a616e5582166cd7ca43160cdf8fe4
# rar file in hex: 526172211a0700ce997380000d00000000000000e15a13d318ef2de8bd7cff5eb67de5d1089e3975fff1b8cf5dca71eb812de26a3e3b887df33d6bdd9368b17dc6285d0ad4d91ea6d44c75583ed095907a3a2e5952373a3fad861d365b40db7392ce740c0d8260f9b7605a9341e25b5ec294b471ff56f0f26ad67a41e15a13d318ef2de8c80a616e5582166cd7ca43160cdf8fe4
# my $pass = "abcdefghijklmnopqrstuvwxyzab";
# my $salt = pack ("H*", "e15a13d318ef2de8");
#
# Helper functions
#
sub rotl32
{
my $x = shift;
my $n = shift;
die if ($n > 32);
return (($x << $n) | ($x >> (32 - $n))) & 0xffffffff;
}
sub blk
{
my $b = shift;
my $i = shift;
$$b[$i & 15] = rotl32 ($$b[($i + 13) & 15] ^
$$b[($i + 8) & 15] ^
$$b[($i + 2) & 15] ^
$$b[($i + 0) & 15], 1);
return $$b[$i & 15];
}
sub blk0
{
my $b = shift;
my $i = shift;
my $x = $$b[$i];
$$b[$i] = (($x & 0x000000ff) << 24) |
(($x & 0x0000ff00) << 8) |
(($x & 0x00ff0000) >> 8) |
(($x & 0xff000000) >> 24);
return $$b[$i];
}
sub R0
{
my ($b, $v, $w, $x, $y, $z, $i) = @_;
$z += (($w & ($x ^ $y)) ^ $y) + blk0 ($b, $i) + $SHA1C00 + rotl32 ($v, 5);
$z &= 0xffffffff;
$w = rotl32 ($w, 30);
return ($z, $w);
}
sub R1
{
my ($b, $v, $w, $x, $y, $z, $i) = @_;
$z += (($w & ($x ^ $y)) ^ $y) + blk ($b, $i) + $SHA1C00 + rotl32 ($v, 5);
$z &= 0xffffffff;
$w = rotl32 ($w, 30);
return ($z, $w);
}
sub R2
{
my ($b, $v, $w, $x, $y, $z, $i) = @_;
$z += ($w ^ $x ^ $y) + blk ($b, $i) + $SHA1C01 + rotl32 ($v, 5);
$z &= 0xffffffff;
$w = rotl32 ($w, 30);
return ($z, $w);
}
sub R3
{
my ($b, $v, $w, $x, $y, $z, $i) = @_;
$z += ((($w | $x) & $y) | ($w & $x)) + blk ($b, $i) + $SHA1C02 + rotl32 ($v, 5);
$z &= 0xffffffff;
$w = rotl32 ($w, 30);
return ($z, $w);
}
sub R4
{
my ($b, $v, $w, $x, $y, $z, $i) = @_;
$z += ($w ^ $x ^ $y) + blk ($b, $i) + $SHA1C03 + rotl32 ($v, 5);
$z &= 0xffffffff;
$w = rotl32 ($w, 30);
return ($z, $w);
}
sub buf_to_block
{
my $buf = shift;
my $block = ();
for (my $i = 0; $i < 64; $i += 4)
{
my $n0 = ord (substr ($$buf, $i + 0, 1));
my $n1 = ord (substr ($$buf, $i + 1, 1));
my $n2 = ord (substr ($$buf, $i + 2, 1));
my $n3 = ord (substr ($$buf, $i + 3, 1));
my $num = ($n3 << 24) | ($n2 << 16) | ($n1 << 8) | $n0;
push (@$block, $num);
}
return $block;
}
sub block_to_buf
{
my $block = shift;
my $buf = "";
for (my $i = 0; $i < 16; $i ++)
{
my $num = $$block[$i];
my $n0 = chr (($num & 0x000000ff) >> 0);
my $n1 = chr (($num & 0x0000ff00) >> 8);
my $n2 = chr (($num & 0x00ff0000) >> 16);
my $n3 = chr (($num & 0xff000000) >> 24);
$buf .= $n0 . $n1 . $n2 . $n3;
}
return $buf;
}
sub sha1_transform
{
my ($state, $buffer) = @_;
my $block = buf_to_block ($buffer);
my $a = $$state[0];
my $b = $$state[1];
my $c = $$state[2];
my $d = $$state[3];
my $e = $$state[4];
($e, $b) = R0 ($block, $a, $b, $c, $d, $e, 0);
($d, $a) = R0 ($block, $e, $a, $b, $c, $d, 1);
($c, $e) = R0 ($block, $d, $e, $a, $b, $c, 2);
($b, $d) = R0 ($block, $c, $d, $e, $a, $b, 3);
($a, $c) = R0 ($block, $b, $c, $d, $e, $a, 4);
($e, $b) = R0 ($block, $a, $b, $c, $d, $e, 5);
($d, $a) = R0 ($block, $e, $a, $b, $c, $d, 6);
($c, $e) = R0 ($block, $d, $e, $a, $b, $c, 7);
($b, $d) = R0 ($block, $c, $d, $e, $a, $b, 8);
($a, $c) = R0 ($block, $b, $c, $d, $e, $a, 9);
($e, $b) = R0 ($block, $a, $b, $c, $d, $e, 10);
($d, $a) = R0 ($block, $e, $a, $b, $c, $d, 11);
($c, $e) = R0 ($block, $d, $e, $a, $b, $c, 12);
($b, $d) = R0 ($block, $c, $d, $e, $a, $b, 13);
($a, $c) = R0 ($block, $b, $c, $d, $e, $a, 14);
($e, $b) = R0 ($block, $a, $b, $c, $d, $e, 15);
($d, $a) = R1 ($block, $e, $a, $b, $c, $d, 16);
($c, $e) = R1 ($block, $d, $e, $a, $b, $c, 17);
($b, $d) = R1 ($block, $c, $d, $e, $a, $b, 18);
($a, $c) = R1 ($block, $b, $c, $d, $e, $a, 19);
($e, $b) = R2 ($block, $a, $b, $c, $d, $e, 20);
($d, $a) = R2 ($block, $e, $a, $b, $c, $d, 21);
($c, $e) = R2 ($block, $d, $e, $a, $b, $c, 22);
($b, $d) = R2 ($block, $c, $d, $e, $a, $b, 23);
($a, $c) = R2 ($block, $b, $c, $d, $e, $a, 24);
($e, $b) = R2 ($block, $a, $b, $c, $d, $e, 25);
($d, $a) = R2 ($block, $e, $a, $b, $c, $d, 26);
($c, $e) = R2 ($block, $d, $e, $a, $b, $c, 27);
($b, $d) = R2 ($block, $c, $d, $e, $a, $b, 28);
($a, $c) = R2 ($block, $b, $c, $d, $e, $a, 29);
($e, $b) = R2 ($block, $a, $b, $c, $d, $e, 30);
($d, $a) = R2 ($block, $e, $a, $b, $c, $d, 31);
($c, $e) = R2 ($block, $d, $e, $a, $b, $c, 32);
($b, $d) = R2 ($block, $c, $d, $e, $a, $b, 33);
($a, $c) = R2 ($block, $b, $c, $d, $e, $a, 34);
($e, $b) = R2 ($block, $a, $b, $c, $d, $e, 35);
($d, $a) = R2 ($block, $e, $a, $b, $c, $d, 36);
($c, $e) = R2 ($block, $d, $e, $a, $b, $c, 37);
($b, $d) = R2 ($block, $c, $d, $e, $a, $b, 38);
($a, $c) = R2 ($block, $b, $c, $d, $e, $a, 39);
($e, $b) = R3 ($block, $a, $b, $c, $d, $e, 40);
($d, $a) = R3 ($block, $e, $a, $b, $c, $d, 41);
($c, $e) = R3 ($block, $d, $e, $a, $b, $c, 42);
($b, $d) = R3 ($block, $c, $d, $e, $a, $b, 43);
($a, $c) = R3 ($block, $b, $c, $d, $e, $a, 44);
($e, $b) = R3 ($block, $a, $b, $c, $d, $e, 45);
($d, $a) = R3 ($block, $e, $a, $b, $c, $d, 46);
($c, $e) = R3 ($block, $d, $e, $a, $b, $c, 47);
($b, $d) = R3 ($block, $c, $d, $e, $a, $b, 48);
($a, $c) = R3 ($block, $b, $c, $d, $e, $a, 49);
($e, $b) = R3 ($block, $a, $b, $c, $d, $e, 50);
($d, $a) = R3 ($block, $e, $a, $b, $c, $d, 51);
($c, $e) = R3 ($block, $d, $e, $a, $b, $c, 52);
($b, $d) = R3 ($block, $c, $d, $e, $a, $b, 53);
($a, $c) = R3 ($block, $b, $c, $d, $e, $a, 54);
($e, $b) = R3 ($block, $a, $b, $c, $d, $e, 55);
($d, $a) = R3 ($block, $e, $a, $b, $c, $d, 56);
($c, $e) = R3 ($block, $d, $e, $a, $b, $c, 57);
($b, $d) = R3 ($block, $c, $d, $e, $a, $b, 58);
($a, $c) = R3 ($block, $b, $c, $d, $e, $a, 59);
($e, $b) = R4 ($block, $a, $b, $c, $d, $e, 60);
($d, $a) = R4 ($block, $e, $a, $b, $c, $d, 61);
($c, $e) = R4 ($block, $d, $e, $a, $b, $c, 62);
($b, $d) = R4 ($block, $c, $d, $e, $a, $b, 63);
($a, $c) = R4 ($block, $b, $c, $d, $e, $a, 64);
($e, $b) = R4 ($block, $a, $b, $c, $d, $e, 65);
($d, $a) = R4 ($block, $e, $a, $b, $c, $d, 66);
($c, $e) = R4 ($block, $d, $e, $a, $b, $c, 67);
($b, $d) = R4 ($block, $c, $d, $e, $a, $b, 68);
($a, $c) = R4 ($block, $b, $c, $d, $e, $a, 69);
($e, $b) = R4 ($block, $a, $b, $c, $d, $e, 70);
($d, $a) = R4 ($block, $e, $a, $b, $c, $d, 71);
($c, $e) = R4 ($block, $d, $e, $a, $b, $c, 72);
($b, $d) = R4 ($block, $c, $d, $e, $a, $b, 73);
($a, $c) = R4 ($block, $b, $c, $d, $e, $a, 74);
($e, $b) = R4 ($block, $a, $b, $c, $d, $e, 75);
($d, $a) = R4 ($block, $e, $a, $b, $c, $d, 76);
($c, $e) = R4 ($block, $d, $e, $a, $b, $c, 77);
($b, $d) = R4 ($block, $c, $d, $e, $a, $b, 78);
($a, $c) = R4 ($block, $b, $c, $d, $e, $a, 79);
$$state[0] = ($$state[0] + $a) & 0xffffffff;
$$state[1] = ($$state[1] + $b) & 0xffffffff;
$$state[2] = ($$state[2] + $c) & 0xffffffff;
$$state[3] = ($$state[3] + $d) & 0xffffffff;
$$state[4] = ($$state[4] + $e) & 0xffffffff;
$$buffer = block_to_buf ($block);
}
sub sha1_getstate
{
my $ctx = shift;
my $info = $ctx->getstate;
# state:
my ($state) = $info =~ m/H:([a-f0-9:]*)/;
$state =~ s/://g;
$state = pack ("H*", $state);
my $state_arr = ();
for (my $i = 0; $i < 20; $i += 4)
{
my $num = unpack ("L>", substr ($state, $i, 4));
push (@$state_arr, $num);
}
# block:
my ($block) = $info =~ m/block:([a-f0-9:]*)/;
$block =~ s/://g;
$block = pack ("H*", $block);
return ($state_arr, $block);
}
sub sha1_putstate
{
my $ctx = shift;
my $state = shift;
my $block = shift;
my $count = shift;
# state:
my $state_str = "";
for (my $i = 0; $i < 5; $i ++)
{
$state_str = $state_str . sprintf ("%08x", $$state[$i]) . ":";
}
$state_str .= "00000000:00000000:00000000";
# block:
$block = unpack ("H*", $block);
my $block_str = "";
for (my $i = 0; $i < 128; $i += 2)
{
if ($i != 0)
{
$block_str .= ":";
}
$block_str .= substr ($block, $i, 2);
}
# block_cnt:
my $block_cnt = $count & 63;
# output:
my $str = 'alg:1
H:' . $state_str . '
block:' . $block_str . '
blockcnt:' . ($block_cnt * 8) . '
lenhh:0
lenhl:0
lenlh:0
lenll:' . ($count * 8) . '
';
$ctx->putstate ($str);
}
sub sha1_update_rar29
{
my $ctx = shift;
my $data = shift;
my $len = shift;
my $count = shift;
my $rar29_mod = 0; # avoid our own transform () implementation as much as possible
my $j = $count & 63;
if (($j + $len) > 63)
{
my $i = 64 - $j;
if (($i + 63) < $len)
{
$count += $len;
my ($state, $block) = sha1_getstate ($ctx);
substr ($block, $j, $i) = substr ($$data, 0, $i);
sha1_transform ($state, \$block);
while (($i + 63) < $len)
{
my $workspace = substr ($$data, $i, 64);
sha1_transform ($state, \$workspace);
substr ($$data, $i, 64) = $workspace;
$i += 64;
}
$j = 0;
if ($len > $i)
{
substr ($block, $j, $len - $i) = substr ($$data, $i, $len - $i);
}
sha1_putstate ($ctx, $state, $block, $count);
$rar29_mod = 1;
}
}
if ($rar29_mod == 0)
{
$ctx->add ($$data);
}
}
sub rar3_hp
{
my $pass = shift;
my $salt = shift;
# convert to utf16le:
my $buf = encode ("UTF-16LE", $pass);
# add the salt to the password buffer:
$buf .= $salt;
my $len = length ($buf);
my $count = 0;
my $ctx = Digest::SHA->new ('SHA1');
my $iv = "";
# main loop:
for (my $i = 0; $i < $ITERATIONS; $i++)
{
sha1_update_rar29 ($ctx, \$buf, $len, $count);
$count += $len;
my $pos = substr (pack ("L<", $i), 0, 3);
$ctx->add ($pos);
$count += 3;
if (($i & 0x3fff) == 0)
{
my $dgst = $ctx->clone->digest;
$iv .= substr ($dgst, 19, 1);
}
}
my $k = $ctx->digest;
# byte swap:
$k = substr ($k, 3, 1) . substr ($k, 2, 1) . substr ($k, 1, 1) . substr ($k, 0, 1) .
substr ($k, 7, 1) . substr ($k, 6, 1) . substr ($k, 5, 1) . substr ($k, 4, 1) .
substr ($k, 11, 1) . substr ($k, 10, 1) . substr ($k, 9, 1) . substr ($k, 8, 1) .
substr ($k, 15, 1) . substr ($k, 14, 1) . substr ($k, 13, 1) . substr ($k, 12, 1);
my $aes = Crypt::CBC->new (
-cipher => "Crypt::Rijndael",
-key => $k,
-iv => $iv,
-keysize => 16,
-literal_key => 1,
-header => 'none');
return $aes->encrypt ($FIXED_RAW_STRING);
}
#
# Start
#
# main hash generation function:
my $hash = rar3_hp ($pass, $salt);
#
# Output
#
print sprintf ("\$RAR3\$*0*%s*%s\n", unpack ("H*", $salt), unpack ("H*", substr ($hash, 0, 16)));
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment