[slow sign in] Reduce number of kdf iterations for PDF database key (#1343)

`kdf_iter` parameter is reduced to 3200. This change is done because of
performance reasons, currently key derivation is too slow on some mobile
devices. The number of iterations before this commit is 64000, default
value in `sqlcipher` from version `3.0.0`.
fda4c68bb4/CHANGELOG.md (300---2013-11-05)

Implementation:
`sqlcipher_export` is used for migration, check out the link below
for details
https://www.zetetic.net/sqlcipher/sqlcipher-api/#sqlcipher_export
This commit is contained in:
Roman Volosovskyi :: Darkviolet Lightgreen Halcyon 2019-01-11 12:12:23 +02:00 committed by Andrea Maria Piana
parent 8f2e347e4f
commit d6216f1aa4
2 changed files with 83 additions and 5 deletions

View File

@ -21,6 +21,17 @@ import (
// A safe max number of rows
const maxNumberOfRows = 100000000
// The default number of kdf iterations in sqlcipher (from version 3.0.0)
// https://github.com/sqlcipher/sqlcipher/blob/fda4c68bb474da7e955be07a2b807bda1bb19bd2/CHANGELOG.md#300---2013-11-05
// https://www.zetetic.net/sqlcipher/sqlcipher-api/#kdf_iter
const defaultKdfIterationsNumber = 64000
// The reduced number of kdf iterations (for performance reasons) which is
// currently used for derivation of the database key
// https://github.com/status-im/status-go/pull/1343
// https://notes.status.im/i8Y_l7ccTiOYq09HVgoFwA
const kdfIterationsNumber = 3200
// SQLLitePersistence represents a persistence service tied to an SQLite database
type SQLLitePersistence struct {
db *sql.DB
@ -70,7 +81,7 @@ func MigrateDBFile(oldPath string, newPath string, oldKey string, newKey string)
return err
}
db, err := openDB(newPath, oldKey)
db, err := openDB(newPath, oldKey, defaultKdfIterationsNumber)
if err != nil {
return err
}
@ -85,7 +96,66 @@ func MigrateDBFile(oldPath string, newPath string, oldKey string, newKey string)
}
func openDB(path string, key string) (*sql.DB, error) {
// MigrateDBKeyKdfIterations changes the number of kdf iterations executed
// during the database key derivation. This change is necessary because
// of performance reasons.
// https://github.com/status-im/status-go/pull/1343
// `sqlcipher_export` is used for migration, check out this link for details:
// https://www.zetetic.net/sqlcipher/sqlcipher-api/#sqlcipher_export
func MigrateDBKeyKdfIterations(oldPath string, newPath string, key string) error {
_, err := os.Stat(oldPath)
// No files, nothing to do
if os.IsNotExist(err) {
return nil
}
// Any other error, throws
if err != nil {
return err
}
db, err := openDB(oldPath, key, defaultKdfIterationsNumber)
if err != nil {
return err
}
attach := fmt.Sprintf(
"ATTACH DATABASE '%s' AS newdb KEY '%s'",
newPath,
key)
if _, err = db.Exec(attach); err != nil {
return err
}
changeKdfIter := fmt.Sprintf(
"PRAGMA newdb.kdf_iter = %d",
kdfIterationsNumber)
if _, err = db.Exec(changeKdfIter); err != nil {
return err
}
exportDB := "SELECT sqlcipher_export('newdb')"
if _, err = db.Exec(exportDB); err != nil {
return err
}
if err = db.Close(); err != nil {
return err
}
if err = os.Remove(oldPath); err != nil {
return err
}
return nil
}
func openDB(path string, key string, kdfIter int) (*sql.DB, error) {
db, err := sql.Open("sqlite3", path)
if err != nil {
return nil, err
@ -104,7 +174,9 @@ func openDB(path string, key string) (*sql.DB, error) {
return nil, err
}
if _, err = db.Exec("PRAGMA cypher_page_size=4096"); err != nil {
kdfString := fmt.Sprintf("PRAGMA kdf_iter = '%d'", kdfIter)
if _, err = db.Exec(kdfString); err != nil {
return nil, err
}
return db, nil
@ -136,7 +208,7 @@ func (s *SQLLitePersistence) GetSessionStorage() dr.SessionStorage {
// Open opens a file at the specified path
func (s *SQLLitePersistence) Open(path string, key string) error {
db, err := openDB(path, key)
db, err := openDB(path, key, kdfIterationsNumber)
if err != nil {
return err
}

View File

@ -129,6 +129,7 @@ func (s *Service) InitProtocol(address string, password string) error {
v0Path := filepath.Join(s.dataDir, fmt.Sprintf("%x.db", address))
v1Path := filepath.Join(s.dataDir, fmt.Sprintf("%s.db", s.installationID))
v2Path := filepath.Join(s.dataDir, fmt.Sprintf("%s.v2.db", s.installationID))
v3Path := filepath.Join(s.dataDir, fmt.Sprintf("%s.v3.db", s.installationID))
if err := chat.MigrateDBFile(v0Path, v1Path, "ON", password); err != nil {
return err
@ -141,7 +142,12 @@ func (s *Service) InitProtocol(address string, password string) error {
os.Remove(v2Path)
}
persistence, err := chat.NewSQLLitePersistence(v2Path, hashedPassword)
if err := chat.MigrateDBKeyKdfIterations(v2Path, v3Path, hashedPassword); err != nil {
os.Remove(v2Path)
os.Remove(v3Path)
}
persistence, err := chat.NewSQLLitePersistence(v3Path, hashedPassword)
if err != nil {
return err
}