zcrypto

package
v0.0.0-...-fd3dc7f Latest Latest
Warning

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

Go to latest
Published: Feb 21, 2018 License: GPL-3.0 Imports: 14 Imported by: 0

Documentation

Overview

Package zcrypto provides easy to use cryptographic interfaces.

When using zcrypto for encrypting messages and files, you are encouraged to use the CryptoProvider interface rather than the EncryptionKey type. EncryptionKey does not perform any sort of integrity checking, CryptoProvider combines an EncryptionKey and an IntegrityKey to provide both confidentiality and integrity.

Example Usage:

func main() {
	cr, err := zcrypto.NewCryptoProvider()

	// Encrypting
	encrypted, err := cr.Encrypt([]byte("Hello World!"))
	err := cr.EncryptFile("sourceFile.txt", "encrypted.zpc")

	// Decrypting
	decrypted, err := cr.Decrypt(encrypted)
	err := cr.EncryptFile("encrypted.zpc", "decrypted.txt")

	// Signing
	sig, err := cr.Sign([]byte("Some important message"))
	fileSig, err := cr.SignFile("sourceFile.txt")

	// Verifying Signatures
	valid := cr.Verify([]byte("Some important message"), sig)
	validFile := cr.VerifyFile(sourceFile.txt, fileSig)
}

Algorithms

XSalsa20 is used to encrypt data.

Blake2 with a secret key is used to provide message integrity.

Ed25519 is used for asymmetric signatures.

Encrypted Message Structure

Encrypted messages are formatted like so

[MAC][Nonce][Ciphertext]

The MAC is calculated over the Nonce & Ciphertext. The MAC is first to encourage to verifying the MAC before decryption.

File Encryption

Files are encrypted & decrypted using the SalsaWriter and SalsaReader types. SalsaWriter & SalsaReader automatically handle chunking, maintaining the XSalsa20 counter, and calculating/verifying the file MAC.

SalsaWriter

Initializing a new SalsaWriter automatically writes out an IntHashSize block of zeros to the start of the io.WriteSeeker as a placeholder for the MAC. The MAC will be written out once SalsaWriter.Close() is called. SalsaWriter.Closed will be set to true and any further writes will fail with SalsaWriterClosedError.

SalsaReader

Initializing a new SalsaReader automatically checks the io.ReadSeeker's MAC. If the MAC is invalid, it will return a MACMismatchError and set SalsaReader.Integrous to false. Any further reads or seeks will fail with UnintegrousReadError.

Index

Constants

View Source
const (
	// EncKeySize is the size of an encryption key.
	// We use XSalsa20 for encryption, so this is 32 bytes (256 bits).
	EncKeySize = 32
	// EncNonceSize is the size of our encryption nonce.
	// We use XSalsa20 for encryption, so this is 24 bytes (192 bits).
	EncNonceSize = 24
	// EncBlockSize is the size of our encryption blocks.
	// We use XSalsa20 for encryption, which operates on 64 byte (512 bit) blocks.
	EncBlockSize = 64

	// IntKeySize is the size of an integrity key.
	// We use Blake2-512 for integrity checking, so this is 64 bytes (512 bits).
	IntKeySize = 64
	// IntHashSize is the size of an integrity hash.
	// We use Blake2-512 for integrity checking, so this is 64 bytes (512 bits).
	IntHashSize = 64

	// AuthFullSize is the size of a keypair with both public & private keys.
	// We use ed25519 for signing, so this is (32 bytes + 32 bytes) = 64 bytes (512 bits).
	AuthFullSize = 64
	// AuthHalfSize is the size of a keypair with a single key.
	// zcrypto assumes if you only have one key that its a public key.
	// We use ed25519 for signing, so this is 32 bytes (256 bits).
	AuthHalfSize = 32
	// AuthSigSize is the size of a signature
	// We use ed25519 for signing, so this is 64 bytes (512 bits).
	AuthSigSize = 64

	// MsgOverhead is the overhead on a standard message (ie not a file)
	// Every message needs a new nonce and an integrity hash
	MsgOverhead = EncNonceSize + IntHashSize
	// FileOverhead is the overhead on an encrypted file
	// Every file needs a new nonce, integrity hash, and a counter representing the number of "dummy bytes" in that file
	FileOverhead = EncNonceSize + IntHashSize + 4 // 4 bytes for the int32 extraByte count

	// FileChunkSize is the size of chunk we use when reading in files.
	// We chunk files so smaller devices don't have to read the entire file into memory in order to decrypt.
	FileChunkSize = 128 * 1024
)

Variables

This section is empty.

Functions

func HashFile

func HashFile(path string, hasher hash.Hash) ([]byte, error)

HashFile uses the hasher to calculate a hash for a file

func HashReader

func HashReader(r io.Reader, hasher hash.Hash) ([]byte, error)

HashReader uses the hasher to calculate a hash for a reader

Types

type AuthPair

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

AuthPair provides authentication via public/private keys

func AuthPairFromBytes

func AuthPairFromBytes(b []byte) (AuthPair, error)

AuthPairFromBytes creates an AuthPair from a byte slice

b must be either AuthFullSize or AuthHalfSize in length

If len(b) is AuthFullSize, the AuthPair will be able to sign & verify messages

If len(b) is AuthHalfSize, the AuthPair will only be able to verify messages

func NewAuthPair

func NewAuthPair() (AuthPair, error)

NewAuthPair generates a new public/private key pair

func (AuthPair) Bytes

func (pair AuthPair) Bytes() []byte

Bytes returns a byte slice representing the AuthPair

func (AuthPair) Sign

func (pair AuthPair) Sign(msg []byte) ([]byte, error)

Sign generates a signature for a message. If the AuthPair does not have a private key this will return an error.

func (AuthPair) SignFile

func (pair AuthPair) SignFile(path string) ([]byte, error)

SignFile generates a signature for a file. If the AuthPair does not have a private key this will return an error.

SignFile first calculates the blake2b-512 hash of the file and then calls AuthPair.Sign on the resultant hash

func (AuthPair) Verify

func (pair AuthPair) Verify(msg, testSig []byte) bool

Verify checks a message against its signature

If the signature is valid, it will return true. Otherwise, it will return false.

If the AuthPair does not have a public key, it will return false

func (AuthPair) VerifyFile

func (pair AuthPair) VerifyFile(path string, testSig []byte) (bool, error)

VerifyFile checks a file against its signature

If the signature is valid, it will return true. Otherwise, it will return false.

If the AuthPair does not have a public key, it will return false

type AuthPairBadSizeError

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

AuthPairBadSizeError is returned if an invalid sized byte slice is used as an AuthPair.

func (AuthPairBadSizeError) Error

func (e AuthPairBadSizeError) Error() string

type CryptoProvider

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

CryptoProvider provides encryption, integrity, and authentication using symmetric keys for encryption and public/private keys for authentication.

func CryptoProviderFromBytes

func CryptoProviderFromBytes(b []byte) (*CryptoProvider, error)

CryptoProviderFromBytes creates a CryptoProvider from a byte slice

b must be EncKeySize+IntKeySize+AuthFullSize in length

func NewCryptoProvider

func NewCryptoProvider() (*CryptoProvider, error)

NewCryptoProvider generates a new CryptoProvider with random keys

func (*CryptoProvider) Decrypt

func (c *CryptoProvider) Decrypt(msg []byte) ([]byte, error)

Decrypt decrypts an encrypted byte slice

If the message's MAC is invalid decryption will return a nil & an error

func (*CryptoProvider) DecryptFile

func (c *CryptoProvider) DecryptFile(inPath, outPath string) error

DecryptFile decrypts a file

If the file's MAC is invalid decryption will return an error

func (*CryptoProvider) Encrypt

func (c *CryptoProvider) Encrypt(msg []byte) ([]byte, error)

Encrypt encrypts a byte slice & generates a MAC

The MAC is prepended to the encrypted slice. This is to encourage MAC validation before decryption.

func (*CryptoProvider) EncryptFile

func (c *CryptoProvider) EncryptFile(inPath, outPath string) error

EncryptFile encrypts a file & generates a MAC

The MAC is prepended to the encrypted file. This is to encourage MAC validation before decryption.

func (*CryptoProvider) Sign

func (c *CryptoProvider) Sign(msg []byte) ([]byte, error)

Sign signs a message

Sign will fail if the CryptoProvider does not have a private auth key.

func (*CryptoProvider) SignFile

func (c *CryptoProvider) SignFile(path string) ([]byte, error)

SignFile signs a file

SignFile will fail if the CryptoProvider does not have a private auth key.

func (*CryptoProvider) Verify

func (c *CryptoProvider) Verify(msg, sig []byte) bool

Verify checks the signature of a message

Verify will fail if the CryptoProvider does not have a public auth key.

func (*CryptoProvider) VerifyFile

func (c *CryptoProvider) VerifyFile(path string, sig []byte) (bool, error)

VerifyFile checks the signature of a file

VerifyFile will fail if the CryptoProvider does not have a public auth key.

type CryptoProviderBadSizeError

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

CryptoProviderBadSizeError is returned if an invalid sized byte slice is used as an CryptoProvider.

func (CryptoProviderBadSizeError) Error

type EncKeyBadSizeError

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

EncKeyBadSizeError is returned if an invalid sized byte slice is used as an EncryptionKey.

func (EncKeyBadSizeError) Error

func (e EncKeyBadSizeError) Error() string

type EncNonceBadSizeError

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

EncNonceBadSizeError is returned if an invalid sized byte slice is used as a SalsaNonce.

func (EncNonceBadSizeError) Error

func (e EncNonceBadSizeError) Error() string

type EncryptionKey

type EncryptionKey []byte

EncryptionKey must be EncKeySize bytes long.

func NewEncryptionKey

func NewEncryptionKey() (EncryptionKey, error)

NewEncryptionKey generates a new random encryption key

func (EncryptionKey) Decrypt

func (key EncryptionKey) Decrypt(msg []byte) ([]byte, error)

Decrypt decrypts a message

Important! Decrypt does NOT validate a MAC. If you want to use Decrypt, make sure to validate a MAC beforehand. Failure to do so will result in decapitation.

func (EncryptionKey) Encrypt

func (key EncryptionKey) Encrypt(msg []byte) ([]byte, error)

Encrypt encrypts a message

Important! Encrypt does NOT calculate a MAC. If you want to use Encrypt, make sure to include a MAC or you're just asking for trouble.

The returned byte slice is Nonce + Ciphertext

type IntKeyBadSizeError

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

IntKeyBadSizeError is returned if an invalid sized byte slice is used as an IntegrityKey.

func (IntKeyBadSizeError) Error

func (e IntKeyBadSizeError) Error() string

type IntegrityKey

type IntegrityKey []byte

IntegrityKey must be IntKeySize bytes long

func NewIntegrityKey

func NewIntegrityKey() (IntegrityKey, error)

NewIntegrityKey generates a new random integrity key

func (IntegrityKey) NewHash

func (key IntegrityKey) NewHash() (hash.Hash, error)

NewHash creates a new keyed hash.Hash object

func (IntegrityKey) Sign

func (key IntegrityKey) Sign(msg []byte) ([]byte, error)

Sign calculates the hash of the byte slice

func (IntegrityKey) SignFile

func (key IntegrityKey) SignFile(path string) ([]byte, error)

SignFile calculates the hash of a file

func (IntegrityKey) Verify

func (key IntegrityKey) Verify(msg []byte, testSig []byte) (bool, error)

Verify validates a message against its hash

func (IntegrityKey) VerifyFile

func (key IntegrityKey) VerifyFile(path string, testSig []byte) (bool, error)

VerifyFile validates a file against its hash

type InvalidSignatureError

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

InvalidSignatureError is returned if a decryption is attempted on a tampered message

func (InvalidSignatureError) Error

func (e InvalidSignatureError) Error() string

type MACMismatchError

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

MACMismatchError is returned if the calculated MAC of a ciphertext does not match the provided MAC.

func (MACMismatchError) Error

func (e MACMismatchError) Error() string

type MsgTooShortError

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

MsgTooShortError is returned if the ciphertext is too short to be valid.

func (MsgTooShortError) Error

func (e MsgTooShortError) Error() string

type NoPrivKeyError

type NoPrivKeyError struct{}

NoPrivKeyError is returned if an AuthPair attempts to do something that requires a private key (such as signing) and it does not have one.

func (NoPrivKeyError) Error

func (e NoPrivKeyError) Error() string

type SalsaNonce

type SalsaNonce [16]byte

SalsaNonce is a helper type for keeping track of an XSalsa20 nonce's counter

func (*SalsaNonce) Bytes

func (n *SalsaNonce) Bytes() *[16]byte

Bytes returns a pointer to the raw SalsaNonce bytes

This function returns a pointer because salsa.XORKeyStream takes a pointer

func (*SalsaNonce) Copy

func (n *SalsaNonce) Copy() SalsaNonce

Copy returns a copy of this SalsaNonce

func (*SalsaNonce) Counter

func (n *SalsaNonce) Counter() uint64

Counter returns the uint64 representation of the SalsaNonce's counter

func (*SalsaNonce) Decr

func (n *SalsaNonce) Decr(count int)

Decr decrements the SalsaNonce counter by count

func (*SalsaNonce) Incr

func (n *SalsaNonce) Incr(count int)

Incr increments the SalsaNonce counter by count

func (*SalsaNonce) Set

func (n *SalsaNonce) Set(count uint64)

Set sets the SalsaNonce counter to count

type SalsaReader

type SalsaReader struct {

	// Integrous is true if the reader's MAC was valid, false otherwise
	Integrous bool
	// contains filtered or unexported fields
}

SalsaReader decrypts an io.ReadSeeker

func NewSalsaReader

func NewSalsaReader(encKey EncryptionKey, intKey IntegrityKey, backing io.ReadSeeker) (*SalsaReader, error)

NewSalsaReader creates a new SalsaReader which will read from backing

This function validates the backing's MAC and will block until the validation is finished. If the validation fails, it will return an error and block the SalsaReader from reading.

func (*SalsaReader) Read

func (sr *SalsaReader) Read(p []byte) (int, error)

Read decrypts and returns data

If the SalsaReader's validation failed in NewSalsaReader, this will return an error

func (*SalsaReader) Seek

func (sr *SalsaReader) Seek(offset int64, whence int) (int64, error)

Seek seeks to an offset in the DECRYPTED file. So seeking to position will put you at MsgOverhead in the backing stream, which is the start of the actual encrypted information.

Diagram

                     v Seek(0,0) will put you here
[MAC, Nonce, Etc ::: Actual Encrypted Data]
                  ^ MsgOverhead bytes

If the SalsaReader's validation failed in NewSalsaReader, this will return an error

func (*SalsaReader) WriteTo

func (sr *SalsaReader) WriteTo(w io.Writer) (int64, error)

WriteTo decrypts the entire backing reader and writes the decrypted contents to the given writer

WriteTo reads from the backing reader in FileChunkSize byte blocks

type SalsaWriter

type SalsaWriter struct {

	// Closed is true if the stream is closed & the MAC has been written
	Closed bool
	// contains filtered or unexported fields
}

SalsaWriter encrypts data and writes it to an io.WriteSeeker

func NewSalsaWriter

func NewSalsaWriter(encKey EncryptionKey, intKey IntegrityKey, backing io.WriteSeeker) (*SalsaWriter, error)

NewSalsaWriter creates a new SalsaWriter that will write to backing

This function leaves a IntHashSize byte block at the start of the backing stream, to hold the position of the MAC once its been calculated.

func (*SalsaWriter) Close

func (sw *SalsaWriter) Close() error

Close encrypts the remainder of the internal buffer & flushes it to the backing, then calculates the MAC of the entire backing and writes it to the start, in the placeholder NewSalsaWriter left earlier.

func (*SalsaWriter) ReadFrom

func (sw *SalsaWriter) ReadFrom(r io.Reader) (int64, error)

ReadFrom encrypts the entirety of a reader and writes the encrypted contents to backing

ReadFrom reads from the reader in FileChunkSize byte blocks

func (*SalsaWriter) Write

func (sw *SalsaWriter) Write(p []byte) (int, error)

Write encrypts a byte slice and writes it to the backing

XSalsa20 operates on 64 byte blocks, so to keep everything consistent we only write full 64 byte blocks. To manage this, we keep an internal buffer. When writing new data to the SalsaWriter we check the buffer size. If the buffer can be filled with bytes from p, we do that first, encrypt the buffer, and then flush the buffer. After that, we encrypt & write as many full blocks of p as we can, and store the leftovers in the internal buffer.

type SalsaWriterClosedError

type SalsaWriterClosedError struct{}

SalsaWriterClosedError is returned if a write is attempted to a closed salsa writer

func (SalsaWriterClosedError) Error

func (e SalsaWriterClosedError) Error() string

type SoughtBehindError

type SoughtBehindError struct{}

SoughtBehindError is returned if a seek is attempted behind the start of a SalsaReader's actual data.

func (SoughtBehindError) Error

func (e SoughtBehindError) Error() string

type UnintegrousReadError

type UnintegrousReadError struct{}

UnintegrousReadError is returned if a read or seek is attempted on a tampered SalsaReader.

func (UnintegrousReadError) Error

func (e UnintegrousReadError) Error() string

Jump to

Keyboard shortcuts

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