Created
May 14, 2020 16:17
-
-
Save philsmd/ff18b8ef76dfaad07b623ef829298257 to your computer and use it in GitHub Desktop.
rar3_hp_V2.pl
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/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