bcrypt and null kdf done, work on ciphers next (then keytypes)
This commit is contained in:
11
kdf/bcrypt/consts.go
Normal file
11
kdf/bcrypt/consts.go
Normal file
@@ -0,0 +1,11 @@
|
||||
package bcrypt
|
||||
|
||||
const (
|
||||
Name string = "bcrypt"
|
||||
// DefaultRounds is the default per OpenSSH, not per the bcrypt_pbkdf spec itself. It is recommended to use e.g. 100 rounds.
|
||||
DefaultRounds uint32 = 16
|
||||
// DefaultSaltLen is the default per OpenSSH, not per the bcrypt_pbkdf spec itself.
|
||||
DefaultSaltLen int = 16
|
||||
// DefaultKeyLen is suitable for AES256-CTR but may not be for others. TODO: revisit this and find something more flexible?
|
||||
DefaultKeyLen uint32 = 48
|
||||
)
|
||||
246
kdf/bcrypt/funcs.go
Normal file
246
kdf/bcrypt/funcs.go
Normal file
@@ -0,0 +1,246 @@
|
||||
package bcrypt
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"crypto/rand"
|
||||
"encoding/binary"
|
||||
|
||||
"github.com/dchest/bcrypt_pbkdf"
|
||||
"r00t2.io/sshkeys/internal"
|
||||
`r00t2.io/sshkeys/kdf/errs`
|
||||
)
|
||||
|
||||
/*
|
||||
Setup must be called before DeriveKey. It configures a .
|
||||
|
||||
If secret is nil or an empty byte slice, ErrNoSecret will be returned.
|
||||
|
||||
If salt is nil or an empty byte slice, one will be randomly generated of DefaultSaltLen length.
|
||||
|
||||
If rounds is 0, DefaultRounds will be used.
|
||||
|
||||
If keyLen is 0, DefaultKeyLen will be used.
|
||||
*/
|
||||
func (k *KDF) Setup(secret, salt []byte, rounds, keyLen uint32) (err error) {
|
||||
|
||||
if secret == nil || len(secret) == 0 {
|
||||
err = errs.ErrNoSecret
|
||||
return
|
||||
}
|
||||
|
||||
if salt == nil || len(salt) == 0 {
|
||||
salt = make([]byte, DefaultSaltLen)
|
||||
if _, err = rand.Read(salt); err != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
if rounds == 0 {
|
||||
rounds = DefaultRounds
|
||||
}
|
||||
|
||||
if keyLen == 0 {
|
||||
keyLen = DefaultKeyLen
|
||||
}
|
||||
|
||||
k.secret = secret
|
||||
k.salt = salt
|
||||
k.rounds = rounds
|
||||
k.keyLen = keyLen
|
||||
k.hasSalt = true
|
||||
k.hasRounds = true
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
/*
|
||||
SetupAuto is used to provide out-of-band configuration if the KDF options were found via kdf.UnpackKDF.
|
||||
|
||||
You can test this by running KDF.AutoOK.
|
||||
*/
|
||||
func (k *KDF) SetupAuto(secret []byte, keyLen uint32) (err error) {
|
||||
|
||||
if !k.AutoOK() {
|
||||
err = errs.ErrUnknownKdf
|
||||
return
|
||||
}
|
||||
|
||||
if keyLen == 0 {
|
||||
keyLen = DefaultKeyLen
|
||||
}
|
||||
|
||||
k.secret = secret
|
||||
k.keyLen = keyLen
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
/*
|
||||
DeriveKey returns the derived key from a configured bcrypt.KDF.
|
||||
|
||||
It must be called *after* Setup.
|
||||
*/
|
||||
func (k *KDF) DeriveKey() (key []byte, err error) {
|
||||
|
||||
if k.secret == nil {
|
||||
err = errs.ErrNoSecret
|
||||
return
|
||||
}
|
||||
if k.salt == nil {
|
||||
err = errs.ErrNoSalt
|
||||
return
|
||||
}
|
||||
if k.rounds == 0 {
|
||||
err = errs.ErrNoRounds
|
||||
return
|
||||
}
|
||||
if k.keyLen == 0 {
|
||||
err = errs.ErrNoKeyLen
|
||||
}
|
||||
|
||||
if k.key, err = bcrypt_pbkdf.Key(k.secret, k.salt, int(k.rounds), int(k.keyLen)); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
key = k.key
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// Name returns bcrypt.Name.
|
||||
func (k *KDF) Name() (name string) {
|
||||
|
||||
name = Name
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// NameBytes returns the byte form of bcrypt.Name with leading bytecount allocator.
|
||||
func (k *KDF) NameBytes() (name []byte) {
|
||||
|
||||
var nb []byte
|
||||
var s = k.Name()
|
||||
|
||||
nb = []byte(s)
|
||||
|
||||
name = make([]byte, 4)
|
||||
binary.BigEndian.PutUint32(name, uint32(len(nb)))
|
||||
name = append(name, nb...)
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// PackedBytes returns block 3.0 and recursed.
|
||||
func (k *KDF) PackedBytes() (buf *bytes.Reader, err error) {
|
||||
|
||||
var rounds = make([]byte, 4)
|
||||
var packer *bytes.Reader
|
||||
var w = new(bytes.Buffer)
|
||||
|
||||
// block 3.0.0.0 and block 3.0.0.0.0
|
||||
if packer, err = internal.ReadSizeBytes(k.salt, true); err != nil {
|
||||
return
|
||||
}
|
||||
if _, err = packer.WriteTo(w); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
// block 3.0.0.1
|
||||
binary.BigEndian.PutUint32(rounds, k.rounds)
|
||||
if _, err = w.Write(rounds); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
// block 3.0
|
||||
if buf, err = internal.ReadSizeBytes(w, true); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// Rounds returns the number of rounds used in derivation.
|
||||
func (k *KDF) Rounds() (rounds uint32) {
|
||||
|
||||
rounds = k.rounds
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// Salt returns the salt bytes.
|
||||
func (k *KDF) Salt() (salt []byte) {
|
||||
|
||||
salt = k.salt
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
/*
|
||||
AutoOK returns true if a kdf.UnpackKDF call was able to fetch the bcrypt.KDF options successfully, in which case the caller may use bcrypt.KDF.SetupAuto.
|
||||
|
||||
If false, it will need to be manually configured via bcrypt.KDF.Setup.
|
||||
*/
|
||||
func (k *KDF) AutoOK() (ok bool) {
|
||||
|
||||
ok = true
|
||||
|
||||
if k.salt == nil || len(k.salt) == 0 {
|
||||
ok = false
|
||||
}
|
||||
|
||||
if k.rounds == 0 {
|
||||
ok = false
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// IsPlain indicates if this kdf.KDF actually does derivation (false) or not (true).
|
||||
func (k *KDF) IsPlain() (plain bool) {
|
||||
|
||||
plain = false
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
/*
|
||||
AddSalt adds a salt as parsed from kdf.UnpackKDF.
|
||||
|
||||
If a salt has already been set, a no-op will be performed.
|
||||
If you want to use a different salt, you will need to create a new bcrypt.KDF.
|
||||
*/
|
||||
func (k *KDF) AddSalt(salt []byte) (err error) {
|
||||
|
||||
if salt == nil || len(salt) == 0 {
|
||||
err = errs.ErrNoSalt
|
||||
return
|
||||
}
|
||||
if k.hasSalt {
|
||||
return
|
||||
}
|
||||
k.salt = salt
|
||||
k.hasSalt = true
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
/*
|
||||
AddRounds adds the rounds as parsed from kdf.UnpackKDF.
|
||||
|
||||
If the number of rounds has already been set, a no-op will be performed.
|
||||
If you want to use a different number of rounds, you will need to create a new bcrypt.KDF.
|
||||
*/
|
||||
func (k *KDF) AddRounds(rounds uint32) (err error) {
|
||||
|
||||
if rounds == 0 {
|
||||
err = errs.ErrNoRounds
|
||||
return
|
||||
}
|
||||
if k.hasRounds {
|
||||
return
|
||||
}
|
||||
k.rounds = rounds
|
||||
k.hasRounds = true
|
||||
|
||||
return
|
||||
}
|
||||
25
kdf/bcrypt/types.go
Normal file
25
kdf/bcrypt/types.go
Normal file
@@ -0,0 +1,25 @@
|
||||
package bcrypt
|
||||
|
||||
/*
|
||||
BcryptPbkdf combines bcrypt hashing algorithm with PBKDF2 key derivation.
|
||||
|
||||
(bcrypt) https://www.usenix.org/legacy/events/usenix99/provos/provos_html/node1.html
|
||||
(PBKDF2) https://datatracker.ietf.org/doc/html/rfc2898
|
||||
http://www.tedunangst.com/flak/post/bcrypt-pbkdf
|
||||
*/
|
||||
type KDF struct {
|
||||
// salt is used to salt the hash for each round in rounds.
|
||||
salt []byte
|
||||
// rounds controls how many iterations of salting/hashing is done.
|
||||
rounds uint32
|
||||
// keyLen is how long the derived key should be in bytes.
|
||||
keyLen uint32
|
||||
// secret is the "passphrase" used to seed the key creation.
|
||||
secret []byte
|
||||
// key is used to store the derived key.
|
||||
key []byte
|
||||
// hasSalt is true if a salt has been set.
|
||||
hasSalt bool
|
||||
// hasRounds is true if a number of rounds have been set.
|
||||
hasRounds bool
|
||||
}
|
||||
@@ -1,11 +0,0 @@
|
||||
package kdf
|
||||
|
||||
const (
|
||||
BcryptPbkdfName string = "bcrypt"
|
||||
// BcryptPbkdfDefaultRounds is the default per OpenSSH, not per the bcrypt_pbkdf spec itself. It is recommended to use e.g. 100 rounds.
|
||||
BcryptPbkdfDefaultRounds uint32 = 16
|
||||
// BcryptPbkdfDefaultSaltLen is the default per OpenSSH, not per the bcrypt_pbkdf spec itself.
|
||||
BcryptPbkdfDefaultSaltLen int = 16
|
||||
// BcryptPbkdfDefaultKeyLen is suitable for AES256-CTR but may not be for others. TODO: revisit this and find something more flexible.
|
||||
BcryptPbkdfDefaultKeyLen uint32 = 48
|
||||
)
|
||||
@@ -1,5 +0,0 @@
|
||||
package kdf
|
||||
|
||||
const (
|
||||
NullName string = "none"
|
||||
)
|
||||
@@ -1,4 +1,4 @@
|
||||
package kdf
|
||||
package errs
|
||||
|
||||
import (
|
||||
"errors"
|
||||
23
kdf/funcs.go
23
kdf/funcs.go
@@ -2,6 +2,10 @@ package kdf
|
||||
|
||||
import (
|
||||
"strings"
|
||||
|
||||
`r00t2.io/sshkeys/kdf/bcrypt`
|
||||
`r00t2.io/sshkeys/kdf/errs`
|
||||
`r00t2.io/sshkeys/kdf/null`
|
||||
)
|
||||
|
||||
/*
|
||||
@@ -12,12 +16,12 @@ import (
|
||||
func GetKDF(name string) (k KDF, err error) {
|
||||
|
||||
switch strings.ToLower(name) {
|
||||
case BcryptPbkdfName:
|
||||
k = &BcryptPbkdf{}
|
||||
case NullName, "":
|
||||
k = &Null{}
|
||||
case bcrypt.Name:
|
||||
k = &bcrypt.KDF{}
|
||||
case null.Name, "":
|
||||
k = &null.KDF{}
|
||||
default:
|
||||
err = ErrUnknownKdf
|
||||
err = errs.ErrUnknownKdf
|
||||
return
|
||||
}
|
||||
|
||||
@@ -25,18 +29,21 @@ func GetKDF(name string) (k KDF, err error) {
|
||||
}
|
||||
|
||||
/*
|
||||
UnpackKDF returns a KDF from raw data as packed in a private key's bytes.
|
||||
UnpackKDF returns a kdf.KDF from raw data as packed in a private key's bytes.
|
||||
|
||||
KDF.Setup must be called on the resulting KDF.
|
||||
kdf.KDF.Setup must be called on the resulting kdf.KDF.
|
||||
|
||||
data can be:
|
||||
|
||||
- a []byte, which can be:
|
||||
- the full private key bytes
|
||||
- KDF section (e.g. _ref/format.ed25519 2.0 + (3.0 to 3.0.0.1) or 2.0.0 + (3.0 to 3.0.0.1))
|
||||
- KDF section (e.g. ED25519 private key block 2.0 + (block 3.0 to block 3.0.0.1) OR
|
||||
block 2.0.0 + (block 3.0 to block 3.0.0.1))
|
||||
- a *bytes.Buffer, which supports the same as above
|
||||
*/
|
||||
func UnpackKDF(data interface{}) (k KDF, err error) {
|
||||
|
||||
// TODO
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
@@ -1,226 +0,0 @@
|
||||
package kdf
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"crypto/rand"
|
||||
"encoding/binary"
|
||||
|
||||
bcryptPbkdf "github.com/dchest/bcrypt_pbkdf"
|
||||
"r00t2.io/sshkeys/internal"
|
||||
)
|
||||
|
||||
/*
|
||||
Setup must be called before DeriveKey. It configures a BcryptPbkdf.
|
||||
|
||||
If secret is nil or an empty byte slice, ErrNoSecret will be returned.
|
||||
|
||||
If salt is nil or an empty byte slice, one will be randomly generated of BcryptPbkdfDefaultSaltLen length.
|
||||
|
||||
If rounds is 0, BcryptPbkdfDefaultRounds will be used.
|
||||
|
||||
If keyLen is 0, BcryptPbkdfDefaultKeyLen will be used.
|
||||
*/
|
||||
func (b *BcryptPbkdf) Setup(secret, salt []byte, rounds, keyLen uint32) (err error) {
|
||||
|
||||
if secret == nil || len(secret) == 0 {
|
||||
err = ErrNoSecret
|
||||
return
|
||||
}
|
||||
|
||||
if salt == nil || len(salt) == 0 {
|
||||
salt = make([]byte, BcryptPbkdfDefaultSaltLen)
|
||||
if _, err = rand.Read(salt); err != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
if rounds == 0 {
|
||||
rounds = BcryptPbkdfDefaultRounds
|
||||
}
|
||||
|
||||
if keyLen == 0 {
|
||||
keyLen = BcryptPbkdfDefaultKeyLen
|
||||
}
|
||||
|
||||
b.secret = secret
|
||||
b.salt = salt
|
||||
b.rounds = rounds
|
||||
b.keyLen = keyLen
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
/*
|
||||
SetupAuto is used to provide out-of-band configuration if the KDF options were found via GetKdfFromBytes.
|
||||
|
||||
You can test this by running KDF.AutoOK.
|
||||
*/
|
||||
func (b *BcryptPbkdf) SetupAuto(secret []byte, keyLen uint32) (err error) {
|
||||
|
||||
if !b.AutoOK() {
|
||||
err = ErrUnknownKdf
|
||||
return
|
||||
}
|
||||
|
||||
if keyLen == 0 {
|
||||
keyLen = BcryptPbkdfDefaultKeyLen
|
||||
}
|
||||
|
||||
b.secret = secret
|
||||
b.keyLen = keyLen
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
/*
|
||||
DeriveKey returns the derived key from a BcryptPbkdf.
|
||||
|
||||
It must be called *after* Setup.
|
||||
*/
|
||||
func (b *BcryptPbkdf) DeriveKey() (key []byte, err error) {
|
||||
|
||||
if b.secret == nil {
|
||||
err = ErrNoSecret
|
||||
return
|
||||
}
|
||||
if b.salt == nil {
|
||||
err = ErrNoSalt
|
||||
return
|
||||
}
|
||||
if b.rounds == 0 {
|
||||
err = ErrNoRounds
|
||||
return
|
||||
}
|
||||
if b.keyLen == 0 {
|
||||
err = ErrNoKeyLen
|
||||
}
|
||||
|
||||
if b.key, err = bcryptPbkdf.Key(b.secret, b.salt, int(b.rounds), int(b.keyLen)); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
key = b.key
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// Name returns BcryptPbkdfName.
|
||||
func (b *BcryptPbkdf) Name() (name string) {
|
||||
|
||||
name = BcryptPbkdfName
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// NameBytes returns the byte form of BcryptPbkdf.Name with leading bytecount allocator.
|
||||
func (b *BcryptPbkdf) NameBytes() (name []byte) {
|
||||
|
||||
var nb []byte
|
||||
var s = b.Name()
|
||||
|
||||
nb = []byte(s)
|
||||
|
||||
name = make([]byte, 4)
|
||||
binary.BigEndian.PutUint32(name, uint32(len(nb)))
|
||||
name = append(name, nb...)
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// PackedBytes returns 3.0 and recursed.
|
||||
func (b *BcryptPbkdf) PackedBytes() (buf *bytes.Reader, err error) {
|
||||
|
||||
var rounds = make([]byte, 4)
|
||||
var packer *bytes.Reader
|
||||
var w = new(bytes.Buffer)
|
||||
|
||||
// 3.0.0.0 and 3.0.0.0.0
|
||||
if packer, err = internal.ReadSizeBytes(b.salt, true); err != nil {
|
||||
return
|
||||
}
|
||||
if _, err = packer.WriteTo(w); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
// 3.0.0.1
|
||||
binary.BigEndian.PutUint32(rounds, b.rounds)
|
||||
if _, err = w.Write(rounds); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
// 3.0
|
||||
if buf, err = internal.ReadSizeBytes(w, true); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// Rounds returns the number of rounds used in derivation.
|
||||
func (b *BcryptPbkdf) Rounds() (rounds uint32) {
|
||||
|
||||
rounds = b.rounds
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// Salt returns the salt bytes.
|
||||
func (b *BcryptPbkdf) Salt() (salt []byte) {
|
||||
|
||||
salt = b.salt
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
/*
|
||||
AutoOK returns true if a GetKdfFromBytes call was able to fetch the KDF options successfully, in which case the caller may use KDF.SetupAuto.
|
||||
|
||||
If false, it will need to be manually configured via KDF.Setup.
|
||||
*/
|
||||
func (b *BcryptPbkdf) AutoOK() (ok bool) {
|
||||
|
||||
ok = true
|
||||
|
||||
if b.salt == nil || len(b.salt) == 0 {
|
||||
ok = false
|
||||
}
|
||||
|
||||
if b.rounds == 0 {
|
||||
ok = false
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// IsPlain indicates if this KDF actually does derivation (false) or not (true).
|
||||
func (b *BcryptPbkdf) IsPlain() (plain bool) {
|
||||
|
||||
plain = false
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// addSalt adds a salt as parsed from GetKdfFromBytes.
|
||||
func (b *BcryptPbkdf) addSalt(salt []byte) (err error) {
|
||||
|
||||
if salt == nil || len(salt) == 0 {
|
||||
err = ErrNoSalt
|
||||
return
|
||||
}
|
||||
b.salt = salt
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// addRounds adds the rounds as parsed from GetKdfFromBytes
|
||||
func (b *BcryptPbkdf) addRounds(rounds uint32) (err error) {
|
||||
|
||||
if rounds == 0 {
|
||||
err = ErrNoRounds
|
||||
return
|
||||
}
|
||||
|
||||
b.rounds = rounds
|
||||
|
||||
return
|
||||
}
|
||||
@@ -1,137 +0,0 @@
|
||||
package kdf
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/binary"
|
||||
)
|
||||
|
||||
/*
|
||||
Setup must be called before DeriveKey. It configures a Null.
|
||||
|
||||
Note that this doesn't actually do anything, it's here for interface compat.
|
||||
It is recommended to use nil/zero values.
|
||||
*/
|
||||
func (n *Null) Setup(secret, salt []byte, rounds, keyLen uint32) (err error) {
|
||||
|
||||
_, _, _, _ = secret, salt, rounds, keyLen
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
/*
|
||||
SetupAuto is used to provide out-of-band configuration if the KDF options were found via GetKdfFromBytes.
|
||||
|
||||
Note that this doesn't actually do anything, it's here for interface compat.
|
||||
It is recommended to use nil/zero values.
|
||||
*/
|
||||
func (n *Null) SetupAuto(secret []byte, keyLen uint32) (err error) {
|
||||
|
||||
_, _ = secret, keyLen
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
/*
|
||||
DeriveKey returns the derived key from a Null.
|
||||
|
||||
Note that this doesn't actually do anything, it's here for interface compat.
|
||||
key will ALWAYS be a nil byte slice.
|
||||
*/
|
||||
func (n *Null) DeriveKey() (key []byte, err error) {
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// Name returns NullName.
|
||||
func (n *Null) Name() (name string) {
|
||||
|
||||
name = NullName
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// NameBytes returns the byte form of Null.Name with leading bytecount allocator.
|
||||
func (n *Null) NameBytes() (name []byte) {
|
||||
|
||||
var b []byte
|
||||
var s = n.Name()
|
||||
|
||||
b = []byte(s)
|
||||
|
||||
name = make([]byte, 4)
|
||||
binary.BigEndian.PutUint32(name, uint32(len(b)))
|
||||
name = append(name, b...)
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// PackedBytes returns 3.0 and recursed.
|
||||
func (n *Null) PackedBytes() (buf *bytes.Reader, err error) {
|
||||
|
||||
// This is static.
|
||||
buf = bytes.NewReader([]byte{0x0, 0x0, 0x0, 0x0})
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
/*
|
||||
Rounds returns the number of rounds used in derivation.
|
||||
|
||||
Note that this will always return 0; it's here for interface compat.
|
||||
*/
|
||||
func (n *Null) Rounds() (rounds uint32) {
|
||||
|
||||
rounds = 0
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
/*
|
||||
Salt returns the salt bytes.
|
||||
|
||||
Note that this will always return nil; it's here for interface compat.
|
||||
*/
|
||||
func (n *Null) Salt() (salt []byte) {
|
||||
|
||||
salt = nil
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
/*
|
||||
AutoOK returns true if a GetKdfFromBytes call was able to fetch the KDF options successfully, in which case the caller may use KDF.SetupAuto.
|
||||
|
||||
If false, it will need to be manually configured via KDF.Setup.
|
||||
|
||||
Note that this won't actually do anything and ok will always return as true.
|
||||
*/
|
||||
func (n *Null) AutoOK() (ok bool) {
|
||||
|
||||
ok = true
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// IsPlain indicates if this KDF actually does derivation (false) or not (true).
|
||||
func (n *Null) IsPlain() (plain bool) {
|
||||
|
||||
plain = true
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// addSalt is a no-op, just here for interface compat.
|
||||
func (n *Null) addSalt(salt []byte) (err error) {
|
||||
|
||||
_ = salt
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// addRounds is a no-op; just here for interface compat.
|
||||
func (n *Null) addRounds(rounds uint32) (err error) {
|
||||
|
||||
_ = rounds
|
||||
|
||||
return
|
||||
}
|
||||
5
kdf/null/consts.go
Normal file
5
kdf/null/consts.go
Normal file
@@ -0,0 +1,5 @@
|
||||
package null
|
||||
|
||||
const (
|
||||
Name string = "none"
|
||||
)
|
||||
137
kdf/null/funcs.go
Normal file
137
kdf/null/funcs.go
Normal file
@@ -0,0 +1,137 @@
|
||||
package null
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/binary"
|
||||
)
|
||||
|
||||
/*
|
||||
Setup must be called before DeriveKey. It configures a null.KDF.
|
||||
|
||||
Note that this doesn't actually do anything, it's here for interface compat.
|
||||
It is recommended to use nil/zero values.
|
||||
*/
|
||||
func (k *KDF) Setup(secret, salt []byte, rounds, keyLen uint32) (err error) {
|
||||
|
||||
_, _, _, _ = secret, salt, rounds, keyLen
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
/*
|
||||
SetupAuto is used to provide out-of-band configuration if the null.KDF options were found via kdf.UnpackKDF.
|
||||
|
||||
Note that this doesn't actually do anything, it's here for interface compat.
|
||||
It is recommended to use nil/zero values.
|
||||
*/
|
||||
func (k *KDF) SetupAuto(secret []byte, keyLen uint32) (err error) {
|
||||
|
||||
_, _ = secret, keyLen
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
/*
|
||||
DeriveKey returns the derived key from a null.KDF.
|
||||
|
||||
Note that this doesn't actually do anything, it's here for interface compat.
|
||||
key will ALWAYS be a nil byte slice.
|
||||
*/
|
||||
func (k *KDF) DeriveKey() (key []byte, err error) {
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// Name returns null.Name.
|
||||
func (k *KDF) Name() (name string) {
|
||||
|
||||
name = Name
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// NameBytes returns the byte form of null.Name with leading bytecount allocator.
|
||||
func (k *KDF) NameBytes() (name []byte) {
|
||||
|
||||
var b []byte
|
||||
var s = k.Name()
|
||||
|
||||
b = []byte(s)
|
||||
|
||||
name = make([]byte, 4)
|
||||
binary.BigEndian.PutUint32(name, uint32(len(b)))
|
||||
name = append(name, b...)
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// PackedBytes returns block 3.0 and recursed.
|
||||
func (k *KDF) PackedBytes() (buf *bytes.Reader, err error) {
|
||||
|
||||
// This is static.
|
||||
buf = bytes.NewReader([]byte{0x0, 0x0, 0x0, 0x0})
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
/*
|
||||
Rounds returns the number of rounds used in derivation.
|
||||
|
||||
Note that this will always return 0; it's here for interface compat.
|
||||
*/
|
||||
func (k *KDF) Rounds() (rounds uint32) {
|
||||
|
||||
rounds = 0
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
/*
|
||||
Salt returns the salt bytes.
|
||||
|
||||
Note that this will always return nil; it's here for interface compat.
|
||||
*/
|
||||
func (k *KDF) Salt() (salt []byte) {
|
||||
|
||||
salt = nil
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
/*
|
||||
AutoOK returns true if a kdf.UnpackKDF call was able to fetch the null.KDF options successfully, in which case the caller may use null.KDF.SetupAuto.
|
||||
|
||||
If false, it will need to be manually configured via null.KDF.Setup.
|
||||
|
||||
Note that this won't actually do anything and ok will always return as true.
|
||||
*/
|
||||
func (k *KDF) AutoOK() (ok bool) {
|
||||
|
||||
ok = true
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// IsPlain indicates if this kdf.KDF actually does derivation (false) or not (true).
|
||||
func (k *KDF) IsPlain() (plain bool) {
|
||||
|
||||
plain = true
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// AddSalt is a no-op, just here for interface compat.
|
||||
func (k *KDF) AddSalt(salt []byte) (err error) {
|
||||
|
||||
_ = salt
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// AddRounds is a no-op; just here for interface compat.
|
||||
func (k *KDF) AddRounds(rounds uint32) (err error) {
|
||||
|
||||
_ = rounds
|
||||
|
||||
return
|
||||
}
|
||||
4
kdf/null/types.go
Normal file
4
kdf/null/types.go
Normal file
@@ -0,0 +1,4 @@
|
||||
package null
|
||||
|
||||
// KDF is a dummy kdf.KDF that is used for unencrypted/plain SSH private keys. It literally does nothing.
|
||||
type KDF struct{}
|
||||
31
kdf/types.go
31
kdf/types.go
@@ -26,31 +26,8 @@ type KDF interface {
|
||||
IsPlain() (plain bool)
|
||||
// PackedBytes returns the bytes suitable for serializing into a key file.
|
||||
PackedBytes() (buf *bytes.Reader, err error)
|
||||
// addSalt adds the salt as parsed from the private key.
|
||||
addSalt(salt []byte) (err error)
|
||||
// addRounds adds the rounds as parsed from the private key.
|
||||
addRounds(rounds uint32) (err error)
|
||||
// AddSalt adds the salt as parsed from the private key.
|
||||
AddSalt(salt []byte) (err error)
|
||||
// AddRounds adds the rounds as parsed from the private key.
|
||||
AddRounds(rounds uint32) (err error)
|
||||
}
|
||||
|
||||
/*
|
||||
BcryptPbkdf combines bcrypt hashing algorithm with PBKDF2 key derivation.
|
||||
|
||||
(bcrypt) https://www.usenix.org/legacy/events/usenix99/provos/provos_html/node1.html
|
||||
(PBKDF2) https://datatracker.ietf.org/doc/html/rfc2898
|
||||
http://www.tedunangst.com/flak/post/bcrypt-pbkdf
|
||||
*/
|
||||
type BcryptPbkdf struct {
|
||||
// salt is used to salt the hash for each round in rounds.
|
||||
salt []byte
|
||||
// rounds controls how many iterations of salting/hashing is done.
|
||||
rounds uint32
|
||||
// keyLen is how long the derived key should be in bytes.
|
||||
keyLen uint32
|
||||
// secret is the "passphrase" used to seed the key creation.
|
||||
secret []byte
|
||||
// key is used to store the derived key.
|
||||
key []byte
|
||||
}
|
||||
|
||||
// Null is a dummy KDF that is used for unencrypted/plain SSH private keys. It literally does nothing.
|
||||
type Null struct{}
|
||||
|
||||
Reference in New Issue
Block a user