Getting back a password from Polkawallet JSON File
#6
I've received your PM , but I can't do much about it without knowing the exact password (I'm not going to waste my time to crack it). DId you generate this hash or is this a public available test (github link ?) ?

but there is also good news, I've investigated this now a little bit and found out the exact algorithm details.

As expected, it's using Scrypt as key derivation (derive a key from the password) with parameters N = 32768, r = 8 and p = 1 (so quite high N value, difficult to crack fast).

After that the "encoded" part needs to be split again (it also contains the salt for scrypt and the N,r,p values at the start, but the Nrp parameters are hard-coded in the source code at the time of this writing). The "encoded" part contains both the verifier and also the message that needs to be "decrypted".
Polkawallet uses xsalsa20 to generate a new subkey from the key derived from the scrypt hashing of the password and afterwards uses Poly1305 to verify/decrypt/test the message (authentication, verifier). So it basically just uses the NaCl standard.

I've coded this as a POC (proof of concept) cracker for you in both python and perl, just for demonstration.

python (polkawallet.py):
Code:
#!/usr/bin/env python3

# Author: philsmd
# Date: July 2021
# License: public domain, credits go to philsmd and hashcat

# Note: NaCl uses XSalsa20 and Poly1305 for decrypting the data.
# Key derivation is done by scrypt (32768, 8, 1)

# only tested with version 3 of a PolkaWallet test wallet

from base64 import b64decode

import sys
import struct
import scrypt # py-scrypt (or use hashlib.scrypt or passlib.hash.scrypt)

from nacl.secret import SecretBox # install PyNaCl

#
# Constants
#

SCRYPT_DEFAULT_N = 32768 # 1 << 15 (2^15)
SCRYPT_DEFAULT_P =     1
SCRYPT_DEFAULT_R =     8


#
# Examples
#

# const PAIR = '{"address":"FLiSDPCcJ6auZUGXALLj6jpahcP6adVFDBUQznPXUQ7yoqH","encoded":"ILjSgYaGvq1zaCz/kx+aqfLaHBjLXz0Qsmr6RnkOVU4AgAAAAQAAAAgAAAB5R2hm5kgXyc0NQYFxvMU4zCdjB+ugs/ibEooqCvuudbaeKn3Ee47NkCqU1ecOJV+eeaVn4W4dRvIpj5kGmQOGsewR+MiQ/B0G9NFh7JXV0qcPlk2QMNW1/mbJrTO4miqL448BSkP7ZOhUV6HFUpMt3B9HwjiRLN8RORcFp0ID/Azs4Jl/xOpXNzbgQGIffWgCIKTxN9N1ku6tdlG4","encoding":{"content":["pkcs8","sr25519"],"type":["scrypt","xsalsa20-poly1305"],"version":"3"},"meta":{"genesisHash":"0xb0a8d493285c2df73290dfb7e61f870f17b41801197a149ca93654499ea3dafe","name":"version3","tags":[],"whenCreated":1595277797639,"whenEdited":1595278378596}}';
# PASS3 = "version3";

ENCODED = "ILjSgYaGvq1zaCz/kx+aqfLaHBjLXz0Qsmr6RnkOVU4AgAAAAQAAAAgAAAB5R2hm5kgXyc0NQYFxvMU4zCdjB+ugs/ibEooqCvuudbaeKn3Ee47NkCqU1ecOJV+eeaVn4W4dRvIpj5kGmQOGsewR+MiQ/B0G9NFh7JXV0qcPlk2QMNW1/mbJrTO4miqL448BSkP7ZOhUV6HFUpMt3B9HwjiRLN8RORcFp0ID/Azs4Jl/xOpXNzbgQGIffWgCIKTxN9N1ku6tdlG4"


#
# Start
#

if len (sys.argv) < 2:
  print ("ERROR: Please specify the dict file within the command line", file=sys.stderr)

  sys.exit (1)

fp = None

try:
  fp = open (sys.argv[1])
except:
  print ("ERROR: Could not open dictionary file '%s'" % sys.argv[1], file=sys.stderr)

  sys.exit (1)

raw_data = b64decode (ENCODED)

salt = raw_data[0:32]

scrypt_n = struct.unpack ("<I", raw_data[32:36])[0]
scrypt_p = struct.unpack ("<I", raw_data[36:40])[0]
scrypt_r = struct.unpack ("<I", raw_data[40:44])[0]

if scrypt_n != SCRYPT_DEFAULT_N:
  print ("ERROR: Scrypt N value not valid", file=sys.stderr)

  sys.exit (1)

if scrypt_p != SCRYPT_DEFAULT_P:
  print ("ERROR: Scrypt P value not valid", file=sys.stderr)

  sys.exit (1)

if scrypt_r != SCRYPT_DEFAULT_R:
  print ("ERROR: Scrypt R value not valid", file=sys.stderr)

  sys.exit (1)

offset = 32 + (3 * 4) # 32 byte salt + 3 numbers (N, p, r)

nonce     = raw_data[offset +  0:offset + 24]
encrypted = raw_data[offset + 24:]

cracked = False

password = fp.readline ()

while password:
  key = scrypt.hash (password.strip (), salt, N = SCRYPT_DEFAULT_N, r = SCRYPT_DEFAULT_R, p = SCRYPT_DEFAULT_P, buflen = 32)

  box = SecretBox (key)

  try:
    box.decrypt (encrypted, nonce)

    print ("Password found: '%s'" % password.strip ())

    cracked = True

    break
  except:
    password = fp.readline ()


# Cleanup:

fp.close ()


# Exit codes:

if cracked:
  sys.exit (0)
else:
  sys.exit (1)

(note PyNaCl and scrypt must be installed with python pip or similar)

perl (polkawallet.pl):
Code:
#!/usr/bin/env perl

# Author: philsmd
# Date: July 2021
# License: public domain, credits go to philsmd and hashcat

# Note: NaCl uses XSalsa20 and Poly1305 for decrypting the data.
# Key derivation is done by scrypt (32768, 8, 1)

# only tested with version 3 of a PolkaWallet test wallet

use strict;
use warnings;

use MIME::Base64     qw (decode_base64);
use Crypt::ScryptKDF qw (scrypt_raw);
use Crypt::Sodium    qw (crypto_secretbox_open);
# Unfortunately, Crypt::NaCl::Sodium seems to be outdated (and not compiling)

#
# Constants
#

my $SCRYPT_DEFAULT_N = 32768; # 1 << 15 (2 ^ 15)
my $SCRYPT_DEFAULT_P =     1;
my $SCRYPT_DEFAULT_R =     8;


#
# Examples
#

# const PAIR = '{"address":"FLiSDPCcJ6auZUGXALLj6jpahcP6adVFDBUQznPXUQ7yoqH","encoded":"ILjSgYaGvq1zaCz/kx+aqfLaHBjLXz0Qsmr6RnkOVU4AgAAAAQAAAAgAAAB5R2hm5kgXyc0NQYFxvMU4zCdjB+ugs/ibEooqCvuudbaeKn3Ee47NkCqU1ecOJV+eeaVn4W4dRvIpj5kGmQOGsewR+MiQ/B0G9NFh7JXV0qcPlk2QMNW1/mbJrTO4miqL448BSkP7ZOhUV6HFUpMt3B9HwjiRLN8RORcFp0ID/Azs4Jl/xOpXNzbgQGIffWgCIKTxN9N1ku6tdlG4","encoding":{"content":["pkcs8","sr25519"],"type":["scrypt","xsalsa20-poly1305"],"version":"3"},"meta":{"genesisHash":"0xb0a8d493285c2df73290dfb7e61f870f17b41801197a149ca93654499ea3dafe","name":"version3","tags":[],"whenCreated":1595277797639,"whenEdited":1595278378596}}';
#my $PASS    = "version3";

my $ENCODED = "ILjSgYaGvq1zaCz/kx+aqfLaHBjLXz0Qsmr6RnkOVU4AgAAAAQAAAAgAAAB5R2hm5kgXyc0NQYFxvMU4zCdjB+ugs/ibEooqCvuudbaeKn3Ee47NkCqU1ecOJV+eeaVn4W4dRvIpj5kGmQOGsewR+MiQ/B0G9NFh7JXV0qcPlk2QMNW1/mbJrTO4miqL448BSkP7ZOhUV6HFUpMt3B9HwjiRLN8RORcFp0ID/Azs4Jl/xOpXNzbgQGIffWgCIKTxN9N1ku6tdlG4";


#
# Start
#

my $raw_data = decode_base64 ($ENCODED);

my $salt = substr ($raw_data, 0, 32);

my $scrypt_n = unpack ("I<", substr ($raw_data, 32, 4));
my $scrypt_p = unpack ("I<", substr ($raw_data, 36, 4));
my $scrypt_r = unpack ("I<", substr ($raw_data, 40, 4));

if ($scrypt_n != $SCRYPT_DEFAULT_N)
{
  print STDERR "ERROR: Scrypt N value not valid\n";

  exit (1);
}

if ($scrypt_p != $SCRYPT_DEFAULT_P)
{
  print STDERR "ERROR: Scrypt P value not valid\n";

  exit (1);
}

if ($scrypt_r != $SCRYPT_DEFAULT_R)
{
  print STDERR "ERROR: Scrypt R value not valid\n";

  exit (1);
}

my $nonce     = substr ($raw_data, 32 + (3 * 4) +  0, 24);
my $encrypted = substr ($raw_data, 32 + (3 * 4) + 24);

while (my $pass = <>)
{
  chomp ($pass);

  my $key = scrypt_raw ($pass, $salt, $SCRYPT_DEFAULT_N, $SCRYPT_DEFAULT_R, $SCRYPT_DEFAULT_P, 32);

  my $decrypted = crypto_secretbox_open ($encrypted, $nonce, $key);

  next if (! defined ($decrypted));

  print "Password found: '$pass'\n";

  exit (0);
}

exit (1);

(note Crypt::ScryptKDF and Crypt::Sodium must be installed with perl cpan or similar)

perl with my own xsalsa20 + poly1305 code/explanation of how that works (polkawallet_xsalsa20_poly1305.pl):
Code:
#!/usr/bin/env perl

# Author: philsmd
# Date: July 2021
# License: public domain, credits go to philsmd and hashcat

# Note: NaCl uses XSalsa20 and Poly1305 for decrypting the data.
# Key derivation is done by scrypt (32768, 8, 1)

use strict;
use warnings;

use MIME::Base64     qw (decode_base64);
use Crypt::ScryptKDF qw (scrypt_raw);


#
# Constants
#

my $SCRYPT_DEFAULT_N = 32768; # 1 << 15 (2 ^ 15)
my $SCRYPT_DEFAULT_P =     1;
my $SCRYPT_DEFAULT_R =     8;


#
# Examples
#

# const PAIR = '{"address":"FLiSDPCcJ6auZUGXALLj6jpahcP6adVFDBUQznPXUQ7yoqH","encoded":"ILjSgYaGvq1zaCz/kx+aqfLaHBjLXz0Qsmr6RnkOVU4AgAAAAQAAAAgAAAB5R2hm5kgXyc0NQYFxvMU4zCdjB+ugs/ibEooqCvuudbaeKn3Ee47NkCqU1ecOJV+eeaVn4W4dRvIpj5kGmQOGsewR+MiQ/B0G9NFh7JXV0qcPlk2QMNW1/mbJrTO4miqL448BSkP7ZOhUV6HFUpMt3B9HwjiRLN8RORcFp0ID/Azs4Jl/xOpXNzbgQGIffWgCIKTxN9N1ku6tdlG4","encoding":{"content":["pkcs8","sr25519"],"type":["scrypt","xsalsa20-poly1305"],"version":"3"},"meta":{"genesisHash":"0xb0a8d493285c2df73290dfb7e61f870f17b41801197a149ca93654499ea3dafe","name":"version3","tags":[],"whenCreated":1595277797639,"whenEdited":1595278378596}}';
#my $PASS    = "version3";

my $ENCODED = "ILjSgYaGvq1zaCz/kx+aqfLaHBjLXz0Qsmr6RnkOVU4AgAAAAQAAAAgAAAB5R2hm5kgXyc0NQYFxvMU4zCdjB+ugs/ibEooqCvuudbaeKn3Ee47NkCqU1ecOJV+eeaVn4W4dRvIpj5kGmQOGsewR+MiQ/B0G9NFh7JXV0qcPlk2QMNW1/mbJrTO4miqL448BSkP7ZOhUV6HFUpMt3B9HwjiRLN8RORcFp0ID/Azs4Jl/xOpXNzbgQGIffWgCIKTxN9N1ku6tdlG4";


#
# Helper functions
#

sub rotate
{
  my $x = shift;
  my $o = shift; # offset

  $x &= 0xffffffff;

  return (($x << $o) | ($x >> (32 - $o))) & 0xffffffff;
}

sub u32le_from_bytes
{
  my $x = shift;
  my $o = shift; # offset

  return (ord (substr ($x, $o + 0, 1)) <<  0) |
         (ord (substr ($x, $o + 1, 1)) <<  8) |
         (ord (substr ($x, $o + 2, 1)) << 16) |
         (ord (substr ($x, $o + 3, 1)) << 24);
}

sub u32le_to_bytes
{
  my $x = shift;

  return chr (($x >>  0) & 0xff) .
         chr (($x >>  8) & 0xff) .
         chr (($x >> 16) & 0xff) .
         chr (($x >> 24) & 0xff);
}

sub salsa20_core
{
  my $n = shift; # nonce
  my $k = shift; # key
  my $t = shift; # type

  my $S = "expand 32-byte k"; # SIGMA

  my @x = ();

  $x[ 0] = u32le_from_bytes ($S,  0);
  $x[ 1] = u32le_from_bytes ($k,  0);
  $x[ 2] = u32le_from_bytes ($k,  4);
  $x[ 3] = u32le_from_bytes ($k,  8);
  $x[ 4] = u32le_from_bytes ($k, 12);
  $x[ 5] = u32le_from_bytes ($S,  4);

  $x[ 6] = u32le_from_bytes ($n,  0);
  $x[ 7] = u32le_from_bytes ($n,  4);
  $x[ 8] = u32le_from_bytes ($n,  8);
  $x[ 9] = u32le_from_bytes ($n, 12);

  $x[10] = u32le_from_bytes ($S,  8);
  $x[11] = u32le_from_bytes ($k, 16);
  $x[12] = u32le_from_bytes ($k, 20);
  $x[13] = u32le_from_bytes ($k, 24);
  $x[14] = u32le_from_bytes ($k, 28);
  $x[15] = u32le_from_bytes ($S, 12);

  my @j = ();

  for (my $i = 0; $i < 16; $i++)
  {
    $j[$i] = $x[$i];
  }

  for (my $i = 20; $i > 0; $i -= 2) # 20 rounds
  {
    $x[ 4] ^= rotate ($x[ 0] + $x[12],  7); # don't forget the u32 logical ANDs (& 0xffffffff)
    $x[ 8] ^= rotate ($x[ 4] + $x[ 0],  9);
    $x[12] ^= rotate ($x[ 8] + $x[ 4], 13);
    $x[ 0] ^= rotate ($x[12] + $x[ 8], 18);

    $x[ 9] ^= rotate ($x[ 5] + $x[ 1],  7);
    $x[13] ^= rotate ($x[ 9] + $x[ 5],  9);
    $x[ 1] ^= rotate ($x[13] + $x[ 9], 13);
    $x[ 5] ^= rotate ($x[ 1] + $x[13], 18);

    $x[14] ^= rotate ($x[10] + $x[ 6],  7);
    $x[ 2] ^= rotate ($x[14] + $x[10],  9);
    $x[ 6] ^= rotate ($x[ 2] + $x[14], 13);
    $x[10] ^= rotate ($x[ 6] + $x[ 2], 18);

    $x[ 3] ^= rotate ($x[15] + $x[11],  7);
    $x[ 7] ^= rotate ($x[ 3] + $x[15],  9);
    $x[11] ^= rotate ($x[ 7] + $x[ 3], 13);
    $x[15] ^= rotate ($x[11] + $x[ 7], 18);

    $x[ 1] ^= rotate ($x[ 0] + $x[ 3],  7);
    $x[ 2] ^= rotate ($x[ 1] + $x[ 0],  9);
    $x[ 3] ^= rotate ($x[ 2] + $x[ 1], 13);
    $x[ 0] ^= rotate ($x[ 3] + $x[ 2], 18);

    $x[ 6] ^= rotate ($x[ 5] + $x[ 4],  7);
    $x[ 7] ^= rotate ($x[ 6] + $x[ 5],  9);
    $x[ 4] ^= rotate ($x[ 7] + $x[ 6], 13);
    $x[ 5] ^= rotate ($x[ 4] + $x[ 7], 18);

    $x[11] ^= rotate ($x[10] + $x[ 9],  7);
    $x[ 8] ^= rotate ($x[11] + $x[10],  9);
    $x[ 9] ^= rotate ($x[ 8] + $x[11], 13);
    $x[10] ^= rotate ($x[ 9] + $x[ 8], 18);

    $x[12] ^= rotate ($x[15] + $x[14],  7);
    $x[13] ^= rotate ($x[12] + $x[15],  9);
    $x[14] ^= rotate ($x[13] + $x[12], 13);
    $x[15] ^= rotate ($x[14] + $x[13], 18);
  }

  for (my $i = 0; $i < 16; $i++)
  {
    $x[$i] += $j[$i]; # & 0xffffffff
  }

  if ($t == 1)
  {
    $x[ 0] -= u32le_from_bytes ($S,  0);
    $x[ 5] -= u32le_from_bytes ($S,  4);
    $x[10] -= u32le_from_bytes ($S,  8);
    $x[15] -= u32le_from_bytes ($S, 12);

    $x[ 6] -= u32le_from_bytes ($n,  0);
    $x[ 7] -= u32le_from_bytes ($n,  4);
    $x[ 8] -= u32le_from_bytes ($n,  8);
    $x[ 9] -= u32le_from_bytes ($n, 12);
  }


  # Output:

  my $out = "";

  if ($t == 1)
  {
    $out .= u32le_to_bytes ($x[ 0]);
    $out .= u32le_to_bytes ($x[ 5]);
    $out .= u32le_to_bytes ($x[10]);
    $out .= u32le_to_bytes ($x[15]);

    $out .= u32le_to_bytes ($x[ 6]);
    $out .= u32le_to_bytes ($x[ 7]);
    $out .= u32le_to_bytes ($x[ 8]);
    $out .= u32le_to_bytes ($x[ 9]);
  }
  else
  {
    $out .= u32le_to_bytes ($x[ 0]);
    $out .= u32le_to_bytes ($x[ 1]);
    $out .= u32le_to_bytes ($x[ 2]);
    $out .= u32le_to_bytes ($x[ 3]);

    $out .= u32le_to_bytes ($x[ 4]);
    $out .= u32le_to_bytes ($x[ 5]);
    $out .= u32le_to_bytes ($x[ 6]);
    $out .= u32le_to_bytes ($x[ 7]);
  }

  return $out;
}

sub xsalsa20_subkey
{
  my $nonce = shift;
  my $key1  = shift;

  my $n1 = substr ($nonce,  0, 16);
  my $n2 = substr ($nonce, 16,  8) . "\x00" x 8; # also use last 8 bytes of the nonce

  my $key2 = salsa20_core ($n1, $key1, 1);
  my $out  = salsa20_core ($n2, $key2, 0);

  return $out;
}

sub poly1305_add
{
  my $h = shift; # array pointer
  my $c = shift; # array pointer

  my $u = 0;

  for (my $i = 0; $i < 17; $i++)
  {
    $u = ($u + $$h[$i] + $$c[$i]) & 0xffffffff;

    $$h[$i] = $u & 255;

    $u >>= 8;
  }
}

sub poly1305_calc_verifier
{
  my $m = shift; # message
  my $k = shift; # key

  my $l = length ($m);

  my @PN = (5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 252); # -P

  my @x = (0) x 17;
  my @h = (0) x 17;
  my @c = (0) x 17;
  my @r = (0) x 17;

  for (my $i = 0; $i < 16; $i++)
  {
    $r[$i] = ord (substr ($k, $i, 1));
  }

  $r[ 3] &=  15;
  $r[ 4] &= 252;
  $r[ 7] &=  15;
  $r[ 8] &= 252;
  $r[11] &=  15;
  $r[12] &= 252;
  $r[15] &=  15;

  my $pos = 0;

  while ($l > 0)
  {
    for (my $i = 0; $i < 17; $i++)
    {
      $c[$i] = 0;
    }

    my $z = 0;

    for ($z = 0; ($z < 16) && ($z < $l); $z++)
    {
      $c[$z] = ord (substr ($m, $pos + $z, 1));
    }

    $c[$z] = 1;

    $pos += $z;
    $l   -= $z;

    poly1305_add (\@h, \@c);

    for (my $i = 0; $i < 17; $i++)
    {
      $x[$i] = 0;

      for (my $j = 0; $j < 17; $j++)
      {
        if ($j <= $i)
        {
          $x[$i] += $h[$j] * $r[$i - $j +  0] *   1;
        }
        else
        {
          $x[$i] += $h[$j] * $r[$i - $j + 17] * 320;
        }

        $x[$i] &= 0xffffffff; # needed ? just to be safe
      }
    }

    for (my $i = 0; $i < 17; $i++)
    {
      $h[$i] = $x[$i];
    }

    my $u = 0;

    for (my $i = 0; $i < 16; $i++)
    {
      $u = ($u + $h[$i]) & 0xffffffff;

      $h[$i] = $u & 255;

      $u >>= 8;
    }

    $u = ($u + $h[16]) & 0xffffffff;

    $h[16] = $u & 3;

    $u = (5 * ($u >> 2)) & 0xffffffff;

    for (my $i = 0; $i < 16; $i++)
    {
      $u = ($u + $h[$i]) & 0xffffffff;

      $h[$i] = $u & 255;

      $u >>= 8;
    }

    $u = ($u + $h[16]) & 0xffffffff;

    $h[16] = $u;
  }


  my @g = (0) x 17;

  for (my $i = 0; $i < 17; $i++)
  {
    $g[$i] = $h[$i];
  }

  poly1305_add (\@h, \@PN);


  my $s = -($h[16] >> 7);


  for (my $i = 0; $i < 17; $i++)
  {
    $h[$i] ^= $s & ($g[$i] ^ $h[$i]);
  }


  for (my $i = 0; $i < 16; $i++)
  {
    $c[$i] = ord (substr ($k, $i + 16, 1));
  }

  $c[16] = 0;

  poly1305_add (\@h, \@c);


  # Output:

  my $out = "";

  for (my $i = 0; $i < 16; $i++)
  {
    $out .= chr ($h[$i]);
  }

  return $out;
}

sub poly1305_auth_verify
{
  my $v = shift; # verifier
  my $m = shift; # message
  my $k = shift; # key

  my $x = poly1305_calc_verifier ($m, $k);

  if ($x eq $v)
  {
    return 1; # success
  }

  return 0; # fail
}


#
# Start
#

my $raw_data = decode_base64 ($ENCODED);

my $salt = substr ($raw_data, 0, 32);

my $scrypt_n = unpack ("I<", substr ($raw_data, 32, 4));
my $scrypt_p = unpack ("I<", substr ($raw_data, 36, 4));
my $scrypt_r = unpack ("I<", substr ($raw_data, 40, 4));

if ($scrypt_n != $SCRYPT_DEFAULT_N)
{
  print STDERR "ERROR: Scrypt N value not valid\n";

  exit (1);
}

if ($scrypt_p != $SCRYPT_DEFAULT_P)
{
  print STDERR "ERROR: Scrypt P value not valid\n";

  exit (1);
}

if ($scrypt_r != $SCRYPT_DEFAULT_R)
{
  print STDERR "ERROR: Scrypt R value not valid\n";

  exit (1);
}

my $nonce    = substr ($raw_data, 32 + (3 * 4) +  0, 24);
my $verifier = substr ($raw_data, 32 + (3 * 4) + 24, 16);
my $message  = substr ($raw_data, 32 + (3 * 4) + 40);

while (my $pass = <>)
{
  chomp ($pass);

  my $key = scrypt_raw ($pass, $salt, $SCRYPT_DEFAULT_N, $SCRYPT_DEFAULT_R, $SCRYPT_DEFAULT_P, 32);

  my $subkey = xsalsa20_subkey ($nonce, $key);

  next if (poly1305_auth_verify ($verifier, $message, $subkey) == 0); # 0 means incorrect

  print "Password found: '$pass'\n";

  exit (0);
}

exit (1);

you can run these "cracker" tools like this, for python
Code:
python3 polkawallet.py dict.txt

for perl:
Code:
perl polkawallet.pl dict.txt

the dictionary file (dict.txt) must contain the password (in this case "version3" without quotes works for that specific wallet).

If you want to test/crack another wallet, you need to change the "ENCODED" part with your specific data within the python/perl scripts.

I"m not sure if this specific algorithm should be implemented in hashcat, you can still request it on github, but it's very diffictult to crack and I didn't hear a lot (unitl now) about this wallet, so maybe the interest from other users is very tiny.

Nonetheless, you can still use the crackers/POC above to test thousands up to millions of password candidates that you want to test quite quickly.



update: want to include some sources for interested readers about the algorithm details:
- https://github.com/polkadot-js/common/bl...s.ts#L5-L7
- https://github.com/jedisct1/libsodium/bl...1305.c#L25
- https://github.com/dchest/tweetnacl-js/b...#L259-L260
- https://github.com/dchest/tweetnacl-js/b...cl.js#L186
- https://github.com/neilalexander/jnacl/b...va#L58-L60
- https://stackoverflow.com/questions/6347...-nodejs-12
- https://github.com/dchest/tweetnacl-util...cl-util.js
- https://github.com/neilalexander/jnacl/b...va#L58-L60
- https://github.com/neilalexander/jnacl/b...0.java#L44
- https://github.com/dchest/tweetnacl-js/b...cl.js#L259
- https://github.com/dchest/tweetnacl-js/b...cl.js#L163
Reply


Messages In This Thread
RE: Getting back a password from Polkawallet JSON File - by philsmd - 07-19-2021, 10:53 AM