gormcrypto

package module
v1.0.3 Latest Latest
Warning

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

Go to latest
Published: Oct 1, 2021 License: Apache-2.0 Imports: 7 Imported by: 0

README

gorm-crypto

Encrypts any value of JSON compatible type

Installation

To install gorm-crypto you need to, as usual, run this command:

go get github.com/pkosilo/gorm-crypto

How to use it?

Initialize

First of all you need to initialize the library before migrating models. To do so, you need to decide which algorithm you want to use. (By the way, it's possible to select serializer/deserialize, so in the future you will be able to customize your flow even more).

RSA

If you want to use RSA, then you need to generate or load key pair and initialize library with algorithm.RSA with your private and public keys. To do so, you can simply run code like this (you can also use different public and private key files) in your app:

var privateKey *rsa.PrivateKey
var publicKey *rsa.PublicKey

// Different behaviour if there is already a PEM with private key or not
if _, err := os.Stat("private_key.pem"); os.IsNotExist(err) {
  // There is no PEM
  
  // Generate key pair
  privateKey, publicKey, err = helpers.RSAGenerateKeyPair(4096)

  if err != nil {
    panic(err)
  }

  // Store it
  privateKeyBytes := helpers.RSAPrivateKeyToBytes(privateKey)
  err := ioutil.WriteFile("private_key.pem", privateKeyBytes, 0644)

  if err != nil {
    panic(err)
  }
} else {
  // There is a PEM
  
  // Read PEM file with private key
  bytes, err := ioutil.ReadFile("private_key.pem")
  if err != nil {
    panic(err)
  }

  // Bytes to private key
  privateKey, err = helpers.RSABytesToPrivateKey(bytes)
  if err != nil {
    panic(err)
  }
  publicKey = &privateKey.PublicKey
}

// Use privateKey and publicKey to initialize gormcrypto
gormcrypto.Init(algorithms.NewRSA(privateKey, publicKey), serialization.NewJSON())
AES256GCM

To use this library with AES256GCM, you need to initialize it with algorithm.AES256GCM with your key passed. There is an example how to initialize library with AES256GCM:

aes, err := algorithms.NewAES256GCM([]byte("passphrasewhichneedstobe32bytes!"))
// algorithms.NewAES can fall with an error, so you should handle it
if err != nil {
  panic(err)
}
gorm.Init(aes, serialization.NewJSON())
AES256CBC

To use this library with AES256CBC, you need to initialize it with algorithm.AES256CBC with your key passed. There is an example how to initialize library with AES256CBC:

aes, err := algorithms.NewAES256CBC([]byte("passphrasewhichneedstobe32bytes!"))
// algorithms.NewAES can fall with an error, so you should handle it
if err != nil {
  panic(err)
}
gorm.Init(aes, serialization.NewJSON())
Fallbacks

Sometimes you may need to change your algorithm or rotate the keys, the library lets you do so. You just need to initialize the library with InitWithFallbacks:

// The fallback algorithm
rsa := algorithms.NewRSA(privateKey, publicKey)

// The main algorithm
aes, err := algorithms.NewAES([]byte("passphrasewhichneedstobe32bytes!"))
if err != nil {
  panic(err)
}
gormcrypto.InitWithFallbacks([]algorithms.Algorithm{aes, rsa}, []serialization.Serializer{serialization.NewJSON()})

The first algorithm/serializer in the array is the main algorithm, others are the fallback algorithms.

Use it in a model

There is an example of a model with EncryptedValue:

type Application struct {
  gorm.Model
  Name               string                      `json:"name"`
  Phone              string                      `json:"phone"`
  Email              string                      `json:"email"`
  Address            gormcrypto.EncryptedValue  `json:"address"`
}

Create a record with it

There is an example of DB.Create with a model with EncryptedValue:

application := Application {
  Name: "Anonymous",
  Phone: "+375290000000",
  Email: "example@example.com",
  Address: gormcrypto.EncryptedValue{Raw: "Oktyabr'skaya Ploshchad' 1, Minsk 220030"},
}

if err = models.DB.Create(&model).Error; err != nil {
  panic(err)
}

Read a record with it

There is an example of finding a value using DB.Find and using EncryptedValue.Raw to access the decrypted value:

var application Application

if err := db.Find(&application, 1).Error; err != nil {
  panic(err)
}

fmt.Printf("Decrypted (raw) address: %s", application.Address.Raw.(string))

Signing capabilties

To initialize library for signing with SignedValue you should call InitSigning function like this:

gormcrypto.InitSigning([]signing.SignatureAlgorithm{signing.NewECDSA(privateKey, publicKey)}, []serialization.Serializer{serialization.NewJSON()})

Then you can use SignedValue in you structs.

Signing algorithms
ECDSA

Example:

// Generate key pair
privateKey, publicKey, _ := helpers.ECDSAGenerateKeyPair()
algo := NewECDSA(privateKey, publicKey)
Ed25519

Example:

// Generate key pair
privateKey, publicKey, _ := helpers.Ed25519GenerateKeyPair()
algo := NewEd25519(&privateKey, &publicKey)
SignedValue
How to sign?

There is an example of usage of SignedValue:

application := Application {
  Name: "Anonymous",
  Phone: "+375290000000",
  Email: "example@example.com",
  Address: gormcrypto.SignedValue{Raw: "Oktyabr'skaya Ploshchad' 1, Minsk 220030"},
}

if err = models.DB.Create(&model).Error; err != nil {
  panic(err)
}
How to access data and verify integrity?

You can access data by using Raw field:

var application Application

if err := db.Find(&application, 1).Error; err != nil {
  panic(err)
}

fmt.Printf("Raw address: %s", application.Address.Raw.(string))

And you can verify integrity by accessing Valid field:

valid := application.Address.Valid // true if is valid, false if is not

Remember: if you change Raw field, then the Valid field won't be affected, so after changing Raw field you cannot trust Valid field.

Intented use case

SignedValue is not intended to be used for multiple reads and writes. It is intended to be used to save information to the database with signature and then read it after sometime.

Documentation

Index

Constants

This section is empty.

Variables

View Source
var Algorithms []algorithms.Algorithm
View Source
var SignatureAlgorithms []signing.SignatureAlgorithm
View Source
var SignatureSerializers []serialization.Serializer

Functions

func Init added in v1.0.1

func Init(algorithm algorithms.Algorithm, serializer serialization.Serializer)

Init initializes library with specified algorithm

func InitSigning added in v1.0.1

func InitSigning(algorithms []signing.SignatureAlgorithm, serializers []serialization.Serializer)

InitSigning initializes library's signing capabilities

func InitWithFallbacks added in v1.0.1

func InitWithFallbacks(algorithms []algorithms.Algorithm, serializers []serialization.Serializer)

InitWithFallbacks initializes library with fallback methods

Types

type EncryptedValue

type EncryptedValue struct {
	Raw interface{} `json:"Raw"`
}

func (*EncryptedValue) Scan

func (j *EncryptedValue) Scan(value interface{}) error

Scan decrypts and deserializes value from DB, implements sql.Scanner interface

func (EncryptedValue) Value

func (j EncryptedValue) Value() (driver.Value, error)

Value returns serialized and encrypted value, implement driver.Valuer interface

type SignedValue added in v1.0.1

type SignedValue struct {
	Raw   interface{} `json:"Raw"`
	Valid bool        `json:"Valid"`
}

func (*SignedValue) Scan added in v1.0.1

func (j *SignedValue) Scan(value interface{}) error

Scan deserializes and verifies value from DB, implements sql.Scanner interface

func (SignedValue) Value added in v1.0.1

func (j SignedValue) Value() (driver.Value, error)

Value returns serialized value with signature, implement driver.Valuer interface

Directories

Path Synopsis

Jump to

Keyboard shortcuts

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