/////////////////////////////////////////////////////////////////////////////// // Copyright © 2020 xx network SEZC // // // // Use of this source code is governed by a license that can be found in the // // LICENSE file // /////////////////////////////////////////////////////////////////////////////// package api import ( "github.com/pkg/errors" "gitlab.com/elixxir/crypto/fastRNG" "gitlab.com/xx_network/crypto/chacha" "gitlab.com/xx_network/crypto/csprng" xxMnemonic "gitlab.com/xx_network/crypto/mnemonic" "gitlab.com/xx_network/primitives/utils" "path/filepath" "strings" ) const mnemonicFile = ".recovery" // StoreSecretWithMnemonic creates a mnemonic and uses it to encrypt the secret. // This encrypted data saved in storage. func StoreSecretWithMnemonic(secret []byte, path string) (string, error) { // Use fastRNG for RNG ops (AES fortuna based RNG using system RNG) rng := fastRNG.NewStreamGenerator(12, 1024, csprng.NewSystemRNG).GetStream() // Ensure path is appended by filepath separator "/" if !strings.HasSuffix(path, string(filepath.Separator)) { path = path + string(filepath.Separator) } // Create a mnemonic mnemonic, err := xxMnemonic.GenerateMnemonic(rng, 32) if err != nil { return "", errors.Errorf("Failed to generate mnemonic: %v", err) } // Decode mnemonic decodedMnemonic, err := xxMnemonic.DecodeMnemonic(mnemonic) if err != nil { return "", errors.Errorf("Failed to decode mnemonic: %v", err) } // Encrypt secret with mnemonic as key ciphertext, err := chacha.Encrypt(decodedMnemonic, secret, rng) if err != nil { return "", errors.Errorf("Failed to encrypt secret with mnemonic: %v", err) } // Save encrypted secret to file recoveryFile := path + mnemonicFile err = utils.WriteFileDef(recoveryFile, ciphertext) if err != nil { return "", errors.Errorf("Failed to save mnemonic information to file") } return mnemonic, nil } // LoadSecretWithMnemonic loads the encrypted secret from storage and decrypts // the secret using the given mnemonic. func LoadSecretWithMnemonic(mnemonic, path string) (secret []byte, err error) { // Ensure path is appended by filepath separator "/" if !strings.HasSuffix(path, string(filepath.Separator)) { path = path + string(filepath.Separator) } // Ensure that the recovery file exists recoveryFile := path + mnemonicFile if !utils.Exists(recoveryFile) { return nil, errors.Errorf("Recovery file does not exist. " + "Did you properly set up recovery or provide an incorrect filepath?") } // Read file from storage data, err := utils.ReadFile(recoveryFile) if err != nil { return nil, errors.Errorf("Failed to load mnemonic information: %v", err) } // Decode mnemonic decodedMnemonic, err := xxMnemonic.DecodeMnemonic(mnemonic) if err != nil { return nil, errors.Errorf("Failed to decode mnemonic: %v", err) } // Decrypt the stored secret secret, err = chacha.Decrypt(decodedMnemonic, data) if err != nil { return nil, errors.Errorf("Failed to decrypt secret: %v", err) } return secret, nil }