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: TPM2_RSA_Encrypt and TPM2_RSA_Decrypt #356

Merged
merged 1 commit into from
Apr 11, 2024
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
14 changes: 14 additions & 0 deletions tpm2/structures.go
Original file line number Diff line number Diff line change
Expand Up @@ -2284,6 +2284,20 @@ type TPMTRSAScheme struct {
Details TPMUAsymScheme `gotpm:"tag=Scheme"`
}

// TPMIAlgRSADecrypt represents a TPMI_ALG_RSA_DECRYPT.
// See definition in Part 2: Structures, section 11.2.4.3.
type TPMIAlgRSADecrypt = TPMAlgID

// TPMTRSADecrypt represents a TPMT_RSA_DECRYPT.
// See definition in Part 2: Structures, section 11.2.4.4.
type TPMTRSADecrypt struct {
marshalByReflection
// scheme selector
Scheme TPMIAlgRSADecrypt `gotpm:"nullable"`
// scheme parameters
Details TPMUAsymScheme `gotpm:"tag=Scheme"`
}

// TPM2BPublicKeyRSA represents a TPM2B_PUBLIC_KEY_RSA.
// See definition in Part 2: Structures, section 11.2.4.5.
type TPM2BPublicKeyRSA TPM2BData
Expand Down
137 changes: 137 additions & 0 deletions tpm2/test/rsa_encryption_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,137 @@
package tpm2test

import (
"bytes"
"testing"

. "github.com/google/go-tpm/tpm2"
"github.com/google/go-tpm/tpm2/transport/simulator"
)

func TestRSAEncryption(t *testing.T) {
theTpm, err := simulator.OpenSimulator()
if err != nil {
t.Fatalf("could not connect to TPM simulator: %v", err)
}
t.Cleanup(func() {
if err := theTpm.Close(); err != nil {
t.Errorf("%v", err)
}
})

createPrimaryCmd := CreatePrimary{
PrimaryHandle: TPMRHOwner,
InPublic: New2B(RSASRKTemplate),
}
createPrimaryRsp, err := createPrimaryCmd.Execute(theTpm)
if err != nil {
t.Fatalf("%v", err)
}
t.Cleanup(func() {
flushContextCmd := FlushContext{FlushHandle: createPrimaryRsp.ObjectHandle}
if _, err := flushContextCmd.Execute(theTpm); err != nil {
t.Errorf("%v", err)
}
})

createCmd := Create{
ParentHandle: NamedHandle{
Handle: createPrimaryRsp.ObjectHandle,
Name: createPrimaryRsp.Name,
},
InPublic: New2B(TPMTPublic{
Type: TPMAlgRSA,
NameAlg: TPMAlgSHA256,
ObjectAttributes: TPMAObject{
FixedTPM: true,
STClear: false,
FixedParent: true,
SensitiveDataOrigin: true,
UserWithAuth: true,
AdminWithPolicy: false,
NoDA: true,
EncryptedDuplication: false,
Restricted: false,
Decrypt: true,
SignEncrypt: true,
},
Parameters: NewTPMUPublicParms(
TPMAlgRSA,
&TPMSRSAParms{
KeyBits: 2048,
},
),
Unique: NewTPMUPublicID(
TPMAlgRSA,
&TPM2BPublicKeyRSA{
Buffer: make([]byte, 256),
},
),
}),
}
createRsp, err := createCmd.Execute(theTpm)
if err != nil {
t.Fatalf("%v", err)
}

loadCmd := Load{
ParentHandle: NamedHandle{
Handle: createPrimaryRsp.ObjectHandle,
Name: createPrimaryRsp.Name,
},
InPrivate: createRsp.OutPrivate,
InPublic: createRsp.OutPublic,
}
loadRsp, err := loadCmd.Execute(theTpm)
if err != nil {
t.Fatalf("%v", err)
}
t.Cleanup(func() {
flushContextCmd := FlushContext{FlushHandle: loadRsp.ObjectHandle}
if _, err := flushContextCmd.Execute(theTpm); err != nil {
t.Errorf("%v", err)
}
})

message := []byte("secret")

encryptCmd := RSAEncrypt{
KeyHandle: loadRsp.ObjectHandle,
Message: TPM2BPublicKeyRSA{Buffer: message},
InScheme: TPMTRSADecrypt{
Scheme: TPMAlgOAEP,
Details: NewTPMUAsymScheme(
TPMAlgOAEP,
&TPMSEncSchemeOAEP{
HashAlg: TPMAlgSHA256,
},
),
},
}
encryptRsp, err := encryptCmd.Execute(theTpm)
if err != nil {
t.Fatalf("%v", err)
}

decryptCmd := RSADecrypt{
KeyHandle: loadRsp.ObjectHandle,
CipherText: TPM2BPublicKeyRSA{Buffer: encryptRsp.OutData.Buffer},
InScheme: TPMTRSADecrypt{
Scheme: TPMAlgOAEP,
Details: NewTPMUAsymScheme(
TPMAlgOAEP,
&TPMSEncSchemeOAEP{
HashAlg: TPMAlgSHA256,
},
),
},
}
decryptRsp, err := decryptCmd.Execute(theTpm)
if err != nil {
t.Fatalf("%v", err)
}

if !bytes.Equal(message, decryptRsp.Message.Buffer) {
t.Errorf("want %x got %x", message, decryptRsp.Message.Buffer)
}
}
62 changes: 62 additions & 0 deletions tpm2/tpm2.go
Original file line number Diff line number Diff line change
Expand Up @@ -423,6 +423,68 @@ type CreateLoadedResponse struct {
Name TPM2BName
}

// RSAEncrypt is the input to TPM2_RSA_Encrypt
// See definition in Part 3, Commands, section 14.2.
type RSAEncrypt struct {
// reference to public portion of RSA key to use for encryption
KeyHandle handle `gotpm:"handle"`
// message to be encrypted
Message TPM2BPublicKeyRSA
// the padding scheme to use if scheme associated with keyHandle is TPM_ALG_NULL
InScheme TPMTRSADecrypt `gotpm:"nullable"`
// optional label L to be associated with the message
Label TPM2BData `gotpm:"optional"`
}

// Command implements the Command interface.
func (RSAEncrypt) Command() TPMCC { return TPMCCRSAEncrypt }

// Execute executes the command and returns the response.
func (cmd RSAEncrypt) Execute(t transport.TPM, s ...Session) (*RSAEncryptResponse, error) {
var rsp RSAEncryptResponse
if err := execute[RSAEncryptResponse](t, cmd, &rsp, s...); err != nil {
return nil, err
}
return &rsp, nil
}

// RSAEncryptResponse is the response from TPM2_RSA_Encrypt
type RSAEncryptResponse struct {
// encrypted output
OutData TPM2BPublicKeyRSA
}

// RSADecrypt is the input to TPM2_RSA_Decrypt
// See definition in Part 3, Commands, section 14.3.
type RSADecrypt struct {
// RSA key to use for decryption
KeyHandle handle `gotpm:"handle,auth"`
// cipher text to be decrypted
CipherText TPM2BPublicKeyRSA
// the padding scheme to use if scheme associated with keyHandle is TPM_ALG_NULL
InScheme TPMTRSADecrypt `gotpm:"nullable"`
// label whose association with the message is to be verified
Label TPM2BData `gotpm:"optional"`
}

// Command implements the Command interface.
func (RSADecrypt) Command() TPMCC { return TPMCCRSADecrypt }

// Execute executes the command and returns the response.
func (cmd RSADecrypt) Execute(t transport.TPM, s ...Session) (*RSADecryptResponse, error) {
var rsp RSADecryptResponse
if err := execute[RSADecryptResponse](t, cmd, &rsp, s...); err != nil {
return nil, err
}
return &rsp, nil
}

// RSADecryptResponse is the response from TPM2_RSA_Decrypt
type RSADecryptResponse struct {
// decrypted output
Message TPM2BPublicKeyRSA
}

// ECDHZGen is the input to TPM2_ECDHZGen.
// See definition in Part 3, Commands, section 14.5
type ECDHZGen struct {
Expand Down