ccp

package module
v0.2.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Feb 22, 2026 License: 0BSD Imports: 9 Imported by: 0

README

ccp

ccp is a cli utility that encrypts/decrypts files using ChaCha20-Poly1305 (or the XChaCha variant).

This is intended more as a building block for people who know what they are doing than as an end-user tool.

If you are looking for a user-friendly solution to secure your files, you should look elsewhere, for example at age.

Usage

ccp encrypt -k file/containing/key -n file/containing/nonce cleartext.file ciphertext.file
ccp decrypt -k file/containing/key -n file/containing/nonce cleartext.file ciphertext.file

You can use - to signify the the key or nonce should be read from stdin, for example:

ccp encrypt -k - -n file/containing/nonce cleartext.file ciphertext.file

(of course using /dev/stdin works too).

Keys and nonces may be specified as base-64 or base-32 encoded strings.
For example, the following will print "Lorem ipsum dolor sit amet":

key=$(head -c 32 /dev/urandom | base64)
nonce=$(head -c 12 /dev/urandom | base64)

echo "Lorem ipsum dolor sit amet" \
| ccp encrypt --key64 "$key" --nonce64 "$nonce" \
| ccp decrypt --key64 "$key" --nonce64 "$nonce"

When encrypting, ccp may also generate random keys and/or nonces:

ccp encrypt -K destination/for/generated/key -N destination/for/generated/nonce cleartext.file ciphertext.file

For additional details, see ccp -h, ccp encrypt -h, and ccp decrypt -h.

Implementation (and go mini-library)

This utility ueses the ChaCha20 implementation from golang.org/x/crypto/chacha20 and the Poly1305 one from golang.org/x/crypto/poly1305, however it re-impleents ChaCha20-Poly1305 as specified in RFC 8439.

The reason for this choice is mainly that I didn't like that the ChaCha20-Poly1305 implementation provided in golang.org/x/crypto/chacha20poly1305 requires to read the whole cleartext/ciphertext before ecnrypting/decrypting it.

So the implementation included in this utility is a regular io.Writer (available as a mini-library, shall you want to use it).

You might notice that golang.org/x/[email protected]/poly1305 is deprecated. If you read the deprecation notice you'll see that it basicaly says "you are not good enough to know when to use this", which... I won't comment on. If they ever remove it (which I don't think they'll ever do), I'll just switch to a different implementation.

Documentation

Index

Constants

This section is empty.

Variables

View Source
var ChaCha20Poly1305 = Algorithm{"ChaCha20-Poly1305", 12} //nolint:gochecknoglobals // this is a constant (kinda)

ChaCha20Poly1305 is the Algorithm instance representing ChaCha20-Poly1305.

View Source
var XChaCha20Poly1305 = Algorithm{"XChaCha20-Poly1305", 24} //nolint:gochecknoglobals // this is a constant (kinda)

XChaCha20Poly1305 is the Algorithm instance representing XChaCha20-Poly1305.

Functions

func Copy

func Copy(dst io.Writer, src io.Reader, key Key, nonce Nonce, aad []byte, mode Mode, buffer []byte) error

Copy calls CopyBuffer allocating a new buffer.

func CopyBuffer

func CopyBuffer(dst io.Writer, src io.Reader, key Key, nonce Nonce, aad []byte, mode Mode, buffer []byte) error

CopyBuffer processes (encrypts/decrypts) the entire contents from src and writes the resulting ciper/cleartext into dst. As errors are obviously non-recoverable, this function doesn't return the number of bytes written (unlike io.CopyBuffer).

Types

type Algorithm

type Algorithm struct {
	// contains filtered or unexported fields
}

Algorithm represents and algorithm variant (ChaCha20-Poly1305 or XChaCha20-Poly1305); it provides some metadata and constcutors for keys and nonces.

Rather than instantiating this type, use one of the provided instances.

func (Algorithm) KeySize

func (Algorithm) KeySize() int

KeySize gives the algorithm's required byte length for keys, which is 32.

func (Algorithm) NewKey

func (a Algorithm) NewKey(bytes []byte) (*Key, error)

NewKey creates a Key copying the bytes in the give slice, whose length must match the length required by the algorithm (ie. 32).

Returns a WrongKeySizeError if the slice is the wrong size.

func (Algorithm) NewNonce

func (a Algorithm) NewNonce(bytes []byte) (*Nonce, error)

NewNonce creates a Nonce copying the bytes in the give slice, whose length must match the length required by the algorithm (ie. 12 or 24).

Returns WrongNonceSizeError if the slice is the wrong size.

func (Algorithm) NewRandomKey

func (Algorithm) NewRandomKey() *Key

NewRandomKey returns a random Key.

func (Algorithm) NewRandomNonce

func (a Algorithm) NewRandomNonce() *Nonce

NewRandomNonce returns a random Nonce.

func (Algorithm) NonceSize

func (a Algorithm) NonceSize() int

NonceSize gives the algorithm's required byte length for nonces, which is 12 for ChaCha20-Poly1305 and 24 for XChaCha20-Poly1305.

func (Algorithm) Overhead

func (Algorithm) Overhead() int

Overhead gives the difference between the byte lengths of a ciphertext and the corresponding plaintext, which is 16 (ie. the length of the Poly1305 tag that's appended to the ciphertext).

func (Algorithm) String

func (a Algorithm) String() string

String gives the name of the algorithm: "ChaCha20-Poly1305" or "XChaCha20-Poly1305".

type Key

type Key struct {
	// contains filtered or unexported fields
}

func (Key) AppendBytes

func (k Key) AppendBytes(dst []byte) []byte

AppendBytes appends the key's bytes to the given slice, returning the resulting slice.

func (Key) Bytes

func (k Key) Bytes() []byte

Bytes returns a copy of the bytes in the key.

type Mode

type Mode bool

Mode is a Writer's operating mode (either Encryption or Decryption).

const (
	Encryption Mode = true
	Decryption Mode = false
)

type Nonce

type Nonce struct {
	// contains filtered or unexported fields
}

func (Nonce) AppendBytes

func (n Nonce) AppendBytes(dst []byte) []byte

AppendBytes appends the nonce's bytes to the given slice, returning the resulting slice.

func (Nonce) Bytes

func (n Nonce) Bytes() []byte

Bytes returns a copy of the bytes in the nonce.

type TagVerificationFailedError

type TagVerificationFailedError struct{}

func (TagVerificationFailedError) Error

type Writer

type Writer struct {
	// contains filtered or unexported fields
}

Writer is a io.WriteCloser (and io.ReeaderFrom) that encrypts or decrypts data according to ChaCha20-Poly1305 (see rfc8439) and writes it to an underlying io.Writer.

func NewWriter

func NewWriter(key Key, nonce Nonce, additionalData []byte, mode Mode, writer io.Writer, buffer []byte) *Writer

NewWriter creates a new Writer that wraps the provided one.

The writer will use will use ChaCha20-POly1305 or XChaCha20-POly1305 depending on the provided nonce.

The provided buffer will be used during I/O only (ie. ReadFrom() and Write()) and can be shared or used for other purposes as long it's not used concurrently.

func (*Writer) Close

func (ccpw *Writer) Close() error

Close finalizes the poly1305 MAC, writing it to the underlying writer if encrypting, and verifying it's the expected one if decrypting.

When encrypting, this will fail if the underlying Writer returns an error, which will be returned untouched.

When decrypting, this will fail with a TagVerificationFailedError if the Poly1305 tag at the end of the ciphertext does not match the one computed while decrypting.

After an error occurrs here, in Write(), or in WriteFrom() This function wil consistently return the same error (wrapped).

func (*Writer) ReadFrom

func (ccpw *Writer) ReadFrom(in io.Reader) (int64, error)

ReadFrom reads data from r until EOF or error and returns the number of bytes read (see io.ReaderFrom).

This will fail if an error is returned while reading from the given Reader, or while writitng to the underlying Writer. In either case, any error which will be returned untouched (except EOF from the Reader, of course).

After an error occurrs here, in Write(), or in Close() This function wil consistently return the same error (wrapped).

func (*Writer) Write

func (ccpw *Writer) Write(bytes []byte) (int, error)

Write encrypts/decrypts the provided bytes and writes them to the underlying writer.

When encrypting, all provided bytes will be encrypted and written to the underlying writer.

When decrypting, the last 16 bytes of ciphertext are the expected poly1305 MAC and so a call to Write() will always keep the latest 16 bytes aside for this purpose. These 16 bytes will not be written to the underlying Writer(this function will still report them as read, of course).

This will fail if the underlying Writer returns an error, which will be returned untouched.

After an error occurrs here, in WriteFrom(), or in Close() This function wil consistently return the same error (wrapped).

type WrongKeySizeError

type WrongKeySizeError struct {
	// contains filtered or unexported fields
}

func (WrongKeySizeError) Error

func (e WrongKeySizeError) Error() string

type WrongNonceSizeError

type WrongNonceSizeError struct {
	// contains filtered or unexported fields
}

func (WrongNonceSizeError) Error

func (e WrongNonceSizeError) Error() string

Directories

Path Synopsis
cmd
ccp command
internal

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL