fix(@desktop/keycard): change db password for a keycard users

DB password for a Keycard user is now `publicKey` of encryption derivation.
kdf iterations for keycard users are set to 256000 so it's the same as we have
for regular users.

Fixes: #8066
This commit is contained in:
Sale Djenic 2022-10-28 13:42:09 +02:00 committed by r4bbit.eth
parent d147d7058e
commit 02d3398fbc
10 changed files with 117 additions and 78 deletions

View File

@ -291,8 +291,11 @@ proc verifyPassword*(self: Controller, password: string): bool =
proc convertSelectedKeyPairToKeycardAccount*(self: Controller, password: string): bool =
if not serviceApplicable(self.accountsService):
return
let acc = self.accountsService.createAccountFromMnemonic(self.getSeedPhrase(), includeEncryption = true)
singletonInstance.localAccountSettings.setStoreToKeychainValue(LS_VALUE_NOT_NOW)
return self.accountsService.convertToKeycardAccount(self.tmpSelectedKeyPairDto.keyUid, password)
return self.accountsService.convertToKeycardAccount(self.tmpSelectedKeyPairDto.keyUid,
currentPassword = password,
newPassword = acc.derivedAccounts.encryption.publicKey)
proc getLoggedInAccount*(self: Controller): AccountDto =
if not serviceApplicable(self.accountsService):

View File

@ -8,6 +8,10 @@ proc newKeyPairMigrateFailureState*(flowType: FlowType, backState: State): KeyPa
proc delete*(self: KeyPairMigrateFailureState) =
self.State.delete
method executePrimaryCommand*(self: KeyPairMigrateFailureState, controller: Controller) =
if self.flowType == FlowType.SetupNewKeycard:
controller.terminateCurrentFlow(lastStepInTheCurrentFlow = true)
method executeTertiaryCommand*(self: KeyPairMigrateFailureState, controller: Controller) =
if self.flowType == FlowType.SetupNewKeycard:
controller.terminateCurrentFlow(lastStepInTheCurrentFlow = true)

View File

@ -272,7 +272,7 @@ proc buildKeyPairsList[T](self: Module[T], excludeAlreadyMigratedPairs: bool): s
locked = false,
name = singletonInstance.userProfile.getName(),
image = singletonInstance.userProfile.getIcon(),
icon = "wallet",
icon = "",
pairType = KeyPairType.Profile,
derivedFrom = a.derivedfrom)
for ga in accounts:

View File

@ -294,36 +294,40 @@ proc importMnemonic*(self: Controller): bool =
self.delegate.importAccountError(error)
return false
proc setupAccount(self: Controller, accountId: string, storeToKeychain: bool, keycardUsage: bool) =
proc setupKeychain(self: Controller, store: bool) =
if store:
singletonInstance.localAccountSettings.setStoreToKeychainValue(LS_VALUE_STORE)
self.storePasswordToKeychain()
else:
singletonInstance.localAccountSettings.setStoreToKeychainValue(LS_VALUE_NEVER)
proc setupAccount(self: Controller, accountId: string, storeToKeychain: bool) =
self.delegate.moveToLoadingAppState()
let error = self.accountsService.setupAccount(accountId, self.tmpPassword, self.tmpDisplayName, keycardUsage)
let error = self.accountsService.setupAccount(accountId, self.tmpPassword, self.tmpDisplayName)
if error != "":
self.delegate.setupAccountError(error)
else:
if storeToKeychain:
singletonInstance.localAccountSettings.setStoreToKeychainValue(LS_VALUE_STORE)
self.storePasswordToKeychain()
else:
singletonInstance.localAccountSettings.setStoreToKeychainValue(LS_VALUE_NEVER)
self.setupKeychain(storeToKeychain)
proc storeGeneratedAccountAndLogin*(self: Controller, storeToKeychain: bool) =
let accounts = self.getGeneratedAccounts()
if accounts.len == 0:
error "list of generated accounts is empty"
return
let accountId = accounts[0].id
self.setupAccount(accountId, storeToKeychain, keycardUsage = false)
self.setupAccount(accountId, storeToKeychain)
proc storeImportedAccountAndLogin*(self: Controller, storeToKeychain: bool) =
let accountId = self.getImportedAccount().id
self.setupAccount(accountId, storeToKeychain, keycardUsage = false)
self.setupAccount(accountId, storeToKeychain)
proc storeKeycardAccountAndLogin*(self: Controller, storeToKeychain: bool) =
if self.importMnemonic():
let accountId = self.getImportedAccount().id
self.delegate.moveToLoadingAppState()
self.delegate.storeKeyPairForNewKeycardUser()
self.storeMetadataForNewKeycardUser()
self.setupAccount(accountId, storeToKeychain, keycardUsage = true)
self.accountsService.setupAccountKeycard(KeycardEvent(), useImportedAcc = true)
self.setupKeychain(storeToKeychain)
else:
error "an error ocurred while importing mnemonic"
@ -334,12 +338,8 @@ proc setupKeycardAccount*(self: Controller, storeToKeychain: bool) =
else:
self.delegate.moveToLoadingAppState()
self.delegate.storeKeyPairForNewKeycardUser()
self.accountsService.setupAccountKeycard(self.tmpKeycardEvent)
if storeToKeychain:
singletonInstance.localAccountSettings.setStoreToKeychainValue(LS_VALUE_STORE)
self.storePasswordToKeychain()
else:
singletonInstance.localAccountSettings.setStoreToKeychainValue(LS_VALUE_NEVER)
self.accountsService.setupAccountKeycard(self.tmpKeycardEvent, useImportedAcc = false)
self.setupKeychain(storeToKeychain)
proc getOpenedAccounts*(self: Controller): seq[AccountDto] =
return self.accountsService.openedAccounts()

View File

@ -12,5 +12,5 @@ const PATH_EIP_1581* = "m/43'/60'/1581'"
const PATH_DEFAULT_WALLET* = PATH_WALLET_ROOT & "/0"
# EIP1581 Chat Key 0, the default whisper key
const PATH_WHISPER* = PATH_EIP_1581 & "/0'/0"
# EIP1581 Encryption Key
const PATH_ENCRYPTION* = PATH_EIP_1581 & "/1'/0"

View File

@ -7,6 +7,7 @@ import ../../../common/account_constants
include ../../../common/[json_utils]
type DerivedAccountDetails* = object
privateKey*: string
publicKey*: string
address*: string
derivationPath*: string
@ -16,9 +17,11 @@ type DerivedAccounts* = object
walletRoot*: DerivedAccountDetails
defaultWallet*: DerivedAccountDetails
eip1581*: DerivedAccountDetails
encryption*: DerivedAccountDetails
type GeneratedAccountDto* = object
id*: string
privateKey*: string
publicKey*: string
address*: string
keyUid*: string
@ -37,6 +40,7 @@ proc toDerivedAccountDetails(jsonObj: JsonNode, derivationPath: string):
# handle it a bit different.
result = DerivedAccountDetails()
result.derivationPath = derivationPath
discard jsonObj.getProp("privateKey", result.privateKey)
discard jsonObj.getProp("publicKey", result.publicKey)
discard jsonObj.getProp("address", result.address)
@ -51,10 +55,13 @@ proc toDerivedAccounts*(jsonObj: JsonNode): DerivedAccounts =
result.defaultWallet = toDerivedAccountDetails(derivedObj, derivationPath)
elif(derivationPath == PATH_EIP_1581):
result.eip1581 = toDerivedAccountDetails(derivedObj, derivationPath)
elif(derivationPath == PATH_ENCRYPTION):
result.encryption = toDerivedAccountDetails(derivedObj, derivationPath)
proc toGeneratedAccountDto*(jsonObj: JsonNode): GeneratedAccountDto =
result = GeneratedAccountDto()
discard jsonObj.getProp("id", result.id)
discard jsonObj.getProp("privateKey", result.privateKey)
discard jsonObj.getProp("publicKey", result.publicKey)
discard jsonObj.getProp("address", result.address)
discard jsonObj.getProp("keyUid", result.keyUid)

View File

@ -21,7 +21,7 @@ export dto_generated_accounts
logScope:
topics = "accounts-service"
const PATHS = @[PATH_WALLET_ROOT, PATH_EIP_1581, PATH_WHISPER, PATH_DEFAULT_WALLET]
const PATHS = @[PATH_WALLET_ROOT, PATH_EIP_1581, PATH_WHISPER, PATH_DEFAULT_WALLET, PATH_ENCRYPTION]
const ACCOUNT_ALREADY_EXISTS_ERROR = "account already exists"
const output_csv {.booldefine.} = false
const KDF_ITERATIONS* {.intdefine.} = 256_000
@ -336,18 +336,10 @@ proc addKeycardDetails(self: Service, settingsJson: var JsonNode, accountData: v
if not accountData.isNil:
accountData["keycard-pairing"] = kcDataObj{"key"}
proc setupAccount*(self: Service, accountId, password, displayName: string, keycardUsage: bool): string =
proc setupAccount*(self: Service, accountId, password, displayName: string): string =
try:
let installationId = $genUUID()
var accountDataJson = self.getAccountDataForAccountId(accountId, displayName)
var usedPassword = password
if password.len == 0:
# this means we're setting up an account using keycard
usedPassword = accountDataJson{"key-uid"}.getStr
self.setKeyStoreDir(accountDataJson{"key-uid"}.getStr)
let subaccountDataJson = self.getSubaccountDataForAccountId(accountId, displayName)
var settingsJson = self.getAccountSettings(accountId, installationId, displayName)
let nodeConfigJson = self.getDefaultNodeConfig(installationId)
@ -358,15 +350,16 @@ proc setupAccount*(self: Service, accountId, password, displayName: string, keyc
error "error: ", procName="setupAccount", errDesription = description
return description
let hashedPassword = hashString(usedPassword)
self.setKeyStoreDir(accountDataJson{"key-uid"}.getStr)
let hashedPassword = hashString(password)
discard self.storeAccount(accountId, hashedPassword)
discard self.storeDerivedAccounts(accountId, hashedPassword, PATHS)
if keycardUsage:
self.addKeycardDetails(settingsJson, accountDataJson)
self.loggedInAccount = self.saveAccountAndLogin(hashedPassword,
accountDataJson,
subaccountDataJson,
settingsJson,
nodeConfigJson)
self.loggedInAccount = self.saveAccountAndLogin(hashedPassword, accountDataJson,
subaccountDataJson, settingsJson, nodeConfigJson)
self.setLocalAccountSettingsFile()
if self.getLoggedInAccount.isValid():
@ -377,16 +370,40 @@ proc setupAccount*(self: Service, accountId, password, displayName: string, keyc
error "error: ", procName="setupAccount", errName = e.name, errDesription = e.msg
return e.msg
proc setupAccountKeycard*(self: Service, keycardData: KeycardEvent) =
proc setupAccountKeycard*(self: Service, keycardData: KeycardEvent, useImportedAcc: bool) =
try:
let installationId = $genUUID()
var keyUid = keycardData.keyUid
var address = keycardData.masterKey.address
var whisperPrivateKey = keycardData.whisperKey.privateKey
var whisperPublicKey = keycardData.whisperKey.publicKey
var whisperAddress = keycardData.whisperKey.address
var walletPublicKey = keycardData.walletKey.publicKey
var walletAddress = keycardData.walletKey.address
var walletRootAddress = keycardData.walletRootKey.address
var eip1581Address = keycardData.eip1581Key.address
var encryptionPublicKey = keycardData.encryptionKey.publicKey
if useImportedAcc:
keyUid = self.importedAccount.keyUid
address = self.importedAccount.address
whisperPublicKey = self.importedAccount.derivedAccounts.whisper.publicKey
whisperAddress = self.importedAccount.derivedAccounts.whisper.address
walletPublicKey = self.importedAccount.derivedAccounts.defaultWallet.publicKey
walletAddress = self.importedAccount.derivedAccounts.defaultWallet.address
walletRootAddress = self.importedAccount.derivedAccounts.walletRoot.address
eip1581Address = self.importedAccount.derivedAccounts.eip1581.address
encryptionPublicKey = self.importedAccount.derivedAccounts.encryption.publicKey
let alias = generateAliasFromPk(keycardData.whisperKey.publicKey)
whisperPrivateKey = self.importedAccount.derivedAccounts.whisper.privateKey
if whisperPrivateKey.startsWith("0x"):
whisperPrivateKey = whisperPrivateKey[2 .. ^1]
let installationId = $genUUID()
let alias = generateAliasFromPk(whisperPublicKey)
let openedAccounts = self.openedAccounts()
var displayName: string
for acc in openedAccounts:
if acc.keyUid == keycardData.keyUid:
if acc.keyUid == keyUid:
displayName = acc.name
break
if displayName.len == 0:
@ -395,26 +412,27 @@ proc setupAccountKeycard*(self: Service, keycardData: KeycardEvent) =
var accountDataJson = %* {
"name": alias,
"display-name": displayName,
"address": keycardData.masterKey.address,
"key-uid": keycardData.keyUid
"address": address,
"key-uid": keyUid,
"kdfIterations": KDF_ITERATIONS,
}
self.setKeyStoreDir(keycardData.keyUid)
self.setKeyStoreDir(keyUid)
let nodeConfigJson = self.getDefaultNodeConfig(installationId)
let subaccountDataJson = %* [
{
"public-key": keycardData.walletKey.publicKey,
"address": keycardData.walletKey.address,
"public-key": walletPublicKey,
"address": walletAddress,
"color": "#4360df",
"wallet": true,
"path": PATH_DEFAULT_WALLET,
"name": "Status account",
"derived-from": keycardData.masterKey.address,
"derived-from": address,
"emoji": self.defaultWalletEmoji,
},
{
"public-key": keycardData.whisperKey.publicKey,
"address": keycardData.whisperKey.address,
"public-key": whisperPublicKey,
"address": whisperAddress,
"name": alias,
"path": PATH_WHISPER,
"chat": true,
@ -423,14 +441,14 @@ proc setupAccountKeycard*(self: Service, keycardData: KeycardEvent) =
]
var settingsJson = %* {
"key-uid": keycardData.keyUid,
"public-key": keycardData.whisperKey.publicKey,
"key-uid": keyUid,
"public-key": whisperPublicKey,
"name": alias,
"display-name": "",
"address": keycardData.whisperKey.address,
"eip1581-address": keycardData.eip1581Key.address,
"dapps-address": keycardData.walletKey.address,
"wallet-root-address": keycardData.walletRootKey.address,
"address": whisperAddress,
"eip1581-address": eip1581Address,
"dapps-address": walletAddress,
"wallet-root-address": walletRootAddress,
"preview-privacy?": true,
"signing-phrase": generateSigningPhrase(3),
"log-level": $LogLevel.INFO,
@ -443,7 +461,7 @@ proc setupAccountKeycard*(self: Service, keycardData: KeycardEvent) =
"appearance": 0,
"installation-id": installationId,
"current-user-status": {
"publicKey": keycardData.whisperKey.publicKey,
"publicKey": whisperPublicKey,
"statusType": 1,
"clock": 0,
"text": ""
@ -458,10 +476,8 @@ proc setupAccountKeycard*(self: Service, keycardData: KeycardEvent) =
error "error: ", procName="setupAccountKeycard", errDesription = description
return
let hashedPassword = hashString(keycardData.keyUid) # using hashed keyUid as password
self.loggedInAccount = self.saveKeycardAccountAndLogin(keycardData.whisperKey.privateKey,
hashedPassword,
self.loggedInAccount = self.saveKeycardAccountAndLogin(chatKey = whisperPrivateKey,
password = encryptionPublicKey,
accountDataJson,
subaccountDataJson,
settingsJson,
@ -470,15 +486,27 @@ proc setupAccountKeycard*(self: Service, keycardData: KeycardEvent) =
except Exception as e:
error "error: ", procName="setupAccount", errName = e.name, errDesription = e.msg
proc createAccountFromMnemonic*(self: Service, mnemonic: string): GeneratedAccountDto =
proc createAccountFromMnemonic*(self: Service, mnemonic: string, includeEncryption = false, includeWhisper = false,
includeRoot = false, includeDefaultWallet = false, includeEip1581 = false): GeneratedAccountDto =
if mnemonic.len == 0:
error "empty mnemonic"
return
var paths: seq[string]
if includeEncryption:
paths.add(PATH_ENCRYPTION)
if includeWhisper:
paths.add(PATH_WHISPER)
if includeRoot:
paths.add(PATH_WALLET_ROOT)
if includeDefaultWallet:
paths.add(PATH_DEFAULT_WALLET)
if includeEip1581:
paths.add(PATH_EIP_1581)
try:
let response = status_account.createAccountFromMnemonic(mnemonic)
let response = status_account.createAccountFromMnemonicAndDeriveAccountsForPaths(mnemonic, paths)
return toGeneratedAccountDto(response.result)
except Exception as e:
error "error: ", procName="createAccountFromMnemonic", errName = e.name, errDesription = e.msg
error "error: ", procName="createAccountFromMnemonicAndDeriveAccountsForPaths", errName = e.name, errDesription = e.msg
proc importMnemonic*(self: Service, mnemonic: string): string =
if mnemonic.len == 0:
@ -609,10 +637,8 @@ proc loginAccountKeycard*(self: Service, keycardData: KeycardEvent): string =
var settingsJson: JsonNode
self.addKeycardDetails(settingsJson, accountDataJson)
let hashedPassword = hashString(keycardData.keyUid) # using hashed keyUid as password
let response = status_account.loginWithKeycard(keycardData.whisperKey.privateKey,
hashedPassword,
keycardData.encryptionKey.publicKey,
accountDataJson)
var error = "response doesn't contain \"error\""
@ -642,7 +668,7 @@ proc verifyAccountPassword*(self: Service, account: string, password: string): b
error "error: ", procName="verifyAccountPassword", errName = e.name, errDesription = e.msg
proc convertToKeycardAccount*(self: Service, keyUid: string, password: string): bool =
proc convertToKeycardAccount*(self: Service, keyUid: string, currentPassword: string, newPassword: string): bool =
try:
var accountDataJson = %* {
"name": self.getLoggedInAccount().name,
@ -659,11 +685,9 @@ proc convertToKeycardAccount*(self: Service, keyUid: string, password: string):
error "error: ", procName="convertToKeycardAccount", errDesription = description
return
let hashedCurrentPassword = hashString(password)
let hashedNewPassword = hashString(keyUid)
let response = status_account.convertToKeycardAccount(self.keyStoreDir, accountDataJson, settingsJson, hashedCurrentPassword,
hashedNewPassword)
let hashedCurrentPassword = hashString(currentPassword)
let response = status_account.convertToKeycardAccount(self.keyStoreDir, accountDataJson, settingsJson,
hashedCurrentPassword, newPassword)
if(response.result.contains("error")):
let errMsg = response.result["error"].getStr

View File

@ -134,17 +134,18 @@ proc multiAccountImportMnemonic*(mnemonic: string): RpcResponse[JsonNode] {.rais
error "error doing rpc request", methodName = "multiAccountImportMnemonic", exception=e.msg
raise newException(RpcException, e.msg)
proc createAccountFromMnemonic*(mnemonic: string): RpcResponse[JsonNode] {.raises: [Exception].} =
proc createAccountFromMnemonicAndDeriveAccountsForPaths*(mnemonic: string, paths: seq[string]): RpcResponse[JsonNode] {.raises: [Exception].} =
let payload = %* {
"mnemonicPhrase": mnemonic,
"paths": paths,
"Bip39Passphrase": ""
}
try:
let response = status_go.createAccountFromMnemonic($payload)
let response = status_go.createAccountFromMnemonicAndDeriveAccountsForPaths($payload)
result.result = Json.decode(response, JsonNode)
except RpcException as e:
error "error doing rpc request", methodName = "createAccountFromMnemonic", exception=e.msg
error "error doing rpc request", methodName = "createAccountFromMnemonicAndDeriveAccountsForPaths", exception=e.msg
raise newException(RpcException, e.msg)
proc deriveAccounts*(accountId: string, paths: seq[string]): RpcResponse[JsonNode] {.raises: [Exception].} =

@ -1 +1 @@
Subproject commit 00a352da93cef3010dd6c213b87a66ce1d9cad01
Subproject commit 7be103a29b321e5593dda29529bad6368dccc0ba

2
vendor/status-go vendored

@ -1 +1 @@
Subproject commit 956534210111815202ba001bbc69a3411ebbb429
Subproject commit caa20e616e7dc8422faa25fd95a62287ca3103a8