package v0 import ( "crypto/rand" "errors" "git.openprivacy.ca/openprivacy/log" "golang.org/x/crypto/nacl/secretbox" "golang.org/x/crypto/pbkdf2" "golang.org/x/crypto/sha3" "io" "io/ioutil" "path" ) // createKey derives a key from a password func createKey(password string) ([32]byte, [128]byte, error) { var salt [128]byte if _, err := io.ReadFull(rand.Reader, salt[:]); err != nil { log.Errorf("Cannot read from random: %v\n", err) return [32]byte{}, salt, err } dk := pbkdf2.Key([]byte(password), salt[:], 4096, 32, sha3.New512) var dkr [32]byte copy(dkr[:], dk) return dkr, salt, nil } //encryptFileData encrypts the cwtchPeer via the specified key. func encryptFileData(data []byte, key [32]byte) ([]byte, error) { var nonce [24]byte if _, err := io.ReadFull(rand.Reader, nonce[:]); err != nil { log.Errorf("Cannot read from random: %v\n", err) return nil, err } encrypted := secretbox.Seal(nonce[:], data, &nonce, &key) return encrypted, nil } //decryptFile decrypts the passed ciphertext into a cwtchPeer via the specified key. func decryptFile(ciphertext []byte, key [32]byte) ([]byte, error) { var decryptNonce [24]byte copy(decryptNonce[:], ciphertext[:24]) decrypted, ok := secretbox.Open(nil, ciphertext[24:], &decryptNonce, &key) if ok { return decrypted, nil } return nil, errors.New("Failed to decrypt") } // Load instantiates a cwtchPeer from the file store func readEncryptedFile(directory, filename, password string) ([]byte, error) { encryptedbytes, err := ioutil.ReadFile(path.Join(directory, filename)) if err == nil && len(encryptedbytes) > 128 { var dkr [32]byte //Separate the salt from the encrypted bytes, then generate the derived key salt, encryptedbytes := encryptedbytes[0:128], encryptedbytes[128:] dk := pbkdf2.Key([]byte(password), salt, 4096, 32, sha3.New512) copy(dkr[:], dk) data, err := decryptFile(encryptedbytes, dkr) if err == nil { return data, nil } return nil, err } return nil, err }