Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(core): support for ec-wrapping #499

Open
wants to merge 5 commits into
base: main
Choose a base branch
from
Open
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
5 changes: 4 additions & 1 deletion .github/spellcheck.ignore
Original file line number Diff line number Diff line change
Expand Up @@ -118,4 +118,7 @@ uri
with-client-creds
with-client-creds-file
yaml
ztdf
ztdf
rsa
ec
secp
25 changes: 23 additions & 2 deletions cmd/tdf-decrypt.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import (
"github.com/opentdf/otdfctl/pkg/cli"
"github.com/opentdf/otdfctl/pkg/man"
"github.com/opentdf/otdfctl/pkg/utils"
"github.com/opentdf/platform/lib/ocrypto"
"github.com/spf13/cobra"
)

Expand All @@ -18,12 +19,26 @@ var assertionVerification string
const TDF_MAX_FILE_SIZE = int64(10 * 1024 * 1024 * 1024) // 10 GB

func dev_tdfDecryptCmd(cmd *cobra.Command, args []string) {
c := cli.New(cmd, args, cli.WithPrintJson())
c := cli.New(cmd, args)
h := NewHandler(c)
defer h.Close()

output := c.Flags.GetOptionalString("out")
disableAssertionVerification := c.Flags.GetOptionalBool("no-verify-assertions")
sessionKeyAlgStr := c.Flags.GetOptionalString("session-key-algorithm")
var sessionKeyAlgorithm ocrypto.KeyType
switch sessionKeyAlgStr {
case string(ocrypto.RSA2048Key):
sessionKeyAlgorithm = ocrypto.RSA2048Key
case string(ocrypto.EC256Key):
sessionKeyAlgorithm = ocrypto.EC256Key
case string(ocrypto.EC384Key):
sessionKeyAlgorithm = ocrypto.EC384Key
case string(ocrypto.EC521Key):
sessionKeyAlgorithm = ocrypto.EC521Key
default:
sessionKeyAlgorithm = ocrypto.RSA2048Key
}

// check for piped input
piped := readPipedStdin()
Expand All @@ -44,7 +59,7 @@ func dev_tdfDecryptCmd(cmd *cobra.Command, args []string) {
cli.ExitWithError("Must provide ONE of the following to decrypt: [file argument, stdin input]", errors.New("no input provided"))
}

decrypted, err := h.DecryptBytes(bytesToDecrypt, assertionVerification, disableAssertionVerification)
decrypted, err := h.DecryptBytes(bytesToDecrypt, assertionVerification, disableAssertionVerification, sessionKeyAlgorithm)
if err != nil {
cli.ExitWithError("Failed to decrypt file", err)
}
Expand Down Expand Up @@ -90,6 +105,12 @@ func init() {
"",
decryptCmd.GetDocFlag("with-assertion-verification-keys").Description,
)
decryptCmd.Flags().StringP(
decryptCmd.GetDocFlag("session-key-algorithm").Name,
decryptCmd.GetDocFlag("session-key-algorithm").Shorthand,
decryptCmd.GetDocFlag("session-key-algorithm").Default,
decryptCmd.GetDocFlag("session-key-algorithm").Description,
)
decryptCmd.Flags().Bool(
decryptCmd.GetDocFlag("no-verify-assertions").Name,
decryptCmd.GetDocFlag("no-verify-assertions").DefaultAsBool(),
Expand Down
23 changes: 22 additions & 1 deletion cmd/tdf-encrypt.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import (
"github.com/opentdf/otdfctl/pkg/cli"
"github.com/opentdf/otdfctl/pkg/man"
"github.com/opentdf/otdfctl/pkg/utils"
"github.com/opentdf/platform/lib/ocrypto"
"github.com/spf13/cobra"
)

Expand Down Expand Up @@ -44,6 +45,20 @@ func dev_tdfEncryptCmd(cmd *cobra.Command, args []string) {
attrValues = c.Flags.GetStringSlice("attr", attrValues, cli.FlagsStringSliceOptions{Min: 0})
tdfType := c.Flags.GetOptionalString("tdf-type")
kasURLPath := c.Flags.GetOptionalString("kas-url-path")
wrappingKeyAlgStr := c.Flags.GetOptionalString("wrapping-key-algorithm")
var wrappingKeyAlgorithm ocrypto.KeyType
switch wrappingKeyAlgStr {
case string(ocrypto.RSA2048Key):
wrappingKeyAlgorithm = ocrypto.RSA2048Key
case string(ocrypto.EC256Key):
wrappingKeyAlgorithm = ocrypto.EC256Key
case string(ocrypto.EC384Key):
wrappingKeyAlgorithm = ocrypto.EC384Key
case string(ocrypto.EC521Key):
wrappingKeyAlgorithm = ocrypto.EC521Key
default:
wrappingKeyAlgorithm = ocrypto.RSA2048Key
}

piped := readPipedStdin()

Expand Down Expand Up @@ -95,7 +110,7 @@ func dev_tdfEncryptCmd(cmd *cobra.Command, args []string) {
)

// Do the encryption
encrypted, err := h.EncryptBytes(tdfType, bytesSlice, attrValues, fileMimeType, kasURLPath, c.Flags.GetOptionalBool("ecdsa-binding"), assertions)
encrypted, err := h.EncryptBytes(tdfType, bytesSlice, attrValues, fileMimeType, kasURLPath, c.Flags.GetOptionalBool("ecdsa-binding"), assertions, wrappingKeyAlgorithm)
if err != nil {
cli.ExitWithError("Failed to encrypt", err)
}
Expand Down Expand Up @@ -158,6 +173,12 @@ func init() {
encryptCmd.GetDocFlag("tdf-type").Default,
encryptCmd.GetDocFlag("tdf-type").Description,
)
encryptCmd.Flags().StringP(
encryptCmd.GetDocFlag("wrapping-key-algorithm").Name,
encryptCmd.GetDocFlag("wrapping-key-algorithm").Shorthand,
encryptCmd.GetDocFlag("wrapping-key-algorithm").Default,
encryptCmd.GetDocFlag("wrapping-key-algorithm").Description,
)
encryptCmd.Flags().Bool(
encryptCmd.GetDocFlag("ecdsa-binding").Name,
false,
Expand Down
22 changes: 22 additions & 0 deletions docs/man/decrypt/_index.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,15 @@ command:
- name: no-verify-assertions
description: disable verification of assertions
default: false
- name: session-key-algorithm
shorthand: s
description: The type of session key algorithm to use for decryption
enum:
- rsa:2048
- ec:secp256r1
- ec:secp384r1
- ec:secp521r1
default: rsa:2048
- name: with-assertion-verification-keys
description: >
EXPERIMENTAL: path to JSON file of keys to verify signed assertions. See examples for more information.
Expand Down Expand Up @@ -44,6 +53,19 @@ $ echo "hello world" | otdfctl encrypt | otdfctl decrypt | cat
hello world
```

## Session Key Algorithm
The session-key-algorithm specifies the algorithm to use for the wrapping key. The available options are:
- rsa:2048
- ec:secp256r1
- ec:secp384r1
- ec:secp521r1

Example
```shell
# Decrypt a file using the ec:secp256r1 algorithm for the session key
otdfctl decrypt hello.txt --session-key-algorithm ec:secp256r1
```

### ZTDF Assertion Verification (experimental)

To verify the signed assertions (metadata bound to the TDF), you can provide verification keys. The supported assertion signing algorithms are HS256 and RS256 so the keys provided should either be an HS256 key or a public RS256 key.
Expand Down
22 changes: 22 additions & 0 deletions docs/man/encrypt/_index.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,15 @@ command:
- name: attr
shorthand: a
description: Attribute value Fully Qualified Names (FQNs, i.e. 'https://example.com/attr/attr1/value/value1') to apply to the encrypted data.
- name: wrapping-key-algorithm
shorthand: w
description: The algorithm to use for the wrapping key
enum:
- rsa:2048
- ec:secp256r1
- ec:secp384r1
- ec:secp521r1
default: rsa:2048
- name: mime-type
description: The MIME type of the input data. If not provided, the MIME type is inferred from the input data.
- name: tdf-type
Expand Down Expand Up @@ -64,6 +73,19 @@ $ echo "hello world" | otdfctl encrypt | otdfctl decrypt | cat
hello world
```

## Wrapping Key Algorithm
The wrapping-key-algorithm specifies the algorithm to use for the wrapping key. The available options are:
- rsa:2048
- ec:secp256r1
- ec:secp384r1
- ec:secp521r1

Example
```shell
# Encrypt a file using the ec:secp256r1 algorithm for the wrapping key
otdfctl encrypt hello.txt --wrapping-key-algorithm ec:secp256r1 --out hello.txt.tdf
```

## Attributes

Attributes can be added to the encrypted data. The attribute value is a Fully Qualified Name (FQN) that is used to
Expand Down
6 changes: 3 additions & 3 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,9 @@ require (
github.com/golang-jwt/jwt v3.2.2+incompatible
github.com/google/uuid v1.6.0
github.com/opentdf/platform/lib/flattening v0.1.3
github.com/opentdf/platform/protocol/go v0.2.27
github.com/opentdf/platform/sdk v0.3.27
github.com/opentdf/platform/lib/ocrypto v0.1.8
github.com/opentdf/platform/protocol/go v0.2.28
github.com/opentdf/platform/sdk v0.3.28
github.com/spf13/cobra v1.8.1
github.com/spf13/viper v1.19.0
github.com/stretchr/testify v1.10.0
Expand Down Expand Up @@ -79,7 +80,6 @@ require (
github.com/muesli/reflow v0.3.0 // indirect
github.com/muesli/termenv v0.15.3-0.20240618155329-98d742f6907a // indirect
github.com/muhlemmer/gu v0.3.1 // indirect
github.com/opentdf/platform/lib/ocrypto v0.1.8 // indirect
github.com/pelletier/go-toml/v2 v2.2.2 // indirect
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect
github.com/rivo/uniseg v0.4.7 // indirect
Expand Down
8 changes: 4 additions & 4 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -228,10 +228,10 @@ github.com/opentdf/platform/lib/flattening v0.1.3 h1:IuOm/wJVXNrzOV676Ticgr0wyBk
github.com/opentdf/platform/lib/flattening v0.1.3/go.mod h1:Gs/T+6FGZKk9OAdz2Jf1R8CTGeNRYrq1lZGDeYT3hrY=
github.com/opentdf/platform/lib/ocrypto v0.1.8 h1:FUKMHsVCjU4NmgaXgS1RFstl19tkX/7USTIubAuUBlA=
github.com/opentdf/platform/lib/ocrypto v0.1.8/go.mod h1:UTtqh8mvhAYA+sEnaMxpr/406e84L5Q1sAxtKGIXfu4=
github.com/opentdf/platform/protocol/go v0.2.27 h1:ZnfXvVio+j/LzfEY8cHo8/tS45XAPWa2xO7Y1tn/hWs=
github.com/opentdf/platform/protocol/go v0.2.27/go.mod h1:eldxqX2oF2ADtG8ivhfwn1lALVMX4aaUM+Lp9ynOJXs=
github.com/opentdf/platform/sdk v0.3.27 h1:O9jCdpnxz3FEaTXj/hAOixR5mk/APsalcWCexGxfwkM=
github.com/opentdf/platform/sdk v0.3.27/go.mod h1:ZJyz6hy0CMiD3MFfG4PrByTnSJnEtArTGA6ZoR1Xg6E=
github.com/opentdf/platform/protocol/go v0.2.28 h1:UfX+yFWFGCtxsvCyIO62p4v7CBtcVR+2dCqHq3O0vy4=
github.com/opentdf/platform/protocol/go v0.2.28/go.mod h1:eldxqX2oF2ADtG8ivhfwn1lALVMX4aaUM+Lp9ynOJXs=
github.com/opentdf/platform/sdk v0.3.28 h1:rdfZCc5nLXDoljZEDin312T0K/RbNO5mpu1GlMTi8to=
github.com/opentdf/platform/sdk v0.3.28/go.mod h1:25xOGtsBPqbj8VDbn5yN5i6D/9fXNy/WDAM1NSPIXcY=
github.com/opentracing/opentracing-go v1.2.0 h1:uEJPy/1a5RIPAJ0Ov+OIO8OxWu77jEv+1B0VhjKrZUs=
github.com/opentracing/opentracing-go v1.2.0/go.mod h1:GxEUsuufX4nBwe+T+Wl9TAgYrxe9dPLANfrWvHYVTgc=
github.com/pelletier/go-toml/v2 v2.2.2 h1:aYUidT7k73Pcl9nb2gScu7NSrKCSHIDE89b3+6Wq+LM=
Expand Down
18 changes: 15 additions & 3 deletions pkg/handlers/tdf.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import (
"strings"

"github.com/opentdf/otdfctl/pkg/utils"
"github.com/opentdf/platform/lib/ocrypto"
"github.com/opentdf/platform/sdk"
)

Expand All @@ -38,7 +39,16 @@ type TDFInspect struct {
UnencryptedMetadata []byte
}

func (h Handler) EncryptBytes(tdfType string, unencrypted []byte, attrValues []string, mimeType string, kasUrlPath string, ecdsaBinding bool, assertions string) (*bytes.Buffer, error) {
func (h Handler) EncryptBytes(
tdfType string,
unencrypted []byte,
attrValues []string,
mimeType string,
kasUrlPath string,
ecdsaBinding bool,
assertions string,
wrappingKeyAlgorithm ocrypto.KeyType,
) (*bytes.Buffer, error) {
var encrypted []byte
enc := bytes.NewBuffer(encrypted)

Expand All @@ -55,6 +65,7 @@ func (h Handler) EncryptBytes(tdfType string, unencrypted []byte, attrValues []s
URL: h.platformEndpoint + kasUrlPath,
}),
sdk.WithMimeType(mimeType),
sdk.WithWrappingKeyAlg(wrappingKeyAlgorithm),
}

var assertionConfigs []sdk.AssertionConfig
Expand Down Expand Up @@ -115,7 +126,7 @@ func (h Handler) EncryptBytes(tdfType string, unencrypted []byte, attrValues []s
}
}

func (h Handler) DecryptBytes(toDecrypt []byte, assertionVerificationKeysFile string, disableAssertionCheck bool) (*bytes.Buffer, error) {
func (h Handler) DecryptBytes(toDecrypt []byte, assertionVerificationKeysFile string, disableAssertionCheck bool, sessionKeyAlgorithm ocrypto.KeyType) (*bytes.Buffer, error) {
out := &bytes.Buffer{}
pt := io.Writer(out)
ec := bytes.NewReader(toDecrypt)
Expand All @@ -125,7 +136,8 @@ func (h Handler) DecryptBytes(toDecrypt []byte, assertionVerificationKeysFile st
return nil, err
}
case sdk.Standard:
opts := []sdk.TDFReaderOption{sdk.WithDisableAssertionVerification(disableAssertionCheck)}
opts := []sdk.TDFReaderOption{sdk.WithDisableAssertionVerification(disableAssertionCheck),
sdk.WithSessionKeyType(sessionKeyAlgorithm)}
var assertionVerificationKeys sdk.AssertionVerificationKeys
if assertionVerificationKeysFile != "" {
// read the file
Expand Down
Loading