-
Notifications
You must be signed in to change notification settings - Fork 38
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
Use cosmosDB in the gateway and encrypt data with encryption key generated inside the enclave #2104
Changes from 11 commits
a6ca871
da5361b
e5c796c
e9edd47
dde7135
f0caa6d
0196b8a
b8437af
1470467
18c034f
a2f97d3
e0a07c9
421be90
9f8911a
211b87c
a82f8d4
23aa123
fda0871
611bc99
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,12 +1,14 @@ | ||
package common | ||
|
||
type AccountDB struct { | ||
AccountAddress []byte | ||
Signature []byte | ||
SignatureType int | ||
type GWUserDB struct { | ||
ID string `json:"id"` // Required by CosmosDB | ||
UserId []byte `json:"userId"` | ||
PrivateKey []byte `json:"privateKey"` | ||
Accounts []GWAccountDB `json:"accounts"` // List of Accounts | ||
} | ||
|
||
type UserDB struct { | ||
UserID []byte | ||
PrivateKey []byte | ||
type GWAccountDB struct { | ||
AccountAddress []byte `json:"accountAddress"` | ||
Signature []byte `json:"signature"` | ||
SignatureType int `json:"signatureType"` | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,55 @@ | ||
package encryption | ||
|
||
import ( | ||
"crypto/aes" | ||
"crypto/cipher" | ||
"crypto/hmac" | ||
"crypto/rand" | ||
"crypto/sha256" | ||
"errors" | ||
"fmt" | ||
"io" | ||
) | ||
|
||
type Encryptor struct { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. please add a good comment describing the encryption approach. AES-GCM with key size, nonce size. How we generate a nonce for each. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. added a comment There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. thanks. |
||
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) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. can this be reused? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. this should not be reused (it has it's internal state and by reusing we might get different outputs) |
||
h.Write(data) | ||
return h.Sum(nil) | ||
} |
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") | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
there is an ID field in the EncryptedDocument as well.
Is this one here necessary?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No necessary, removed now.