Skip to content

Commit

Permalink
ec ephemeral key packed-in
Browse files Browse the repository at this point in the history
cleanups
  • Loading branch information
dmihalcik-virtru committed Feb 10, 2025
1 parent 8e3750d commit 36f7878
Show file tree
Hide file tree
Showing 9 changed files with 196 additions and 262 deletions.
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.

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

0 comments on commit 36f7878

Please sign in to comment.