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
4 changes: 2 additions & 2 deletions .golangci.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,7 @@ linters:
exclusions:
generated: lax
rules:
- path: '^auth/cache\.go$'
- path: '^creds/cache\.go$'
linters:
- gosec
# crypto/sha1 is used for hashing, not encryption.
Expand All @@ -112,7 +112,7 @@ linters:
- gosec
# local static files server doesn't need timeout
text: "G114: Use of net/http serve function that has no support for setting timeouts"
- path: '^auth/command_test\.go$'
- path: '^creds/command_test\.go$'
linters:
- gosec
# unit test only, and we know overflow doesn't happen
Expand Down
130 changes: 0 additions & 130 deletions auth/cipher.go

This file was deleted.

4 changes: 0 additions & 4 deletions auth/doc.go

This file was deleted.

88 changes: 88 additions & 0 deletions cipher/aes.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
package cipher

import (
"crypto/aes"
"crypto/cipher"
"crypto/rand"
"errors"
"fmt"
"io"
)

type (
AesKeyFunc func(*[AesKeySize]byte) error

AesGcm struct {
key [AesKeySize]byte
}
)

const (
AesKeySize = 32
)

var (
ErrCipher = errors.New("cipher failure")
)

// Non-nil returned error wraps [ErrCipher].
func NewAesGcm(fn AesKeyFunc) (*AesGcm, error) {
aes := AesGcm{}

err := fn(&aes.key)
if err != nil {
return nil, fmt.Errorf("%w: failed to get encryption key: %s", ErrCipher, err.Error())
}

return &aes, nil
}

// Non-nil returned error wraps [ErrCipher].
func (c *AesGcm) Encrypt(plaintext []byte) ([]byte, error) {
block, err := aes.NewCipher(c.key[:])
if err != nil {
return nil, fmt.Errorf("%w: failed to initialize AES block cipher: %s", ErrCipher, err.Error())
}

gcm, err := cipher.NewGCM(block)
if err != nil {
return nil, fmt.Errorf("%w: failed to create GCM: %s", ErrCipher, err.Error())
}

// The GCM nonce size is fixed at 12 bytes.
nonce := make([]byte, gcm.NonceSize())
if _, err := io.ReadFull(rand.Reader, nonce); err != nil {
return nil, fmt.Errorf("%w: failed to initialize nonce: %s", ErrCipher, err.Error())
}

// The first return value is 'nonce + ciphertext + tag'.
return gcm.Seal(nonce, nonce, plaintext, nil), nil
}

// Non-nil returned error wraps [ErrCipher].
func (c *AesGcm) Decrypt(ciphertext []byte) ([]byte, error) {
block, err := aes.NewCipher(c.key[:])
if err != nil {
return nil, fmt.Errorf("%w: failed to initialize AES block cipher: %s", ErrCipher, err.Error())
}

gcm, err := cipher.NewGCM(block)
if err != nil {
return nil, fmt.Errorf("%w: failed to create GCM: %s", ErrCipher, err.Error())
}

// Extract nonce from the beginning of the ciphertext.
nonceSize := gcm.NonceSize()
if len(ciphertext) < nonceSize {
return nil, fmt.Errorf("%w: ciphertext too short", ErrCipher)
}

nonce, ciphertextActual := ciphertext[:nonceSize], ciphertext[nonceSize:]

plaintext, err := gcm.Open(nil, nonce, ciphertextActual, nil)
if err != nil {
return nil, fmt.Errorf("%w: AES-GCM authentication failure, the data have been tampered: %s", ErrCipher, err.Error())
}

return plaintext, nil
}
11 changes: 6 additions & 5 deletions cmd/toolkit-assume-role/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,12 @@ import (

"github.com/aws/aws-sdk-go-v2/config"

"github.com/kxue43/cli-toolkit/auth"
"github.com/kxue43/cli-toolkit/creds"
"github.com/kxue43/cli-toolkit/terminal"
)

var (
cmd = auth.AssumeRoleCmd{}
cmd = creds.AssumeRoleCmd{}

helpMsg = `Usage: %s -mfa-serial=STRING -profile=STRING [flags] <RoleArn>

Expand Down Expand Up @@ -48,16 +49,16 @@ func main() {

flag.Parse()

ttyDevice, err := os.OpenFile("/dev/tty", os.O_RDWR|os.O_SYNC, 0600)
device, err := os.OpenFile("/dev/tty", os.O_RDWR|os.O_SYNC, 0600)
if err != nil {
exitCode = 1

return
}

defer func() { _ = ttyDevice.Close() }()
defer func() { _ = device.Close() }()

tty := auth.NewTTY(ttyDevice, "toolkit-assume-role: ", 0)
tty := terminal.NewTTY(device, "toolkit-assume-role: ", 0)
defer func() {
if tty.FlushLogs() != nil {
exitCode = 1
Expand Down
Loading