sasquatch

package module
v0.0.0-...-a98cc9b Latest Latest
Warning

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

Go to latest
Published: May 6, 2022 License: BSD-3-Clause Imports: 28 Imported by: 2

README

sasquatch

Build Status Coverage Status Go ReportCard GoDoc

A simple data encryption library, heavily inspired by @Benjojo12 and @FiloSottile's fantastic age project.

Features

  • Multiple recipients
  • Supports encrypting with your existing SSH keys / ssh-agent
  • Convenient API

Crypto Backends

  • ssh-rsa
  • ssh-ed25519
  • ssh-agent signing challenge (excluding ECDSA identities, as ECDSA signatures aren't deterministic)
  • scrypt / password

Example

Encryption
buf := bytes.NewBuffer(nil)

alice, err := sasquatch.ParseRecipient("ssh-ed25519 ...")
bob, err := sasquatch.ParseRecipient("ssh-rsa ...")

rcp := []sasquatch.Recipient{alice, bob}
w, err := sasquatch.Encrypt(buf, rcp...)

data := []byte("Hello Alice, Hey Bob!")
w.Write(data)
w.Close()

ioutil.WriteFile("/tmp/sasquatch.encrypted", buf.Bytes(), 0644)
Decryption
buf, err := ioutil.ReadFile("/tmp/sasquatch.encrypted")

// find all available identities
identities := sasquatch.FindIdentities()
r, err := sasquatch.Decrypt(buf, identities...)

buf, err := ioutil.ReadAll(r)
ioutil.WriteFile("/tmp/sasquatch.decrypted", buf.Bytes(), 0644)
ssh-agent Challenge
// encryption
signers, err := sasquatch.SSHAgentSigners()
rcp, err := sasquatch.NewChallengeRecipient(signers[0])
sasquatch.Encrypt(buf, rcp)

// decryption
id, err := sasquatch.NewChallengeIdentity(signers[0])
r, err := sasquatch.Decrypt(buf, id)
scrypt / password Encryption
// encryption
rcp, err := sasquatch.NewScryptRecipient("password")
sasquatch.Encrypt(buf, rcp)

// decryption
id, err := sasquatch.NewScryptIdentity("password")
r, err := sasquatch.Decrypt(buf, id)

Documentation

Index

Constants

View Source
const BytesPerLine = ColumnsPerLine / 4 * 3
View Source
const ColumnsPerLine = 64

Variables

View Source
var EncodeToString = b64.EncodeToString
View Source
var ErrIncorrectIdentity = errors.New("incorrect identity for recipient block")

Functions

func DecodeString

func DecodeString(s string) ([]byte, error)

func Decrypt

func Decrypt(src io.Reader, identities ...Identity) (io.Reader, error)

Decrypt returns a Reader reading the decrypted plaintext of the encrypted file read from src. All identities will be tried until one successfully decrypts the file.

func Encrypt

func Encrypt(dst io.Writer, recipients ...Recipient) (io.WriteCloser, error)

Encrypt returns a WriteCloser. Writes to the returned value are encrypted and written to dst as an encrypted file. Every recipient will be able to decrypt the file.

The caller must call Close on the returned value when done for the last chunk to be encrypted and flushed to dst.

func FindSSHKeys

func FindSSHKeys() ([]string, error)

FindSSHKeys looks in a user's ~/.ssh dir for possible SSH keys. If no keys are found we return an empty slice.

func NewlineWriter

func NewlineWriter(dst io.Writer) io.Writer

NewlineWriter returns a Writer that writes to dst, inserting an LF character every ColumnsPerLine bytes. It does not insert a newline neither at the beginning nor at the end of the stream.

func SSHAgentSigners

func SSHAgentSigners() ([]ssh.Signer, error)

SSHAgentSigners connect to ssh-agent and returns all available signers.

Types

type ChallengeIdentity

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

ChallengeIdentity is a challenge-based identity, supporting SSH agents.

func NewChallengeIdentity

func NewChallengeIdentity(signer ssh.Signer) (*ChallengeIdentity, error)

NewChallengeIdentity returns a new ChallengeIdentity with the provided challenge signer.

func (*ChallengeIdentity) Match

func (i *ChallengeIdentity) Match(block *Stanza) error

Match implements IdentityMatcher without decrypting the payload, to ensure the agent is only contacted if necessary.

func (*ChallengeIdentity) Type

func (*ChallengeIdentity) Type() string

func (*ChallengeIdentity) Unwrap

func (i *ChallengeIdentity) Unwrap(block *Stanza) ([]byte, error)

type ChallengeRecipient

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

func NewChallengeRecipient

func NewChallengeRecipient(signer ssh.Signer) (*ChallengeRecipient, error)

NewChallengeRecipient returns a new ChallengeRecipient with the provided signer.

func (*ChallengeRecipient) Type

func (*ChallengeRecipient) Type() string

func (*ChallengeRecipient) Wrap

func (r *ChallengeRecipient) Wrap(fileKey []byte) (*Stanza, error)

type Ed25519Identity

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

func NewEd25519Identity

func NewEd25519Identity(key ed25519.PrivateKey) (*Ed25519Identity, error)

func (*Ed25519Identity) Type

func (*Ed25519Identity) Type() string

func (*Ed25519Identity) Unwrap

func (i *Ed25519Identity) Unwrap(block *Stanza) ([]byte, error)

type Ed25519Recipient

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

func NewEd25519Recipient

func NewEd25519Recipient(pk ssh.PublicKey) (*Ed25519Recipient, error)

func (*Ed25519Recipient) Type

func (*Ed25519Recipient) Type() string

func (*Ed25519Recipient) Wrap

func (r *Ed25519Recipient) Wrap(fileKey []byte) (*Stanza, error)

type EncryptedSSHIdentity

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

EncryptedSSHIdentity is an IdentityMatcher implementation based on a passphrase encrypted SSH private key.

It provides public key based matching and deferred decryption so the passphrase is only requested if necessary. If the application knows it will unconditionally have to decrypt the private key, it would be simpler to use ssh.ParseRawPrivateKeyWithPassphrase directly and pass the result to NewEd25519Identity or NewRSAIdentity.

func NewEncryptedSSHIdentity

func NewEncryptedSSHIdentity(pubKey ssh.PublicKey, pemBytes []byte, passphrase func() ([]byte, error)) (*EncryptedSSHIdentity, error)

NewEncryptedSSHIdentity returns a new EncryptedSSHIdentity.

pubKey must be the public key associated with the encrypted private key, and it must have type "ssh-ed25519" or "ssh-rsa". For OpenSSH encrypted files it can be extracted from an ssh.PassphraseMissingError, otherwise in can often be found in ".pub" files.

pemBytes must be a valid input to ssh.ParseRawPrivateKeyWithPassphrase. passphrase is a callback that will be invoked by Unwrap when the passphrase is necessary.

func (*EncryptedSSHIdentity) Match

func (i *EncryptedSSHIdentity) Match(block *Stanza) error

Match implements IdentityMatcher without decrypting the private key, to ensure the passphrase is only obtained if necessary.

func (*EncryptedSSHIdentity) Type

func (i *EncryptedSSHIdentity) Type() string

Type returns the type of the underlying private key, "ssh-ed25519" or "ssh-rsa".

func (*EncryptedSSHIdentity) Unwrap

func (i *EncryptedSSHIdentity) Unwrap(block *Stanza) (fileKey []byte, err error)

Unwrap implements Identity. If the private key is still encrypted, it will request the passphrase. The decrypted private key will be cached after the first successful invocation.

type Header struct {
	Recipients []*Stanza
	MAC        []byte
}

func Parse

func Parse(input io.Reader) (*Header, io.Reader, error)

Parse returns the header and a Reader that begins at the start of the payload.

func (*Header) Marshal

func (h *Header) Marshal(w io.Writer) error

func (*Header) MarshalWithoutMAC

func (h *Header) MarshalWithoutMAC(w io.Writer) error

type Identity

type Identity interface {
	Type() string
	Unwrap(block *Stanza) (fileKey []byte, err error)
}

An Identity is a private key or other value that can decrypt an opaque file key from a recipient stanza.

Unwrap must return ErrIncorrectIdentity for recipient blocks that don't match the identity, any other error might be considered fatal.

func FindIdentities

func FindIdentities() []Identity

FindIdentities returns all available identities.

func ParseIdentitiesFile

func ParseIdentitiesFile(name string) ([]Identity, error)

ParseIdentitiesFile retrieves all identities found in a private key.

type IdentityMatcher

type IdentityMatcher interface {
	Identity
	Match(block *Stanza) error
}

IdentityMatcher can be optionally implemented by an Identity that can communicate whether it can decrypt a recipient stanza without decrypting it.

If an Identity implements IdentityMatcher, its Unwrap method will only be invoked on blocks for which Match returned nil. Match must return ErrIncorrectIdentity for recipient blocks that don't match the identity, any other error might be considered fatal.

type LazyScryptIdentity

type LazyScryptIdentity struct {
	Passphrase func() (string, error)
}

func (*LazyScryptIdentity) Type

func (i *LazyScryptIdentity) Type() string

func (*LazyScryptIdentity) Unwrap

func (i *LazyScryptIdentity) Unwrap(block *Stanza) (fileKey []byte, err error)

type ParseError

type ParseError string

func (ParseError) Error

func (e ParseError) Error() string

type RSAIdentity

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

func NewRSAIdentity

func NewRSAIdentity(key *rsa.PrivateKey) (*RSAIdentity, error)

func (*RSAIdentity) Type

func (*RSAIdentity) Type() string

func (*RSAIdentity) Unwrap

func (i *RSAIdentity) Unwrap(block *Stanza) ([]byte, error)

type RSARecipient

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

func NewRSARecipient

func NewRSARecipient(pk ssh.PublicKey) (*RSARecipient, error)

func (*RSARecipient) Type

func (*RSARecipient) Type() string

func (*RSARecipient) Wrap

func (r *RSARecipient) Wrap(fileKey []byte) (*Stanza, error)

type Recipient

type Recipient interface {
	Type() string
	Wrap(fileKey []byte) (*Stanza, error)
}

A Recipient is a public key or other value that can encrypt an opaque file key to a recipient stanza.

func FindRecipients

func FindRecipients() []Recipient

FindRecipients returns all available recipients.

func ParseRecipient

func ParseRecipient(s string) (Recipient, error)

ParseRecipient creates a Recipient from an SSH public key.

type ScryptIdentity

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

ScryptIdentity is a password-based identity.

func NewScryptIdentity

func NewScryptIdentity(password string) (*ScryptIdentity, error)

NewScryptIdentity returns a new ScryptIdentity with the provided password.

func (*ScryptIdentity) Type

func (*ScryptIdentity) Type() string

func (*ScryptIdentity) Unwrap

func (i *ScryptIdentity) Unwrap(block *Stanza) ([]byte, error)

type ScryptRecipient

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

ScryptRecipient is a password-based recipient.

If a ScryptRecipient is used, it must be the only recipient for the file: it can't be mixed with other recipient types and can't be used multiple times for the same file.

func NewScryptRecipient

func NewScryptRecipient(password string) (*ScryptRecipient, error)

NewScryptRecipient returns a new ScryptRecipient with the provided password.

func (*ScryptRecipient) Type

func (*ScryptRecipient) Type() string

func (*ScryptRecipient) Wrap

func (r *ScryptRecipient) Wrap(fileKey []byte) (*Stanza, error)

type Stanza

type Stanza struct {
	Type string
	Args []string
	Body []byte
}

A Stanza is a section of the header that encapsulates the file key as encrypted to a specific recipient.

func (*Stanza) Marshal

func (r *Stanza) Marshal(w io.Writer) error

Directories

Path Synopsis
Package stream implements a variant of the STREAM chunked encryption scheme.
Package stream implements a variant of the STREAM chunked encryption scheme.

Jump to

Keyboard shortcuts

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