Commit
This can be used for generating world-readable configuration files containing secrets (such as passwords). ‘encryptString keyFile str’ encrypts the string ‘str’ using the key stored in ‘keyFile’. Keys can be generated using ‘nix-store --generate-key’. Files containing encrypted strings can be decrypted using ‘nix-store --decrypt’.
- Loading branch information
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -18,6 +18,8 @@ | |
#include <cstring> | ||
#include <dlfcn.h> | ||
|
||
#include <sodium.h> | ||
|
||
|
||
namespace nix { | ||
|
||
|
@@ -1465,6 +1467,40 @@ static void prim_compareVersions(EvalState & state, const Pos & pos, Value * * a | |
} | ||
|
||
|
||
/************************************************************* | ||
* Cryptography | ||
*************************************************************/ | ||
|
||
|
||
/* Encrypt a string using a key stored in a file. */ | ||
static void prim_encryptString(EvalState & state, const Pos & pos, Value * * args, Value & v) | ||
{ | ||
PathSet context; | ||
Path path = state.coerceToPath(pos, *args[0], context); | ||
if (!context.empty()) | ||
throw EvalError(format("string ‘%1%’ cannot refer to other paths, at %2%") % path % pos); | ||
|
||
// FIXME: lock/wipe the key in memory. | ||
string key = base64Decode(readFile(path)); | ||
if (key.size() != crypto_secretbox_KEYBYTES) | ||
throw Error(format("file ‘%1%’ does not contain a key created using ‘nix-store --generate-key’") % path); | ||
|
||
string s = state.forceStringNoCtx(*args[1], pos); | ||
|
||
/* Note: since the nonce is random, encryptString is | ||
non-deterministic, which is unfortunate... */ | ||
string nonce(crypto_secretbox_NONCEBYTES, 0); | ||
This comment has been minimized.
Sorry, something went wrong.
This comment has been minimized.
Sorry, something went wrong.
edolstra
Author
Owner
|
||
randombytes_buf((unsigned char *) nonce.data(), nonce.size()); | ||
|
||
string res(crypto_secretbox_MACBYTES + s.size(), ' '); | ||
if (crypto_secretbox_easy((unsigned char *) res.data(), (unsigned char *) s.data(), | ||
s.size(), (unsigned char *) nonce.data(), (unsigned char *) key.data()) != 0) | ||
throw Error("encryption failed"); | ||
|
||
mkString(v, "<{|nixcrypt:" + base64Encode(nonce + res) + "|}>"); | ||
} | ||
|
||
|
||
/************************************************************* | ||
* Primop registration | ||
*************************************************************/ | ||
|
@@ -1600,6 +1636,9 @@ void EvalState::createBaseEnv() | |
// Derivations | ||
addPrimOp("derivationStrict", 1, prim_derivationStrict); | ||
|
||
// Cryptography | ||
addPrimOp("__encryptString", 2, prim_encryptString); | ||
|
||
/* Add a wrapper around the derivation primop that computes the | ||
`drvPath' and `outPath' attributes lazily. */ | ||
string path = findFile("nix/derivation.nix"); | ||
|
Should we make a cache that some random bytes are associated with the hash of their inputs? This would at least remove the non-determinism from local evaluation, avoiding recompilation&restart of services which depends on a configuration file with a password.