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 ( "fmt" "log" d1lib "github.com/cybercryptio/d1-lib" "github.com/cybercryptio/d1-lib/data" "github.com/gofrs/uuid" ) // 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 uuid.UUID gid uuid.UUID oid uuid.UUID } // createUserData instantiates a user with its private and public data. func createUserData(d1 d1lib.D1) UserData { uid, gid, token := NewUser() privateUserObject := data.Object{ Plaintext: []byte("Plaintext"), AssociatedData: []byte("AssociatedData"), } oid, err := d1.Encrypt(token, &privateUserObject) if err != nil { log.Fatalf("Error encrypting object: %v", err) } err = d1.AddGroupsToAccess(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() { // Instantiate the D1 library with the given keys. d1, err := d1lib.New(&keyProvider, &ioProvider, &idProvider) if err != nil { log.Fatalf("Error instantiating D1: %v", err) } // Create three users with their data. alice := createUserData(d1) bob := createUserData(d1) charlie := createUserData(d1) // charlie wants to share her data with bob. err = d1.AddGroupsToAccess(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(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(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(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 ( "fmt" "log" d1lib "github.com/cybercryptio/d1-lib" "github.com/cybercryptio/d1-lib/data" "github.com/cybercryptio/d1-lib/id" "github.com/cybercryptio/d1-lib/io" "github.com/cybercryptio/d1-lib/key" "github.com/gofrs/uuid" ) // 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() (uuid.UUID, uuid.UUID, string) { uid, password, err := (&idProvider).NewUser(id.ScopeAll) if err != nil { log.Fatalf("Error creating user: %v", err) } token, _, err := (&idProvider).LoginUser(uid, password) if err != nil { log.Fatalf("Error logging in user: %v", err) } gid, err := idProvider.NewGroup(token, id.ScopeAll) if err != nil { log.Fatalf("Error creating group: %v", err) } err = idProvider.AddUserToGroups(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() { // Instantiate the D1 library with the given keys. d1, err := d1lib.New(&keyProvider, &ioProvider, &idProvider) if err != nil { log.Fatalf("Error instantiating D1: %v", err) } // Create a basic user. _, _, token := NewUser() // 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(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(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
Index ¶
- Variables
- type D1
- func (d *D1) AddGroupsToAccess(token string, oid uuid.UUID, groups ...uuid.UUID) error
- func (d *D1) AuthorizeUser(token string, oid uuid.UUID) error
- func (d *D1) CreateToken(plaintext []byte) (data.SealedToken, error)
- func (d *D1) Decrypt(token string, oid uuid.UUID) (data.Object, error)
- func (d *D1) Delete(token string, oid uuid.UUID) error
- func (d *D1) Encrypt(token string, object *data.Object) (uuid.UUID, error)
- func (d *D1) GetAccessGroups(token string, oid uuid.UUID) (map[uuid.UUID]struct{}, error)
- func (d *D1) GetTokenContents(token *data.SealedToken) ([]byte, error)
- func (d *D1) RemoveGroupsFromAccess(token string, oid uuid.UUID, groups ...uuid.UUID) error
- func (d *D1) Update(token string, oid uuid.UUID, object *data.Object) error
Examples ¶
Constants ¶
This section is empty.
Variables ¶
var ErrNotAuthenticated = errors.New("user not authenticated")
Error returned if the caller cannot be authenticated by the Identity Provider.
var ErrNotAuthorized = errors.New("user not authorized")
Error returned if a user tries to access data they are not authorized for.
Functions ¶
This section is empty.
Types ¶
type D1 ¶ added in v1.0.18
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 (*D1) AddGroupsToAccess ¶ added in v1.0.18
AddGroupsToAccess appends the provided groups to the object's access list, giving them access to the associated object. The authorizing user must be part of the access list.
The input ID is the identifier obtained by previously calling Encrypt.
Required scopes: - ModifyAccessGroups
func (*D1) AuthorizeUser ¶
AuthorizeUser checks whether the provided user 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 user is not authorized.
The input ID is the identifier obtained by previously calling Encrypt.
Required scopes: - GetAccessGroups
func (*D1) CreateToken ¶ added in v1.0.18
func (d *D1) CreateToken(plaintext []byte) (data.SealedToken, error)
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.
Example ¶
// Instantiate the D1 library with the given keys. d1, err := d1lib.New(&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([]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(&token) if err != nil { log.Fatalf("Invalid token: %v", err) } fmt.Printf("%s", tokenContents)
Output: token contents
func (*D1) Decrypt ¶ added in v1.0.18
Decrypt fetches a sealed object and extracts the plaintext. The authorizing user 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 ¶ added in v1.0.18
Delete deletes a sealed object. The authorizing user 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 ¶ added in v1.0.18
Encrypt creates a new sealed object containing the provided plaintext data as well as an access list that controls access to that data. The calling user is automatically added to the access list. To grant other users access, see AddGroupsToAccess and AddUserToGroups.
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 ¶ added in v1.0.18
GetAccessGroups extracts the set of group IDs contained in the object's access list. The authorizing user 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 groups/users have access to the associated object.
Required scopes: - GetAccessGroups
func (*D1) GetTokenContents ¶ added in v1.0.18
func (d *D1) GetTokenContents(token *data.SealedToken) ([]byte, error)
GetTokenContents extracts the plaintext data from a sealed token, provided that the token has not expired.
func (*D1) RemoveGroupsFromAccess ¶ added in v1.0.18
RemoveGroupsFromAccess removes the provided groups from the object's access list, preventing them from accessing the associated object. The authorizing user must be part of the access object.
The input ID is the identifier obtained by previously calling Encrypt.
Required scopes: - ModifyAccessGroups
func (*D1) Update ¶ added in v1.0.18
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 user 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. |