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
- func HashFile(path string, hasher hash.Hash) ([]byte, error)
- func HashReader(r io.Reader, hasher hash.Hash) ([]byte, error)
- type AuthPair
- type AuthPairBadSizeError
- type CryptoProvider
- func (c *CryptoProvider) Decrypt(msg []byte) ([]byte, error)
- func (c *CryptoProvider) DecryptFile(inPath, outPath string) error
- func (c *CryptoProvider) Encrypt(msg []byte) ([]byte, error)
- func (c *CryptoProvider) EncryptFile(inPath, outPath string) error
- func (c *CryptoProvider) Sign(msg []byte) ([]byte, error)
- func (c *CryptoProvider) SignFile(path string) ([]byte, error)
- func (c *CryptoProvider) Verify(msg, sig []byte) bool
- func (c *CryptoProvider) VerifyFile(path string, sig []byte) (bool, error)
- type CryptoProviderBadSizeError
- type EncKeyBadSizeError
- type EncNonceBadSizeError
- type EncryptionKey
- type IntKeyBadSizeError
- type IntegrityKey
- func (key IntegrityKey) NewHash() (hash.Hash, error)
- func (key IntegrityKey) Sign(msg []byte) ([]byte, error)
- func (key IntegrityKey) SignFile(path string) ([]byte, error)
- func (key IntegrityKey) Verify(msg []byte, testSig []byte) (bool, error)
- func (key IntegrityKey) VerifyFile(path string, testSig []byte) (bool, error)
- type InvalidSignatureError
- type MACMismatchError
- type MsgTooShortError
- type NoPrivKeyError
- type SalsaNonce
- type SalsaReader
- type SalsaWriter
- type SalsaWriterClosedError
- type SoughtBehindError
- type UnintegrousReadError
Constants ¶
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 ¶
Types ¶
type AuthPair ¶
type AuthPair struct {
// contains filtered or unexported fields
}
AuthPair provides authentication via public/private keys
func AuthPairFromBytes ¶
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 ¶
NewAuthPair generates a new public/private key pair
func (AuthPair) Sign ¶
Sign generates a signature for a message. If the AuthPair does not have a private key this will return an error.
func (AuthPair) SignFile ¶
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
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 ¶
func (e CryptoProviderBadSizeError) Error() string
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
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
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