From 7c3c3e482b4005bd3644ab4b9806ff2feac16813 Mon Sep 17 00:00:00 2001 From: Marvin Gajek Date: Sun, 17 Nov 2024 17:33:06 +0100 Subject: [PATCH 01/14] remove gitkeep --- docs/.gitkeep | 0 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 docs/.gitkeep diff --git a/docs/.gitkeep b/docs/.gitkeep deleted file mode 100644 index e69de29..0000000 From b8e4a78c24a4bd241f47fa218e1b259d237fe6a5 Mon Sep 17 00:00:00 2001 From: Marvin Gajek Date: Mon, 18 Nov 2024 09:38:15 +0100 Subject: [PATCH 02/14] consider domains in use case overview --- docs/diagrams/use-case-overview.mmd | 70 +++++++++++++++++++++-------- 1 file changed, 51 insertions(+), 19 deletions(-) diff --git a/docs/diagrams/use-case-overview.mmd b/docs/diagrams/use-case-overview.mmd index c743d3b..8c10774 100644 --- a/docs/diagrams/use-case-overview.mmd +++ b/docs/diagrams/use-case-overview.mmd @@ -1,27 +1,59 @@ graph TD; +%% Actors (Users) Admin["Administrator"] Owner["Owner"] Grantee["Grantee"] -Admin --> UC1["Manage All Blobs"] -Admin --> UC2["Manage Cryptographic Keys"] -Admin --> UC3["Logout"] - -Owner --> UC4["Upload Own Blobs"] -Owner --> UC5["Delete Own Blobs"] -Owner --> UC6["Grant Download Permission"] -Owner --> UC7["Grant View Permission"] -Owner --> UC8["Encrypt Own Blobs"] -Owner --> UC9["Decrypt Own Blobs"] -Owner --> UC10["Hash Own Blobs"] -Owner --> UC11["Verify Blob Signature"] -Owner --> UC12["Logout"] - -Grantee --> UC13["Download Blob with Permission"] -Grantee --> UC14["View Blob with Permission"] -Grantee --> UC15["Verify Blob Signature"] -Grantee --> UC16["Logout"] +%% Use Cases Grouped by Domain +subgraph Blob_Management ["Blob Management"] + UC1["Manage All Blobs"] + UC4["Upload Own Blobs"] + UC5["Delete Own Blobs"] + UC13["Download Blob with Permission"] + UC14["View Blob with Permission"] +end +subgraph Cryptographic_Management ["Cryptographic Management"] + UC2["Manage Cryptographic Keys"] +end + +subgraph Cryptographic_Key_Operations ["Cryptographic Key Operations"] + UC8["Encrypt Own Blobs"] + UC9["Decrypt Own Blobs"] + UC10["Hash Own Blobs"] + UC11["Verify Blob Signature"] +end + +subgraph Permission_Management ["Permission Management"] + UC6["Grant Download Permission"] + UC7["Grant View Permission"] + UC15["Verify Blob Signature"] +end + +%% Actor -> Use Cases +Admin --> UC1 +Admin --> UC2 + +Owner --> UC4 +Owner --> UC5 +Owner --> UC6 +Owner --> UC7 +Owner --> UC8 +Owner --> UC9 +Owner --> UC10 +Owner --> UC11 + +Grantee --> UC13 +Grantee --> UC14 +Grantee --> UC15 + +%% Class definitions for actors classDef actor fill:#ADD8E6,stroke:#333,stroke-width:2px; -class Admin,Owner,Grantee actor; \ No newline at end of file +class Admin,Owner,Grantee actor; + +%% Class definitions for domains +class Blob_Management fill:#FFD700,stroke:#333,stroke-width:2px; +class Cryptographic_Management fill:#90EE90,stroke:#333,stroke-width:2px; +class Cryptographic_Key_Operations fill:#98FB98,stroke:#333,stroke-width:2px; +class Permission_Management fill:#FF6347,stroke:#333,stroke-width:2px; From 64b8b9ad615a51b078bffd2c6c9474fb62023448 Mon Sep 17 00:00:00 2001 From: Marvin Gajek Date: Mon, 18 Nov 2024 09:40:56 +0100 Subject: [PATCH 03/14] consider domains in use case overview --- docs/diagrams/use-case-overview.mmd | 68 +++++++++++++++++++++-------- 1 file changed, 49 insertions(+), 19 deletions(-) diff --git a/docs/diagrams/use-case-overview.mmd b/docs/diagrams/use-case-overview.mmd index c743d3b..fcc5ee2 100644 --- a/docs/diagrams/use-case-overview.mmd +++ b/docs/diagrams/use-case-overview.mmd @@ -1,27 +1,57 @@ graph TD; +%% Actors (Users) Admin["Administrator"] Owner["Owner"] Grantee["Grantee"] -Admin --> UC1["Manage All Blobs"] -Admin --> UC2["Manage Cryptographic Keys"] -Admin --> UC3["Logout"] - -Owner --> UC4["Upload Own Blobs"] -Owner --> UC5["Delete Own Blobs"] -Owner --> UC6["Grant Download Permission"] -Owner --> UC7["Grant View Permission"] -Owner --> UC8["Encrypt Own Blobs"] -Owner --> UC9["Decrypt Own Blobs"] -Owner --> UC10["Hash Own Blobs"] -Owner --> UC11["Verify Blob Signature"] -Owner --> UC12["Logout"] - -Grantee --> UC13["Download Blob with Permission"] -Grantee --> UC14["View Blob with Permission"] -Grantee --> UC15["Verify Blob Signature"] -Grantee --> UC16["Logout"] +%% Use Cases Grouped by Domain +subgraph Blob_Management ["Blob Management"] + UC1["Manage All Blobs"] + UC4["Upload Own Blobs"] + UC5["Delete Own Blobs"] + UC13["Download Blob with Permission"] + UC14["View Blob with Permission"] +end +subgraph Cryptographic_Management ["Cryptographic Management"] + UC2["Manage Cryptographic Keys"] +end + +subgraph Cryptographic_Key_Operations ["Cryptographic Key Operations"] + UC8["Encrypt Own Blobs"] + UC9["Decrypt Own Blobs"] + UC10["Hash Own Blobs"] + UC11["Verify Blob Signature"] +end + +subgraph Permission_Management ["Permission Management"] + UC6["Grant Download Permission"] + UC7["Grant View Permission"] +end + +%% Actor -> Use Cases +Admin --> UC1 +Admin --> UC2 + +Owner --> UC4 +Owner --> UC5 +Owner --> UC6 +Owner --> UC7 +Owner --> UC8 +Owner --> UC9 +Owner --> UC10 +Owner --> UC11 + +Grantee --> UC13 +Grantee --> UC14 + +%% Class definitions for actors classDef actor fill:#ADD8E6,stroke:#333,stroke-width:2px; -class Admin,Owner,Grantee actor; \ No newline at end of file +class Admin,Owner,Grantee actor; + +%% Class definitions for domains +class Blob_Management fill:#FFD700,stroke:#333,stroke-width:2px; +class Cryptographic_Management fill:#90EE90,stroke:#333,stroke-width:2px; +class Cryptographic_Key_Operations fill:#98FB98,stroke:#333,stroke-width:2px; +class Permission_Management fill:#FF6347,stroke:#333,stroke-width:2px; From 99d162332241510d72e4d603f0fb434b83a72a48 Mon Sep 17 00:00:00 2001 From: Marvin Gajek Date: Mon, 18 Nov 2024 10:17:23 +0100 Subject: [PATCH 04/14] consider domains in use case overview --- docs/diagrams/use-case-overview.mmd | 79 ++++++++++++++++++++++------- 1 file changed, 60 insertions(+), 19 deletions(-) diff --git a/docs/diagrams/use-case-overview.mmd b/docs/diagrams/use-case-overview.mmd index c743d3b..a0b62a2 100644 --- a/docs/diagrams/use-case-overview.mmd +++ b/docs/diagrams/use-case-overview.mmd @@ -1,27 +1,68 @@ graph TD; +%% Actors (Users) Admin["Administrator"] Owner["Owner"] Grantee["Grantee"] -Admin --> UC1["Manage All Blobs"] -Admin --> UC2["Manage Cryptographic Keys"] -Admin --> UC3["Logout"] - -Owner --> UC4["Upload Own Blobs"] -Owner --> UC5["Delete Own Blobs"] -Owner --> UC6["Grant Download Permission"] -Owner --> UC7["Grant View Permission"] -Owner --> UC8["Encrypt Own Blobs"] -Owner --> UC9["Decrypt Own Blobs"] -Owner --> UC10["Hash Own Blobs"] -Owner --> UC11["Verify Blob Signature"] -Owner --> UC12["Logout"] - -Grantee --> UC13["Download Blob with Permission"] -Grantee --> UC14["View Blob with Permission"] -Grantee --> UC15["Verify Blob Signature"] -Grantee --> UC16["Logout"] +%% Use Cases Grouped by Domain +subgraph Blob_Management ["Blob Management"] + UC1["Manage All Blobs"] + UC2["Upload Own Blobs"] + UC3["Delete Own Blobs"] + UC4["Download Blob with Permission"] + UC5["View Blob with Permission"] +end +subgraph Key_Management ["Key Management"] + UC6["Manage Cryptographic Keys"] + UC7["Manage Own Cryptographic Keys"] +end + +subgraph Metadata_Management ["Metadata Management"] + UC8["Manage Metadata"] + UC9["Manage Own Metadata"] + UC10["View public Metadata"] +end + +subgraph Key_Operations ["Key Operations"] + UC11["Encrypt Own Blobs"] + UC12["Decrypt Own Blobs"] + UC13["Hash Own Blobs"] + UC14["Verify Blob Signature"] +end + +subgraph Permission_Management ["Permission Management"] + UC15["Grant Download Permission"] + UC16["Grant View Permission"] +end + +%% Actor -> Use Cases +Admin --> UC1 +Admin --> UC6 +Admin --> UC7 + +Owner --> UC2 +Owner --> UC3 +Owner --> UC4 +Owner --> UC8 +Owner --> UC9 +Owner --> UC10 +Owner --> UC11 +Owner --> UC12 +Owner --> UC13 +Owner --> UC14 + +Grantee --> UC4 +Grantee --> UC5 +Grantee --> UC12 + +%% Class definitions for actors classDef actor fill:#ADD8E6,stroke:#333,stroke-width:2px; -class Admin,Owner,Grantee actor; \ No newline at end of file +class Admin,Owner,Grantee actor; + +%% Class definitions for domains +class Blob_Management fill:#FFD700,stroke:#333,stroke-width:2px; +class Key_Management fill:#90EE90,stroke:#333,stroke-width:2px; +class Key_Operations fill:#98FB98,stroke:#333,stroke-width:2px; +class Permission_Management fill:#FF6347,stroke:#333,stroke-width:2px; From 407b6dafd274bf7836ef1b15e8f92474b3b1067f Mon Sep 17 00:00:00 2001 From: Marvin Gajek Date: Mon, 18 Nov 2024 10:32:35 +0100 Subject: [PATCH 05/14] setup domain models and create files for contracts --- internal/domain/.gitkeep | 1 - internal/domain/contracts/blob_management.go | 1 + internal/domain/contracts/key_management.go | 1 + internal/domain/contracts/key_operations.go | 1 + .../domain/contracts/metadata_management.go | 1 + .../domain/contracts/permission_management.go | 1 + internal/domain/model/blob.go | 16 ++++++++++++++++ internal/domain/model/key.go | 15 +++++++++++++++ internal/domain/model/metadata.go | 18 ++++++++++++++++++ 9 files changed, 54 insertions(+), 1 deletion(-) delete mode 100644 internal/domain/.gitkeep create mode 100644 internal/domain/contracts/blob_management.go create mode 100644 internal/domain/contracts/key_management.go create mode 100644 internal/domain/contracts/key_operations.go create mode 100644 internal/domain/contracts/metadata_management.go create mode 100644 internal/domain/contracts/permission_management.go create mode 100644 internal/domain/model/blob.go create mode 100644 internal/domain/model/key.go create mode 100644 internal/domain/model/metadata.go diff --git a/internal/domain/.gitkeep b/internal/domain/.gitkeep deleted file mode 100644 index 760c903..0000000 --- a/internal/domain/.gitkeep +++ /dev/null @@ -1 +0,0 @@ -Domain models, service contracts \ No newline at end of file diff --git a/internal/domain/contracts/blob_management.go b/internal/domain/contracts/blob_management.go new file mode 100644 index 0000000..a3f0514 --- /dev/null +++ b/internal/domain/contracts/blob_management.go @@ -0,0 +1 @@ +package contracts diff --git a/internal/domain/contracts/key_management.go b/internal/domain/contracts/key_management.go new file mode 100644 index 0000000..a3f0514 --- /dev/null +++ b/internal/domain/contracts/key_management.go @@ -0,0 +1 @@ +package contracts diff --git a/internal/domain/contracts/key_operations.go b/internal/domain/contracts/key_operations.go new file mode 100644 index 0000000..a3f0514 --- /dev/null +++ b/internal/domain/contracts/key_operations.go @@ -0,0 +1 @@ +package contracts diff --git a/internal/domain/contracts/metadata_management.go b/internal/domain/contracts/metadata_management.go new file mode 100644 index 0000000..a3f0514 --- /dev/null +++ b/internal/domain/contracts/metadata_management.go @@ -0,0 +1 @@ +package contracts diff --git a/internal/domain/contracts/permission_management.go b/internal/domain/contracts/permission_management.go new file mode 100644 index 0000000..a3f0514 --- /dev/null +++ b/internal/domain/contracts/permission_management.go @@ -0,0 +1 @@ +package contracts diff --git a/internal/domain/model/blob.go b/internal/domain/model/blob.go new file mode 100644 index 0000000..5735c99 --- /dev/null +++ b/internal/domain/model/blob.go @@ -0,0 +1,16 @@ +package model + +import "time" + +// Blob represents metadata on the actual file being stored +type Blob struct { + BlobID string `gorm:"primaryKey"` + BlobStoragePath string + UploadTime time.Time + UserID string + FileName string + FileSize int + FileType string + Metadata []Metadata + CryptographicKey CryptographicKey `gorm:"foreignKey:KeyID"` +} diff --git a/internal/domain/model/key.go b/internal/domain/model/key.go new file mode 100644 index 0000000..ea11b04 --- /dev/null +++ b/internal/domain/model/key.go @@ -0,0 +1,15 @@ +package model + +import "time" + +// CryptographicKey represents the encryption key entity +type CryptographicKey struct { + KeyID string `gorm:"primaryKey"` + KeyValue string + KeyType string + CreatedAt time.Time + ExpiresAt time.Time + UserID string `gorm:"index"` + Metadata []Metadata + Blobs []Blob +} diff --git a/internal/domain/model/metadata.go b/internal/domain/model/metadata.go new file mode 100644 index 0000000..26ab5cb --- /dev/null +++ b/internal/domain/model/metadata.go @@ -0,0 +1,18 @@ +package model + +import "time" + +// Metadata represents metadata related to a file (BLOB) +type Metadata struct { + MetadataID string `gorm:"primaryKey"` + BlobID string + KeyID string + CreatedAt time.Time + UpdatedAt time.Time + EncryptionAlg string + ContentType string + Size int + UserID string + CryptographicKey CryptographicKey `gorm:"foreignKey:KeyID"` + Blob Blob `gorm:"foreignKey:BlobID"` +} From 234236732d12de52a1607b1de1523284b1f57930 Mon Sep 17 00:00:00 2001 From: Marvin Gajek Date: Mon, 18 Nov 2024 10:34:23 +0100 Subject: [PATCH 06/14] replace file with blob --- docs/diagrams/erd.mmd | 6 +++--- internal/domain/model/blob.go | 8 ++++---- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/docs/diagrams/erd.mmd b/docs/diagrams/erd.mmd index 68bfc3f..0590c15 100644 --- a/docs/diagrams/erd.mmd +++ b/docs/diagrams/erd.mmd @@ -25,9 +25,9 @@ erDiagram string blob_storage_path datetime upload_time string user_id FK - string file_name - int file_size - string file_type + string blob_name + int blob_size + string blob_type } CRYPTOGRAPHIC_KEY ||--o| METADATA : "used in" diff --git a/internal/domain/model/blob.go b/internal/domain/model/blob.go index 5735c99..814289c 100644 --- a/internal/domain/model/blob.go +++ b/internal/domain/model/blob.go @@ -2,15 +2,15 @@ package model import "time" -// Blob represents metadata on the actual file being stored +// Blob represents metadata on the actual blob being stored type Blob struct { BlobID string `gorm:"primaryKey"` BlobStoragePath string UploadTime time.Time UserID string - FileName string - FileSize int - FileType string + BlobName string + BlobSize int + BlobType string Metadata []Metadata CryptographicKey CryptographicKey `gorm:"foreignKey:KeyID"` } From ba449519c0d3a952fe64ea9bfe31eca37ca169dc Mon Sep 17 00:00:00 2001 From: Marvin Gajek Date: Mon, 18 Nov 2024 10:46:21 +0100 Subject: [PATCH 07/14] reduce entities --- docs/diagrams/erd.mmd | 19 ++++--------------- internal/domain/model/blob.go | 21 ++++++++++++--------- internal/domain/model/key.go | 3 --- internal/domain/model/metadata.go | 18 ------------------ 4 files changed, 16 insertions(+), 45 deletions(-) delete mode 100644 internal/domain/model/metadata.go diff --git a/docs/diagrams/erd.mmd b/docs/diagrams/erd.mmd index 0590c15..d5cdd96 100644 --- a/docs/diagrams/erd.mmd +++ b/docs/diagrams/erd.mmd @@ -1,25 +1,12 @@ erDiagram CRYPTOGRAPHIC_KEY { string key_id PK - string key_value string key_type datetime created_at datetime expires_at string user_id FK } - METADATA { - string metadata_id PK - string blob_id FK - string key_id FK - datetime created_at - datetime updated_at - string encryption_algorithm - string content_type - int size - string user_id FK - } - BLOB { string blob_id PK string blob_storage_path @@ -28,8 +15,10 @@ erDiagram string blob_name int blob_size string blob_type + string encryption_algorithm + string hash_algorithm + bool is_encrypted + bool is_signed } - CRYPTOGRAPHIC_KEY ||--o| METADATA : "used in" CRYPTOGRAPHIC_KEY ||--o| BLOB : "associated with" - BLOB ||--o| METADATA : "has metadata" diff --git a/internal/domain/model/blob.go b/internal/domain/model/blob.go index 814289c..d34af51 100644 --- a/internal/domain/model/blob.go +++ b/internal/domain/model/blob.go @@ -4,13 +4,16 @@ import "time" // Blob represents metadata on the actual blob being stored type Blob struct { - BlobID string `gorm:"primaryKey"` - BlobStoragePath string - UploadTime time.Time - UserID string - BlobName string - BlobSize int - BlobType string - Metadata []Metadata - CryptographicKey CryptographicKey `gorm:"foreignKey:KeyID"` + BlobID string `gorm:"primaryKey"` + BlobStoragePath string + UploadTime time.Time + UserID string + BlobName string + BlobSize int + BlobType string + EncryptionAlgorithm string + HashAlgorithm string + IsEncrypted bool + IsSigned bool + CryptographicKey CryptographicKey `gorm:"foreignKey:KeyID"` } diff --git a/internal/domain/model/key.go b/internal/domain/model/key.go index ea11b04..2f3e2d0 100644 --- a/internal/domain/model/key.go +++ b/internal/domain/model/key.go @@ -5,11 +5,8 @@ import "time" // CryptographicKey represents the encryption key entity type CryptographicKey struct { KeyID string `gorm:"primaryKey"` - KeyValue string KeyType string CreatedAt time.Time ExpiresAt time.Time UserID string `gorm:"index"` - Metadata []Metadata - Blobs []Blob } diff --git a/internal/domain/model/metadata.go b/internal/domain/model/metadata.go deleted file mode 100644 index 26ab5cb..0000000 --- a/internal/domain/model/metadata.go +++ /dev/null @@ -1,18 +0,0 @@ -package model - -import "time" - -// Metadata represents metadata related to a file (BLOB) -type Metadata struct { - MetadataID string `gorm:"primaryKey"` - BlobID string - KeyID string - CreatedAt time.Time - UpdatedAt time.Time - EncryptionAlg string - ContentType string - Size int - UserID string - CryptographicKey CryptographicKey `gorm:"foreignKey:KeyID"` - Blob Blob `gorm:"foreignKey:BlobID"` -} From b8f79e87296a19647b0a33e2b94d479aea1a9f40 Mon Sep 17 00:00:00 2001 From: Marvin Gajek Date: Mon, 18 Nov 2024 11:40:52 +0100 Subject: [PATCH 08/14] add interface signatures --- internal/domain/contracts/blob_management.go | 20 ++++++++ internal/domain/contracts/key_management.go | 20 ++++++++ internal/domain/contracts/key_operations.go | 46 +++++++++++++++++++ .../domain/contracts/metadata_management.go | 29 ++++++++++++ .../domain/contracts/permission_management.go | 6 +++ 5 files changed, 121 insertions(+) diff --git a/internal/domain/contracts/blob_management.go b/internal/domain/contracts/blob_management.go index a3f0514..34a0b84 100644 --- a/internal/domain/contracts/blob_management.go +++ b/internal/domain/contracts/blob_management.go @@ -1 +1,21 @@ package contracts + +import ( + "crypto_vault_service/internal/domain/model" + "mime/multipart" +) + +// BlobManagement defines methods for managing blob operations. +type BlobManagement interface { + // Upload handles the upload of a blob from a multipart form. + // Returns the created Blob metadata and any error encountered. + Upload(form *multipart.Form) (*model.Blob, error) + + // Download retrieves a blob by its ID, returning the metadata and file data. + // Returns the Blob metadata, file data as a byte slice, and any error. + Download(blobId string) (*model.Blob, []byte, error) + + // Delete removes a blob by its ID. + // Returns the deleted Blob metadata and any error encountered. + Delete(blobId string) (*model.Blob, error) +} diff --git a/internal/domain/contracts/key_management.go b/internal/domain/contracts/key_management.go index a3f0514..00ad295 100644 --- a/internal/domain/contracts/key_management.go +++ b/internal/domain/contracts/key_management.go @@ -1 +1,21 @@ package contracts + +import ( + "crypto_vault_service/internal/domain/model" + "mime/multipart" +) + +// KeyManagement defines methods for managing cryptographic key operations. +type KeyManagement interface { + // Upload handles the upload of a cryptographic key from a multipart form. + // Returns the created key metadata and any error encountered. + Upload(form *multipart.Form) (*model.CryptographicKey, error) + + // Download retrieves a cryptographic key by its ID, returning the metadata and key data. + // Returns the key metadata, key data as a byte slice, and any error. + Download(keyId string) (*model.CryptographicKey, []byte, error) + + // Delete removes a cryptographic key by its ID. + // Returns the deleted key metadata and any error encountered. + Delete(keyId string) (*model.CryptographicKey, error) +} diff --git a/internal/domain/contracts/key_operations.go b/internal/domain/contracts/key_operations.go index a3f0514..63bc212 100644 --- a/internal/domain/contracts/key_operations.go +++ b/internal/domain/contracts/key_operations.go @@ -1 +1,47 @@ package contracts + +// KeyOperations defines methods for key management, encryption, signing, and PKCS#11 operations. +type KeyOperations interface { + + // ---Key generation--- + + // GenerateKey generates keys for specified type and size (e.g., AES, RSA, ECDSA) + GenerateKey(keyType string, keySize int) ([]byte, error) + + // ---Key storage and retrieval--- + + // SaveKey saves a key to a file + SaveKey(key []byte, filename string) error + // LoadKey loads a key from a file + LoadKey(filename string) ([]byte, error) + + // ---Encryption and Decryption (Symmetric algorithms like AES)--- + + // Encrypt encrypts data with symmetric keys (e.g. AES) + Encrypt(plainText []byte, key []byte) ([]byte, error) + // Decrypt decrypts data with symmetric keys (e.g. AES) + Decrypt(cipherText []byte, key []byte) ([]byte, error) + + // ---Asymmetric Encryption (RSA, ECDSA, PKCS#11)--- + + // EncryptWithPublicKey encrypts with public key using asymmetric algorithms (RSA, ECDSA) and optionally a PKCS#11 interface + EncryptWithPublicKey(plainText []byte, publicKey interface{}) ([]byte, error) + // DecryptWithPrivateKey decrypt with private key using asymmetric algorithms (RSA, ECDSA) and optionally a PKCS#11 interface + DecryptWithPrivateKey(cipherText []byte, privateKey interface{}) ([]byte, error) + + // ---Signing and Verification (For RSA, ECDSA)--- + + // Sign signs message with private key using asymmetric algorithms (RSA, ECDSA) + Sign(message []byte, privateKey interface{}) ([]byte, error) + // Verify verifies signatures with private key using asymmetric algorithms (RSA, ECDSA) + Verify(message []byte, signature []byte, publicKey interface{}) (bool, error) + + // ---PKCS#11 Operations--- + + // InitializeToken initializes PKCS#11 token in the specified slot + InitializeToken(slot string) error + // AddKeyToToken adds key to the PKCS#11 token + AddKeyToToken() error + // DeleteKeyFromToken deletes key from PKCS#11 token by type and label + DeleteKeyFromToken(objectType, objectLabel string) error +} diff --git a/internal/domain/contracts/metadata_management.go b/internal/domain/contracts/metadata_management.go index a3f0514..2bb507c 100644 --- a/internal/domain/contracts/metadata_management.go +++ b/internal/domain/contracts/metadata_management.go @@ -1 +1,30 @@ package contracts + +import ( + "crypto_vault_service/internal/domain/model" +) + +// MetadataManagement defines the methods for managing Blob and CryptographicKey metadata +type MetadataManagement interface { + // ---CRUD operations for Blob metadata--- + + // CreateBlob creates a new blob + CreateBlob(blob *model.Blob) (*model.Blob, error) + // GetBlob retrieves blob by ID + GetBlob(blobID string) (*model.Blob, error) + // UpdateBlob updates a blob's metadata + UpdateBlob(blobID string, updates *model.Blob) (*model.Blob, error) + // DeleteBlob deletes a blob by ID + DeleteBlob(blobID string) error + + // ---CRUD operations for CryptographicKey metadata--- + + // CreateCryptographicKey creates a new cryptographic key + CreateCryptographicKey(key *model.CryptographicKey) (*model.CryptographicKey, error) + // GetCryptographicKey retrieves cryptographic key by ID + GetCryptographicKey(keyID string) (*model.CryptographicKey, error) + // UpdateCryptographicKey updates cryptographic key metadata + UpdateCryptographicKey(keyID string, updates *model.CryptographicKey) (*model.CryptographicKey, error) + // DeleteCryptographicKey deletes a cryptographic key by ID + DeleteCryptographicKey(keyID string) error +} diff --git a/internal/domain/contracts/permission_management.go b/internal/domain/contracts/permission_management.go index a3f0514..8f20a6d 100644 --- a/internal/domain/contracts/permission_management.go +++ b/internal/domain/contracts/permission_management.go @@ -1 +1,7 @@ package contracts + +// PoC with OpenFGA required for signatures + +// PermissionManagement Interface +type PermissionManagement interface { +} From 99ffcdb568e7c625ab04e4a82740fb82d4eb71c0 Mon Sep 17 00:00:00 2001 From: Marvin Gajek Date: Mon, 18 Nov 2024 11:47:23 +0100 Subject: [PATCH 09/14] rename interface signatures --- internal/domain/contracts/key_operations.go | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/internal/domain/contracts/key_operations.go b/internal/domain/contracts/key_operations.go index 63bc212..320e1a2 100644 --- a/internal/domain/contracts/key_operations.go +++ b/internal/domain/contracts/key_operations.go @@ -17,10 +17,10 @@ type KeyOperations interface { // ---Encryption and Decryption (Symmetric algorithms like AES)--- - // Encrypt encrypts data with symmetric keys (e.g. AES) - Encrypt(plainText []byte, key []byte) ([]byte, error) - // Decrypt decrypts data with symmetric keys (e.g. AES) - Decrypt(cipherText []byte, key []byte) ([]byte, error) + // EncryptWithSymmetricKey encrypts data with symmetric keys (e.g. AES) + EncryptWithSymmetricKey(plainText []byte, key []byte) ([]byte, error) + // DecryptWithSymmetricKey decrypts data with symmetric keys (e.g. AES) + DecryptWithSymmetricKey(cipherText []byte, key []byte) ([]byte, error) // ---Asymmetric Encryption (RSA, ECDSA, PKCS#11)--- @@ -31,10 +31,10 @@ type KeyOperations interface { // ---Signing and Verification (For RSA, ECDSA)--- - // Sign signs message with private key using asymmetric algorithms (RSA, ECDSA) - Sign(message []byte, privateKey interface{}) ([]byte, error) - // Verify verifies signatures with private key using asymmetric algorithms (RSA, ECDSA) - Verify(message []byte, signature []byte, publicKey interface{}) (bool, error) + // SignWithPrivateKey signs message with private key using asymmetric algorithms (RSA, ECDSA) and optionally a PKCS#11 interface + SignWithPrivateKey(message []byte, privateKey interface{}) ([]byte, error) + // VerifyWithPublicKey verifies signatures with public key using asymmetric algorithms (RSA, ECDSA) and optionally a PKCS#11 interface + VerifyWithPublicKey(message []byte, signature []byte, publicKey interface{}) (bool, error) // ---PKCS#11 Operations--- From 8ee3930a5d76fa2f6fa23e37bd29ce85ed84ad6c Mon Sep 17 00:00:00 2001 From: Marvin Gajek Date: Mon, 18 Nov 2024 11:49:55 +0100 Subject: [PATCH 10/14] modify Delete(...) interface signatures --- internal/domain/contracts/blob_management.go | 4 ++-- internal/domain/contracts/key_management.go | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/internal/domain/contracts/blob_management.go b/internal/domain/contracts/blob_management.go index 34a0b84..13d37df 100644 --- a/internal/domain/contracts/blob_management.go +++ b/internal/domain/contracts/blob_management.go @@ -16,6 +16,6 @@ type BlobManagement interface { Download(blobId string) (*model.Blob, []byte, error) // Delete removes a blob by its ID. - // Returns the deleted Blob metadata and any error encountered. - Delete(blobId string) (*model.Blob, error) + // Returns any error encountered. + Delete(blobId string) error } diff --git a/internal/domain/contracts/key_management.go b/internal/domain/contracts/key_management.go index 00ad295..6dbbd53 100644 --- a/internal/domain/contracts/key_management.go +++ b/internal/domain/contracts/key_management.go @@ -16,6 +16,6 @@ type KeyManagement interface { Download(keyId string) (*model.CryptographicKey, []byte, error) // Delete removes a cryptographic key by its ID. - // Returns the deleted key metadata and any error encountered. - Delete(keyId string) (*model.CryptographicKey, error) + // Returns any error encountered. + Delete(keyId string) error } From be3186bde3924ae09e7fd075181f3bc44c80469c Mon Sep 17 00:00:00 2001 From: Marvin Gajek Date: Mon, 18 Nov 2024 12:03:44 +0100 Subject: [PATCH 11/14] add validator package and validate properties --- go.mod | 2 +- go.sum | 2 ++ internal/domain/model/blob.go | 50 ++++++++++++++++++++++++++--------- internal/domain/model/key.go | 35 +++++++++++++++++++----- 4 files changed, 69 insertions(+), 20 deletions(-) diff --git a/go.mod b/go.mod index f7695fa..bbb04ab 100644 --- a/go.mod +++ b/go.mod @@ -19,7 +19,7 @@ require ( github.com/gin-contrib/sse v0.1.0 // indirect github.com/go-playground/locales v0.14.1 // indirect github.com/go-playground/universal-translator v0.18.1 // indirect - github.com/go-playground/validator/v10 v10.22.1 // indirect + github.com/go-playground/validator/v10 v10.23.0 // indirect github.com/goccy/go-json v0.10.3 // indirect github.com/google/go-cmp v0.5.9 // indirect github.com/inconshreveable/mousetrap v1.1.0 // indirect diff --git a/go.sum b/go.sum index 781b328..1deeb7c 100644 --- a/go.sum +++ b/go.sum @@ -27,6 +27,8 @@ github.com/go-playground/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJn github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91TpwSH2VMlDf28Uj24BCp08ZFTUY= github.com/go-playground/validator/v10 v10.22.1 h1:40JcKH+bBNGFczGuoBYgX4I6m/i27HYW8P9FDk5PbgA= github.com/go-playground/validator/v10 v10.22.1/go.mod h1:dbuPbCMFw/DrkbEynArYaCwl3amGuJotoKCe95atGMM= +github.com/go-playground/validator/v10 v10.23.0 h1:/PwmTwZhS0dPkav3cdK9kV1FsAmrL8sThn8IHr/sO+o= +github.com/go-playground/validator/v10 v10.23.0/go.mod h1:dbuPbCMFw/DrkbEynArYaCwl3amGuJotoKCe95atGMM= github.com/goccy/go-json v0.10.3 h1:KZ5WoDbxAIgm2HNbYckL0se1fHD6rz5j4ywS6ebzDqA= github.com/goccy/go-json v0.10.3/go.mod h1:oq7eo15ShAhp70Anwd5lgX2pLfOS3QCiwU/PULtXL6M= github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= diff --git a/internal/domain/model/blob.go b/internal/domain/model/blob.go index d34af51..adc0342 100644 --- a/internal/domain/model/blob.go +++ b/internal/domain/model/blob.go @@ -1,19 +1,43 @@ package model -import "time" +import ( + "fmt" + "time" + + "github.com/go-playground/validator/v10" +) // Blob represents metadata on the actual blob being stored type Blob struct { - BlobID string `gorm:"primaryKey"` - BlobStoragePath string - UploadTime time.Time - UserID string - BlobName string - BlobSize int - BlobType string - EncryptionAlgorithm string - HashAlgorithm string - IsEncrypted bool - IsSigned bool - CryptographicKey CryptographicKey `gorm:"foreignKey:KeyID"` + BlobID string `gorm:"primaryKey" validate:"required,uuid4"` // BlobID is required and must be a valid UUID + BlobStoragePath string `validate:"required"` // BlobStoragePath is required + UploadTime time.Time `validate:"required"` // UploadTime is required + UserID string `validate:"required,uuid4"` // UserID is required and must be a valid UUID + BlobName string `validate:"required,min=1,max=255"` // BlobName is required, and its length must be between 1 and 255 characters + BlobSize int `validate:"required,min=1"` // BlobSize must be greater than 0 + BlobType string `validate:"required,min=1,max=50"` // BlobType is required, and its length must be between 1 and 50 characters + EncryptionAlgorithm string `validate:"omitempty,oneof=AES RSA ECDSA"` // EncryptionAlgorithm is optional and must be one of the listed algorithms + HashAlgorithm string `validate:"omitempty,oneof=SHA256 SHA512 MD5"` // HashAlgorithm is optional and must be one of the listed algorithms + IsEncrypted bool `validate:"required"` // IsEncrypted is required (true/false) + IsSigned bool `validate:"required"` // IsSigned is required (true/false) + CryptographicKey CryptographicKey `gorm:"foreignKey:KeyID" validate:"required"` // CryptographicKey is required + KeyID string `validate:"omitempty,uuid4"` // KeyID is optional and must be a valid UUID +} + +// Validate for validating Blob struct +func (b *Blob) Validate() error { + // Initialize the validator + validate := validator.New() + + // Validate the struct + err := validate.Struct(b) + if err != nil { + // If validation fails, return a formatted error + var validationErrors []string + for _, err := range err.(validator.ValidationErrors) { + validationErrors = append(validationErrors, fmt.Sprintf("Field: %s, Tag: %s", err.Field(), err.Tag())) + } + return fmt.Errorf("Validation failed: %v", validationErrors) + } + return nil // Return nil if validation passes } diff --git a/internal/domain/model/key.go b/internal/domain/model/key.go index 2f3e2d0..df70e53 100644 --- a/internal/domain/model/key.go +++ b/internal/domain/model/key.go @@ -1,12 +1,35 @@ package model -import "time" +import ( + "fmt" + "time" + + "github.com/go-playground/validator/v10" +) // CryptographicKey represents the encryption key entity type CryptographicKey struct { - KeyID string `gorm:"primaryKey"` - KeyType string - CreatedAt time.Time - ExpiresAt time.Time - UserID string `gorm:"index"` + KeyID string `gorm:"primaryKey" validate:"required,uuid4"` // KeyID is required and must be a valid UUID + KeyType string `validate:"required,oneof=AES RSA ECDSA"` // KeyType is required and must be one of the listed types + CreatedAt time.Time `validate:"required"` // CreatedAt is required + ExpiresAt time.Time `validate:"required,gtefield=CreatedAt"` // ExpiresAt is required and must be after CreatedAt + UserID string `gorm:"index" validate:"required,uuid4"` // UserID is required and must be a valid UUID +} + +// Validate for validating CryptographicKey struct +func (k *CryptographicKey) Validate() error { + // Initialize the validator + validate := validator.New() + + // Validate the struct + err := validate.Struct(k) + if err != nil { + // If validation fails, return a formatted error + var validationErrors []string + for _, err := range err.(validator.ValidationErrors) { + validationErrors = append(validationErrors, fmt.Sprintf("Field: %s, Tag: %s", err.Field(), err.Tag())) + } + return fmt.Errorf("Validation failed: %v", validationErrors) + } + return nil // Return nil if validation passes } From c162462742e4eaf0163858395d690f746f8a7318 Mon Sep 17 00:00:00 2001 From: root Date: Mon, 18 Nov 2024 11:13:05 +0000 Subject: [PATCH 12/14] add unit tests for Validate(...) methods --- test/integration/domain/.gitkeep | 1 - test/unit/domain/.gitkeep | 1 - test/unit/domain/blob_test.go | 82 ++++++++++++++++++++++++++++++++ test/unit/domain/key_test.go | 58 ++++++++++++++++++++++ 4 files changed, 140 insertions(+), 2 deletions(-) delete mode 100644 test/integration/domain/.gitkeep delete mode 100644 test/unit/domain/.gitkeep create mode 100644 test/unit/domain/blob_test.go create mode 100644 test/unit/domain/key_test.go diff --git a/test/integration/domain/.gitkeep b/test/integration/domain/.gitkeep deleted file mode 100644 index 760c903..0000000 --- a/test/integration/domain/.gitkeep +++ /dev/null @@ -1 +0,0 @@ -Domain models, service contracts \ No newline at end of file diff --git a/test/unit/domain/.gitkeep b/test/unit/domain/.gitkeep deleted file mode 100644 index 760c903..0000000 --- a/test/unit/domain/.gitkeep +++ /dev/null @@ -1 +0,0 @@ -Domain models, service contracts \ No newline at end of file diff --git a/test/unit/domain/blob_test.go b/test/unit/domain/blob_test.go new file mode 100644 index 0000000..bc96eff --- /dev/null +++ b/test/unit/domain/blob_test.go @@ -0,0 +1,82 @@ +package model + +import ( + "crypto_vault_service/internal/domain/model" + "testing" + "time" + + "github.com/google/uuid" + "github.com/stretchr/testify/assert" +) + +// TestBlobValidation tests the Validator method for Blob +func TestBlobValidation(t *testing.T) { + // Valid Blob + validBlob := model.Blob{ + BlobID: uuid.New().String(), // Valid UUID + BlobStoragePath: "/path/to/blob", + UploadTime: time.Now(), + UserID: uuid.New().String(), // Valid UUID + BlobName: "test_blob.txt", + BlobSize: 12345, + BlobType: "text", + EncryptionAlgorithm: "AES", + HashAlgorithm: "SHA256", + IsEncrypted: true, + IsSigned: false, + CryptographicKey: model.CryptographicKey{KeyID: "abc123", KeyType: "AES", CreatedAt: time.Now(), ExpiresAt: time.Now().Add(24 * time.Hour), UserID: "e2b073b5-3e23-4fbd-b44b-c607b04c9c3e"}, + KeyID: "abc123", + } + + // Validate the valid Blob + err := validBlob.Validate() + assert.Nil(t, err, "Expected no validation errors for valid Blob") + + // Invalid Blob (empty BlobID, invalid BlobSize) + invalidBlob := model.Blob{ + BlobID: "", // Invalid empty BlobID + BlobStoragePath: "/path/to/blob", + UploadTime: time.Now(), + UserID: "invalid-uuid", // Invalid UserID + BlobName: "test_blob.txt", + BlobSize: -12345, // Invalid BlobSize (negative) + BlobType: "text", + EncryptionAlgorithm: "AES", + HashAlgorithm: "SHA256", + IsEncrypted: true, + IsSigned: false, + CryptographicKey: model.CryptographicKey{KeyID: "abc123", KeyType: "AES", CreatedAt: time.Now(), ExpiresAt: time.Now().Add(24 * time.Hour), UserID: "e2b073b5-3e23-4fbd-b44b-c607b04c9c3e"}, + KeyID: "abc123", + } + + // Validate the invalid Blob + err = invalidBlob.Validate() + assert.NotNil(t, err, "Expected validation errors for invalid Blob") + assert.Contains(t, err.Error(), "Field: BlobID, Tag: required") + assert.Contains(t, err.Error(), "Field: BlobSize, Tag: min") + assert.Contains(t, err.Error(), "Field: UserID, Tag: uuid4") +} + +// TestBlobValidationEdgeCases tests validation edge cases for Blob +func TestBlobValidationEdgeCases(t *testing.T) { + // Test missing BlobName (should fail) + invalidBlob := model.Blob{ + BlobID: uuid.New().String(), // Valid UUID + BlobStoragePath: "/path/to/blob", + UploadTime: time.Now(), + UserID: uuid.New().String(), // Valid UUID + BlobName: "", // Invalid empty BlobName + BlobSize: 12345, + BlobType: "text", + EncryptionAlgorithm: "AES", + HashAlgorithm: "SHA256", + IsEncrypted: true, + IsSigned: false, + CryptographicKey: model.CryptographicKey{KeyID: "abc123", KeyType: "AES", CreatedAt: time.Now(), ExpiresAt: time.Now().Add(24 * time.Hour), UserID: "e2b073b5-3e23-4fbd-b44b-c607b04c9c3e"}, + KeyID: "abc123", + } + + err := invalidBlob.Validate() + assert.NotNil(t, err, "Expected validation error for missing BlobName") + assert.Contains(t, err.Error(), "Field: BlobName, Tag: required") +} diff --git a/test/unit/domain/key_test.go b/test/unit/domain/key_test.go new file mode 100644 index 0000000..d0956ad --- /dev/null +++ b/test/unit/domain/key_test.go @@ -0,0 +1,58 @@ +package model + +import ( + "crypto_vault_service/internal/domain/model" + "testing" + "time" + + "github.com/google/uuid" + "github.com/stretchr/testify/assert" +) + +// TestCryptographicKeyValidation tests the Validator method for CryptographicKey +func TestCryptographicKeyValidation(t *testing.T) { + // Valid CryptographicKey + validKey := model.CryptographicKey{ + KeyID: uuid.New().String(), // Valid UUID + KeyType: "AES", // Valid KeyType + CreatedAt: time.Now(), + ExpiresAt: time.Now().Add(time.Hour * 24), // Valid ExpiresAt + UserID: uuid.New().String(), // Valid UserID + } + + // Validate the valid CryptographicKey + err := validKey.Validate() + assert.Nil(t, err, "Expected no validation errors for valid CryptographicKey") + + // Invalid CryptographicKey (empty KeyID, invalid KeyType, expired) + invalidKey := model.CryptographicKey{ + KeyID: "", // Invalid empty KeyID + KeyType: "InvalidType", // Invalid KeyType + CreatedAt: time.Now(), + ExpiresAt: time.Now().Add(-time.Hour * 24), // Invalid ExpiresAt (before CreatedAt) + UserID: "invalid-user-id", // Invalid UserID + } + + // Validate the invalid CryptographicKey + err = invalidKey.Validate() + assert.NotNil(t, err, "Expected validation errors for invalid CryptographicKey") + assert.Contains(t, err.Error(), "Field: KeyID, Tag: required") + assert.Contains(t, err.Error(), "Field: KeyType, Tag: oneof") + assert.Contains(t, err.Error(), "Field: ExpiresAt, Tag: gtefield") +} + +// TestCryptographicKeyValidations tests the validation edge cases for CryptographicKey +func TestCryptographicKeyValidations(t *testing.T) { + // Test missing UserID (should fail) + invalidKey := model.CryptographicKey{ + KeyID: uuid.New().String(), // Valid UUID + KeyType: "AES", // Valid KeyType + CreatedAt: time.Now(), + ExpiresAt: time.Now().Add(time.Hour * 24), // Valid ExpiresAt + UserID: "", // Invalid empty UserID + } + + err := invalidKey.Validate() + assert.NotNil(t, err, "Expected validation error for missing UserID") + assert.Contains(t, err.Error(), "Field: UserID, Tag: required") +} From a95497ba2240d0fac7010d15b5d3d69ec042dd12 Mon Sep 17 00:00:00 2001 From: root Date: Mon, 18 Nov 2024 11:21:17 +0000 Subject: [PATCH 13/14] modify validate tag --- internal/domain/model/blob.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/internal/domain/model/blob.go b/internal/domain/model/blob.go index adc0342..123b791 100644 --- a/internal/domain/model/blob.go +++ b/internal/domain/model/blob.go @@ -18,8 +18,8 @@ type Blob struct { BlobType string `validate:"required,min=1,max=50"` // BlobType is required, and its length must be between 1 and 50 characters EncryptionAlgorithm string `validate:"omitempty,oneof=AES RSA ECDSA"` // EncryptionAlgorithm is optional and must be one of the listed algorithms HashAlgorithm string `validate:"omitempty,oneof=SHA256 SHA512 MD5"` // HashAlgorithm is optional and must be one of the listed algorithms - IsEncrypted bool `validate:"required"` // IsEncrypted is required (true/false) - IsSigned bool `validate:"required"` // IsSigned is required (true/false) + IsEncrypted bool `validate:"-"` // IsEncrypted is required (true/false) + IsSigned bool `validate:"-"` // IsSigned is required (true/false) CryptographicKey CryptographicKey `gorm:"foreignKey:KeyID" validate:"required"` // CryptographicKey is required KeyID string `validate:"omitempty,uuid4"` // KeyID is optional and must be a valid UUID } From b41a4d0f4c94f224b3d62f054d0d701cf193ca56 Mon Sep 17 00:00:00 2001 From: root Date: Mon, 18 Nov 2024 11:23:04 +0000 Subject: [PATCH 14/14] modify Blob Validate(...) test --- test/unit/domain/blob_test.go | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/test/unit/domain/blob_test.go b/test/unit/domain/blob_test.go index bc96eff..cc521da 100644 --- a/test/unit/domain/blob_test.go +++ b/test/unit/domain/blob_test.go @@ -23,9 +23,9 @@ func TestBlobValidation(t *testing.T) { EncryptionAlgorithm: "AES", HashAlgorithm: "SHA256", IsEncrypted: true, - IsSigned: false, - CryptographicKey: model.CryptographicKey{KeyID: "abc123", KeyType: "AES", CreatedAt: time.Now(), ExpiresAt: time.Now().Add(24 * time.Hour), UserID: "e2b073b5-3e23-4fbd-b44b-c607b04c9c3e"}, - KeyID: "abc123", + IsSigned: false, // Explicitly set to false + CryptographicKey: model.CryptographicKey{KeyID: uuid.New().String(), KeyType: "AES", CreatedAt: time.Now(), ExpiresAt: time.Now().Add(24 * time.Hour), UserID: uuid.New().String()}, + KeyID: uuid.New().String(), // Use valid UUID here } // Validate the valid Blob @@ -45,8 +45,8 @@ func TestBlobValidation(t *testing.T) { HashAlgorithm: "SHA256", IsEncrypted: true, IsSigned: false, - CryptographicKey: model.CryptographicKey{KeyID: "abc123", KeyType: "AES", CreatedAt: time.Now(), ExpiresAt: time.Now().Add(24 * time.Hour), UserID: "e2b073b5-3e23-4fbd-b44b-c607b04c9c3e"}, - KeyID: "abc123", + CryptographicKey: model.CryptographicKey{KeyID: uuid.New().String(), KeyType: "AES", CreatedAt: time.Now(), ExpiresAt: time.Now().Add(24 * time.Hour), UserID: uuid.New().String()}, + KeyID: uuid.New().String(), // Use valid UUID } // Validate the invalid Blob @@ -72,8 +72,8 @@ func TestBlobValidationEdgeCases(t *testing.T) { HashAlgorithm: "SHA256", IsEncrypted: true, IsSigned: false, - CryptographicKey: model.CryptographicKey{KeyID: "abc123", KeyType: "AES", CreatedAt: time.Now(), ExpiresAt: time.Now().Add(24 * time.Hour), UserID: "e2b073b5-3e23-4fbd-b44b-c607b04c9c3e"}, - KeyID: "abc123", + CryptographicKey: model.CryptographicKey{KeyID: uuid.New().String(), KeyType: "AES", CreatedAt: time.Now(), ExpiresAt: time.Now().Add(24 * time.Hour), UserID: uuid.New().String()}, + KeyID: uuid.New().String(), } err := invalidBlob.Validate()