Commit 96cf6388 authored by ale's avatar ale

Update dependencies

parent 9f34b8e2
......@@ -15,7 +15,8 @@ import (
"golang.org/x/crypto/scrypt"
)
// PasswordHash is a convenience interface common to all types in this package.
// PasswordHash is the interface for a password hashing algorithm
// implementation.
type PasswordHash interface {
// ComparePassword returns true if the given password matches
// the encrypted one.
......@@ -25,12 +26,20 @@ type PasswordHash interface {
Encrypt(string) string
}
// SystemCryptPasswordHash uses the glibc crypt function.
type SystemCryptPasswordHash struct{}
// systemCryptPasswordHash uses the glibc crypt function.
type systemCryptPasswordHash struct {
hashStr string
}
// NewSystemCrypt returns a PasswordHash that uses the system crypt(3)
// function, specifically glibc with its SHA512 algorithm.
func NewSystemCrypt() PasswordHash {
return &systemCryptPasswordHash{"$6$"}
}
// ComparePassword returns true if the given password matches the
// encrypted one.
func (s *SystemCryptPasswordHash) ComparePassword(encrypted, password string) bool {
func (s *systemCryptPasswordHash) ComparePassword(encrypted, password string) bool {
enc2, err := crypt.Crypt(password, encrypted)
if err != nil {
return false
......@@ -39,8 +48,8 @@ func (s *SystemCryptPasswordHash) ComparePassword(encrypted, password string) bo
}
// Encrypt the given password using glibc crypt.
func (s *SystemCryptPasswordHash) Encrypt(password string) string {
salt := fmt.Sprintf("$6$%x$", getRandomBytes(16))
func (s *systemCryptPasswordHash) Encrypt(password string) string {
salt := fmt.Sprintf("%s%x$", s.hashStr, getRandomBytes(16))
enc, err := crypt.Crypt(password, salt)
if err != nil {
panic(err)
......@@ -54,28 +63,48 @@ var (
)
// Argon2PasswordHash uses the Argon2 hashing algorithm.
type Argon2PasswordHash struct{}
type argon2PasswordHash struct {
// Encoding parameters.
params argon2Params
}
// NewArgon2 returns an Argon2i-based PasswordHash using the default parameters.
func NewArgon2() PasswordHash {
return NewArgon2WithParams(
defaultArgon2Params.Time,
defaultArgon2Params.Memory,
defaultArgon2Params.Threads,
)
}
// NewArgon2WithParams returns an Argon2i-based PasswordHash using the
// specified parameters for time, memory, and number of threads.
func NewArgon2WithParams(time, mem uint32, threads uint8) PasswordHash {
return &argon2PasswordHash{
params: argon2Params{
Time: time,
Memory: mem,
Threads: threads,
},
}
}
// ComparePassword returns true if the given password matches the
// encrypted one.
func (s *Argon2PasswordHash) ComparePassword(encrypted, password string) bool {
func (s *argon2PasswordHash) ComparePassword(encrypted, password string) bool {
params, salt, dk, err := decodeArgon2Hash(encrypted)
if err != nil {
return false
}
dk2 := argon2.Key([]byte(password), salt, params.Time, params.Memory, params.Threads, argonKeyLen)
//log.Printf("params=%+v, salt=%+v, dk=%v, dk2=%v", params, salt, dk, dk2)
return subtle.ConstantTimeCompare(dk, dk2) == 1
}
// Encrypt the given password with the Argon2 algorithm.
func (s *Argon2PasswordHash) Encrypt(password string) string {
func (s *argon2PasswordHash) Encrypt(password string) string {
salt := getRandomBytes(argonSaltLen)
params := defaultArgon2Params
dk := argon2.Key([]byte(password), salt, params.Time, params.Memory, params.Threads, argonKeyLen)
return encodeArgon2Hash(params, salt, dk)
dk := argon2.Key([]byte(password), salt, s.params.Time, s.params.Memory, s.params.Threads, argonKeyLen)
return encodeArgon2Hash(s.params, salt, dk)
}
type argon2Params struct {
......@@ -84,13 +113,12 @@ type argon2Params struct {
Threads uint8
}
// Default Argon2 parameters are tuned for a high-traffic
// authentication service (<1ms per operation).
var defaultArgon2Params = argon2Params{
Time: 4,
Memory: 32 * 1024,
Threads: 1,
// Test fails with threads > 1 !!
//Threads: uint8(runtime.NumCPU()),
Time: 1,
Memory: 4 * 1024,
Threads: 4,
}
func encodeArgon2Hash(params argon2Params, salt, dk []byte) string {
......@@ -139,11 +167,35 @@ var (
)
// ScryptPasswordHash uses the scrypt hashing algorithm.
type ScryptPasswordHash struct{}
type scryptPasswordHash struct {
params scryptParams
}
// NewScrypt returns a PasswordHash that uses the scrypt algorithm
// with the default parameters.
func NewScrypt() PasswordHash {
return NewScryptWithParams(
defaultScryptParams.N,
defaultScryptParams.R,
defaultScryptParams.P,
)
}
// NewScryptWithParams returns a PasswordHash that uses the scrypt
// algorithm with the specified parameters.
func NewScryptWithParams(n, r, p int) PasswordHash {
return &scryptPasswordHash{
params: scryptParams{
N: n,
R: r,
P: p,
},
}
}
// ComparePassword returns true if the given password matches
// the encrypted one.
func (s *ScryptPasswordHash) ComparePassword(encrypted, password string) bool {
func (s *scryptPasswordHash) ComparePassword(encrypted, password string) bool {
params, salt, dk, err := decodeScryptHash(encrypted)
if err != nil {
return false
......@@ -152,21 +204,19 @@ func (s *ScryptPasswordHash) ComparePassword(encrypted, password string) bool {
if err != nil {
return false
}
//log.Printf("params=%+v, salt=%+v, dk=%v, dk2=%v", params, salt, dk, dk2)
return subtle.ConstantTimeCompare(dk, dk2) == 1
}
// Encrypt the given password with the scrypt algorithm.
func (s *ScryptPasswordHash) Encrypt(password string) string {
func (s *scryptPasswordHash) Encrypt(password string) string {
salt := getRandomBytes(scryptSaltLen)
params := defaultScryptParams
dk, err := scrypt.Key([]byte(password), salt, params.N, params.R, params.P, scryptKeyLen)
dk, err := scrypt.Key([]byte(password), salt, s.params.N, s.params.R, s.params.P, scryptKeyLen)
if err != nil {
panic(err)
}
return encodeScryptHash(params, salt, dk)
return encodeScryptHash(s.params, salt, dk)
}
type scryptParams struct {
......@@ -224,12 +274,13 @@ func getRandomBytes(n int) []byte {
return b
}
// A registry of default handlers for decoding passwords.
var prefixRegistry = map[string]PasswordHash{
"$1$": &SystemCryptPasswordHash{},
"$5$": &SystemCryptPasswordHash{},
"$6$": &SystemCryptPasswordHash{},
"$s$": &ScryptPasswordHash{},
"$a2$": &Argon2PasswordHash{},
"$1$": NewSystemCrypt(),
"$5$": NewSystemCrypt(),
"$6$": NewSystemCrypt(),
"$s$": NewScrypt(),
"$a2$": NewArgon2(),
}
// ComparePassword returns true if the given password matches the
......@@ -245,7 +296,11 @@ func ComparePassword(encrypted, password string) bool {
// DefaultEncryptAlgorithm is used by the Encrypt function to encrypt
// passwords.
var DefaultEncryptAlgorithm PasswordHash = &Argon2PasswordHash{}
var DefaultEncryptAlgorithm PasswordHash
func init() {
DefaultEncryptAlgorithm = NewArgon2()
}
// Encrypt will encrypt a password with the default algorithm.
func Encrypt(password string) string {
......
......@@ -13,6 +13,7 @@ import (
"syscall"
"time"
"github.com/coreos/go-systemd/daemon"
"github.com/prometheus/client_golang/prometheus"
"github.com/prometheus/client_golang/prometheus/promhttp"
)
......@@ -82,7 +83,8 @@ func Serve(h http.Handler, config *ServerConfig, addr string) error {
return err
}
// Create the net.Listener, then notify systemd that we are ready to serve.
// Create the net.Listener first, so we can detect
// initialization-time errors safely.
l, err := net.Listen("tcp", addr)
if err != nil {
return err
......@@ -113,6 +115,9 @@ func Serve(h http.Handler, config *ServerConfig, addr string) error {
signal.Notify(sigCh, syscall.SIGINT, syscall.SIGTERM)
// Notify systemd that we are ready to serve.
daemon.SdNotify(false, "READY=1")
err = srv.Serve(l)
if err != http.ErrServerClosed {
return err
......
package userenckey
import (
"bytes"
"crypto/rand"
"errors"
"io"
"github.com/lunixbochs/struc"
"github.com/miscreant/miscreant/go"
"golang.org/x/crypto/argon2"
)
// Current algorithm: Argon2 KDF + AES-SIV key encryption.
const algoArgon2AESSIV = 1
const aeadAlgo = "AES-SIV"
// Struct members have stupid names to reduce the size of the resulting gob!
type argon2Params struct {
Time uint32 `struc:"uint32,little"`
Memory uint32 `struc:"uint32,little"`
Threads uint8 `struc:"uint8"`
}
// Default Argon2 parameters are tuned for a high-traffic
// authentication service (<1ms per operation).
var defaultArgon2Params = argon2Params{
Time: 1,
Memory: 4 * 1024,
Threads: 4,
}
const (
keyLen = 64
saltLen = 32
)
func argon2KDF(params argon2Params, salt, pw []byte) []byte {
return argon2.Key(pw, salt, params.Time, params.Memory, params.Threads, keyLen)
}
// An encrypted container stores an opaque blob of binary data along
// with metadata about the encryption itself, to allow for a
// controlled amount of algorithm malleability accounting for future
// updates. The structure is binary-packed (as opposed to using higher
// level serializations such as encoding/gob) because we'd like to be
// able to read it from other languages if necessary.
type container struct { // nolint: maligned
Algo uint8 `struc:"uint8"`
Params argon2Params
SaltLen uint8 `struc:"uint8,sizeof=Salt"`
Salt []byte
DataLen uint16 `struc:"uint16,little,sizeof=Data"`
Data []byte
}
// Convert to an opaque encoded ("wire") representation.
func (c *container) Marshal() ([]byte, error) {
var buf bytes.Buffer
err := struc.Pack(&buf, c)
if err != nil {
return nil, err
}
return buf.Bytes(), nil
}
// Parse a key object from the wire representation.
func unmarshalContainer(b []byte) (c container, err error) {
err = struc.Unpack(bytes.NewReader(b), &c)
return
}
func newContainer(data, pw []byte) (container, error) {
return encryptArgon2AESSIV(data, pw)
}
func (c container) decrypt(pw []byte) ([]byte, error) {
// Only one supported kdf/algo combination right now.
if c.Algo == algoArgon2AESSIV {
return c.decryptArgon2AESSIV(pw)
}
return nil, errors.New("unsupported algo")
}
func (c container) decryptArgon2AESSIV(pw []byte) ([]byte, error) {
// Run the KDF and create the AEAD cipher.
dk := argon2KDF(c.Params, c.Salt, pw)
cipher, err := miscreant.NewAEAD(aeadAlgo, dk, 0)
if err != nil {
return nil, err
}
// Decrypt the data and obtain the DER-encoded private key.
dec, err := cipher.Open(nil, nil, c.Data, nil)
return dec, err
}
func encryptArgon2AESSIV(data, pw []byte) (container, error) {
c := container{
Algo: algoArgon2AESSIV,
Params: defaultArgon2Params,
Salt: genRandomSalt(),
}
// Run the KDF and create the AEAD cipher.
dk := argon2KDF(c.Params, c.Salt, pw)
cipher, err := miscreant.NewAEAD(aeadAlgo, dk, 0)
if err != nil {
return container{}, err
}
// Encrypt the data (a DER-encoded ECDSA private key).
c.Data = cipher.Seal(nil, nil, data, nil)
return c, nil
}
func genRandomSalt() []byte {
var b [saltLen]byte
if _, err := io.ReadFull(rand.Reader, b[:]); err != nil {
panic(err)
}
return b[:]
}
package userenckey
import (
"crypto/ecdsa"
"crypto/elliptic"
"crypto/rand"
"crypto/x509"
"encoding/pem"
"errors"
)
// ErrBadPassword is returned on decryption failure.
var ErrBadPassword = errors.New("could not decrypt key with password")
func encodePublicKeyToPEM(pub *ecdsa.PublicKey) ([]byte, error) {
der, err := x509.MarshalPKIXPublicKey(pub)
if err != nil {
return nil, err
}
return pem.EncodeToMemory(&pem.Block{Type: "PUBLIC KEY", Bytes: der}), nil
}
// Key (unencrypted).
type Key struct {
rawBytes []byte
}
// GenerateKey generates a new ECDSA key pair, and returns the
// PEM-encoded public and private key (in order).
func GenerateKey() ([]byte, *Key, error) {
priv, err := ecdsa.GenerateKey(elliptic.P224(), rand.Reader)
if err != nil {
return nil, nil, err
}
//privBytes, err := encodePrivateKeyToPEM(priv)
privBytes, err := x509.MarshalECPrivateKey(priv)
if err != nil {
return nil, nil, err
}
pubBytes, err := encodePublicKeyToPEM(&priv.PublicKey)
if err != nil {
return nil, nil, err
}
return pubBytes, &Key{privBytes}, nil
}
// PEM returns the key in PEM-encoded format.
func (k *Key) PEM() ([]byte, error) {
// Parse the ASN.1 data and encode it with PKCS8 (in PEM format).
priv, err := k.PrivateKey()
if err != nil {
return nil, err
}
return encodePrivateKeyToPEM(priv)
}
// PrivateKey parses the DER-encoded ASN.1 data in Key and returns the
// private key object.
func (k *Key) PrivateKey() (*ecdsa.PrivateKey, error) {
return x509.ParseECPrivateKey(k.rawBytes)
}
// Encrypt a key with a password and a random salt.
func Encrypt(key *Key, pw []byte) ([]byte, error) {
c, err := newContainer(key.rawBytes, pw)
if err != nil {
return nil, err
}
return c.Marshal()
}
// Decrypt one out of multiple keys with the specified password. The
// keys share the same cleartext, but have been encrypted with
// different passwords.
func Decrypt(encKeys [][]byte, pw []byte) (*Key, error) {
for _, encKey := range encKeys {
c, err := unmarshalContainer(encKey)
if err != nil {
//log.Printf("parse error: %v", err)
continue
}
if dec, err := c.decrypt(pw); err == nil {
return &Key{dec}, nil
}
}
return nil, ErrBadPassword
}
// +build go1.10
package userenckey
import (
"crypto/ecdsa"
"crypto/x509"
"encoding/pem"
)
// Encode a private key to PEM-encoded PKCS8.
func encodePrivateKeyToPEM(priv *ecdsa.PrivateKey) ([]byte, error) {
der, err := x509.MarshalPKCS8PrivateKey(priv)
if err != nil {
return nil, err
}
return pem.EncodeToMemory(&pem.Block{Type: "PRIVATE KEY", Bytes: der}), nil
}
// +build !go1.10
package userenckey
import (
"bytes"
"crypto/ecdsa"
"crypto/x509"
"encoding/pem"
"os/exec"
)
// Encode a private key to PEM-encoded PKCS8.
//
// In Go versions prior to 1.10, we must shell out to openssl to
// convert the private key to PKCS8 format.
func encodePrivateKeyToPEM(priv *ecdsa.PrivateKey) ([]byte, error) {
der, err := x509.MarshalECPrivateKey(priv)
if err != nil {
return nil, err
}
pkcs1 := pem.EncodeToMemory(&pem.Block{Type: "EC PRIVATE KEY", Bytes: der})
/* #nosec */
cmd := exec.Command("/usr/bin/openssl", "pkey")
cmd.Stdin = bytes.NewReader(pkcs1)
return cmd.Output()
}
[![Join the chat at https://gitter.im/golang-barcode/Lobby](https://badges.gitter.im/golang-barcode/Lobby.svg)](https://gitter.im/golang-barcode/Lobby?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
## Introduction ##
This is a package for GO which can be used to create different types of barcodes.
## Supported Barcode Types ##
......
Copyright (c) 2015 Ryan Hileman
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
[![Build Status](https://travis-ci.org/lunixbochs/struc.svg?branch=master)](https://travis-ci.org/lunixbochs/struc)
struc
====
Struc exists to pack and unpack C-style structures from bytes, which is useful for binary files and network protocols. It could be considered an alternative to `encoding/binary`, which requires massive boilerplate for some similar operations.
Take a look at an [example comparing `struc` and `encoding/binary`](https://bochs.info/p/cxvm9)
Struc considers usability first. That said, it does cache reflection data and aims to be competitive with `encoding/binary` struct packing in every way, including performance.
Example struct
----
```Go
type Example struct {
Var int `struc:"int32,sizeof=Str"`
Str string
Weird []byte `struc:"[8]int64"`
Var []int `struc:"[]int32,little"`
}
```
Struct tag format
----
- ```Var []int `struc:"[]int32,little,sizeof=StringField"` ``` will pack Var as a slice of little-endian int32, and link it as the size of `StringField`.
- `sizeof=`: Indicates this field is a number used to track the length of a another field. `sizeof` fields are automatically updated on `Pack()` based on the current length of the tracked field, and are used to size the target field during `Unpack()`.
- Bare values will be parsed as type and endianness.
Endian formats
----
- `big` (default)
- `little`
Recognized types
----
- `pad` - this type ignores field contents and is backed by a `[length]byte` containing nulls
- `bool`
- `byte`
- `int8`, `uint8`
- `int16`, `uint16`
- `int32`, `uint32`
- `int64`, `uint64`
- `float32`
- `float64`
Types can be indicated as arrays/slices using `[]` syntax. Example: `[]int64`, `[8]int32`.
Bare slice types (those with no `[size]`) must have a linked `Sizeof` field.
Private fields are ignored when packing and unpacking.
Example code
----
```Go
package main
import (
"bytes"
"github.com/lunixbochs/struc"
)
type Example struct {
A int `struc:"big"`
// B will be encoded/decoded as a 16-bit int (a "short")
// but is stored as a native int in the struct
B int `struc:"int16"`
// the sizeof key links a buffer's size to any int field
Size int `struc:"int8,little,sizeof=Str"`
Str string
// you can get freaky if you want
Str2 string `struc:"[5]int64"`
}
func main() {
var buf bytes.Buffer
t := &Example{1, 2, 0, "test", "test2"}
err := struc.Pack(&buf, t)
o := &Example{}
err = struc.Unpack(&buf, o)
}
```
Benchmark
----
`BenchmarkEncode` uses struc. `Stdlib` benchmarks use equivalent `encoding/binary` code. `Manual` encodes without any reflection, and should be considered an upper bound on performance (which generated code based on struc definitions should be able to achieve).
```
BenchmarkEncode 1000000 1265 ns/op
BenchmarkStdlibEncode 1000000 1855 ns/op
BenchmarkManualEncode 5000000 284 ns/op
BenchmarkDecode 1000000 1259 ns/op
BenchmarkStdlibDecode 1000000 1656 ns/op
BenchmarkManualDecode 20000000 89.0 ns/op
```
package struc
import (
"encoding/binary"
"io"
"reflect"
)
type byteWriter struct {
buf []byte
pos int
}
func (b byteWriter) Write(p []byte) (int, error) {
capacity := len(b.buf) - b.pos
if capacity < len(p) {
p = p[:capacity]
}
if len(p) > 0 {
copy(b.buf[b.pos:], p)
b.pos += len(p)
}
return len(p), nil
}
type binaryFallback reflect.Value
func (b binaryFallback) String() string {
return b.String()
}
func (b binaryFallback) Sizeof(val reflect.Value, options *Options) int {
return binary.Size(val.Interface())
}
func (b binaryFallback) Pack(buf []byte, val reflect.Value, options *Options) (int, error) {
tmp := byteWriter{buf: buf}
var order binary.ByteOrder = binary.BigEndian
if options.Order != nil {
order = options.Order
}
err := binary.Write(tmp, order, val.Interface())
return tmp.pos, err
}
func (b binaryFallback) Unpack(r io.Reader, val reflect.Value, options *Options) error {
var order binary.ByteOrder = binary.BigEndian
if options.Order != nil {
order = options.Order
}
return binary.Read(r, order, val.Interface())
}