Documentation
¶
Overview ¶
D1 is a library that provides easy access to data encryption with built in access control.
Example (AccessControl) ¶
This example demonstrates how to use the D1 library to enforce discretionary access control for binary data.
package main import ( "context" "fmt" "log" "github.com/gofrs/uuid" d1lib "github.com/cybercryptio/d1-lib/v2" "github.com/cybercryptio/d1-lib/v2/data" ) // The UserData struct models the data of a user. It contains both private data that should be kept confidential and public data that can be shared // with other users, being protected cryptographically. type UserData struct { private PrivateUserData public PublicUserData } type PrivateUserData struct { token string data data.Object } type PublicUserData struct { uid string gid string oid uuid.UUID } // createUserData instantiates a user with its private and public data. func createUserData(ctx context.Context, d1 d1lib.D1) UserData { uid, gid, token := NewUser(ctx) privateUserObject := data.Object{ Plaintext: []byte("Plaintext"), AssociatedData: []byte("AssociatedData"), } oid, err := d1.Encrypt(ctx, token, &privateUserObject) if err != nil { log.Fatalf("Error encrypting object: %v", err) } err = d1.AddGroupsToAccess(ctx, token, oid, gid) if err != nil { log.Fatalf("Error adding group to access list: %v", err) } return UserData{ PrivateUserData{token, privateUserObject}, PublicUserData{uid, gid, oid}, } } // This example demonstrates how to use the D1 library to enforce discretionary access control for binary data. func main() { ctx := context.Background() // Instantiate the D1 library with the given keys. d1, err := d1lib.New(ctx, &keyProvider, &ioProvider, &idProvider) if err != nil { log.Fatalf("Error instantiating D1: %v", err) } // Create three users with their data. alice := createUserData(ctx, d1) bob := createUserData(ctx, d1) charlie := createUserData(ctx, d1) // charlie wants to share her data with bob. err = d1.AddGroupsToAccess(ctx, charlie.private.token, charlie.public.oid, bob.public.uid) if err != nil { log.Fatalf("Error adding group to access: %v", err) } // bob can now decrypt charlie's encrypted data. charliesDecryptedData, err := d1.Decrypt(ctx, bob.private.token, charlie.public.oid) if err != nil { log.Fatalf("Error decrypting object: %v", err) } fmt.Printf("%s %s\n", charliesDecryptedData.Plaintext, charliesDecryptedData.AssociatedData) // alice wants to form a group with charlie so that all of his previously encrypted data can be decrypted by charlie. err = idProvider.AddUserToGroups(ctx, alice.private.token, charlie.public.uid, alice.public.gid) if err != nil { log.Fatalf("Error adding user to group: %v", err) } // charlie can now decrypt all of alice's previously encrypted data. alicesDecryptedData, err := d1.Decrypt(ctx, charlie.private.token, alice.public.oid) if err != nil { log.Fatalf("Error decrypting object: %v", err) } fmt.Printf("%s %s\n", alicesDecryptedData.Plaintext, alicesDecryptedData.AssociatedData) }
Output: Plaintext AssociatedData Plaintext AssociatedData
Example (BasicEncryptDecrypt) ¶
This is a basic example demonstrating how to use the D1 library to encrypt and decrypt binary data.
package main import ( "context" "fmt" "log" d1lib "github.com/cybercryptio/d1-lib/v2" "github.com/cybercryptio/d1-lib/v2/data" "github.com/cybercryptio/d1-lib/v2/id" "github.com/cybercryptio/d1-lib/v2/io" "github.com/cybercryptio/d1-lib/v2/key" ) // These are insecure keys used only for demonstration purposes. var keyProvider = key.NewStatic(key.Keys{ KEK: []byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, AEK: []byte{1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, TEK: []byte{2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2}, IEK: []byte{3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3}, }) // Store encrypted data in memory. var ioProvider = io.NewMem() var idProvider, _ = id.NewStandalone( id.StandaloneConfig{ UEK: []byte{4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4}, GEK: []byte{5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5}, TEK: []byte{6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6}, }, &ioProvider, ) func NewUser(ctx context.Context) (string, string, string) { uid, password, err := (&idProvider).NewUser(ctx, id.ScopeAll) if err != nil { log.Fatalf("Error creating user: %v", err) } token, _, err := (&idProvider).LoginUser(ctx, uid, password) if err != nil { log.Fatalf("Error logging in user: %v", err) } gid, err := idProvider.NewGroup(ctx, token, id.ScopeAll) if err != nil { log.Fatalf("Error creating group: %v", err) } err = idProvider.AddUserToGroups(ctx, token, uid, gid) if err != nil { log.Fatalf("Error adding user to group: %v", err) } return uid, gid, token } // This is a basic example demonstrating how to use the D1 library to encrypt and decrypt binary data. func main() { ctx := context.Background() // Instantiate the D1 library with the given keys. d1, err := d1lib.New(ctx, &keyProvider, &ioProvider, &idProvider) if err != nil { log.Fatalf("Error instantiating D1: %v", err) } // Create a basic user. _, _, token := NewUser(ctx) // A simple binary object with associated data. binaryObject := data.Object{ Plaintext: []byte("Plaintext"), AssociatedData: []byte("AssociatedData"), } // Encrypt the object and get the resulting object ID. By default, only the default group of the // user who encrypted the object is allowed to decrypt the object. oid, err := d1.Encrypt(ctx, token, &binaryObject) if err != nil { log.Fatalf("Error encrypting object: %v", err) } // Decrypt the object using the given user as the authorizer. decryptedObject, err := d1.Decrypt(ctx, token, oid) if err != nil { log.Fatalf("Error decrypting object: %v", err) } fmt.Printf("Decrypted object plaintext: %s\nDecrypted object associated data: %s\n", decryptedObject.Plaintext, decryptedObject.AssociatedData) }
Output: Decrypted object plaintext: Plaintext Decrypted object associated data: AssociatedData
Example (CreateToken) ¶
ctx := context.Background() // Instantiate the D1 library with the given keys. d1, err := d1lib.New(ctx, &keyProvider, &ioProvider, &idProvider) if err != nil { log.Fatalf("Error instantiating D1: %v", err) } // Create a token with encrypted contents and default expiry time. token, err := d1.CreateToken(ctx, []byte("token contents")) if err != nil { log.Fatalf("Error creating token: %v", err) } // Validate the token and fetch its decrypted contents. This call will fail if the token has expired or has been tampered with. tokenContents, err := d1.GetTokenContents(ctx, &token) if err != nil { log.Fatalf("Invalid token: %v", err) } fmt.Printf("%s", tokenContents)
Output: token contents
Index ¶
- Variables
- type D1
- func (d *D1) AddGroupsToAccess(ctx context.Context, token string, oid uuid.UUID, groups ...string) error
- func (d *D1) AuthorizeIdentity(ctx context.Context, token string, oid uuid.UUID) error
- func (d *D1) CreateToken(ctx context.Context, plaintext []byte) (data.SealedToken, error)
- func (d *D1) Decrypt(ctx context.Context, token string, oid uuid.UUID) (data.Object, error)
- func (d *D1) Delete(ctx context.Context, token string, oid uuid.UUID) error
- func (d *D1) Encrypt(ctx context.Context, token string, object *data.Object, groups ...string) (uuid.UUID, error)
- func (d *D1) GetAccessGroups(ctx context.Context, token string, oid uuid.UUID) (map[string]struct{}, error)
- func (d *D1) GetTokenContents(ctx context.Context, token *data.SealedToken) ([]byte, error)
- func (d *D1) RemoveGroupsFromAccess(ctx context.Context, token string, oid uuid.UUID, groups ...string) error
- func (d *D1) Update(ctx context.Context, token string, oid uuid.UUID, object *data.Object) error
Examples ¶
Constants ¶
This section is empty.
Variables ¶
var ErrAccessAlreadyExists = errors.New("access already exists")
Error returned if an access list already exists in the IO Provider.
var ErrAccessNotFound = errors.New("access not found")
Error returned if an access list was not found in the IO Provider.
var ErrNotAuthenticated = errors.New("not authenticated")
Error returned if the caller cannot be authenticated by the Identity Provider.
var ErrNotAuthorized = errors.New("not authorized")
Error returned if the caller tries to access data they are not authorized for.
var ErrObjectAlreadyExists = errors.New("object already exists")
Error returned if an object already exists in the IO Provider.
var ErrObjectNotFound = errors.New("object not found")
Error returned if an object was not found in the IO Provider.
Functions ¶
This section is empty.
Types ¶
type D1 ¶
type D1 struct {
// contains filtered or unexported fields
}
D1 is the entry point to the library. All main functionality is exposed through methods on this struct.
func New ¶
func New(ctx context.Context, keyProvider key.Provider, ioProvider io.Provider, idProvider id.Provider) (D1, error)
New creates a new instance of D1 configured with the given providers.
func (*D1) AddGroupsToAccess ¶
func (d *D1) AddGroupsToAccess(ctx context.Context, token string, oid uuid.UUID, groups ...string) error
AddGroupsToAccess appends the provided groups to the object's access list, giving them access to the associated object. The authorizing Identity must be part of the access list.
The input ID is the identifier obtained by previously calling Encrypt.
Required scopes: - ModifyAccessGroups
func (*D1) AuthorizeIdentity ¶
AuthorizeIdentity checks whether the provided Identity is part of the object's access list, i.e. whether they are authorized to access the associated object. An error is returned if the Identity is not authorized.
The input ID is the identifier obtained by previously calling Encrypt.
Required scopes: - GetAccessGroups
func (*D1) CreateToken ¶
CreateToken encapsulates the provided plaintext data in an opaque, self contained token with an expiry time given by TokenValidity.
The contents of the token can be validated and retrieved with the GetTokenContents method.
func (*D1) Decrypt ¶
Decrypt fetches a sealed object and extracts the plaintext. The authorizing Identity must be part of the provided access list, either directly or through group membership.
The input ID is the identifier obtained by previously calling Encrypt.
The unsealed object may contain sensitive data.
Required scopes: - Decrypt
func (*D1) Delete ¶
Delete deletes a sealed object. The authorizing Identity must be part of the provided access list, either directly or through group membership.
The input ID is the identifier obtained by previously calling Encrypt.
Required scopes: - Delete
func (*D1) Encrypt ¶
func (d *D1) Encrypt(ctx context.Context, token string, object *data.Object, groups ...string) (uuid.UUID, error)
Encrypt creates a new sealed object containing the provided plaintext data as well as an access list that controls access to that data. The Identity of the caller is automatically added to the access list. To grant access to other callers either specify them in the optional 'groups' argument or see AddGroupsToAccess.
The returned ID is the unique identifier of the sealed object. It is used to identify the object and related data about the object to the IO Provider, and needs to be provided when decrypting the object.
For all practical purposes, the size of the ciphertext in the SealedObject is len(plaintext) + 48 bytes.
Required scopes: - Encrypt
func (*D1) GetAccessGroups ¶
func (d *D1) GetAccessGroups(ctx context.Context, token string, oid uuid.UUID) (map[string]struct{}, error)
GetAccessGroups extracts the set of group IDs contained in the object's access list. The authorizing Identity must be part of the access list.
The input ID is the identifier obtained by previously calling Encrypt.
The set of group IDs is somewhat sensitive data, as it reveals what Identities have access to the associated object.
Required scopes: - GetAccessGroups
func (*D1) GetTokenContents ¶
GetTokenContents extracts the plaintext data from a sealed token, provided that the token has not expired.
func (*D1) RemoveGroupsFromAccess ¶
func (d *D1) RemoveGroupsFromAccess(ctx context.Context, token string, oid uuid.UUID, groups ...string) error
RemoveGroupsFromAccess removes the provided groups from the object's access list, preventing them from accessing the associated object. The authorizing Identity must be part of the access object.
The input ID is the identifier obtained by previously calling Encrypt.
Required scopes: - ModifyAccessGroups
func (*D1) Update ¶
Update creates a new sealed object containing the provided plaintext data but uses a previously created access list to control access to that data. The authorizing Identity must be part of the provided access list, either directly or through group membership.
The input ID is the identifier obtained by previously calling Encrypt.
Required scopes: - Update
Directories
¶
Path | Synopsis |
---|---|
Package io contains the definition of the IO Provider, as well as various implementations of the concept.
|
Package io contains the definition of the IO Provider, as well as various implementations of the concept. |
Package key contains the definition of the Key Provider, as well as various implementations of the concept.
|
Package key contains the definition of the Key Provider, as well as various implementations of the concept. |