Documentation
¶
Overview ¶
Package memguard is designed to allow you to easily handle sensitive values in memory.
The general working cycle is easy to follow:
// Declare a protected slice and move bytes into it. encryptionKey := memguard.New(32) encryptionKey.Move(generateRandomBytes(32)) // Use the buffer wherever you need it. Encrypt(encryptionKey.Buffer, plaintext) // Destroy it after you're done. encryptionKey.Destroy()
As you'll have noted, the example above does not append or assign the key to the buffer, but rather it uses the built-in API function `Move()`.
b := memguard.New(32)
b.Move([]byte("...")) // Correct.
b.Copy([]byte("...")) // Less correct; original buffer isn't wiped.
b.Buffer = []byte("...") // WRONG
b.Buffer = append(b.Buffer, []byte("...")) // WRONG
If a function that you're using requires an array, you can cast the Buffer to an array and then pass around a pointer. Make sure that you do not dereference the pointer and pass around the resulting value, as this will leave copies all over the place.
key := memguard.NewFromBytes([]byte("yellow submarine"))
// Make sure that the size of the array matches the size of the Buffer.
keyArrayPtr := (*[16]byte)(unsafe.Pointer(&key.Buffer[0]))
The MemGuard API is thread-safe. You can extend this thread-safety to outside of the API functions by using the Mutex that each LockedBuffer exposes. Do not use the mutex when calling a function that is part of the MemGuard API. For example:
b := New(4)
b.Lock()
copy(b.Buffer, []byte("test"))
b.Unlock()
c := New(4)
c.Lock()
c.Copy([]byte("test")) // This will deadlock.
c.Unlock()
When terminating your application, care should be taken to securely cleanup everything.
// Start a listener that will wait for interrupt signals and catch them.
memguard.CatchInterrupt(func() {
// Over here put anything you want executing before program exit.
fmt.Println("Interrupt signal received. Exiting...")
})
// Defer a DestroyAll() in your main() function.
defer memguard.DestroyAll()
// Use memguard.SafeExit() instead of os.Exit().
memguard.SafeExit(0) // 0 is the status code.
Index ¶
- Variables
- func CatchInterrupt(f ExitFunc)
- func DestroyAll()
- func DisableCoreDumps()
- func Equal(a, b *LockedBuffer) (bool, error)
- func SafeExit(c int)
- func Split(b *LockedBuffer, offset int) (*LockedBuffer, *LockedBuffer, error)
- func WipeBytes(buf []byte)
- type ExitFunc
- type LockedBuffer
- func (b *LockedBuffer) Copy(buf []byte) error
- func (b *LockedBuffer) CopyAt(buf []byte, offset int) error
- func (b *LockedBuffer) Destroy()
- func (b *LockedBuffer) EqualTo(buf []byte) (bool, error)
- func (b *LockedBuffer) MarkAsReadOnly() error
- func (b *LockedBuffer) MarkAsReadWrite() error
- func (b *LockedBuffer) Move(buf []byte) error
- func (b *LockedBuffer) MoveAt(buf []byte, offset int) error
Constants ¶
This section is empty.
Variables ¶
var ErrDestroyed = errors.New("memguard.ErrDestroyed: buffer is destroyed")
ErrDestroyed is returned when a function is called on a destroyed LockedBuffer.
var ErrInvalidLength = errors.New("memguard.ErrInvalidLength: length of buffer must be greater than zero")
ErrInvalidLength is returned when a LockedBuffer of smaller than one byte is requested.
var ErrReadOnly = errors.New("memguard.ErrReadOnly: buffer is marked read-only")
ErrReadOnly is returned when a function that needs to modify a LockedBuffer is given a LockedBuffer that is marked as being read-only.
Functions ¶
func CatchInterrupt ¶
func CatchInterrupt(f ExitFunc)
CatchInterrupt starts a goroutine that monitors for interrupt signals. It accepts a function of type ExitFunc and executes that before calling SafeExit(0).
memguard.CatchInterrupt(func() {
fmt.Println("Interrupt signal received. Exiting...")
})
If CatchInterrupt is called multiple times, only the first call is executed and all subsequent calls are ignored.
func DestroyAll ¶
func DestroyAll()
DestroyAll calls Destroy on all LockedBuffers. This function can be called even if no LockedBuffers exist.
func DisableCoreDumps ¶
func DisableCoreDumps()
DisableCoreDumps disables core dumps on Unix systems. On windows it is a no-op.
func Equal ¶ added in v0.4.0
func Equal(a, b *LockedBuffer) (bool, error)
Equal compares the contents of two LockedBuffers in constant time. The LockedBuffers' respective permissions are ignored.
func SafeExit ¶
func SafeExit(c int)
SafeExit exits the program with the specified return code, but calls DestroyAll before doing so.
func Split ¶ added in v0.4.0
func Split(b *LockedBuffer, offset int) (*LockedBuffer, *LockedBuffer, error)
Split takes a LockedBuffer and splits it at a specified offset, then returning the two created LockedBuffers. The permissions of the original are copied over, and the original is preserved. This can be called with a LockedBuffer that is marked ReadOnly.
Types ¶
type ExitFunc ¶
type ExitFunc func()
ExitFunc is a function type that takes no arguments and returns no values. It is passed to CatchInterrupt which executes it before terminating the application securely.
type LockedBuffer ¶
type LockedBuffer struct {
// Exposed mutex for implementing thread-safety
// both within and outside of the API.
sync.Mutex
// Buffer holds the secure values themselves.
Buffer []byte
// A boolean flag indicating if this
// memory has been marked as read-only.
ReadOnly bool
// A boolean flag indicating whether this
// LockedBuffer has been destroyed. No API
// calls succeed on a destroyed buffer.
Destroyed bool
}
LockedBuffer implements a structure that holds protected values.
func Duplicate ¶ added in v0.4.0
func Duplicate(b *LockedBuffer) (*LockedBuffer, error)
Duplicate takes a LockedBuffer as an argument and creates a new one with the same contents and permissions. The original LockedBuffer is preserved.
func GenKey ¶ added in v0.4.0
func GenKey(length int) (*LockedBuffer, error)
GenKey creates a LockedBuffer that is filled with cryptographically-secure pseudo-random bytes instead of zeroes.
func New ¶
func New(length int) (*LockedBuffer, error)
New creates a new *LockedBuffer and returns it. The LockedBuffer's state is `ReadWrite`. Length must be greater than zero.
func NewFromBytes ¶
func NewFromBytes(buf []byte) (*LockedBuffer, error)
NewFromBytes creates a new *LockedBuffer from a byte slice, attempting to destroy the old value before returning. It is identicle to calling New() followed by Move().
func Trim ¶ added in v0.4.0
func Trim(b *LockedBuffer, offset, size int) (*LockedBuffer, error)
Trim shortens a LockedBuffer to a specified size. The returned `LockedBuffer.Buffer` is equal to `b.Buffer[offset:offset+size]`. This can be called with a LockedBuffer that is marked ReadOnly. The permissions of the original LockedBuffer are also copied over.
func (*LockedBuffer) Copy ¶
func (b *LockedBuffer) Copy(buf []byte) error
Copy copies bytes from a byte slice into a LockedBuffer, preserving the original slice. This is insecure, and so Move() should be favoured unless you have a specific need. You should aim to call WipeBytes(buf) as soon as possible.
func (*LockedBuffer) CopyAt ¶ added in v0.4.0
func (b *LockedBuffer) CopyAt(buf []byte, offset int) error
CopyAt copies bytes from a byte slice into a LockedBuffer, preserving the original slice. This is insecure, and so Move() should be favoured unless you have a specific need. It also takes an offset, and starts copying at that index. You should aim to call WipeBytes(buf) as soon as possible.
func (*LockedBuffer) Destroy ¶
func (b *LockedBuffer) Destroy()
Destroy verifies that everything went well, wipes the Buffer, and then unlocks and frees all related memory. This function should be called on all LockedBuffers before exiting. If the LockedBuffer has already been destroyed, then nothing happens and the function returns.
func (*LockedBuffer) EqualTo ¶ added in v0.4.0
func (b *LockedBuffer) EqualTo(buf []byte) (bool, error)
EqualTo compares a LockedBuffer to a byte slice in constant time.
func (*LockedBuffer) MarkAsReadOnly ¶ added in v0.4.0
func (b *LockedBuffer) MarkAsReadOnly() error
MarkAsReadOnly makes the buffer read-only. After setting this, any other action will trigger a SIGSEGV violation.
func (*LockedBuffer) MarkAsReadWrite ¶ added in v0.4.0
func (b *LockedBuffer) MarkAsReadWrite() error
MarkAsReadWrite makes the buffer readable and writable. This is the default state of new LockedBuffers.
func (*LockedBuffer) Move ¶
func (b *LockedBuffer) Move(buf []byte) error
Move copies bytes from a byte slice into a LockedBuffer, wiping the original slice afterwards.