### Run Go Tests with Race Detector Source: https://github.com/awnumar/memguard/blob/master/examples/README.md Execute Go tests with the race detector enabled for the examples directory. This command can be used to run tests for individual modules or all examples. ```bash go test -v -race ./examples/module_name ``` ```bash go test -v -race ./examples/... ``` -------------------------------- ### Install MemGuard Go Package Source: https://github.com/awnumar/memguard/blob/master/README.md Use this command to add MemGuard to your Go project. It is recommended to pin a specific version due to the experimental nature of the API. ```bash go get github.com/awnumar/memguard ``` -------------------------------- ### Create and Open Encrypted Enclave Source: https://context7.com/awnumar/memguard/llms.txt Use NewEnclave to encrypt a byte slice into a sealed container, wiping the source. NewEnclaveRandom generates random bytes. Open decrypts the Enclave into a LockedBuffer. An error occurs if the session key was rotated. ```go package main import ( "fmt" "github.com/awnumar/memguard" "github.com/awnumar/memguard/core" ) func main() { defer memguard.Purge() // Seal from a raw byte slice (src is wiped). src := []byte("sensitive-value") enc := memguard.NewEnclave(src) fmt.Println("src wiped:", src) // src wiped: [0 0 0 0 0 0 0 0 0 0 0 0 0 0 0] fmt.Println("enclave size:", enc.Size()) // enclave size: 15 // Generate a 32-byte random key, never exposed in plaintext. keyEnc := memguard.NewEnclaveRandom(32) // Open returns an immutable LockedBuffer. buf, err := enc.Open() if err != nil { panic(err) // core.ErrDecryptionFailed if session was purged } defer buf.Destroy() fmt.Println("value:", buf.String()) // value: sensitive-value // After Purge, all open attempts fail. memguard.Purge() _, err = keyEnc.Open() fmt.Println("after purge error:", err == core.ErrDecryptionFailed) // true } ``` -------------------------------- ### Manage Session Lifecycle with MemGuard Source: https://context7.com/awnumar/memguard/llms.txt Manage the security lifecycle of a program session using functions like CatchInterrupt, CatchSignal, Purge, SafeExit, and SafePanic. These functions ensure sensitive memory is wiped before program exit or panic. ```go package main import ( "fmt" "os" "github.com/awnumar/memguard" ) func main() { // Intercept SIGINT: wipe memory then exit with code 1. memguard.CatchInterrupt() // Advanced: custom callback on SIGINT or SIGTERM. memguard.CatchSignal(func(s os.Signal) { fmt.Fprintln(os.Stderr, "signal received:", s) }, os.Interrupt) // Guarantee all LockedBuffers are destroyed when main returns. defer memguard.Purge() key := memguard.NewEnclaveRandom(32) buf, err := key.Open() if err != nil { memguard.SafePanic(err) // wipes memory before panicking } defer buf.Destroy() fmt.Println("key length:", buf.Size()) // key length: 32 // Wipe an arbitrary (non-guarded) byte slice. plaintext := []byte("secret password") memguard.WipeBytes(plaintext) // Overwrite an arbitrary slice with cryptographically-secure random bytes. nonce := make([]byte, 24) memguard.ScrambleBytes(nonce) memguard.SafeExit(0) // wipes memory before calling os.Exit(0) } ``` -------------------------------- ### Create Immutable Random Buffer with memguard Source: https://context7.com/awnumar/memguard/llms.txt Use NewBufferRandom to generate a cryptographically-secure random buffer of a specified size. The buffer is immediately frozen and immutable. Useful for keys, nonces, and IVs. ```go package main import ( "fmt" "github.com/awnumar/memguard" ) func main() { defer memguard.Purge() // 32-byte random key, immediately immutable. key := memguard.NewBufferRandom(32) defer key.Destroy() fmt.Println("size:", key.Size()) // size: 32 fmt.Println("mutable:", key.IsMutable()) // mutable: false // Access as various numeric types (zero-copy casts). u64 := key.Uint64() // []uint64 of length 4 u32 := key.Uint32() // []uint32 of length 8 u16 := key.Uint16() // []uint16 of length 16 i8 := key.Int8() // []int8 of length 32 fmt.Println("uint64[0]:", u64[0]) fmt.Println("uint32[0]:", u32[0]) fmt.Println("uint16[0]:", u16[0]) fmt.Println("int8[0]:", i8[0]) // Fixed-size array pointer for APIs that require *[32]byte. arr32 := key.ByteArray32() // *[32]byte — do NOT dereference and store _ = arr32 } ``` -------------------------------- ### Time-constant copy into a LockedBuffer Source: https://context7.com/awnumar/memguard/llms.txt Copy performs a constant-time copy of a byte slice into the beginning of a LockedBuffer. CopyAt allows specifying a byte offset. Unlike Move, the source slice is not zeroed. Use Copy when the source is also a LockedBuffer or when you need the source to remain intact. ```go package main import ( "fmt" "github.com/awnumar/memguard" ) func main() { defer memguard.Purge() buf := memguard.NewBuffer(8) defer buf.Destroy() src := []byte{0x01, 0x02, 0x03, 0x04} // Copy into the first 4 bytes. buf.Copy(src) fmt.Println("after Copy:", buf.Bytes()) // after Copy: [1 2 3 4 0 0 0 0] // Copy into bytes 4-7. buf.CopyAt(4, []byte{0x05, 0x06, 0x07, 0x08}) fmt.Println("after CopyAt:", buf.Bytes()) // after CopyAt: [1 2 3 4 5 6 7 8] // src is not wiped. fmt.Println("src intact:", src) // src intact: [1 2 3 4] } ``` -------------------------------- ### Cast LockedBuffer to Numeric Types and Structs in Go Source: https://context7.com/awnumar/memguard/llms.txt Demonstrates casting a LockedBuffer to various numeric types (Uint64, Uint32) and fixed-size byte arrays. Also shows how to cast to arbitrary struct types using unsafe.Pointer. ```Go package main import ( "fmt" "unsafe" "github.com/awnumar/memguard" ) type CryptoState struct { Key [32]byte Counter uint64 } func main() { defer memguard.Purge() // --- Built-in numeric casts --- buf := memguard.NewBufferRandom(32) defer buf.Destroy() u64s := buf.Uint64() // []uint64, len=4 u32s := buf.Uint32() // []uint32, len=8 fmt.Printf("uint64 view: %v\n", u64s[:2]) fmt.Printf("uint32 view: %v\n", u32s[:4]) // Fixed-size array pointer (for crypto APIs requiring *[32]byte). arr := buf.ByteArray32() // *[32]byte _ = arr // pass to crypto function as-is; do not dereference/store // --- Struct cast --- s := new(CryptoState) structBuf := memguard.NewBuffer(int(unsafe.Sizeof(*s))) defer structBuf.Destroy() state := (*CryptoState)(unsafe.Pointer(&structBuf.Bytes()[0])) state.Counter = 1 copy(state.Key[:], "my-32-byte-secret-key-here!12345") fmt.Println("counter:", state.Counter) // counter: 1 fmt.Println("key set:", state.Key[0] == 'm') // key set: true // --- Fixed-size array cast example --- tenBuf := memguard.NewBuffer(10) defer tenBuf.Destroy() arr10 := (*[10]byte)(unsafe.Pointer(&tenBuf.Bytes()[0])) arr10[0] = 0xFF fmt.Println("arr10[0]:", arr10[0]) // arr10[0]: 255 } ``` -------------------------------- ### Time-constant move into a LockedBuffer (wipes source) Source: https://context7.com/awnumar/memguard/llms.txt Move copies a byte slice into a LockedBuffer and then zeroes the source. MoveAt does the same at a given byte offset. This is the preferred method for importing external secrets because it eliminates the plaintext from the original allocation immediately. ```go package main import ( "fmt" "github.com/awnumar/memguard" ) func main() { defer memguard.Purge() buf := memguard.NewBuffer(16) defer buf.Destroy() secret := []byte("my-api-key-12345") buf.Move(secret) fmt.Println("buf:", buf.String()) // buf: my-api-key-12345 fmt.Println("src wiped:", secret) // src wiped: [0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0] // Move into offset (partial replacement). patch := []byte("NEW!") buf.Melt() // need to melt first if frozen buf.MoveAt(0, patch) fmt.Println("after MoveAt:", buf.String()) // after MoveAt: NEW!-api-key-12345 fmt.Println("patch wiped:", patch) // patch wiped: [0 0 0 0] } ``` -------------------------------- ### Create Immutable Buffer from Bytes with memguard Source: https://context7.com/awnumar/memguard/llms.txt Use NewBufferFromBytes to copy data from a byte slice into a new immutable LockedBuffer. The source byte slice is zeroed after the copy. Ideal for importing secrets. ```go package main import ( "fmt" "github.com/awnumar/memguard" ) func main() { defer memguard.Purge() // Imagine this came from user input or a config file. rawSecret := []byte("my-database-password") buf := memguard.NewBufferFromBytes(rawSecret) defer buf.Destroy() // rawSecret has been zeroed by Move internally. fmt.Println("src after import:", rawSecret) // src after import: [0 0 0 0 0 0 ...] fmt.Println("buf size:", buf.Size()) // buf size: 20 fmt.Println("immutable:", !buf.IsMutable()) // immutable: true fmt.Println("as string:", buf.String()) // as string: my-database-password // bytes.Reader for io-compatible use. r := buf.Reader() out := make([]byte, buf.Size()) r.Read(out) fmt.Println("read back:", string(out)) // read back: my-database-password } ``` -------------------------------- ### Read Exact Bytes from Reader into Buffer with memguard Source: https://context7.com/awnumar/memguard/llms.txt Use NewBufferFromReader to read a specific number of bytes from an io.Reader into a locked memory region. Returns an error if fewer bytes are available than requested. Ideal for reading keys from network connections or files. ```go package main import ( "fmt" "io" "strings" "github.com/awnumar/memguard" ) func main() { defer memguard.Purge() // Simulate reading a 16-byte key from a network connection. src := strings.NewReader("0123456789abcdef_extra_data") buf, err := memguard.NewBufferFromReader(src, 16) if err != nil && err != io.ErrUnexpectedEOF { panic(err) } defer buf.Destroy() fmt.Println("bytes read:", buf.Size()) // bytes read: 16 fmt.Println("data:", buf.String()) // data: 0123456789abcdef fmt.Println("immutable:", !buf.IsMutable()) // immutable: true // Seal it for long-term storage. enc := buf.Seal() // buf is destroyed after this fmt.Println("enclave size:", enc.Size()) // enclave size: 16 } ``` -------------------------------- ### Read Until Delimiter from Reader into Buffer with memguard Source: https://context7.com/awnumar/memguard/llms.txt Use NewBufferFromReaderUntil to read from an io.Reader into a dynamically growing LockedBuffer until a delimiter is found. The buffer is trimmed and immutable. Suitable for reading newline-terminated secrets from stdin. ```go package main import ( "fmt" "os" "github.com/awnumar/memguard" ) func readPassword() (*memguard.Enclave, error) { // Read from stdin until newline, store in guarded memory. buf, err := memguard.NewBufferFromReaderUntil(os.Stdin, '\n') if err != nil { return nil, err } if buf.Size() == 0 { return nil, fmt.Errorf("no input") } // Seal immediately; Seal destroys buf. return buf.Seal(), nil } func main() { defer memguard.Purge() memguard.CatchInterrupt() enc, err := readPassword() if err != nil { fmt.Fprintln(os.Stderr, err) return } // Decrypt when needed. buf, err := enc.Open() if err != nil { memguard.SafePanic(err) } defer buf.Destroy() fmt.Printf("received %d-byte password\n", buf.Size()) } ``` -------------------------------- ### Allocate Mutable Guarded Memory with NewBuffer Source: https://context7.com/awnumar/memguard/llms.txt Allocate a zeroed, mutable LockedBuffer of a specified size using kernel memory-locking. Always check IsAlive() or Size() after allocation, as failure returns a destroyed buffer. Destroy the buffer as soon as possible. ```go package main import ( "fmt" "github.com/awnumar/memguard" ) func main() { defer memguard.Purge() // Allocate 32 bytes of mutable guarded memory. buf := memguard.NewBuffer(32) if !buf.IsAlive() { panic("allocation failed") } defer buf.Destroy() fmt.Println("size:", buf.Size()) // size: 32 fmt.Println("mutable:", buf.IsMutable()) // mutable: true // Write sensitive data into the buffer (wipes src after copy). password := []byte("s3cr3t-p4ssword!") buf.Move(password) fmt.Println("src wiped:", password) // src wiped: [0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0] // Time-constant comparison. fmt.Println("equal:", buf.EqualTo([]byte("s3cr3t-p4ssword!"))) // equal: true // Make immutable (kernel enforced); reverse with Melt(). buf.Freeze() fmt.Println("mutable after freeze:", buf.IsMutable()) // mutable after freeze: false buf.Melt() // allow writes again buf.Wipe() // zero the contents } ``` -------------------------------- ### NewEnclave, NewEnclaveRandom, Enclave.Open Source: https://context7.com/awnumar/memguard/llms.txt Encrypts data into sealed containers (Enclaves) or generates random encrypted data. The Open method decrypts the Enclave into a LockedBuffer. ```APIDOC ## `NewEnclave` / `NewEnclaveRandom` / `Enclave.Open` — encrypted at-rest containers `NewEnclave` encrypts a byte slice directly into a sealed container, wiping the source. `NewEnclaveRandom` generates and seals `size` random bytes without ever exposing them in plaintext. `Open` decrypts an `Enclave` and returns its contents in an immutable `LockedBuffer`. Returns an error if the session key has been rotated (via `Purge`) since sealing. ### Method `NewEnclave(src []byte) *Enclave` `NewEnclaveRandom(size int) *Enclave` `(*Enclave) Open() (*LockedBuffer, error)` ### Description - `NewEnclave`: Creates an encrypted enclave from a byte slice. The original byte slice is wiped after encryption. - `NewEnclaveRandom`: Creates an encrypted enclave containing a specified number of random bytes. These bytes are never exposed in plaintext. - `Open`: Decrypts the enclave and returns its contents as a `LockedBuffer`. This operation will fail if the session key has been rotated since the enclave was sealed. ### Response #### Success Response - `NewEnclave`/`NewEnclaveRandom`: Returns an `*Enclave` object representing the encrypted container. - `Open`: Returns an `*LockedBuffer` containing the decrypted data and a `nil` error upon success. #### Error Response - `Open`: Returns an error if decryption fails, for example, if `core.ErrDecryptionFailed` is encountered due to session key rotation. ``` -------------------------------- ### Session Lifecycle Management Source: https://context7.com/awnumar/memguard/llms.txt Functions to manage the security lifecycle of a program session, including signal handling and memory purging. ```APIDOC ## Session Lifecycle Management These top-level functions manage the security lifecycle of an entire program session. `CatchInterrupt` registers a handler that wipes all sensitive data before the process exits on `SIGINT`. `CatchSignal` is the general form that accepts any set of OS signals and a custom callback. `Purge` destroys all live `LockedBuffer` objects and rotates the session encryption key, rendering existing `Enclave` objects undecryptable. `SafeExit` and `SafePanic` are drop-in replacements for `os.Exit` and `panic` that purge sensitive memory first. ### Functions - **`CatchInterrupt()`**: Registers a handler to wipe sensitive data on `SIGINT`. - **`CatchSignal(callback func(os.Signal), signals ...os.Signal)`**: Registers a custom callback for specified OS signals. - **`Purge()`**: Destroys all live `LockedBuffer` objects and rotates the session encryption key. - **`SafeExit(code int)`**: Purges sensitive memory before calling `os.Exit(code)`. - **`SafePanic(v interface{})`**: Purges sensitive memory before calling `panic(v)`. - **`WipeBytes(b []byte)`**: Wipes an arbitrary byte slice. - **`ScrambleBytes(b []byte)`**: Overwrites an arbitrary slice with cryptographically-secure random bytes. ### Example ```go package main import ( "fmt" "os" "github.com/awnumar/memguard" ) func main() { // Intercept SIGINT: wipe memory then exit with code 1. memguard.CatchInterrupt() // Advanced: custom callback on SIGINT or SIGTERM. memguard.CatchSignal(func(s os.Signal) { fmt.Fprintln(os.Stderr, "signal received:", s) }, os.Interrupt) // Guarantee all LockedBuffers are destroyed when main returns. defer memguard.Purge() key := memguard.NewEnclaveRandom(32) buf, err := key.Open() if err != nil { memguard.SafePanic(err) // wipes memory before panicking } defer buf.Destroy() fmt.Println("key length:", buf.Size()) // key length: 32 // Wipe an arbitrary (non-guarded) byte slice. plaintext := []byte("secret password") memguard.WipeBytes(plaintext) // Overwrite an arbitrary slice with cryptographically-secure random bytes. nonce := make([]byte, 24) memguard.ScrambleBytes(nonce) memguard.SafeExit(0) // wipes memory before calling os.Exit(0) } ``` ``` -------------------------------- ### NewBufferFromBytes Source: https://context7.com/awnumar/memguard/llms.txt Constructs a new immutable LockedBuffer by copying the contents of a byte slice. The source byte slice is zeroed after the copy. This is the primary method for importing secrets into the secure enclave. ```APIDOC ## NewBufferFromBytes ### Description Copies the contents of an existing byte slice into a new `LockedBuffer` and then zeroes the source slice. The resulting buffer is immutable. ### Usage ```go func NewBufferFromBytes(src []byte) *LockedBuffer ``` ### Parameters * `src` ([]byte) - The byte slice to copy data from. This slice will be zeroed after the operation. ### Returns * `*LockedBuffer` - A new, immutable buffer containing a copy of the source data. ### Example ```go // Imagine this came from user input or a config file. rawSecret := []byte("my-database-password") buf := memguard.NewBufferFromBytes(rawSecret) defer buf.Destroy() // rawSecret has been zeroed by Move internally. fmt.Println("src after import:", rawSecret) // src after import: [0 0 0 0 0 0 ...] fmt.Println("buf size:", buf.Size()) // buf size: 20 fmt.Println("immutable:", !buf.IsMutable()) // immutable: true fmt.Println("as string:", buf.String()) // as string: my-database-password ``` ``` -------------------------------- ### LockedBuffer.Move / MoveAt Source: https://context7.com/awnumar/memguard/llms.txt Copies a byte slice into a LockedBuffer and then zeroes the source slice. MoveAt copies at a specified offset. This is the preferred method for importing external secrets as it eliminates the plaintext from the original allocation immediately. ```APIDOC ## LockedBuffer.Move / MoveAt ### Description Copies a byte slice into a `LockedBuffer` and then zeroes the source slice. `MoveAt` does the same at a given byte offset. This is the preferred method for importing external secrets because it eliminates the plaintext from the original allocation immediately. ### Methods - `Move(src []byte)` - `MoveAt(offset int, src []byte)` ### Parameters #### Path Parameters None #### Query Parameters None #### Parameters for `Move` - **src** ([]byte) - Required - The byte slice to move. #### Parameters for `MoveAt` - **offset** (int) - Required - The byte offset within the buffer to start moving. - **src** ([]byte) - Required - The byte slice to move. ### Request Example ```go package main import ( "fmt" "github.com/awnumar/memguard" ) func main() { defer memguard.Purge() buf := memguard.NewBuffer(16) defer buf.Destroy() secret := []byte("my-api-key-12345") buf.Move(secret) fmt.Println("buf:", buf.String()) // buf: my-api-key-12345 fmt.Println("src wiped:", secret) // src wiped: [0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0] // Move into offset (partial replacement). patch := []byte("NEW!") buf.Melt() // need to melt first if frozen buf.MoveAt(0, patch) fmt.Println("after MoveAt:", buf.String()) // after MoveAt: NEW!-api-key-12345 fmt.Println("patch wiped:", patch) // patch wiped: [0 0 0 0] } ``` ### Response #### Success Response (200) These methods do not return a value, but modify the `LockedBuffer` in place and zero the source slice. #### Response Example ```go // Example output: buf: my-api-key-12345 src wiped: [0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0] after MoveAt: NEW!-api-key-12345 patch wiped: [0 0 0 0] ``` ``` -------------------------------- ### LockedBuffer.Copy / CopyAt Source: https://context7.com/awnumar/memguard/llms.txt Performs a constant-time copy of a byte slice into the beginning of a LockedBuffer. CopyAt allows specifying a byte offset. The source slice is not zeroed after the copy. ```APIDOC ## LockedBuffer.Copy / CopyAt ### Description Performs a constant-time copy of a byte slice into a `LockedBuffer`. `Copy` copies to the beginning, while `CopyAt` allows specifying a byte offset. Unlike `Move`, the source slice is **not** zeroed. Use `Copy` when the source is also a `LockedBuffer` or when you need the source to remain intact; prefer `Move` otherwise. ### Methods - `Copy(src []byte)` - `CopyAt(offset int, src []byte)` ### Parameters #### Path Parameters None #### Query Parameters None #### Parameters for `Copy` - **src** ([]byte) - Required - The byte slice to copy. #### Parameters for `CopyAt` - **offset** (int) - Required - The byte offset within the buffer to start copying. - **src** ([]byte) - Required - The byte slice to copy. ### Request Example ```go package main import ( "fmt" "github.com/awnumar/memguard" ) func main() { defer memguard.Purge() buf := memguard.NewBuffer(8) defer buf.Destroy() src := []byte{0x01, 0x02, 0x03, 0x04} // Copy into the first 4 bytes. buf.Copy(src) fmt.Println("after Copy:", buf.Bytes()) // after Copy: [1 2 3 4 0 0 0 0] // Copy into bytes 4-7. buf.CopyAt(4, []byte{0x05, 0x06, 0x07, 0x08}) fmt.Println("after CopyAt:", buf.Bytes()) // after CopyAt: [1 2 3 4 5 6 7 8] // src is not wiped. fmt.Println("src intact:", src) // src intact: [1 2 3 4] } ``` ### Response #### Success Response (200) These methods do not return a value, but modify the `LockedBuffer` in place. #### Response Example ```go // Example output: after Copy: [1 2 3 4 0 0 0 0] after CopyAt: [1 2 3 4 5 6 7 8] src intact: [1 2 3 4] ``` ``` -------------------------------- ### NewBufferFromEntireReader Source: https://context7.com/awnumar/memguard/llms.txt Reads all bytes from an io.Reader into a LockedBuffer. It drains the reader completely and grows the buffer page by page. Returns nil error on clean EOF, but provides any data read before a non-EOF error. ```APIDOC ## NewBufferFromEntireReader ### Description Drains an `io.Reader` completely into a `LockedBuffer` that grows by one page at a time as data arrives. Returns `nil` error only on clean EOF. Any data read before a non-EOF error is still returned. Useful for reading entire files or response bodies into protected memory. ### Usage ```go func NewBufferFromEntireReader(r io.Reader) (*LockedBuffer, error) ``` ### Parameters #### Path Parameters None #### Query Parameters None ### Request Body None ### Request Example ```go package main import ( "fmt" "strings" "github.com/awnumar/memguard" ) func main() { defer memguard.Purge() src := strings.NewReader("the quick brown fox jumps over the lazy dog") buf, err := memguard.NewBufferFromEntireReader(src) if err != nil { panic(err) } defer buf.Destroy() fmt.Println("total bytes:", buf.Size()) fmt.Println("content:", buf.String()) } ``` ### Response #### Success Response (200) - **LockedBuffer** (*memguard.LockedBuffer*): A buffer containing all data read from the reader. - **error** (*error*): Nil on clean EOF, otherwise an error indicating why reading stopped. #### Response Example ```go // Example output: total bytes: 43 content: the quick brown fox jumps over the lazy dog ``` ``` -------------------------------- ### Encrypt buffer contents into an Enclave Source: https://context7.com/awnumar/memguard/llms.txt Seal encrypts the contents of a LockedBuffer with XSalsa20Poly1305, stores the ciphertext in a new Enclave, and destroys the source LockedBuffer. If called on a destroyed buffer, nil is returned. Enclave objects are not mlock-limited, making sealing recommended for holding many secrets. ```go package main import ( "fmt" "github.com/awnumar/memguard" ) func main() { defer memguard.Purge() buf := memguard.NewBuffer(32) buf.Move([]byte("32-byte-secret-key-here!12345678")) // Seal destroys buf and returns an Enclave. enc := buf.Seal() fmt.Println("buf alive after seal:", buf.IsAlive()) // buf alive after seal: false fmt.Println("enclave size:", enc.Size()) // enclave size: 32 // Open to use the key. reopened, err := enc.Open() if err != nil { panic(err) } defer reopened.Destroy() fmt.Println("decrypted:", reopened.String()) // decrypted: 32-byte-secret-key-here!12345678 } ``` -------------------------------- ### NewBufferRandom Source: https://context7.com/awnumar/memguard/llms.txt Allocates a new LockedBuffer filled with cryptographically-secure random bytes and immediately freezes it, making it immutable. This is ideal for generating keys, nonces, and IVs. ```APIDOC ## NewBufferRandom ### Description Fills a new `LockedBuffer` with cryptographically-secure random bytes and immediately freezes it (immutable). ### Usage ```go func NewBufferRandom(size int) *LockedBuffer ``` ### Parameters * `size` (int) - The desired size of the buffer in bytes. ### Returns * `*LockedBuffer` - A new, immutable buffer containing random bytes. ### Example ```go // 32-byte random key, immediately immutable. key := memguard.NewBufferRandom(32) defer key.Destroy() fmt.Println("size:", key.Size()) // size: 32 fmt.Println("mutable:", key.IsMutable()) // mutable: false ``` ``` -------------------------------- ### Securely Erase Sensitive Data in Go Byte Slices Source: https://context7.com/awnumar/memguard/llms.txt Utilizes ScrambleBytes to overwrite with random data or WipeBytes to overwrite with zeroes for sensitive byte slices. Useful for intermediate buffers or decoded values before garbage collection. ```Go package main import ( "fmt" "github.com/awnumar/memguard" ) func main() { // Wipe a password received from an HTTP request body. reqBody := []byte("user:hunter2") memguard.WipeBytes(reqBody) fmt.Println("wiped:", reqBody) // wiped: [0 0 0 0 0 0 0 0 0 0 0 0] // Overwrite a nonce with random bytes for re-use prevention. nonce := make([]byte, 24) copy(nonce, "my-old-nonce-value123456") memguard.ScrambleBytes(nonce) fmt.Println("scrambled (not zero):", nonce[0] == 0 && nonce[1] == 0) // likely false } ``` -------------------------------- ### Read all bytes from an io.Reader into a LockedBuffer Source: https://context7.com/awnumar/memguard/llms.txt Use NewBufferFromEntireReader to drain an io.Reader completely into a LockedBuffer. It returns nil error only on clean EOF. Any data read before a non-EOF error is still returned. ```go package main import ( "fmt" "strings" "github.com/awnumar/memguard" ) func main() { defer memguard.Purge() src := strings.NewReader("the quick brown fox jumps over the lazy dog") buf, err := memguard.NewBufferFromEntireReader(src) if err != nil { panic(err) } defer buf.Destroy() fmt.Println("total bytes:", buf.Size()) // total bytes: 43 fmt.Println("content:", buf.String()) // content: the quick brown fox ... } ``` -------------------------------- ### Use Encrypted Stream for Sequential Data Source: https://context7.com/awnumar/memguard/llms.txt Stream provides an encrypted FIFO queue for large datasets. Write data in chunks, read back in chunks using Read, or access individual chunks with Next. Flush drains the entire stream into a single LockedBuffer. ```go package main import ( "fmt" "io" "os" "github.com/awnumar/memguard" ) func main() { defer memguard.Purge() // Generate 16 KiB of random data (simulate incoming network data). data := memguard.NewBufferRandom(1024 * 16) data.Melt() // allow Stream.Write to wipe after copying s := memguard.NewStream() // Write to stream (data is encrypted in chunks). n, _ := s.Write(data.Bytes()) data.Destroy() fmt.Println("written:", n, "bytes") // written: 16384 bytes fmt.Println("stream size:", s.Size()) // stream size: 16384 // Read back in page-sized chunks. chunk := memguard.NewBuffer(os.Getpagesize()) defer chunk.Destroy() var total int for { n, err := s.Read(chunk.Bytes()) total += n if err == io.EOF { break } if err != nil { memguard.SafePanic(err) } } fmt.Println("total read:", total) // total read: 16384 // Alternatively use Next() for chunk-by-chunk LockedBuffer access. s2 := memguard.NewStream() s2.Write([]byte("hello world")) lb, err := s2.Next() if err == nil { defer lb.Destroy() fmt.Println("next chunk:", lb.String()) // next chunk: hello world } // Or Flush to drain everything at once. s3 := memguard.NewStream() s3.Write([]byte("flush me")) all, _ := s3.Flush() defer all.Destroy() fmt.Println("flushed:", all.String()) // flushed: flush me } ``` -------------------------------- ### NewBuffer Source: https://context7.com/awnumar/memguard/llms.txt Allocates a mutable guarded memory region of a specified size. ```APIDOC ## `NewBuffer` — allocate a mutable guarded memory region `NewBuffer` allocates a zeroed, mutable `LockedBuffer` of exactly `size` bytes using kernel memory-locking (`mlock`/`VirtualLock`). The region is surrounded by guard pages; overflows trigger an access violation. If allocation fails (e.g., mlock limit exceeded), a destroyed zero-size buffer is returned — always check `IsAlive()` or `Size()` before use. Destroy the buffer as soon as possible to free the locked memory. ### Function Signature `func NewBuffer(size int) *LockedBuffer` ### Parameters - **size** (int) - The desired size of the buffer in bytes. ### Return Value - **`*LockedBuffer`** - A pointer to the newly allocated `LockedBuffer`. Check `IsAlive()` on the returned buffer to ensure allocation was successful. ### Methods on `LockedBuffer` - **`IsAlive() bool`**: Returns true if the buffer is alive and has not been destroyed. - **`Size() int`**: Returns the size of the buffer in bytes. - **`IsMutable() bool`**: Returns true if the buffer is currently mutable. - **`Move(src []byte)`**: Writes data from `src` into the buffer, wiping `src` afterwards. Only available on mutable buffers. - **`EqualTo(b []byte) bool`**: Performs a time-constant comparison between the buffer's contents and `b`. - **`Freeze()`**: Makes the buffer immutable (kernel enforced). Writes will cause an access violation. - **`Melt()`**: Allows writes to the buffer again after it has been frozen. - **`Wipe()`**: Zeros out the contents of the buffer. - **`Destroy()`**: Frees the memory associated with the buffer. ### Example ```go package main import ( "fmt" "github.com/awnumar/memguard" ) func main() { defer memguard.Purge() // Allocate 32 bytes of mutable guarded memory. buf := memguard.NewBuffer(32) if !buf.IsAlive() { panic("allocation failed") } defer buf.Destroy() fmt.Println("size:", buf.Size()) // size: 32 fmt.Println("mutable:", buf.IsMutable()) // mutable: true // Write sensitive data into the buffer (wipes src after copy). password := []byte("s3cr3t-p4ssword!") buf.Move(password) fmt.Println("src wiped:", password) // src wiped: [0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0] // Time-constant comparison. fmt.Println("equal:", buf.EqualTo([]byte("s3cr3t-p4ssword!"))) // equal: true // Make immutable (kernel enforced); reverse with Melt(). buf.Freeze() fmt.Println("mutable after freeze:", buf.IsMutable()) // mutable after freeze: false buf.Melt() // allow writes again buf.Wipe() // zero the contents } ``` ``` -------------------------------- ### Stream Source: https://context7.com/awnumar/memguard/llms.txt A FIFO encrypted queue for large datasets, supporting chunked reading and writing. Data is stored as Enclave objects. ```APIDOC ## `Stream` — encrypted sequential in-memory store (`io.Reader` / `io.Writer`) `Stream` is a FIFO encrypted queue suitable for large datasets that need to be processed in chunks. Data written via `Write` is broken into chunks of `StreamChunkSize` (default: 4 × page size) and stored as individual `Enclave` objects. `Read` decrypts and returns the next chunk. `Next` returns the next chunk as a `LockedBuffer`. `Flush` drains the entire stream into a single `LockedBuffer`. `Size` returns total stored bytes. ### Methods - `NewStream() *Stream`: Creates a new, empty encrypted stream. - `(*Stream) Write(p []byte) (n int, err error)`: Writes data to the stream. The data is encrypted and stored in chunks. - `(*Stream) Read(p []byte) (n int, err error)`: Reads the next chunk of decrypted data from the stream into the provided byte slice `p`. Returns `io.EOF` when the stream is exhausted. - `(*Stream) Next() (*LockedBuffer, error)`: Returns the next chunk of decrypted data as a `LockedBuffer`. - `(*Stream) Flush() (*LockedBuffer, error)`: Drains the entire stream, decrypts all chunks, and returns the combined decrypted data as a single `LockedBuffer`. - `(*Stream) Size() int`: Returns the total number of bytes currently stored in the stream. ### Description The `Stream` type provides an encrypted, sequential data store. It's designed for handling large amounts of data by breaking it into manageable, encrypted chunks. You can write data to the stream, and then read it back either chunk by chunk using `Read` or `Next`, or all at once using `Flush`. ``` -------------------------------- ### NewBufferFromReaderUntil Source: https://context7.com/awnumar/memguard/llms.txt Reads bytes from an io.Reader into a dynamically growing LockedBuffer until a specified delimiter byte is encountered. The buffer is trimmed and made immutable. This is useful for reading newline-terminated secrets. ```APIDOC ## NewBufferFromReaderUntil ### Description Reads bytes one at a time from an `io.Reader` into a dynamically-growing `LockedBuffer` until the specified delimiter byte is encountered (the delimiter is not included in the result) or an error occurs. The buffer grows in page-size increments and is trimmed to the exact number of bytes read before being returned immutable. ### Usage ```go func NewBufferFromReaderUntil(r io.Reader, delim byte) (*LockedBuffer, error) ``` ### Parameters * `r` (io.Reader) - The reader to read data from. * `delim` (byte) - The delimiter byte to stop reading at. ### Returns * `*LockedBuffer` - A new, immutable buffer containing the data read up to the delimiter. * `error` - An error if reading fails. ### Example ```go // Read from stdin until newline, store in guarded memory. buf, err := memguard.NewBufferFromReaderUntil(os.Stdin, '\n') if err != nil { return nil, err } if buf.Size() == 0 { return nil, fmt.Errorf("no input") } // Seal immediately; Seal destroys buf. return buf.Seal(), nil ``` ``` -------------------------------- ### NewBufferFromReader Source: https://context7.com/awnumar/memguard/llms.txt Reads exactly a specified number of bytes from an io.Reader directly into a locked memory region, creating an immutable buffer. This is efficient for reading secrets from network connections or files without intermediate unprotected allocations. ```APIDOC ## NewBufferFromReader ### Description Reads exactly `size` bytes from any `io.Reader` directly into a locked, guarded memory region. If fewer bytes are available, an error is returned. ### Usage ```go func NewBufferFromReader(r io.Reader, size int) (*LockedBuffer, error) ``` ### Parameters * `r` (io.Reader) - The reader to read data from. * `size` (int) - The exact number of bytes to read. ### Returns * `*LockedBuffer` - A new, immutable buffer containing the read data. * `error` - An error if reading fails or if fewer bytes than `size` are available. ### Example ``` // Simulate reading a 16-byte key from a network connection. src := strings.NewReader("0123456789abcdef_extra_data") buf, err := memguard.NewBufferFromReader(src, 16) if err != nil && err != io.ErrUnexpectedEOF { panic(err) } defer buf.Destroy() fmt.Println("bytes read:", buf.Size()) // bytes read: 16 fmt.Println("data:", buf.String()) // data: 0123456789abcdef fmt.Println("immutable:", !buf.IsMutable()) // immutable: true ``` ``` -------------------------------- ### LockedBuffer.Seal Source: https://context7.com/awnumar/memguard/llms.txt Encrypts the contents of a LockedBuffer with XSalsa20Poly1305 using an ephemeral session key, stores the ciphertext in a new Enclave, and destroys the source LockedBuffer. If called on a destroyed buffer, nil is returned. ```APIDOC ## LockedBuffer.Seal ### Description Encrypts the contents of a `LockedBuffer` with XSalsa20Poly1305 (using an ephemeral session key), stores the ciphertext in a new `Enclave`, and destroys the source `LockedBuffer`. If called on a destroyed buffer, `nil` is returned. Because `Enclave` objects are not mlock-limited, sealing is the recommended way to hold many secrets simultaneously. ### Method Signature ```go func (b *LockedBuffer) Seal() *Enclave ``` ### Parameters None ### Request Example ```go package main import ( "fmt" "github.com/awnumar/memguard" ) func main() { defer memguard.Purge() buf := memguard.NewBuffer(32) buf.Move([]byte("32-byte-secret-key-here!12345678")) // Seal destroys buf and returns an Enclave. enc := buf.Seal() fmt.Println("buf alive after seal:", buf.IsAlive()) // buf alive after seal: false fmt.Println("enclave size:", enc.Size()) // enclave size: 32 // Open to use the key. reopened, err := enc.Open() if err != nil { panic(err) } defer reopened.Destroy() fmt.Println("decrypted:", reopened.String()) // decrypted: 32-byte-secret-key-here!12345678 } ``` ### Response #### Success Response (200) - **Enclave** (*memguard.Enclave*): A new `Enclave` object containing the encrypted data. #### Response Example ```go // Example output: buf alive after seal: false enclave size: 32 decrypted: 32-byte-secret-key-here!12345678 ``` ``` === COMPLETE CONTENT === This response contains all available snippets from this library. No additional content exists. Do not make further requests.