Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 24 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ Security-focused Go helpers for file I/O, in-memory handling of sensitive data,
- Symlink checks and root-scoped file access using `os.OpenRoot`
- Secure in-memory buffers with best-effort zeroization
- JWT/PASETO helpers with strict validation and safe defaults
- MFA helpers for TOTP/HOTP provisioning and verification
- MFA helpers for TOTP/HOTP provisioning, verification, and backup codes
- Password hashing presets for argon2id/bcrypt with rehash detection
- Email and URL validation with optional DNS/redirect/reputation checks
- Random token generation and validation with entropy/length caps
Expand Down Expand Up @@ -214,6 +214,29 @@ func main() {
}
```

```go
package main

import (
"github.com/hyp3rd/sectools/pkg/mfa"
)

func main() {
manager, err := mfa.NewBackupCodeManager()
if err != nil {
panic(err)
}

set, err := manager.Generate()
if err != nil {
panic(err)
}

// Store set.Hashes and display set.Codes once.
_, _, _ = manager.Verify(set.Codes[0], set.Hashes)
}
```

### Password hashing

```go
Expand Down
3 changes: 3 additions & 0 deletions cspell.json
Original file line number Diff line number Diff line change
Expand Up @@ -172,6 +172,8 @@
"redaction",
"redactor",
"Renovate",
"resync",
"Resync",
"sanitization",
"sanitize",
"sanitizer",
Expand Down Expand Up @@ -210,6 +212,7 @@
"Tracef",
"uid",
"umask",
"uppercasing",
"URLHTTP",
"userinfo",
"varnamelen",
Expand Down
2 changes: 2 additions & 0 deletions docs/security-checklist.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,9 @@ This checklist is a quick reference for teams using sectools in production.

- Use `pkg/mfa` for TOTP/HOTP with drift handling and validated secrets.
- Keep TOTP skew and HOTP look-ahead windows small to reduce replay risk.
- Rate limit OTP and backup code verification attempts.
- Store MFA secrets securely; avoid logging provisioning URLs or raw secrets.
- Store only hashed backup codes and delete them after first use.

## Random Tokens

Expand Down
46 changes: 46 additions & 0 deletions docs/usage.md
Original file line number Diff line number Diff line change
Expand Up @@ -267,11 +267,13 @@ func GenerateTOTPKey(opts ...TOTPKeyOption) (*otp.Key, error)
func NewTOTP(secret string, opts ...TOTPOption) (*TOTP, error)
func (t *TOTP) Generate() (string, error)
func (t *TOTP) Verify(code string) (bool, error)
func (t *TOTP) VerifyWithStep(code string) (bool, uint64, error)

func GenerateHOTPKey(opts ...HOTPKeyOption) (*otp.Key, error)
func NewHOTP(secret string, opts ...HOTPOption) (*HOTP, error)
func (h *HOTP) Generate(counter uint64) (string, error)
func (h *HOTP) Verify(code string, counter uint64) (bool, uint64, error)
func (h *HOTP) Resync(code1 string, code2 string, counter uint64) (bool, uint64, error)
```

Behavior:
Expand All @@ -283,6 +285,9 @@ Behavior:
- `otp.Key` exposes `URL()` and `Image()` for QR provisioning.
- Store secrets securely and avoid logging provisioning URLs.
- Update the HOTP counter only when `Verify` returns ok.
- Use `VerifyWithStep` to store the last accepted TOTP step and reject replays.
- Use `Resync` with two consecutive HOTP codes to recover a drifting counter.
- Configure rate limiting with `WithTOTPRateLimiter`, `WithHOTPRateLimiter`, and `WithBackupRateLimiter`.

Example:

Expand Down Expand Up @@ -311,6 +316,47 @@ if !ok {
}
```

### Backup codes

```go
func NewBackupCodeManager(opts ...BackupOption) (*BackupCodeManager, error)
func (m *BackupCodeManager) Generate() (BackupCodeSet, error)
func (m *BackupCodeManager) Verify(code string, hashes []string) (bool, []string, error)
```

Behavior:

- Generates grouped codes for user display and hashed codes for storage.
- Normalizes input by removing spaces/hyphens and uppercasing.
- Uses Argon2id (balanced) for hashing by default; configurable via options.
- `Verify` returns the remaining hashes with the matched entry removed.
- Store only hashes; backup codes are one-time use.

Example:

```go
import "github.com/hyp3rd/sectools/pkg/mfa"

manager, err := mfa.NewBackupCodeManager()
if err != nil {
panic(err)
}

set, err := manager.Generate()
if err != nil {
panic(err)
}

// Persist set.Hashes and show set.Codes to the user once.
ok, remaining, err := manager.Verify(set.Codes[0], set.Hashes)
if err != nil {
panic(err)
}

_ = remaining
_ = ok
```

## pkg/password

```go
Expand Down
Loading
Loading