URI: 
       Title: Asynchronous secure file transfer with nncp
       Author: Solène
       Date: 04 October 2024
       Tags: privacy security network unix
       Description: In this blog post, you will learn about the software nncp
       and how to use it to exchange encrypted data with peers
       
       # Introduction
       
       nncp (node to node copy) is a software to securely exchange data
       between peers.  Is it command line only, it is written in Go and
       compiles on Linux and BSD systems (although it is only packaged for
       FreeBSD in BSDs).
       
       The website will do a better job than me to talk about the numerous
       features, but I will do my best to explain what you can do with it and
       how to use it.
       
  HTML nncp official project website
       
       # Explanations
       
       nncp is a suite of tools to asynchronously exchange data between peers,
       using zero knowledge encryption.  Once peers have exchanged their
       public keys, they are able to encrypt data to send to this peer, this
       is nothing really new to be honest, but there is a twist.
       
       * a peer can directly connect to another using TCP, you can even
       configure different addresses like a tor onion or I2P host and use the
       one you want
       * a peer can connect to another using ssh
       * a peer can generate plain files that will be carried over USB,
       network storage, synchronization software, whatever, to be consumed by
       a peer.  Files can be split in chunks of arbitrary size in order to
       prevent anyone snooping from figuring how many files are exchanged or
       their name (hence zero knowledge).
       * a peer can generate data to burn on a CD or tape (it is working as a
       stream of data instead of plain files)
       * a peer can be reachable through another relay peer
       * when a peer receives files, nncp generates ACK files
       (acknowledgement) that will tell you they correctly received it
       * a peer can request files and/or trigger pre-configured commands you
       expose to this peer
       * a peer can send emails with nncp (requires a specific setup on the
       email server)
       * data transfer can be interrupted and resumed
       
       What is cool with nncp is that files you receive are unpacked in a
       given directory and their integrity is verified.  This is sometimes
       more practical than a network share in which you are never sure when
       you can move / rename / modify / delete the file that was transferred
       to you.
       
       I identified a few "realistic" use cases with nncp:
       
       * exchange files between air gap environments (I tried to exchange
       files over sound or QR codes, I found no reliable open source solution)
       * secure file exchange over physical medium with delivery notification
       (the medium needs to do a round-trip for the notification)
       * start a torrent download remotely, prepare the file to send back once
       downloaded, retrieve the file at your own pace
       * reliable data transfer over poor connections (although I am not sure
       if it beats kermit at this task :D )
       * "simple" file exchange between computers / people over network
       
       This let a lot of room for other imaginative use cases.
       
       # Real world example: Syncthing gateway
       
       My preferred workflow with nncp that I am currently using is a group of
       three syncthing servers.
       
       Each syncthing server is running on a different computer, the location
       does not really matter.  There is a single share between these
       syncthing instances.
       
       The servers where syncthing are running have incoming and outgoing
       directories exposed over a NFS / SMB share, with a directory named
       after each peer in both directories.  Deposing a file in the "outgoing"
       directory of a peer will make nncp to prepare the file for this peer,
       put it into the syncthing share and let it share, the file is consumed
       in the process.
       In the same vein, in the incoming directory, new files are unpacked in
       the incoming directory of emitting peer on the receiver server running
       syncthing.
       
       Why is it cool?  You can just drop a file in the peer you want to send
       to, it disappears locally and magically appears on the remote side.  If
       something wrong happens, due to ACK, you can verify if the file was
       delivered and unpacked.  With three shares, you can almost have two
       connected at the same time.
       
       It is a pretty good file deposit that requires no knowledge to use.
       
       This could be implemented with pure syncthing, however you would have
       to:
       
       * for each peer, configure a one-way directory share in syncthing for
       each other peer to upload data to
       * for each peer, configure a one-way directory share in syncthing for
       each other peer to receive data from
       * for each peer, configure an encrypted share to relay all one way
       share from other peers
       
       This does not scale well.
       
       Side note, I am using syncthing because it is fun and requires no
       infrastructure.  But actually, a webdav filesystem, a Nextcloud drive
       or anything to share data over the network would work just fine.
       
       # Setup
       
       ## Configuration file and private keys
       
       On each peer, you have to generate a configuration file with its
       private keys.  The default path for the configuration file is
       `/etc/nncp.hjson` but nothing prevents you from storing this file
       anywhere, you will have to use the parameter `-cfg /path/to/config`
       file in that case.
       
       Generate the file like this:
       
       ```
       nncp-cfgnew > /etc/nncp.hjson
       ```
       
       The file contains comments, this is helpful if you want to see how the
       file is structured and existing options.  Never share the private keys
       of this file!
       
       I recommend checking the spool and log paths, and decide which user
       should use nncp.  For instance, you can use `/var/spool/nncp` to store
       nncp data (waiting to be delivered or unpacked) and the log file, and
       make your user the owner of this directory.
       
       ## Public keys
       
       Now, generate the public keys (they are just derived from the private
       keys generated earlier) to share with your peers, there is a command
       for this that will read the private keys and output the public keys in
       a format ready to put in the nncp.hjson file of recipients.
       
       ```
       nncp-cfgmin > my-peer-name.pub
       ```
       
       You can share the generated file with anyone, this will allow them to
       send you files.  The peer name of your system is "self", you can rename
       it, it is just an identifier.
       
       ## Import public keys
       
       When import public keys, you just need to add the content generated by
       the command `nncp-cfgmin` of a peer in your nncp configuration file.
       
       Just copy / paste the content in the `neigh` structure within the
       configuration file, just make sure to rename "self" by the identifier
       you want to give to this peer.
       
       If you want to receive data from this peer, make sure to add an
       attribute line `incoming: "/path/to/incoming/data"` for that peer,
       otherwise you will not be able to unpack received file.
       
       # Usage
       
       Now you have peers who exchanged keys, they are able to send data to
       each other.  nncp is a collection of tools, let's see the most common
       and what they do:
       
       * nncp-file: add a file in the spool to deliver to a peer
       * nncp-toss: unpack incoming data (files, commands, file request,
       emails) and generate ack
       * nncp-reass: reassemble files that were split in smaller parts
       * nncp-exec: trigger a pre-configured command on the remote peer, stdin
       data will be passed as the command parameters.  Let's say a peer offers
       a "wget" service, you can use `echo "https://some-domain/uri/" |
       nncp-exec peername wget` to trigger a remote wget.
       
       If you use the client / server model over TCP, you will also use:
       
       * nncp-daemon: the daemon waiting for connections
       * nncp-caller: a daemon occasionally triggering client connections (it
       works like a crontab)
       * nncp-call: trigger a client connection to a peer
       
       If you use asynchronous file transfers, you will use:
       
       * nncp-xfer: generates to / consumes files from a directory for async
       transfer
       
       # Workflow (how to use)
       
       ## Sending files
       
       For sending files, just use `nncp-file file-path peername:`, the file
       name will be used when unpacked, but you can also give the filename you
       want to give once unpacked. 
       
       A directory could be used as a parameter instead of a file, it will be
       stored automatically in a .tar file for delivery. 
       
       Finally, you can send a stream of data using nncp-file stdin, but you
       have to give a name to the resulting file.
       
       ## Sync and file unpacking
       
       This was not really clear from the documentation, so here it is how to
       best use nncp when exchanging files using plain files, the destination
       is `/mnt/nncp` in my examples (it can be an external drive, a syncthing
       share, a NFS mount...):
       
       When you want to sync, always use this scheme:
       
       1. `nncp-xfer -rx /mnt/nncp`
       2. `nncp-toss -gen-ack`
       3. `nncp-xfer -keep -tx -mkdir /mnt/nncp`
       4. `nncp-rm -all -ack`
       
       This receives files using `nncp-xfer -rx`, the files are stored in nncp
       spool directory.  Then, with `nncp-toss -gen-ack`, the files are
       unpacked to the "incoming" directory of each peer who sent files, and
       ACK are generated (older versions of `nncp-toss` does not handle ack,
       you need to generate ack befores and remove them after tx, with
       `nncp-ack -all 4>acks` and `nncp-rm -all -pkt < acks`).
       
       `nncp-xfer -tx` will put in the directory the data you want to send to
       peers, and also the ack files generated by the rx which happened
       before.  The `-keep` flag is crucial here if you want to make use of
       ACK, with `-keep`, the sent data are kept in the pool until you receive
       the ACK for them, otherwise the data are removed from the spool and
       will not be retransmited if the files were not received.  Finally,
       `nncp-rm` will delete all ACK files so you will not transmit them
       again.
       
       # Explanations about ACK
       
       From my experience and documentation reading, there are three cases
       with the spool and ACK:
       
       * the shared drive is missing the files you sent (that are still in
       pool), and you received no ACK, the next time you run `nncp-xfer`, the
       files will be transmitted again
       * when you receive ACK files for files in spool, they are deleted from
       the spool
       * when you do not use `-keep` when sending files with `nncp-xfer`, the
       files will not be stored in the spool so you will not be able to know
       what to retransmit if ACK are missing
       
       ACKs do not clean up themselves, you need to use `nncp-rm`.  It took me
       a while to figure this, my nodes were sending ACKs to each other
       repeatedly.
       
       # Conclusion
       
       I really like nncp as it allows me to securely transfer files between
       my computers without having to care if they are online.  Rsync is not
       always possible because both the sender and receiver need to be up at
       the same time (and reachable correctly).
       
       The way files are delivered is also practical for me, as I already
       shared above, files are unpacked in a defined directory by peer,
       instead of remembering I moved something in a shared drive.  This
       removes the doubt about files being in a shared drive: why is it there?
       Why did I put it there? What was its destination??
       
       I played with various S3 storage to exchange nncp data, but this is for
       another blog post :-)
       
       # Going further
       
       There are more features in nncp, I did not play with all of them.
       
       You can define "areas" in parallel of using peers, you can use emails
       notifications when a remote receives data from you to have a
       confirmation, requesting remote files etc...  It is all in the
       documentation.
       
       I have the idea to use nncp on a SMTP server to store encrypted
       incoming emails until I retrieve them (I am still working at improving
       the security of email storage), stay tuned :)