16, 'r' => 1, 'p' => 1]); $this->assertSame($phrase, EthKeystore::decrypt($utc, $password)); $this->assertNull(EthKeystore::decrypt($utc, 'wrong')); } #[Test] public function pbkdf2_aes_ctr_unlocks_utf8_password(): void { $phrase = 'abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon about'; $password = 'imtoken-utf8-demo'; $salt = random_bytes(32); $iv = random_bytes(16); $derived = hash_pbkdf2('sha256', $password, $salt, 16, 32, true); $ciphertext = openssl_encrypt($phrase, 'aes-128-ctr', substr($derived, 0, 16), OPENSSL_RAW_DATA, $iv); $this->assertIsString($ciphertext); $utc = [ 'version' => 3, 'crypto' => [ 'cipher' => 'aes-128-ctr', 'cipherparams' => ['iv' => bin2hex($iv)], 'ciphertext' => bin2hex($ciphertext), 'kdf' => 'pbkdf2', 'kdfparams' => [ 'c' => 16, 'dklen' => 32, 'prf' => 'hmac-sha256', 'salt' => bin2hex($salt), ], 'mac' => bin2hex(hex2bin(\kornrunner\Keccak::hash(substr($derived, 16, 16).$ciphertext, 256))), ], ]; $this->assertSame($phrase, EthKeystore::decrypt($utc, $password)); $this->assertNull(EthKeystore::decrypt($utc, 'wrong')); $decrypt = new DsKeystoreDecrypt; $this->assertSame($phrase, $decrypt->unlock($utc, [$password])); } #[Test] public function ds_unlock_accepts_keychain_hex_blob(): void { $phrase = 'abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon about'; $password = hex2bin('22d5cb2accb78f1e9d0a2c89d5d1af815fa96b1b8667548b39c75722c11e4ec2'); $this->assertIsString($password); $utc = EthKeystore::encrypt($phrase, $password, ['n' => 16, 'r' => 8, 'p' => 1]); $decrypt = new DsKeystoreDecrypt; $got = $decrypt->unlock($utc, $decrypt->collectPasswords([ 'wallets' => [ 'trustwallet' => [ 'items' => [[ 'account' => 'trustwalletUTC--demo', 'dataHex' => bin2hex($password), ]], ], ], ])); $this->assertSame($phrase, $got); } #[Test] public function python_scrypt_high_n_roundtrip(): void { if (! EthKeystore::scryptReady()) { $this->markTestSkipped('python3 hashlib/pycryptodome scrypt is unavailable'); } $phrase = 'abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon about'; $password = random_bytes(32); $utc = EthKeystore::encrypt($phrase, $password, ['n' => 256, 'r' => 8, 'p' => 1]); $this->assertSame($phrase, EthKeystore::decrypt($utc, $password)); } #[Test] public function aes_256_ctr_unlocks_with_walletcore_mac(): void { $phrase = 'abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon about'; $password = 'trust-aes256'; $salt = random_bytes(32); $iv = random_bytes(16); $derived = hash_pbkdf2('sha256', $password, $salt, 16, 32, true); $ciphertext = openssl_encrypt($phrase, 'aes-256-ctr', $derived, OPENSSL_RAW_DATA, $iv); $this->assertIsString($ciphertext); $utc = [ 'version' => 3, 'crypto' => [ 'cipher' => 'aes-256-ctr', 'cipherparams' => ['iv' => bin2hex($iv)], 'ciphertext' => bin2hex($ciphertext), 'kdf' => 'pbkdf2', 'kdfparams' => [ 'c' => 16, 'dklen' => 32, 'prf' => 'hmac-sha256', 'salt' => bin2hex($salt), ], 'mac' => bin2hex(hex2bin(\kornrunner\Keccak::hash($derived.$ciphertext, 256))), ], ]; $this->assertSame($phrase, EthKeystore::decrypt($utc, $password)); } #[Test] public function unlock_accepts_json_mnemonic_payload(): void { $phrase = 'abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon about'; $password = 'json-payload'; $utc = EthKeystore::encrypt(json_encode(['mnemonic' => $phrase]), $password, ['n' => 16, 'r' => 1, 'p' => 1]); $decrypt = new DsKeystoreDecrypt; $this->assertSame($phrase, $decrypt->unlock($utc, [$password])); } #[Test] public function bitpie_entropy_ascii_hex_unlocks_phrase(): void { $phrase = 'abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon about'; $decrypt = new DsKeystoreDecrypt; $hexes = $decrypt->collectBitpieEntropyHex([ 'wallets' => [ 'bitpie' => [ 'items' => [[ 'account' => 'seedPhraseEntropy', 'dataHex' => bin2hex('00000000000000000000000000000000'), ]], ], ], ]); $this->assertSame(['00000000000000000000000000000000'], $hexes); $this->assertNotSame('', $phrase); } #[Test] public function bitpie_addresses_ignore_base64_noise(): void { $phrase = 'abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon about'; $trx = app(\App\Services\Chain\TronDriver::class)->deriveAddress($phrase, 0); $decrypt = new DsKeystoreDecrypt; $rows = $decrypt->collectBitpieAddresses([ 'wallets' => [ 'trustwallet' => [ 'items' => [[ 'account' => 'trustwalletUTC--demo', 'dataHex' => bin2hex('TVGWDRNV1dNRTNTR1JXR1kzNUdaSFgzNUJ'), ]], ], 'bitpie' => [ 'items' => [[ 'account' => 'userAddressKey', 'dataHex' => bin2hex($trx), ]], ], ], 'sandbox' => [ 'bitpie' => [ 'Library/Preferences/com.bitpie.wallet.plist' => base64_encode( 'kUserAddressesConfigure[{"address":"'.$trx.'","coin_code":"trx-trx"}] TVGWDRNV1dNRTNTR1JXR1kzNUdaSFgzNUJ' ), ], ], ]); $addrs = array_values(array_unique(array_column($rows, 'address'))); $this->assertSame([$trx], $addrs); } }