eraf

package module
v1.0.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Feb 4, 2022 License: MIT Imports: 11 Imported by: 0

README

ERAF Go SDK

Go Report Card GitHub issues GitHub license Go Reference

This is an SDK to read, edit and create Entity-related Authentication Format files, entity meaning a person, a device, an app, an endpoint or whatever it is you want to authenticate.

There is of course some slight overhead. The data fields, like Certificate or Nonce can all be empty, but there is always space reserved for headers, even if no data has been set yet. This overhead currently amounts to 50 bytes. If this is acceptable for your use case, please give it a try and send feedback if it works out for you.

This is Work in Progress which means the library is still changing but currently mostly stable and version 1 will arrive soon.

Due tests

Tested successfully on
  • windows/amd64
  • linux/amd64
  • darwin/amd64
Not yet tested
  • Tests on other OS/Arch combinations (Issue #4)
  • Integration tests in example applications

Purpose

There are a lot of different ways to authenticate an entity. Using username and password, a bearer token or a certificate are just a few examples. This format is for bundling different authentication information into a single, portable file, easily transmittable over the line, e.g. via HTTP or email. You can for example use the Nonce and Tag fields to save meta data for AES encryption of the data (e.g. the certificate) and decrypt the content at the recipient's device. This is just one example of the many possible use cases.

Installation

Once a stable version is released/tagged, you can download it with go get -u github.com/KaiserWerk/ERAF-Go-SDK@vX.X.X and add the import line eraf "github.com/KaiserWerk/ERAF-Go-SDK to your Go file(s).

If you want the bleeding edge version from the master branch, just drop the @version.

Usage

Creating and Marshalling

First, create a new *eraf.Container and fill it with data. Set calls for setting fields can be chained.

cert, _ := ioutil.ReadFile("localhost.cert")
key, _ := ioutil.ReadFile("localhost.key")
sig := sha256.Sum256(cert)

container := eraf.New()
container.
	SetCertificate(cert).
	SetPrivateKey(key).
	SetSignature(sig[:])

Available fields (that means data blocks) for you to use are as follows:

  • VersionMajor
  • VersionMinor
  • VersionPatch
  • Nonce
  • Tag
  • SerialNumber
  • Identifier
  • Certificate
  • PrivateKey
  • Email
  • Username
  • Password
  • Token
  • Signature
  • RootCertificate

There is a setter and getter method for every field. Setters can be chained.

The maximum size (amount of bytes) you can put into any field is that of an unsigned 16 bit integer, that means 65,535 bytes. Byte slices too large will be truncated.

Now, you can either marshal (serialize) the created ERAF container into an io.Writer, directly into a file or into a byte slice:

// into a buffer
var b bytes.Buffer
err := container.Marshal(&b) // as a reference

// or into an http.ResponseWriter
func handler(w http.ResponseWriter, r *http.Request) {
	// some code here
	err := container.Marshal(w)
}

// or into a file, given the file permissions
err := container.MarshalToFile("somefile.eraf", 0744) // the file extension does not matter, actually


// or just get a []byte
var s []byte = container.MarshalBytes()
Reading and Unmarshalling

You can either read an ERAF container from an io.Reader, directly from a file or from a byte slice:

// from an io.Reader
resp, _ := http.Do(req)
defer resp.Body.Close()
container := &eraf.Container{}
err := eraf.Unmarshal(resp.Body, container)

// or directly from a file
container := &eraf.Container{}
err := eraf.UnmarshalFromFile("somefile.eraf", container) // again, the extension doesn't matter

// or from a []byte
container := &eraf.Container{}
err := eraf.UnmarshalBytes(somebytes, container)

The ERAF container implements the io.Reader interface, so you can (for example) supply it as the body parameter for HTTP requests which will read the whole container into the request body:

container := &eraf.Container{}
// set some fields
req, err := http.NewRequest(http.MethodPost, "https://some-url.com/", container)
Obtaining Information

Get some byte amount information:

// Total length
totalLen := container.Len()

// header length (constant)
headerLen := container.HeaderLen()

// payload length
payloadLen := container.PayloadLen()
Obtaining data

Get the version as a properly constructed Semantic Version string:

versionStr := container.GetSemVer() // e.g. 2.14.8

For every Set method there is an equal Get method you can use to read the field from the container, e.g.

n := container.GetNonce()
// or
u := container.GetUsername()
// etc
// ...

You can get just the headers or just the payload for custom parsing as you need:

// Just the headers
headers := container.Headers()

// Just the payload
payload := container.Payload()
Certificate convenience functions

A basic assumption is that all certificate and private key data set is PEM-encoded. For easier certificate handling, there are a few convenience functions:

c := &eraf.Container{}
// set some fields

// obtain the certificate bytes as *x509.Certificate
x509Cert, err := c.GetX509Certificate()

// or certificate and private key combined as *tls.Certificate
tlsCert, err := c.GetTlsCertificate()

// and the root certificate
rootCert, err := c.GetX509RootCertificate()

Encryption & Decryption

Encryption

For every field, there is a method to encrypt it, e.g. for field Email there is a method b, err := container.EncryptEmail(key) which returns the email encrypted with AES using the given key. A nonce is required and must be set beforehand using the SetNonce(n) method, otherwise an error will be returned. The nonce can be reused for subsequent calls. This method does not alter the container.

If you want to encrypt all fields, use err := container.EncryptEverything(key). This method does alter the container. A new nonce will be generated and set automatically. This method replaces all field values with their respective encrypted values.

Decryption

The decryption processes are the exact inverse of the encryption processes. E.g. use email, err := container.DecryptEmail(key) to just decrypt the email.

Otherwise, use err := container.DecryptEverything(key) to simply decrypt every field in place.

Examples

  1. Simple example with encryption
  2. Extended example with encryption and (un)marshalling
  3. Sending an encrypted ERAF container via HTTP and Receiving an ERAF container via HTTP and decrypt it

Tests

Unit tests

Use go test ./... to run all unit tests. Not everything is covered yet. But everything should pass. :)

Benchmark Tests

Use go test -bench=. to run all benchmark tests. Not everything is covered yet.

goos: windows
goarch: amd64
pkg: github.com/KaiserWerk/ERAF-Go-SDK
cpu: AMD FX(tm)-8320 Eight-Core Processor
BenchmarkUnmarshalFromFile-8       15057             83189 ns/op
BenchmarkUnmarshalBytes-8       26284489                43.90 ns/op
BenchmarkMarshal-8               7802852               158.0 ns/op
BenchmarkMarshalToFile-8          139986              8587 ns/op
PASS
coverage: 78.1% of statements

Documentation

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func Unmarshal

func Unmarshal(r io.Reader, target *Container) error

Unmarshal deserializes a ERAF file from the io.Reader into a *Container

func UnmarshalBytes

func UnmarshalBytes(allBytes []byte, target *Container) error

UnmarshalBytes takes a []byte and a pointer to a target container and deserializes the []byte into the container, e.g.:

var b []byte // some data source
var c *eraf.Container = eraf.New()
err := eraf.Unmarshal(b, c)

func UnmarshalFromFile

func UnmarshalFromFile(file string, target *Container) error

UnmarshalFromFile deserializes a ERAF from the given file

Types

type Container

type Container struct {
	// contains filtered or unexported fields
}

Container is the central struct to work with

func New

func New() *Container

New creates a new *Container. Just convenience, not necessary.

func (*Container) DecryptCertificate

func (c *Container) DecryptCertificate(nonce []byte, key []byte) ([]byte, error)

DecryptCertificate decrypts and returns the certificate

func (*Container) DecryptEmail

func (c *Container) DecryptEmail(nonce []byte, key []byte) ([]byte, error)

DecryptEmail decrypts and returns the email address

func (*Container) DecryptEverything

func (c *Container) DecryptEverything(nonce []byte, key []byte) error

DecryptEverything is the obvious counterpart to EncryptEverything. It performs the decryption in place, using either AES-128, AES-192 or AES-256, depending on key length.

func (*Container) DecryptIdentifier

func (c *Container) DecryptIdentifier(nonce []byte, key []byte) ([]byte, error)

DecryptIdentifier decrypts and returns the identifier

func (*Container) DecryptPrivateKey

func (c *Container) DecryptPrivateKey(nonce []byte, key []byte) ([]byte, error)

DecryptPrivateKey decrypts and returns the private key

func (*Container) DecryptRootCertificate

func (c *Container) DecryptRootCertificate(nonce []byte, key []byte) ([]byte, error)

DecryptRootCertificate decrypts and returns the root certificate

func (*Container) DecryptSerialNumber

func (c *Container) DecryptSerialNumber(nonce []byte, key []byte) ([]byte, error)

DecryptSerialNumber decrypts and returns the serial number

func (*Container) DecryptSignature

func (c *Container) DecryptSignature(nonce []byte, key []byte) ([]byte, error)

DecryptSignature decrypts and returns the signature

func (*Container) DecryptToken

func (c *Container) DecryptToken(nonce []byte, key []byte) ([]byte, error)

DecryptToken decrypts and returns the token

func (*Container) DecryptUsername

func (c *Container) DecryptUsername(nonce []byte, key []byte) ([]byte, error)

DecryptUsername decrypts and returns the username

func (*Container) Dump

func (c *Container) Dump(w io.Writer)

Dump just writes all field contents into an io.Writer

func (*Container) EncryptCertificate

func (c *Container) EncryptCertificate(nonce []byte, key []byte) ([]byte, error)

EncryptCertificate encrypts and returns the certificate

func (*Container) EncryptEmail

func (c *Container) EncryptEmail(nonce []byte, key []byte) ([]byte, error)

EncryptEmail encrypts and returns the email address

func (*Container) EncryptEverything

func (c *Container) EncryptEverything(nonce []byte, key []byte) error

EncryptEverything take a nonce and a key to encrypt every data block using AES in place. All blocks will be encrypted and written back, no data is returned. Requires a key with a length of 16 bytes (AES-128), 24 bytes (AES-192) or 32 bytes (AES-256). The nonce requires a length of 12 bytes. You can use SetRandomNonce() to generate a cryptographically secure nonce.

func (*Container) EncryptIdentifier

func (c *Container) EncryptIdentifier(nonce []byte, key []byte) ([]byte, error)

EncryptIdentifier encrypts and returns the identifier

func (*Container) EncryptPrivateKey

func (c *Container) EncryptPrivateKey(nonce []byte, key []byte) ([]byte, error)

EncryptPrivateKey encrypts and returns the private key

func (*Container) EncryptRootCertificate

func (c *Container) EncryptRootCertificate(nonce []byte, key []byte) ([]byte, error)

EncryptRootCertificate encrypts and returns the signature

func (*Container) EncryptSerialNumber

func (c *Container) EncryptSerialNumber(nonce []byte, key []byte) ([]byte, error)

EncryptSerialNumber encrypts and returns the serial number

func (*Container) EncryptSignature

func (c *Container) EncryptSignature(nonce []byte, key []byte) ([]byte, error)

EncryptSignature encrypts and returns the signature

func (*Container) EncryptToken

func (c *Container) EncryptToken(nonce []byte, key []byte) ([]byte, error)

EncryptToken encrypts and returns the token

func (*Container) EncryptUsername

func (c *Container) EncryptUsername(nonce []byte, key []byte) ([]byte, error)

EncryptUsername encrypts and returns the username

func (*Container) GetCertificate

func (c *Container) GetCertificate() []byte

GetCertificate returns the certificate

func (*Container) GetEmail

func (c *Container) GetEmail() []byte

GetEmail returns the email address

func (*Container) GetIdentifier

func (c *Container) GetIdentifier() []byte

GetIdentifier returns the identifier

func (*Container) GetNonce

func (c *Container) GetNonce() []byte

GetNonce returns the nonce

func (*Container) GetPassword

func (c *Container) GetPassword() []byte

GetPassword returns the password

func (*Container) GetPrivateKey

func (c *Container) GetPrivateKey() []byte

GetPrivateKey returns the private key

func (*Container) GetRootCertificate

func (c *Container) GetRootCertificate() []byte

GetRootCertificate returns the root certificate

func (*Container) GetSemVer

func (c *Container) GetSemVer() string

GetSemVer returns the combination of all version elements as a semantic version string

func (*Container) GetSerialNumber

func (c *Container) GetSerialNumber() []byte

GetSerialNumber returns the serial number

func (*Container) GetSignature

func (c *Container) GetSignature() []byte

GetSignature returns the signature

func (*Container) GetTag

func (c *Container) GetTag() []byte

GetTag returns the tag

func (*Container) GetTlsCertificate

func (c *Container) GetTlsCertificate() (*tls.Certificate, error)

GetTlsCertificate returns the certificate as *tls.Certificate

func (*Container) GetToken

func (c *Container) GetToken() []byte

GetToken returns the token

func (*Container) GetUsername

func (c *Container) GetUsername() []byte

GetUsername returns the username

func (*Container) GetVersionMajor

func (c *Container) GetVersionMajor() byte

GetVersionMajor returns the major version

func (*Container) GetVersionMinor

func (c *Container) GetVersionMinor() byte

GetVersionMinor returns the minor version

func (*Container) GetVersionPatch

func (c *Container) GetVersionPatch() byte

GetVersionPatch returns the patch version

func (*Container) GetX509Certificate

func (c *Container) GetX509Certificate() (*x509.Certificate, error)

GetX509Certificate returns the certificate as *x509.Certificate

func (*Container) GetX509RootCertificate

func (c *Container) GetX509RootCertificate() (*x509.Certificate, error)

GetX509RootCertificate returns the root certificate as *x509.Certificate

func (*Container) HeaderLen

func (c *Container) HeaderLen() int

HeaderLen returns the amount of bytes the header consists of

func (*Container) Headers

func (c *Container) Headers() [headerSize]byte

Headers returns just the header array of the ERAF file

func (*Container) Len

func (c *Container) Len() int

Len returns the total amount of bytes of the file

func (*Container) Marshal

func (c *Container) Marshal(w io.Writer) error

Marshal serializes the ERAF file into the given io.Writer

func (*Container) MarshalBytes

func (c *Container) MarshalBytes() []byte

MarshalBytes serializes the container into a []byte

func (*Container) MarshalToFile

func (c *Container) MarshalToFile(file string, perms os.FileMode) error

MarshalToFile serializes the ERAF file into the given file using the given file permissions

func (*Container) Payload

func (c *Container) Payload() []byte

Payload returns just the payload part of the ERAF file

func (*Container) PayloadLen

func (c *Container) PayloadLen() int

PayloadLen returns the amount of bytes the payload takes up

func (*Container) Read

func (c *Container) Read(s []byte) (int, error)

Read reads all bytes into s and returns the number of bytes read as well as an error

func (*Container) SetCertificate

func (c *Container) SetCertificate(cert []byte) *Container

SetCertificate sets a certificate. For the convenience functions to work properly, the certificate expected to be in PEM format

func (*Container) SetEmail

func (c *Container) SetEmail(e []byte) *Container

SetEmail sets an email address

func (*Container) SetIdentifier

func (c *Container) SetIdentifier(id []byte) *Container

SetIdentifier sets an identifier

func (*Container) SetNonce

func (c *Container) SetNonce(n []byte) *Container

SetNonce sets a nonce

func (*Container) SetPassword

func (c *Container) SetPassword(p []byte) *Container

SetPassword sets a password

func (*Container) SetPrivateKey

func (c *Container) SetPrivateKey(pk []byte) *Container

SetPrivateKey sets a private key. For the convenience functions to work properly, the key is expected to be in PEM format

func (*Container) SetRandomNonce

func (c *Container) SetRandomNonce() error

SetRandomNonce generates a 12-byte nonce (mainly for use with AES) and stores it into the nonce field

func (*Container) SetRootCertificate

func (c *Container) SetRootCertificate(rc []byte) *Container

SetRootCertificate sets a root certificate

func (*Container) SetSerialNumber

func (c *Container) SetSerialNumber(sn []byte) *Container

SetSerialNumber sets a serial number

func (*Container) SetSignature

func (c *Container) SetSignature(sig []byte) *Container

SetSignature sets a signature

func (*Container) SetTag

func (c *Container) SetTag(t []byte) *Container

SetTag sets a tag

func (*Container) SetToken

func (c *Container) SetToken(t []byte) *Container

SetToken sets a token

func (*Container) SetUsername

func (c *Container) SetUsername(u []byte) *Container

SetUsername sets a username

func (*Container) SetVersionMajor

func (c *Container) SetVersionMajor(v byte) *Container

SetVersionMajor sets the major version

func (*Container) SetVersionMinor

func (c *Container) SetVersionMinor(v byte) *Container

SetVersionMinor sets the minor version

func (*Container) SetVersionPatch

func (c *Container) SetVersionPatch(v byte) *Container

SetVersionPatch sets the patch version

Directories

Path Synopsis
examples

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL