Skip to content
This repository has been archived by the owner on Apr 17, 2023. It is now read-only.

Use long derivation paths for App Private Keys (courtesy of blockstack.js) #1496

Open
wants to merge 9 commits into
base: develop
Choose a base branch
from
1 change: 1 addition & 0 deletions .flowconfig
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
.*/node_modules/immutable/*
.*/blockstack.js/node_modules/*
.*/blockstack.js/src/*
.*/blockstack.js/.git/*
.*/tmp/nexe/*
.*/node_modules/styled-components/.*
.*/node_modules/.*
Expand Down
11 changes: 4 additions & 7 deletions app/js/UpdateStatePage.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,11 @@ import React, { Component } from 'react'
import Modal from 'react-modal'
import { bindActionCreators } from 'redux'
import { connect } from 'react-redux'
import { decryptMnemonic } from 'blockstack'
import Alert from './components/Alert'
import InputGroup from './components/InputGroup'
import { AccountActions } from './account/store/account'
import { IdentityActions } from './profiles/store/identity'
import { decrypt } from './utils'
import {
CURRENT_VERSION,
updateState,
Expand Down Expand Up @@ -138,21 +138,18 @@ class UpdateStatePage extends Component {



upgradeBlockstackState(event) {
upgradeBlockstackState(event) {
logger.trace('upgradeBlockstackState')
event.preventDefault()
this.setState({ upgradeInProgress: true })
//
// number of identities to generate
// default identity
// copy api settings

const { encryptedBackupPhrase } = this.props
const { password } = this.state

const dataBuffer = new Buffer(encryptedBackupPhrase, 'hex')
const password = this.state.password

decrypt(dataBuffer, password)
decryptMnemonic(encryptedBackupPhrase, password)
.then(backupPhraseBuffer => {
const backupPhrase = backupPhraseBuffer.toString()
logger.debug('upgradeBlockstackState: correct password!')
Expand Down
7 changes: 2 additions & 5 deletions app/js/account/BackupAccountPage.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,10 @@ import { connect } from 'react-redux'
import { bindActionCreators } from 'redux'
import bip39 from 'bip39'
import { HDNode } from 'bitcoinjs-lib'
import { decryptMnemonic } from 'blockstack'

import Alert from '@components/Alert'
import InputGroup from '@components/InputGroup'
import { decrypt } from '@utils'
import log4js from 'log4js'

import { AccountActions } from './store/account'
Expand Down Expand Up @@ -63,11 +63,8 @@ class BackupAccountPage extends Component {

decryptBackupPhrase() {
logger.trace('decryptBackupPhrase')

const password = this.state.password
const dataBuffer = new Buffer(this.props.encryptedBackupPhrase, 'hex')
logger.debug('Trying to decrypt recovery phrase...')
decrypt(dataBuffer, password).then(
decryptMnemonic(this.props.encryptedBackupPhrase, this.state.password).then(
plaintextBuffer => {
logger.debug('Keychain phrase successfully decrypted')
this.updateAlert('success', 'Keychain phrase decrypted')
Expand Down
6 changes: 3 additions & 3 deletions app/js/account/ChangePasswordPage.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,11 @@ import PropTypes from 'prop-types'
import React, { Component } from 'react'
import { bindActionCreators } from 'redux'
import { connect } from 'react-redux'
import { encryptMnemonic, decryptMnemonic } from 'blockstack'

import Alert from '@components/Alert'
import InputGroup from '@components/InputGroup'
import { AccountActions } from './store/account'
import { decrypt, encrypt } from '@utils'
import log4js from 'log4js'

const logger = log4js.getLogger('account/ChangePasswordPage.js')
Expand Down Expand Up @@ -67,7 +67,7 @@ class ChangePasswordPage extends Component {
const newPassword2 = this.state.newPassword2
const dataBuffer = new Buffer(this.props.encryptedBackupPhrase, 'hex')
logger.debug('Trying to decrypt recovery phrase...')
decrypt(dataBuffer, currentPassword).then(
decryptMnemonic(dataBuffer, currentPassword).then(
plaintextBuffer => {
logger.debug('Recovery phrase successfully decrypted')
if (newPassword.length < 8) {
Expand All @@ -77,7 +77,7 @@ class ChangePasswordPage extends Component {
this.updateAlert('danger', 'New passwords must match')
} else {
logger.debug('Trying to re-encrypt recovery phrase with new password...')
encrypt(plaintextBuffer, newPassword).then(ciphertextBuffer => {
encryptMnemonic(plaintextBuffer, newPassword).then(ciphertextBuffer => {
this.props.updateBackupPhrase(ciphertextBuffer.toString('hex'))
this.updateAlert('success', 'Password updated!')
this.setState({
Expand Down
31 changes: 15 additions & 16 deletions app/js/account/store/account/actions.js
Original file line number Diff line number Diff line change
@@ -1,16 +1,13 @@
import { HDNode } from 'bitcoinjs-lib'
import bip39 from 'bip39'
import { randomBytes } from 'crypto'
import {
authorizationHeaderValue,
btcToSatoshis,
satoshisToBtc,
encrypt,
getInsightUrls,
getBlockchainIdentities
} from '@utils'
import { isCoreEndpointDisabled } from '@utils/window-utils'
import { transactions, config, network } from 'blockstack'
import { transactions, config, network, BlockstackWallet } from 'blockstack'

import roundTo from 'round-to'
import * as types from './types'
Expand All @@ -31,7 +28,7 @@ const updateEmail = email => dispatch =>

function createAccount(
encryptedBackupPhrase,
masterKeychain,
keychainB58,
identitiesToGenerate
) {
logger.debug(`createAccount: identitiesToGenerate: ${identitiesToGenerate}`)
Expand All @@ -42,7 +39,7 @@ function createAccount(
firstBitcoinAddress,
identityAddresses,
identityKeypairs
} = getBlockchainIdentities(masterKeychain, identitiesToGenerate)
} = getBlockchainIdentities(keychainB58, identitiesToGenerate)

return {
type: types.CREATE_ACCOUNT,
Expand Down Expand Up @@ -449,20 +446,22 @@ const initializeWallet = (
let masterKeychain = null
if (backupPhrase && bip39.validateMnemonic(backupPhrase)) {
const seedBuffer = bip39.mnemonicToSeed(backupPhrase)
masterKeychain = HDNode.fromSeedBuffer(seedBuffer)
masterKeychain = BlockstackWallet.fromSeedBuffer(seedBuffer)
.toBase58()
} else {
// Create a new wallet
const STRENGTH = 128 // 128 bits generates a 12 word mnemonic
backupPhrase = bip39.generateMnemonic(STRENGTH, randomBytes)
backupPhrase = BlockstackWallet.generateMnemonic()
const seedBuffer = bip39.mnemonicToSeed(backupPhrase)
masterKeychain = HDNode.fromSeedBuffer(seedBuffer)
masterKeychain = BlockstackWallet.fromSeedBuffer(seedBuffer)
.toBase58()
}
return encrypt(new Buffer(backupPhrase), password).then(ciphertextBuffer => {
const encryptedBackupPhrase = ciphertextBuffer.toString('hex')
return dispatch(
createAccount(encryptedBackupPhrase, masterKeychain, identitiesToGenerate)
)
})
return BlockstackWallet.encryptMnemonic(backupPhrase, password)
.then(ciphertextBuffer => {
const encryptedBackupPhrase = ciphertextBuffer.toString('hex')
return dispatch(
createAccount(encryptedBackupPhrase, masterKeychain, identitiesToGenerate)
)
})
}

function newBitcoinAddress() {
Expand Down
9 changes: 4 additions & 5 deletions app/js/account/store/account/reducer.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import * as types from './types'
import { HDNode } from 'bitcoinjs-lib'
import { getBitcoinAddressNode } from '@utils'
import { BlockstackWallet } from 'blockstack'

const initialState = {
accountCreated: false, // persist
Expand Down Expand Up @@ -86,10 +85,10 @@ function AccountReducer(state = initialState, action) {
publicKeychain: state.bitcoinAccount.publicKeychain,
addresses: [
...state.bitcoinAccount.addresses,
getBitcoinAddressNode(
HDNode.fromBase58(state.bitcoinAccount.publicKeychain),
BlockstackWallet.getAddressFromBitcoinKeychain(
state.bitcoinAccount.publicKeychain,
state.bitcoinAccount.addressIndex + 1
).getAddress()
)
],
addressIndex: state.bitcoinAccount.addressIndex + 1,
balances: state.bitcoinAccount.balances
Expand Down
8 changes: 4 additions & 4 deletions app/js/auth/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,13 +13,12 @@ import {
getAppBucketUrl,
isLaterVersion
} from 'blockstack'
import { AppsNode } from '@utils/account-utils'
import { getCorrectAppPrivateKey } from '@utils/account-utils'
import {
fetchProfileLocations,
getDefaultProfileUrl
} from '@utils/profile-utils'
import { getTokenFileUrlFromZoneFile } from '@utils/zone-utils'
import { HDNode } from 'bitcoinjs-lib'
import log4js from 'log4js'
import { uploadProfile } from '../account/utils'
import { signProfileForUpload } from '@utils'
Expand Down Expand Up @@ -209,8 +208,9 @@ class AuthPage extends React.Component {
const privateKey = profileSigningKeypair.key
const appsNodeKey = profileSigningKeypair.appsNodeKey
const salt = profileSigningKeypair.salt
const appsNode = new AppsNode(HDNode.fromBase58(appsNodeKey), salt)
const appPrivateKey = appsNode.getAppNode(appDomain).getAppPrivateKey()

const appPrivateKey = getCorrectAppPrivateKey(this.state.scopes, profile, appsNodeKey,
salt, appDomain)

let profileUrlPromise

Expand Down
25 changes: 6 additions & 19 deletions app/js/profiles/store/identity/actions.js
Original file line number Diff line number Diff line change
@@ -1,14 +1,9 @@
// @flow
import { HDNode } from 'bitcoinjs-lib'
import bip39 from 'bip39'
import * as types from './types'
import { validateProofs } from 'blockstack'
import { validateProofs, decryptMnemonic, BlockstackWallet } from 'blockstack'
import {
authorizationHeaderValue,
decrypt,
deriveIdentityKeyPair,
getIdentityOwnerAddressNode,
getIdentityPrivateKeychain,
resolveZoneFileToProfile
} from '@utils/index'
import { DEFAULT_PROFILE, fetchProfileLocations } from '@utils/profile-utils'
Expand Down Expand Up @@ -221,25 +216,17 @@ function createNewProfile(
dispatch({ type: types.CREATE_NEW_REQUEST })

// Decrypt master keychain
const dataBuffer = new Buffer(encryptedBackupPhrase, 'hex')
logger.debug('createNewProfile: Trying to decrypt backup phrase...')
return decrypt(dataBuffer, password).then(
return decryptMnemonic(encryptedBackupPhrase, password).then(
plaintextBuffer => {
logger.debug('createNewProfile: Backup phrase successfully decrypted')
const backupPhrase = plaintextBuffer.toString()
const seedBuffer = bip39.mnemonicToSeed(backupPhrase)
const masterKeychain = HDNode.fromSeedBuffer(seedBuffer)
const identityPrivateKeychainNode = getIdentityPrivateKeychain(
masterKeychain
)
const wallet = BlockstackWallet.fromSeedBuffer(seedBuffer)

const index = nextUnusedAddressIndex
const identityOwnerAddressNode = getIdentityOwnerAddressNode(
identityPrivateKeychainNode,
index
)
const newIdentityKeypair = deriveIdentityKeyPair(
identityOwnerAddressNode
)
const newIdentityKeypair = wallet.getIdentityKeyPair(index, true)

logger.debug(
`createNewProfile: new identity: ${newIdentityKeypair.address}`
)
Expand Down
4 changes: 2 additions & 2 deletions app/js/seed/index.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import React, { Component } from 'react'
import PropTypes from 'prop-types'
import { decryptMnemonic } from 'blockstack'
import { Initial, Password, Seed, SeedConfirm, Success } from './views'
import { decrypt } from '@utils/encryption-utils'
import { withRouter, browserHistory } from 'react-router'
import { connect } from 'react-redux'
import { bindActionCreators } from 'redux'
Expand Down Expand Up @@ -144,7 +144,7 @@ class SeedContainer extends Component {

const buffer = new Buffer(encryptedBackupPhrase, method)

return decrypt(buffer, password).then(result => {
return decryptMnemonic(buffer, password).then(result => {
if (this.state.seed !== result.toString()) {
return this.setState(
{
Expand Down
8 changes: 4 additions & 4 deletions app/js/sign-in/index.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import React from 'react'
import PropTypes from 'prop-types'
import { decryptMnemonic } from 'blockstack'
import { isBackupPhraseValid } from '@utils'
import { validateMnemonic } from 'bip39'
import { decrypt, isBackupPhraseValid } from '@utils'
import { browserHistory, withRouter } from 'react-router'
import { connect } from 'react-redux'
import { bindActionCreators } from 'redux'
Expand Down Expand Up @@ -169,7 +170,7 @@ class SignIn extends React.Component {
if (this.state.decrypt && !decrypting) {
this.setState({ decrypting: true })

decrypt(
decryptMnemonic(
new Buffer(encryptedKey, 'base64'),
this.state.password
)
Expand All @@ -190,8 +191,7 @@ class SignIn extends React.Component {
key: ''
})
})
}
else {
} else {
this.updateView(VIEWS.EMAIL)
}
}
Expand Down
6 changes: 2 additions & 4 deletions app/js/update/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import PropTypes from 'prop-types'
import { withRouter, browserHistory } from 'react-router'
import { connect } from 'react-redux'
import { bindActionCreators } from 'redux'
import { decryptMnemonic } from 'blockstack'
import { AccountActions } from '../account/store/account'
import { IdentityActions } from '../profiles/store/identity'
import { Initial, Success, NoUpdate } from './views'
Expand All @@ -28,7 +29,6 @@ import {
hasLegacyCoreStateVersion,
migrateLegacyCoreEndpoints
} from '@utils/api-utils'
import { decrypt } from '@utils'
const VIEWS = {
INITIAL: 0,
SUCCESS: 1,
Expand Down Expand Up @@ -134,10 +134,8 @@ class UpdatePage extends React.Component {
console.error('No encryptedBackupPhrase, cannot continue')
return null
}
const dataBuffer = new Buffer(encryptedBackupPhrase, 'hex')
const { password } = this.state

return decrypt(dataBuffer, password)
return decryptMnemonic(encryptedBackupPhrase, this.state.password)
.then(backupPhraseBuffer => {
this.setState(
{
Expand Down
Loading