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" "github.com/gofrs/uuid" d1lib "github.com/cybercryptio/d1-lib" "github.com/cybercryptio/d1-lib/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(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" ) // 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() (string, string, 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 ...string) error
- func (d *D1) AuthorizeIdentity(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[string]struct{}, error)
- func (d *D1) GetTokenContents(token *data.SealedToken) ([]byte, error)
- func (d *D1) RemoveGroupsFromAccess(token string, oid uuid.UUID, groups ...string) 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("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.
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 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 ¶ added in v1.0.18
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 ¶ 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 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 ¶ added in v1.0.18
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 ¶ 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 Identity of the caller is automatically added to the access list. To grant access to other callers, 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 ¶ added in v1.0.18
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 ¶ 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 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 ¶ 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 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. |