qrsecrets

package module
v1.2.0 Latest Latest
Warning

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

Go to latest
Published: Jun 16, 2022 License: GPL-3.0 Imports: 15 Imported by: 0

README

QR Secrets

The Argon2 & Elliptic Curve AES encryption scheme

QR secrets is a cryptographically secure mechanism to store secret data with the highest levels of security. Incorporating; AES256-GCM-HKDF-ARGON2 and ECIES-AES256-GCM-HKDF-SHA256. Rated for a 256 bit security level and requiring two keys, one private Elliptic Curve key and one passphrase known as the Master Key. You only require the master key to encrypt and the public key of Elliptic Curve key. This allows you, if needed, to encrypt on one machine and only decrypt on your hardened secure environment, protecting your other stored secrets from being viewed if one key were to be compromised.

The whole point of this project is to store secrets in encrypted QR codes. This project allows you to securely generate QR codes for sensitive data such as;

  • Cryptocurrency Seeds
  • Password manager master passwords
  • TOTP secrets
  • Banking information
  • Paper key backups
  • Login credentials
  • Secure notes
  • Or anything you want to keep safe & private

QR secrets allows you to not only export to QR codes but also to files to be stored on Disk or Tape.

Security Guarantees

  1. 256 bit security using AES256 + Symmetric key + Salt locked behind PKI with a 521bit Elliptic curve (256 bit security key)
  2. Computationally impossible to brute force.
  3. Quantum resistance, no known quantum attacks brings 256bit security low enough into a realm where it could be cracked.
  4. Even if one key was to be compromised the data would still be secure.
  5. Different keys for each "file" encrypted.
  6. Hide true plaintext length with padding.
  7. Configuration data hidden.
  8. Tamper proof, if any bit was to be modified (other than version num & the magic number) the data would not be able to decrypt (AHEAD Cipher).

Cryptography & Format Breakdown

The data is stored in a byte format, with 3 distinct sections within whats called a Container.

  1. The MetaData section holds the version of the protocol/format, the curve ID and the hash ID which are both used for decrypting the Encrypted Parameters section. And of course it starts with a 16bit magic number to detect the file format of QRsecrets

  2. The Encrypted Parameters section. This holds the salt/nonce which is used in the Argon2 KDF. This section also holds the Argon2 parameters and padding size. This section is encrypted using ECIES to the public key.

  3. The CipherText section is self explanatory it is the section which holds the encrypted data + padding. It uses AES256-GCM-HKDF-ARGON2 with the Master key and the Salt from the Encrypted Parameters section. You can only decrypt this section if you have decrypted the one above.

Curves

QR secrets supports the following curves:

  • nist-p224
  • nist-p256
  • nist-p384
  • nist-p521
  • Brainpool P160t1
  • Brainpool P192r1
  • Brainpool P192t1
  • Brainpool P224r1
  • Brainpool P224t1
  • Brainpool P256r1
  • Brainpool P256t1
  • Brainpool P320r1
  • Brainpool P320t1
  • Brainpool P384r1
  • Brainpool P384t1
  • Brainpool P512r1
  • Brainpool P512t1

Cryptographic Hash Functions

For the Metadata section the following hash functions are available. All of these functions are ran through HKDF to derive a encryption key.

  • SHA256
  • SHA512
  • SHA3-256
  • SHA3-512

KDF Used for main Encryption

This is used to encrypt your secret and thus needs to be the most secure.

  • HKDF-Argon2

KDFs

QRsecrets doesn't allow the modification of the KDF on the Ciphertext section, but rather allows the KDF parameters to be modified. Using Argon2 and HKDF the key is derived.

Package

This repo is both a command line tool and a package you can include into your Go applications.

Install package

go get -u github.com/go-compile/qrsecrets
package main

import (
    "fmt"
    "log"

    "github.com/go-compile/rome/brainpool"
    "github.com/go-compile/qrsecrets"
)

func main() {
	msg := []byte("My secret message.")
	key := "password123SECURE"

	priv, err := brainpool.GenerateP512t1()
	if err != nil {
		t.Fatal(err)
	}

	pub := priv.Public()

	// === ENCRYPT
	container, err := qrsecrets.NewContainer(pub.Name(), qrsecrets.HashSHA256, msg, 10)
	if err != nil {
		t.Fatal(err)
	}

	data, err := container.Marshal(pub, []byte(key))
	if err != nil {
		t.Fatal(err)
	}

	// === DECRYPT
	container, err = qrsecrets.DecodeContainer(bytes.NewBuffer(data), priv, []byte(key))
	if err != nil {
		t.Fatal(err)
	}

	fmt.Println(string(container.CipherText.Plaintext))
}

Screenshots

example
Print the QR code to the terminal, never touches the disk
example
Export QR code directly to a file; png or jpg

Download

Compatible with all major operating systems and more. Even compatible with a raspberry pi.

  • Windows
  • Mac
  • Linux
  • FreeBSD
  • OpenBSD
  • x86
  • Arm
  • Arm64

Download the latest from releases page. You can run via the command line or we recommend adding it to your path.

CLI Usage

Encrypt data

# Basic encrypt with default settings
qrsecrets encrypt ecdsa-P521.pem

# Specify security settings
qrsecrets -preset=high encrypt ecdsa-P521.pem

# Render QR code as PNG
qrsecrets encrypt ecdsa-P521.pem -output=img.png
qrsecrets encrypt ecdsa-P521.pem -output=img.jpg

# Save in binary format instead of using a QR code (required for bigger content)
qrsecrets encrypt ecdsa-P521.pem -output=data.bin

# Encrypt file contents
qrsecrets encrypt ecdsa-P521.pem -file=seed.txt

# Base64 encode output (useful for using external QR scanning/decoding apps)
qrsecrets encrypt ecdsa-P521.pem -base64

# Mixture of different example arguments
qrsecrets -preset=high -hash=sha3_512 encrypt ecdsa-P521.pem -file=seed.txt -output=qr.png

# The masterkey can even be passed in via the CLI, although this is insecure as it will be stored in your bash history
qrsecrets encrypt ecdsa-P521.pem -masterkey="password123"

Decrypt

# Decode QR code and decrypt
qrsecrets decrypt ecdsa-P521.pem image.png

# Decode and decrypt file
qrsecrets decrypt ecdsa-P521.pem secret.bin

# Decode and decrypt base64 encoded container
qrsecrets decrypt ecdsa-P521.pem image.png -base64

# The masterkey can be passed in via the CLI, although this is insecure as it will be stored in your bash history
qrsecrets decrypt ecdsa-P521.pem image.png - masterkey="password123"

Generate private key

qrsecrets generatekey

# You can specify the curve by using presets or specify the curve via the -curve= arg.
qrsecrets -curve=p256 generatekey
qrsecrets -preset=high generatekey

# You can encrypt your private key with a passphrase by using the -encrypt=true argument.

qrsecrets -preset=high generatekey -encrypt=true

# You can also specify a file to save the key to
qrsecrets generatekey -output=private.pem

Help

qrsecrets -help

Build from source

# Clone repo
git clone github.com/go-compile/qrsecrets
# CD into command folder for the CLI
cd qrsecrets/cmd/qrsecrets

# Go build
go build -ldflags="-s -w" -trimpath

Documentation

Index

Constants

View Source
const ProtocolVersion uint8 = 2

ProtocolVersion specifies the default version of the protocol

Variables

View Source
var (
	// MagicNumber is prepended to the container to identify its format
	MagicNumber = []byte{95, 219, 76}

	// ErrSaltInvalid is returned when a salt is the wrong length
	ErrSaltInvalid = errors.New("invalid salt must be 32 bytes long")
	// ErrCurveSupport is returned when a curve is not supported for ECIES
	ErrCurveSupport = errors.New("curve is not supported")
	// ErrCurveMissmatch is returned if you have a different container curve ID to the public key's curve ID
	ErrCurveMissmatch = errors.New("curve of public key does not match curve of container")
	// ErrHashUnsupported is returned when trying to obtain a HKDF with a hash which isn't supported
	ErrHashUnsupported = errors.New("hash is unsupported")
)
View Source
var (
	// ErrNotContainer is returned if the content trying to be decoded is not
	// a container
	ErrNotContainer = errors.New("stream is not a container")
	// ErrProtocolVersionSupport is returned if the version of the protocol
	// in the container is not a supported version and can not be decoded
	ErrProtocolVersionSupport = errors.New("protocol version is not supported")
	// ErrCipherTextShort is returned when ciphertext is too short to be valid
	ErrCipherTextShort = errors.New("ciphertext is too short to be valid")
)

Functions

func HashIDToFunc added in v1.2.0

func HashIDToFunc(hash HashID) func() hash.Hash

HashIDToFunc takes a HashID and returns a hash.Hash

Types

type Container

type Container struct {

	// Curve specifies which curve to use for the ECIES on the metadata section
	Curve CurveID
	// HashID is used with HKDF on the metadata section
	HashID HashID

	MetaData   *SectionMetaData
	CipherText *SectionCipherText
	// contains filtered or unexported fields
}

Container is used to hold the metadata and ciphertext section together and communicate some configuration and protocol version information to the decoder

func DecodeContainer

func DecodeContainer(r io.Reader, priv rome.PrivateKey, masterKey []byte) (*Container, error)

DecodeContainer will decode a container and decrypt it

func NewContainer

func NewContainer(curve string, hash HashID, plaintext []byte, padding int32) (*Container, error)

NewContainer will create a new container to store the secret content

func UnmarshalContainer

func UnmarshalContainer(container []byte, priv rome.PrivateKey, masterKey []byte) (*Container, error)

UnmarshalContainer will decode the provided bytes into a container

func (*Container) Encode

func (c *Container) Encode(w io.Writer, pub rome.PublicKey, masterKey []byte) error

Encode takes a public key to encrypt the metadata section

func (*Container) Marshal

func (c *Container) Marshal(pub rome.PublicKey, masterKey []byte) (data []byte, err error)

Marshal encodes the container and returns it in bytes

type CurveID

type CurveID uint8

CurveID represents a Elliptic or Edwards curve

const (
	// CurveP224 is a nist curve
	CurveP224 CurveID = 1 + iota
	// CurveP256 is a nist curve
	CurveP256
	// CurveP384 is a nist curve
	CurveP384
	// CurveP521 is a nist curve
	CurveP521

	// Brain pool curves
	CurveP160t1
	CurveP192r1
	CurveP192t1
	CurveP224r1
	CurveP224t1
	CurveP256r1
	CurveP256t1
	CurveP320r1
	CurveP320t1
	CurveP384r1
	CurveP384t1
	CurveP512r1
	CurveP512t1
)

func CurveToID

func CurveToID(name string) CurveID

CurveToID converts a curve name to a CurveID

type HashID

type HashID uint8

HashID represents a hashing algorithm

const (
	// HashSHA256 is SHA256
	HashSHA256 HashID = iota
	// HashSHA512 is SHA512
	HashSHA512
	// HashSHA3_256 is SHA3-256
	HashSHA3_256
	// HashSHA3_512 is SHA3-512
	HashSHA3_512
)

func (HashID) String

func (i HashID) String() string

type SectionCipherText

type SectionCipherText struct {
	Plaintext []byte
	Padding   []byte
}

SectionCipherText is used to store the secret content

func (*SectionCipherText) Encode

func (c *SectionCipherText) Encode(w io.Writer, m *SectionMetaData, masterKey []byte) error

Encode encrypts and marshales the plaintext

type SectionMetaData

type SectionMetaData struct {
	// Salt is 32 bytes long
	Salt             []byte
	ArgonMemory      uint32
	ArgonIterations  uint32
	ArgonParallelism uint8
	ArgonKeyLen      uint32
	PaddingSize      uint32
}

SectionMetaData is used to store configuration data on how to decrypt the ciphertext section

func (*SectionMetaData) Encode

func (c *SectionMetaData) Encode(w io.Writer, container *Container, pub rome.PublicKey) error

Encode will write the metadata and encrypt it with ECIES

Directories

Path Synopsis
cmd

Jump to

Keyboard shortcuts

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