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

ec ephemeral key packed-in #1907

Draft
wants to merge 1 commit into
base: main
Choose a base branch
from
Draft
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
7 changes: 0 additions & 7 deletions docs/grpc/index.html

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 0 additions & 1 deletion examples/cmd/decrypt.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@ import (
"path/filepath"

"github.com/opentdf/platform/sdk"

"github.com/spf13/cobra"
)

Expand Down
65 changes: 23 additions & 42 deletions lib/ocrypto/asym_decryption.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,10 @@ import (
"crypto/cipher"
"crypto/ecdh"
"crypto/ecdsa"
"crypto/elliptic"
"crypto/rsa"
"crypto/sha256"
"crypto/x509"
"encoding/asn1"
"encoding/pem"
"errors"
"fmt"
Expand Down Expand Up @@ -112,35 +112,29 @@ func NewECDecryptor(sk *ecdh.PrivateKey) (ECDecryptor, error) {
return ECDecryptor{sk, salt, nil}, nil
}

func (e ECDecryptor) Decrypt(_ []byte) ([]byte, error) {
// TK How to get the ephmeral key into here?
return nil, errors.New("ecdh standard decrypt unimplemented")
}

func (e ECDecryptor) DecryptWithEphemeralKey(data, ephemeral []byte) ([]byte, error) {
func (e ECDecryptor) Decrypt(wrapped []byte) ([]byte, error) {
var ek *ecdh.PublicKey

if pubFromDSN, err := x509.ParsePKIXPublicKey(ephemeral); err == nil {
switch pubFromDSN := pubFromDSN.(type) {
case *ecdsa.PublicKey:
ek, err = ConvertToECDHPublicKey(pubFromDSN)
if err != nil {
return nil, fmt.Errorf("ecdh conversion failure: %w", err)
}
case *ecdh.PublicKey:
ek = pubFromDSN
default:
return nil, errors.New("not an supported type of public key")
}
} else {
ekDSA, err := UncompressECPubKey(convCurve(e.sk.Curve()), ephemeral)
if err != nil {
return nil, err
}
ek, err = ekDSA.ECDH()
var wv ecWrappedValue
var pubFromDSN any

if rest, err := asn1.Unmarshal(wrapped, &wv); err != nil {
return nil, fmt.Errorf("asn1.Unmarshal failure: %w", err)
} else if len(rest) > 0 {
return nil, errors.New("trailing data")
} else if pubFromDSN, err = x509.ParsePKIXPublicKey(wv.EphemeralKey); err != nil {
return nil, fmt.Errorf("ecdh failure: %w", err)
}
switch pubFromDSN := pubFromDSN.(type) {
case *ecdsa.PublicKey:
var err error
ek, err = ConvertToECDHPublicKey(pubFromDSN)
if err != nil {
return nil, fmt.Errorf("ecdh failure: %w", err)
return nil, fmt.Errorf("ecdh conversion failure: %w", err)
}
case *ecdh.PublicKey:
ek = pubFromDSN
default:
return nil, errors.New("not an supported type of public key")
}

ikm, err := e.sk.ECDH(ek)
Expand All @@ -167,28 +161,15 @@ func (e ECDecryptor) DecryptWithEphemeralKey(data, ephemeral []byte) ([]byte, er
}

nonceSize := gcm.NonceSize()
if len(data) < nonceSize {
if len(wv.CipherText) < nonceSize {
return nil, errors.New("ciphertext too short")
}

nonce, ciphertext := data[:nonceSize], data[nonceSize:]
nonce, ciphertext := wv.CipherText[:nonceSize], wv.CipherText[nonceSize:]
plaintext, err := gcm.Open(nil, nonce, ciphertext, nil)
if err != nil {
return nil, fmt.Errorf("gcm.Open failure: %w", err)
}

return plaintext, nil
}

func convCurve(c ecdh.Curve) elliptic.Curve {
switch c {
case ecdh.P256():
return elliptic.P256()
case ecdh.P384():
return elliptic.P384()
case ecdh.P521():
return elliptic.P521()
default:
return nil
}
}
17 changes: 3 additions & 14 deletions lib/ocrypto/asym_encrypt_decrypt_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -249,20 +249,9 @@ bW0CIQDT5QED+8mHFot9JXSx2q1c5mnRvl4yElK0fiHeatBdqw==
t.Fatalf("NewAsymDecryption - failed: %v", err)
}

var decryptedText []byte
ek := asymEncryptor.EphemeralKey()
if ek == nil {
decryptedText, err = asymDecryptor.Decrypt(cipherText)
if err != nil {
t.Fatalf("AsymDecryption decrypt failed: %v", err)
}
} else if ecd, ok := asymDecryptor.(ECDecryptor); ok {
decryptedText, err = ecd.DecryptWithEphemeralKey(cipherText, ek)
if err != nil {
t.Fatalf("AsymDecryption decrypt failed: %v", err)
}
} else {
t.Fatalf("AsymDecryption wrong type: %T", asymDecryptor)
decryptedText, err := asymDecryptor.Decrypt(cipherText)
if err != nil {
t.Fatalf("AsymDecryption decrypt failed: %v", err)
}

if string(decryptedText) != plainText {
Expand Down
56 changes: 23 additions & 33 deletions lib/ocrypto/asym_encryption.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import (
"crypto/sha1" //nolint:gosec // used for padding which is safe
"crypto/sha256"
"crypto/x509"
"encoding/asn1"
"encoding/pem"
"errors"
"fmt"
Expand All @@ -32,16 +33,6 @@ type PublicKeyEncryptor interface {

// PublicKeyInPemFormat Returns public key in pem format, or the empty string if not present
PublicKeyInPemFormat() (string, error)

// Type required to use the scheme for encryption - notably, if it procduces extra metadata.
Type() SchemeType

// For EC schemes, this method returns the public part of the ephemeral key.
// Otherwise, it returns nil.
EphemeralKey() []byte

// Any extra metadata, e.g. the ephemeral public key for EC scheme keys.
Metadata() (map[string]string, error)
}

type AsymEncryption struct {
Expand All @@ -55,6 +46,11 @@ type ECEncryptor struct {
info []byte
}

type ecWrappedValue struct {
EphemeralKey []byte
CipherText []byte
}

func FromPublicPEM(publicKeyInPem string) (PublicKeyEncryptor, error) {
pub, err := getPublicPart(publicKeyInPem)
if err != nil {
Expand Down Expand Up @@ -136,28 +132,6 @@ func (e ECEncryptor) Type() SchemeType {
return EC
}

func (e AsymEncryption) EphemeralKey() []byte {
return nil
}

func (e ECEncryptor) EphemeralKey() []byte {
publicKeyBytes, err := x509.MarshalPKIXPublicKey(e.ek.PublicKey())
if err != nil {
return nil
}
return publicKeyBytes
}

func (e AsymEncryption) Metadata() (map[string]string, error) {
return make(map[string]string), nil
}

func (e ECEncryptor) Metadata() (map[string]string, error) {
m := make(map[string]string)
m["ephemeralPublicKey"] = string(e.EphemeralKey())
return m, nil
}

func (e AsymEncryption) Encrypt(data []byte) ([]byte, error) {
if e.PublicKey == nil {
return nil, errors.New("failed to encrypt, public key is empty")
Expand Down Expand Up @@ -226,7 +200,23 @@ func (e ECEncryptor) Encrypt(data []byte) ([]byte, error) {
}

ciphertext := gcm.Seal(nonce, nonce, data, nil)
return ciphertext, nil

ekb, err := x509.MarshalPKIXPublicKey(e.ek.PublicKey())
if err != nil {
return nil, fmt.Errorf("ephemeral key serialization failed: %w", err)
}

wv := ecWrappedValue{
EphemeralKey: ekb,
CipherText: ciphertext,
}

resp, err := asn1.Marshal(wv)
if err != nil {
return nil, fmt.Errorf("serialization failed: %w", err)
}

return resp, nil
}

// PublicKeyInPemFormat Returns public key in pem format.
Expand Down
Loading
Loading