Skip to content

Commit

Permalink
Use cosmosDB in the gateway and encrypt data with encryption key gene…
Browse files Browse the repository at this point in the history
…rated inside the enclave (#2104)
  • Loading branch information
zkokelj authored Nov 4, 2024
1 parent a98ee3d commit 8ce1944
Show file tree
Hide file tree
Showing 24 changed files with 766 additions and 439 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/manual-deploy-obscuro-gateway.yml
Original file line number Diff line number Diff line change
Expand Up @@ -296,5 +296,5 @@ jobs:
"${{ env.DOCKER_BUILD_TAG_GATEWAY }}" \
ego run /home/ten/go-ten/tools/walletextension/main/main \
-host=0.0.0.0 -port=80 -portWS=81 -nodeHost="${{ env.L2_RPC_URL_VALIDATOR }}" -verbose=true \
-logPath=sys_out -dbType=mariaDB -dbConnectionURL="obscurouser:${{ secrets.OBSCURO_GATEWAY_MARIADB_USER_PWD }}@tcp(obscurogateway-mariadb-${{ github.event.inputs.testnet_type }}.uksouth.cloudapp.azure.com:3306)/ogdb" \
-logPath=sys_out -dbType=cosmosDB -dbConnectionURL="${{ secrets.COSMOS_DB_CONNECTION_STRING }}" \
-rateLimitUserComputeTime="${{ env.GATEWAY_RATE_LIMIT_USER_COMPUTE_TIME }}" -rateLimitWindow="${{ env.GATEWAY_RATE_LIMIT_WINDOW }}" -maxConcurrentRequestsPerUser="${{ env.GATEWAY_MAX_CONCURRENT_REQUESTS_PER_USER }}" '
5 changes: 5 additions & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ go 1.21.11
replace github.com/docker/docker => github.com/docker/docker v20.10.3-0.20220224222438-c78f6963a1c0+incompatible

require (
github.com/Azure/azure-sdk-for-go/sdk/data/azcosmos v1.1.0
github.com/FantasyJony/openzeppelin-merkle-tree-go v1.1.3
github.com/Microsoft/go-winio v0.6.2
github.com/andybalholm/brotli v1.1.1
Expand Down Expand Up @@ -55,6 +56,9 @@ require (

require (
filippo.io/edwards25519 v1.1.0 // indirect
github.com/Azure/azure-sdk-for-go v68.0.0+incompatible // indirect
github.com/Azure/azure-sdk-for-go/sdk/azcore v1.14.0 // indirect
github.com/Azure/azure-sdk-for-go/sdk/internal v1.10.0 // indirect
github.com/Azure/go-ansiterm v0.0.0-20230124172434-306776ec8161 // indirect
github.com/DataDog/zstd v1.5.6 // indirect
github.com/VictoriaMetrics/fastcache v1.12.2 // indirect
Expand Down Expand Up @@ -102,6 +106,7 @@ require (
github.com/go-playground/validator/v10 v10.22.1 // indirect
github.com/goccy/go-json v0.10.3 // indirect
github.com/gogo/protobuf v1.3.2 // indirect
github.com/golang/glog v1.2.2 // indirect
github.com/golang/mock v1.6.0 // indirect
github.com/golang/snappy v0.0.5-0.20220116011046-fa5810519dcb // indirect
github.com/gorilla/mux v1.8.1 // indirect
Expand Down
21 changes: 21 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
@@ -1,11 +1,25 @@
filippo.io/edwards25519 v1.1.0 h1:FNf4tywRC1HmFuKW5xopWpigGjJKiJSV0Cqo0cJWDaA=
filippo.io/edwards25519 v1.1.0/go.mod h1:BxyFTGdWcka3PhytdK4V28tE5sGfRvvvRV7EaN4VDT4=
github.com/Azure/azure-sdk-for-go v68.0.0+incompatible h1:fcYLmCpyNYRnvJbPerq7U0hS+6+I79yEDJBqVNcqUzU=
github.com/Azure/azure-sdk-for-go v68.0.0+incompatible/go.mod h1:9XXNKU+eRnpl9moKnB4QOLf1HestfXbmab5FXxiDBjc=
github.com/Azure/azure-sdk-for-go/sdk/azcore v1.14.0 h1:nyQWyZvwGTvunIMxi1Y9uXkcyr+I7TeNrr/foo4Kpk8=
github.com/Azure/azure-sdk-for-go/sdk/azcore v1.14.0/go.mod h1:l38EPgmsp71HHLq9j7De57JcKOWPyhrsW1Awm1JS6K0=
github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.7.0 h1:tfLQ34V6F7tVSwoTf/4lH5sE0o6eCJuNDTmH09nDpbc=
github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.7.0/go.mod h1:9kIvujWAA58nmPmWB1m23fyWic1kYZMxD9CxaWn4Qpg=
github.com/Azure/azure-sdk-for-go/sdk/data/azcosmos v1.1.0 h1:c726lgbwpwFBuj+Fyrwuh/vUilqFo+hUAOUNjsKj5DI=
github.com/Azure/azure-sdk-for-go/sdk/data/azcosmos v1.1.0/go.mod h1:WzFGxuepAtZIZtQbz8/WviJycLMKJHpaEAqcXONxlag=
github.com/Azure/azure-sdk-for-go/sdk/internal v1.10.0 h1:ywEEhmNahHBihViHepv3xPBn1663uRv2t2q/ESv9seY=
github.com/Azure/azure-sdk-for-go/sdk/internal v1.10.0/go.mod h1:iZDifYGJTIgIIkYRNWPENUnqx6bJ2xnSDFI2tjwZNuY=
github.com/Azure/go-ansiterm v0.0.0-20230124172434-306776ec8161 h1:L/gRVlceqvL25UVaW/CKtUDjefjrs0SPonmDGUVOYP0=
github.com/Azure/go-ansiterm v0.0.0-20230124172434-306776ec8161/go.mod h1:xomTg63KZ2rFqZQzSB4Vz2SUXa1BpHTVz9L5PTmPC4E=
github.com/DataDog/zstd v1.5.6 h1:LbEglqepa/ipmmQJUDnSsfvA8e8IStVcGaFWDuxvGOY=
github.com/DataDog/zstd v1.5.6/go.mod h1:g4AWEaM3yOg3HYfnJ3YIawPnVdXJh9QME85blwSAmyw=
github.com/FantasyJony/openzeppelin-merkle-tree-go v1.1.3 h1:KzMvCFet0baw6uJnxTE/His8YeRgaxlASd4/ISuTvzI=
github.com/FantasyJony/openzeppelin-merkle-tree-go v1.1.3/go.mod h1:OiwyYqbtMkQH+VzA4b8lI+qHnExJy0fIdz+59/8nFes=
github.com/AzureAD/microsoft-authentication-library-for-go v1.2.2 h1:XHOnouVk1mxXfQidrMEnLlPk9UMeRtyBTnEFtxkV0kU=
github.com/AzureAD/microsoft-authentication-library-for-go v1.2.2/go.mod h1:wP83P5OoQ5p6ip3ScPr0BAq0BvuPAvacpEuSzyouqAI=
github.com/DataDog/zstd v1.5.5 h1:oWf5W7GtOLgp6bciQYDmhHHjdhYkALu6S/5Ni9ZgSvQ=
github.com/DataDog/zstd v1.5.5/go.mod h1:g4AWEaM3yOg3HYfnJ3YIawPnVdXJh9QME85blwSAmyw=
github.com/Microsoft/go-winio v0.6.2 h1:F2VQgta7ecxGYO8k3ZZz3RS8fVIXVxONVUPlNERoyfY=
github.com/Microsoft/go-winio v0.6.2/go.mod h1:yd8OoFMLzJbo9gZq8j5qaps8bJ9aShtEA8Ipt1oGCvU=
github.com/VictoriaMetrics/fastcache v1.12.2 h1:N0y9ASrJ0F6h0QaC3o6uJb3NIZ9VKLjCM7NQbSmF7WI=
Expand Down Expand Up @@ -159,6 +173,11 @@ github.com/golang-jwt/jwt v3.2.2+incompatible h1:IfV12K8xAKAnZqdXVzCZ+TOjboZ2keL
github.com/golang-jwt/jwt v3.2.2+incompatible/go.mod h1:8pz2t5EyA70fFQQSrl6XZXzqecmYZeUEB8OUGHkxJ+I=
github.com/golang-jwt/jwt/v4 v4.5.0 h1:7cYmW1XlMY7h7ii7UhUyChSgS5wUJEnm9uZVTGqOWzg=
github.com/golang-jwt/jwt/v4 v4.5.0/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0=
github.com/golang-jwt/jwt/v5 v5.2.1 h1:OuVbFODueb089Lh128TAcimifWaLhJwVflnrgM17wHk=
github.com/golang-jwt/jwt/v5 v5.2.1/go.mod h1:pqrtFR0X4osieyHYxtmOUWsAWrfe1Q5UVIyoH402zdk=
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
github.com/golang/glog v1.2.2 h1:1+mZ9upx1Dh6FmUTFR1naJ77miKiXgALjWOZ3NVFPmY=
github.com/golang/glog v1.2.2/go.mod h1:6AhwSGph0fcJtXVM/PEHPqZlFeoLxhs7/t5UDAwmO+w=
github.com/golang/mock v1.6.0 h1:ErTB+efbowRARo13NNdxyJji2egdxLGQhRaY+DUumQc=
github.com/golang/mock v1.6.0/go.mod h1:p6yTPP+5HYm5mzsMV8JkE6ZKdX+/wYM6Hr+LicevLPs=
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
Expand Down Expand Up @@ -279,6 +298,8 @@ github.com/pelletier/go-toml/v2 v2.2.3 h1:YmeHyLY8mFWbdkNWwpr+qIL2bEqT0o95WSdkNH
github.com/pelletier/go-toml/v2 v2.2.3/go.mod h1:MfCQTFTvCcUyyvvwm1+G6H/jORL20Xlb6rzQu9GuUkc=
github.com/pingcap/errors v0.11.4 h1:lFuQV/oaUMGcD2tqt+01ROSmJs75VG1ToEOkZIZ4nE4=
github.com/pingcap/errors v0.11.4/go.mod h1:Oi8TUi2kEtXXLMJk9l1cGmz20kV3TaQ0usTwv5KuLY8=
github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c h1:+mdjkGKdHQG3305AYmdv1U2eRNDiU2ErMBj1gwrq8eQ=
github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c/go.mod h1:7rwL4CYBLnjLxUqIJNnCWiEdr3bn6IUYi15bNlnbCCU=
github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA=
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
Expand Down
12 changes: 12 additions & 0 deletions tools/walletextension/common/common.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package common

import (
"crypto/rand"
"encoding/json"
"fmt"

Expand All @@ -15,6 +16,8 @@ import (
gethlog "github.com/ethereum/go-ethereum/log"
)

const EncryptionKeySize = 32

// PrivateKeyToCompressedPubKey converts *ecies.PrivateKey to compressed PubKey ([]byte with length 33)
func PrivateKeyToCompressedPubKey(prvKey *ecies.PrivateKey) []byte {
ecdsaPublicKey := prvKey.PublicKey.ExportECDSA()
Expand Down Expand Up @@ -76,3 +79,12 @@ func (r *RPCRequest) Clone() *RPCRequest {
Params: r.Params,
}
}

func GenerateRandomKey() ([]byte, error) {
key := make([]byte, EncryptionKeySize)
_, err := rand.Read(key)
if err != nil {
return nil, err
}
return key, nil
}
1 change: 1 addition & 0 deletions tools/walletextension/common/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,4 +19,5 @@ type Config struct {
RateLimitUserComputeTime time.Duration
RateLimitWindow time.Duration
RateLimitMaxConcurrentRequests int
Debug bool
}
15 changes: 8 additions & 7 deletions tools/walletextension/common/db_types.go
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
package common

type AccountDB struct {
AccountAddress []byte
Signature []byte
SignatureType int
type GWUserDB struct {
UserId []byte `json:"userId"`
PrivateKey []byte `json:"privateKey"`
Accounts []GWAccountDB `json:"accounts"`
}

type UserDB struct {
UserID []byte
PrivateKey []byte
type GWAccountDB struct {
AccountAddress []byte `json:"accountAddress"`
Signature []byte `json:"signature"`
SignatureType int `json:"signatureType"`
}
6 changes: 6 additions & 0 deletions tools/walletextension/enclave.Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,12 @@

FROM ghcr.io/edgelesssys/ego-dev:v1.5.3 AS build-base

# Install ca-certificates package and update it
RUN apt-get update && apt-get install -y \
ca-certificates \
&& update-ca-certificates


# setup container data structure
RUN mkdir -p /home/ten/go-ten

Expand Down
65 changes: 65 additions & 0 deletions tools/walletextension/encryption/encryption.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
package encryption

import (
"crypto/aes"
"crypto/cipher"
"crypto/hmac"
"crypto/rand"
"crypto/sha256"
"errors"
"fmt"
"io"
)

// Encryptor provides AES-GCM encryption/decryption with the following characteristics:
// - Uses AES-256-GCM (Galois/Counter Mode) with a 32-byte key
// - Generates a random 12-byte nonce for each encryption operation using crypto/rand
// - The nonce is prepended to the ciphertext output from Encrypt() and is generated
// using crypto/rand.Reader for cryptographically secure random values
//
// Additionally provides HMAC-SHA256 hashing functionality:
// - Uses the same 32-byte key as the encryption operations
// - Generates a 32-byte (256-bit) message authentication code
// - Suitable for creating secure message digests and verifying data integrity
type Encryptor struct {
gcm cipher.AEAD
key []byte
}

func NewEncryptor(key []byte) (*Encryptor, error) {
if len(key) != 32 {
return nil, fmt.Errorf("key must be 32 bytes long")
}

block, err := aes.NewCipher(key)
if err != nil {
return nil, err
}
gcm, err := cipher.NewGCM(block)
if err != nil {
return nil, err
}
return &Encryptor{gcm: gcm, key: key}, nil
}

func (e *Encryptor) Encrypt(plaintext []byte) ([]byte, error) {
nonce := make([]byte, e.gcm.NonceSize())
if _, err := io.ReadFull(rand.Reader, nonce); err != nil {
return nil, err
}
return e.gcm.Seal(nonce, nonce, plaintext, nil), nil
}

func (e *Encryptor) Decrypt(ciphertext []byte) ([]byte, error) {
if len(ciphertext) < e.gcm.NonceSize() {
return nil, errors.New("ciphertext too short")
}
nonce, ciphertext := ciphertext[:e.gcm.NonceSize()], ciphertext[e.gcm.NonceSize():]
return e.gcm.Open(nil, nonce, ciphertext, nil)
}

func (e *Encryptor) HashWithHMAC(data []byte) []byte {
h := hmac.New(sha256.New, e.key)
h.Write(data)
return h.Sum(nil)
}
115 changes: 115 additions & 0 deletions tools/walletextension/encryption/encryption_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
package encryption

import (
"bytes"
"crypto/rand"
"testing"
)

func TestNewEncryptor(t *testing.T) {
key := make([]byte, 32) // 256-bit key
_, err := rand.Read(key)
if err != nil {
t.Fatalf("Failed to generate random key: %v", err)
}

encryptor, err := NewEncryptor(key)
if err != nil {
t.Fatalf("NewEncryptor failed: %v", err)
}

if encryptor == nil {
t.Fatal("NewEncryptor returned nil")
}
}

func TestEncryptDecrypt(t *testing.T) {
key := make([]byte, 32) // 256-bit key
_, err := rand.Read(key)
if err != nil {
t.Fatalf("Failed to generate random key: %v", err)
}

encryptor, err := NewEncryptor(key)
if err != nil {
t.Fatalf("NewEncryptor failed: %v", err)
}

plaintext := []byte("Hello, World!")

ciphertext, err := encryptor.Encrypt(plaintext)
if err != nil {
t.Fatalf("Encryption failed: %v", err)
}

decrypted, err := encryptor.Decrypt(ciphertext)
if err != nil {
t.Fatalf("Decryption failed: %v", err)
}

if !bytes.Equal(plaintext, decrypted) {
t.Fatalf("Decrypted text does not match original plaintext")
}
}

func TestEncryptDecryptEmptyString(t *testing.T) {
key := make([]byte, 32) // 256-bit key
_, err := rand.Read(key)
if err != nil {
t.Fatalf("Failed to generate random key: %v", err)
}

encryptor, err := NewEncryptor(key)
if err != nil {
t.Fatalf("NewEncryptor failed: %v", err)
}

plaintext := []byte("")

ciphertext, err := encryptor.Encrypt(plaintext)
if err != nil {
t.Fatalf("Encryption of empty string failed: %v", err)
}

decrypted, err := encryptor.Decrypt(ciphertext)
if err != nil {
t.Fatalf("Decryption of empty string failed: %v", err)
}

if !bytes.Equal(plaintext, decrypted) {
t.Fatalf("Decrypted empty string does not match original")
}
}

func TestDecryptInvalidCiphertext(t *testing.T) {
key := make([]byte, 32) // 256-bit key
_, err := rand.Read(key)
if err != nil {
t.Fatalf("Failed to generate random key: %v", err)
}

encryptor, err := NewEncryptor(key)
if err != nil {
t.Fatalf("NewEncryptor failed: %v", err)
}

invalidCiphertext := []byte("This is not a valid ciphertext")

_, err = encryptor.Decrypt(invalidCiphertext)
if err == nil {
t.Fatal("Decryption of invalid ciphertext should have failed, but didn't")
}
}

func TestNewEncryptorInvalidKeySize(t *testing.T) {
invalidKey := make([]byte, 31) // Invalid key size (not 16, 24, or 32 bytes)
_, err := rand.Read(invalidKey)
if err != nil {
t.Fatalf("Failed to generate random key: %v", err)
}

_, err = NewEncryptor(invalidKey)
if err == nil {
t.Fatal("NewEncryptor should have failed with invalid key size, but didn't")
}
}
6 changes: 6 additions & 0 deletions tools/walletextension/main/cli.go
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,10 @@ const (
rateLimitMaxConcurrentRequestsName = "maxConcurrentRequestsPerUser"
rateLimitMaxConcurrentRequestsDefault = 3
rateLimitMaxConcurrentRequestsUsage = "Number of concurrent requests allowed per user. Default: 3"

debugFlagName = "debug"
debugFlagDefault = false
debugFlagUsage = "Flag to enable debug mode"
)

func parseCLIArgs() wecommon.Config {
Expand All @@ -91,6 +95,7 @@ func parseCLIArgs() wecommon.Config {
rateLimitUserComputeTime := flag.Duration(rateLimitUserComputeTimeName, rateLimitUserComputeTimeDefault, rateLimitUserComputeTimeUsage)
rateLimitWindow := flag.Duration(rateLimitWindowName, rateLimitWindowDefault, rateLimitWindowUsage)
rateLimitMaxConcurrentRequests := flag.Int(rateLimitMaxConcurrentRequestsName, rateLimitMaxConcurrentRequestsDefault, rateLimitMaxConcurrentRequestsUsage)
debugFlag := flag.Bool(debugFlagName, debugFlagDefault, debugFlagUsage)
flag.Parse()

return wecommon.Config{
Expand All @@ -109,5 +114,6 @@ func parseCLIArgs() wecommon.Config {
RateLimitUserComputeTime: *rateLimitUserComputeTime,
RateLimitWindow: *rateLimitWindow,
RateLimitMaxConcurrentRequests: *rateLimitMaxConcurrentRequests,
Debug: *debugFlag,
}
}
12 changes: 2 additions & 10 deletions tools/walletextension/main/enclave.json
Original file line number Diff line number Diff line change
Expand Up @@ -14,16 +14,8 @@
],
"files": [
{
"source": "../storage/database/mariadb/001_init.sql",
"target": "/home/ten/go-ten/tools/walletextension/storage/database/mariadb/001_init.sql"
},
{
"source": "../storage/database/mariadb/002_store_incoming_txs.sql",
"target": "/home/ten/go-ten/tools/walletextension/storage/database/mariadb/002_store_incoming_txs.sql"
},
{
"source": "../storage/database/mariadb/003_add_signature_type.sql",
"target": "/home/ten/go-ten/tools/walletextension/storage/database/mariadb/003_add_signature_type.sql"
"source": "/etc/ssl/certs/ca-certificates.crt",
"target": "/etc/ssl/certs/ca-certificates.crt"
}
]
}
Loading

0 comments on commit 8ce1944

Please sign in to comment.