Files
cocos/pkg/resource/decrypt.go
T
Sammy Kerata Oina c59a413765
CI / lint (push) Has been cancelled
CI / test (agent) (push) Has been cancelled
CI / test (cli) (push) Has been cancelled
CI / test (cmd) (push) Has been cancelled
CI / test (internal) (push) Has been cancelled
CI / test (manager, true) (push) Has been cancelled
CI / test (pkg) (push) Has been cancelled
CI / upload-coverage (push) Has been cancelled
NOISSUE - Implement extensible resource downloader framework with support for S3, GCS, and OCI sources (#590)
* feat: implement extensible resource downloader framework with support for S3, GCS, and OCI sources

Signed-off-by: SammyOina <sammyoina@gmail.com>

* refactor: improve resource URL parsing and add support for bare OCI image references

Signed-off-by: Sammy Oina <sammyoina@gmail.com>

* fix: add empty string check and slash requirement for OCI image inference, and update python unit tests with event mock expectations

Signed-off-by: Sammy Oina <sammyoina@gmail.com>

* refactor: introduce OCIClient interface, add test coverage for decryption, and improve resource download error handling

Signed-off-by: Sammy Oina <sammyoina@gmail.com>

* chore: remove trailing whitespace in OCI downloader and HTTP tests

Signed-off-by: Sammy Oina <sammyoina@gmail.com>

---------

Signed-off-by: SammyOina <sammyoina@gmail.com>
Signed-off-by: Sammy Oina <sammyoina@gmail.com>
2026-04-28 11:21:03 +02:00

67 lines
1.8 KiB
Go

// Copyright (c) Ultraviolet
// SPDX-License-Identifier: Apache-2.0
package resource
import (
"crypto/aes"
"crypto/cipher"
"fmt"
"os"
)
const (
// AES-GCM nonce size in bytes.
aesGCMNonceSize = 12
// AES-256 key size in bytes.
aes256KeySize = 32
)
// DecryptFile decrypts an AES-256-GCM encrypted file in place.
// The encrypted file format is: nonce (12 bytes) || ciphertext+tag.
// The key must be exactly 32 bytes (AES-256).
func DecryptFile(encryptedPath string, key []byte) ([]byte, error) {
if len(key) != aes256KeySize {
return nil, fmt.Errorf("invalid key size: expected %d bytes, got %d", aes256KeySize, len(key))
}
ciphertext, err := os.ReadFile(encryptedPath)
if err != nil {
return nil, fmt.Errorf("failed to read encrypted file: %w", err)
}
return DecryptData(ciphertext, key)
}
// DecryptData decrypts AES-256-GCM encrypted data.
// The encrypted data format is: nonce (12 bytes) || ciphertext+tag.
func DecryptData(ciphertext, key []byte) ([]byte, error) {
if len(key) != aes256KeySize {
return nil, fmt.Errorf("invalid key size: expected %d bytes, got %d", aes256KeySize, len(key))
}
if len(ciphertext) < aesGCMNonceSize {
return nil, fmt.Errorf("ciphertext too short: expected at least %d bytes for nonce, got %d", aesGCMNonceSize, len(ciphertext))
}
block, err := aes.NewCipher(key)
if err != nil {
return nil, fmt.Errorf("failed to create AES cipher: %w", err)
}
gcm, err := cipher.NewGCM(block)
if err != nil {
return nil, fmt.Errorf("failed to create GCM cipher: %w", err)
}
nonce := ciphertext[:aesGCMNonceSize]
encData := ciphertext[aesGCMNonceSize:]
plaintext, err := gcm.Open(nil, nonce, encData, nil)
if err != nil {
return nil, fmt.Errorf("decryption failed (authentication error): %w", err)
}
return plaintext, nil
}