Remove YubiKey (not currently functional).
This commit is contained in:
@@ -1,29 +0,0 @@
|
||||
package modhex
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/gokyle/twofactor/modhex"
|
||||
)
|
||||
|
||||
var out = "fjhghrhrhvdrdciihvidhrhfdb"
|
||||
var in = "Hello, world!"
|
||||
|
||||
func ExampleEncoding_EncodeToString() {
|
||||
data := []byte("Hello, world!")
|
||||
str := modhex.StdEncoding.EncodeToString(data)
|
||||
fmt.Println(str)
|
||||
// Output:
|
||||
// fjhghrhrhvdrdciihvidhrhfdb
|
||||
}
|
||||
|
||||
func ExampleEncoding_DecodeString() {
|
||||
str := "fjhghrhrhvdrdciihvidhrhfdb"
|
||||
data, err := modhex.StdEncoding.DecodeString(str)
|
||||
if err != nil {
|
||||
fmt.Printf("%v\n", err)
|
||||
return
|
||||
}
|
||||
fmt.Printf("%s", string(data))
|
||||
// Output:
|
||||
// Hello, world!
|
||||
}
|
||||
112
modhex/modhex.go
112
modhex/modhex.go
@@ -1,112 +0,0 @@
|
||||
// Package modhex implements the modified hexadecimal encoding as used
|
||||
// by Yubico in their series of products.
|
||||
package modhex
|
||||
|
||||
import "fmt"
|
||||
|
||||
// Encoding is a mapping of hexadecimal values to a new byte value.
|
||||
// This means that the encoding for a single byte is two bytes.
|
||||
type Encoding struct {
|
||||
decoding map[byte]byte
|
||||
encoding [16]byte
|
||||
}
|
||||
|
||||
// A CorruptInputError is returned if the input string contains
|
||||
// invalid characters for the encoding or if the input is the wrong
|
||||
// length. It contains the number of bytes written out.
|
||||
type CorruptInputError struct {
|
||||
written int64
|
||||
}
|
||||
|
||||
func (err CorruptInputError) Error() string {
|
||||
return fmt.Sprintf("modhex: corrupt input at byte %d", err.written)
|
||||
}
|
||||
|
||||
func (err CorruptInputError) Written() int64 {
|
||||
return err.written
|
||||
}
|
||||
|
||||
var encodeStd = "cbdefghijklnrtuv"
|
||||
|
||||
// NewEncoding builds a new encoder from the alphabet passed in,
|
||||
// which must be a 16-byte string.
|
||||
func NewEncoding(encoder string) *Encoding {
|
||||
if len(encoder) != 16 {
|
||||
return nil
|
||||
}
|
||||
|
||||
enc := new(Encoding)
|
||||
enc.decoding = make(map[byte]byte)
|
||||
for i := range encoder {
|
||||
enc.encoding[i] = encoder[i]
|
||||
enc.decoding[encoder[i]] = byte(i)
|
||||
}
|
||||
return enc
|
||||
}
|
||||
|
||||
// StdEncoding is the canonical modhex alphabet as used by Yubico.
|
||||
var StdEncoding = NewEncoding(encodeStd)
|
||||
|
||||
// Encode encodes src to dst, writing at most EncodedLen(len(src))
|
||||
// bytes to dst.
|
||||
func (enc *Encoding) Encode(dst, src []byte) {
|
||||
out := dst
|
||||
|
||||
for i := 0; i < len(src) && len(out) > 1; i++ {
|
||||
var b [2]byte
|
||||
b[0] = enc.encoding[(src[i]&0xf0)>>4]
|
||||
b[1] = enc.encoding[src[i]&0xf]
|
||||
copy(out[:2], b[:])
|
||||
out = out[2:]
|
||||
}
|
||||
}
|
||||
|
||||
// EncodedLen returns the encoded length of a buffer of n bytes.
|
||||
func EncodedLen(n int) int {
|
||||
return n << 1
|
||||
}
|
||||
|
||||
// DecodedLen returns the decoded length of a buffer of n bytes.
|
||||
func DecodedLen(n int) int {
|
||||
return n >> 1
|
||||
}
|
||||
|
||||
// Decode decodes src into dst, which will be at most DecodedLen(len(src)).
|
||||
// It returns the number of bytes written, and any error that occurred.
|
||||
func (enc *Encoding) Decode(dst, src []byte) (n int, err error) {
|
||||
out := dst
|
||||
|
||||
for i := 0; i < len(src); i += 2 {
|
||||
if (len(src) - i) < 2 {
|
||||
return i >> 1, CorruptInputError{int64(i >> 1)}
|
||||
}
|
||||
var b byte
|
||||
if high, ok := enc.decoding[src[i]]; !ok {
|
||||
return i >> 1, CorruptInputError{int64(i >> 1)}
|
||||
} else if low, ok := enc.decoding[src[i+1]]; !ok {
|
||||
return i >> 1, CorruptInputError{int64(i >> 1)}
|
||||
} else {
|
||||
b = high << 4
|
||||
b += low
|
||||
out[0] = b
|
||||
out = out[1:]
|
||||
}
|
||||
}
|
||||
return len(dst), nil
|
||||
}
|
||||
|
||||
// EncodeToString is a convenience function to encode src as a
|
||||
// string.
|
||||
func (enc *Encoding) EncodeToString(src []byte) string {
|
||||
dst := make([]byte, EncodedLen(len(src)))
|
||||
enc.Encode(dst, src)
|
||||
return string(dst)
|
||||
}
|
||||
|
||||
// DecodeString decodes the string passed in as its decoded bytes.
|
||||
func (enc *Encoding) DecodeString(s string) ([]byte, error) {
|
||||
dst := make([]byte, DecodedLen(len(s)))
|
||||
src := []byte(s)
|
||||
_, err := enc.Decode(dst, src)
|
||||
return dst, err
|
||||
}
|
||||
@@ -1,163 +0,0 @@
|
||||
package modhex
|
||||
|
||||
import "bytes"
|
||||
import "fmt"
|
||||
import "testing"
|
||||
|
||||
func TestInvalidEncoder(t *testing.T) {
|
||||
s := ""
|
||||
for i := 0; i < 16; i++ {
|
||||
if NewEncoding(s) != nil {
|
||||
fmt.Println("modhex: NewEncoding accepted bad encoding")
|
||||
t.FailNow()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var encodeTests = []struct {
|
||||
In []byte
|
||||
Out []byte
|
||||
}{
|
||||
{[]byte{0x47}, []byte("fi")},
|
||||
{[]byte{0xba, 0xad, 0xf0, 0x0d}, []byte("nlltvcct")},
|
||||
}
|
||||
|
||||
var decodeFail = [][]byte{
|
||||
[]byte{0x47},
|
||||
[]byte("abcdef"),
|
||||
}
|
||||
|
||||
func TestStdEncodingEncode(t *testing.T) {
|
||||
enc := StdEncoding
|
||||
for _, et := range encodeTests {
|
||||
out := make([]byte, EncodedLen(len(et.In)))
|
||||
enc.Encode(out, et.In)
|
||||
if !bytes.Equal(out, et.Out) {
|
||||
fmt.Println("modhex: StdEncoding: bad encoding")
|
||||
fmt.Printf("\texpected: %x\n", et.Out)
|
||||
fmt.Printf("\t actual: %x\n", out)
|
||||
t.FailNow()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestStdDecoding(t *testing.T) {
|
||||
enc := StdEncoding
|
||||
for _, et := range encodeTests {
|
||||
out := make([]byte, DecodedLen(len(et.Out)))
|
||||
n, err := enc.Decode(out, et.Out)
|
||||
if err != nil {
|
||||
fmt.Printf("%v\n", err)
|
||||
t.FailNow()
|
||||
} else if n != len(et.In) {
|
||||
fmt.Println("modhex: bad decoded length")
|
||||
t.FailNow()
|
||||
} else if !bytes.Equal(out, et.In) {
|
||||
fmt.Println("modhex: StdEncoding: bad decoding")
|
||||
fmt.Printf("\texpected: %x\n", et.In)
|
||||
fmt.Printf("\t actual: %x\n", out)
|
||||
t.FailNow()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestStdDecodingFail(t *testing.T) {
|
||||
enc := StdEncoding
|
||||
for _, et := range decodeFail {
|
||||
dst := make([]byte, DecodedLen(len(et)))
|
||||
_, err := enc.Decode(dst, et)
|
||||
if err == nil {
|
||||
fmt.Println("modhex: decode should fail")
|
||||
t.FailNow()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestStdEncodingToString(t *testing.T) {
|
||||
enc := StdEncoding
|
||||
for _, et := range encodeTests {
|
||||
out := enc.EncodeToString(et.In)
|
||||
if out != string(et.Out) {
|
||||
fmt.Println("modhex: StdEncoding: bad encoding")
|
||||
fmt.Printf("\texpected: %x\n", et.Out)
|
||||
fmt.Printf("\t actual: %x\n", out)
|
||||
t.FailNow()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestStdEncodingString(t *testing.T) {
|
||||
enc := StdEncoding
|
||||
for _, et := range encodeTests {
|
||||
out, err := enc.DecodeString(string(et.Out))
|
||||
if err != nil {
|
||||
fmt.Printf("%v\n", err)
|
||||
t.FailNow()
|
||||
} else if !bytes.Equal(out, et.In) {
|
||||
fmt.Println("modhex: StdEncoding: bad encoding")
|
||||
fmt.Printf("\texpected: %x\n", et.In)
|
||||
fmt.Printf("\t actual: %x\n", out)
|
||||
t.FailNow()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var corruptTests = []struct {
|
||||
In []byte
|
||||
Written int64
|
||||
Error string
|
||||
}{
|
||||
{[]byte("aa"), 0, "modhex: corrupt input at byte 0"},
|
||||
{[]byte("ca"), 0, "modhex: corrupt input at byte 0"},
|
||||
{[]byte("ccac"), 1, "modhex: corrupt input at byte 1"},
|
||||
{[]byte("ccca"), 1, "modhex: corrupt input at byte 1"},
|
||||
}
|
||||
|
||||
func TestCorruptInputError(t *testing.T) {
|
||||
enc := StdEncoding
|
||||
for _, ct := range corruptTests {
|
||||
dst := make([]byte, DecodedLen(len(ct.In)))
|
||||
n, err := enc.Decode(dst, ct.In)
|
||||
if err == nil {
|
||||
fmt.Println("modhex: decode should fail")
|
||||
t.FailNow()
|
||||
} else if (err.(CorruptInputError)).Written() != ct.Written {
|
||||
fmt.Printf("modhex: decode should fail at byte %d, failed at byte %d\n",
|
||||
ct.Written, (err.(CorruptInputError)).Written())
|
||||
t.FailNow()
|
||||
} else if err.Error() != ct.Error {
|
||||
fmt.Printf("modhex: invalid error '%s' returned\n", err.Error())
|
||||
fmt.Printf(" (expected '%s')\n", ct.Error)
|
||||
t.FailNow()
|
||||
} else if int64(n) != ct.Written {
|
||||
fmt.Printf("modhex: decode should fail at byte %d, failed at byte %d\n",
|
||||
ct.Written, n)
|
||||
t.FailNow()
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
func TestCorruptInputErrorString(t *testing.T) {
|
||||
enc := StdEncoding
|
||||
for _, ct := range corruptTests {
|
||||
_, err := enc.DecodeString(string(ct.In))
|
||||
if err == nil {
|
||||
fmt.Println("modhex: decode should fail")
|
||||
t.FailNow()
|
||||
} else if (err.(CorruptInputError)).Written() != ct.Written {
|
||||
fmt.Printf("modhex: decode should fail at byte %d, failed at byte %d\n",
|
||||
ct.Written, (err.(CorruptInputError)).Written())
|
||||
t.FailNow()
|
||||
} else if err.Error() != ct.Error {
|
||||
fmt.Printf("modhex: invalid error '%s' returned\n", err.Error())
|
||||
fmt.Printf(" (expected '%s')\n", ct.Error)
|
||||
t.FailNow()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestFoo(t *testing.T) {
|
||||
fmt.Println("Hello, world!->", StdEncoding.EncodeToString([]byte("Hello, world!")))
|
||||
t.FailNow()
|
||||
}
|
||||
1
otp.go
1
otp.go
@@ -13,7 +13,6 @@ type Type uint
|
||||
const (
|
||||
OATH_HOTP = iota
|
||||
OATH_TOTP
|
||||
YUBIKEY
|
||||
)
|
||||
|
||||
// PRNG is an io.Reader that provides a cryptographically secure
|
||||
|
||||
64
yubikey.go
64
yubikey.go
@@ -1,64 +0,0 @@
|
||||
package twofactor
|
||||
|
||||
// Implement YubiKey OTP and YubiKey HOTP.
|
||||
|
||||
import (
|
||||
"github.com/conformal/yubikey"
|
||||
"github.com/gokyle/twofactor/modhex"
|
||||
"hash"
|
||||
)
|
||||
|
||||
// YubiKey is an implementation of the YubiKey hard token. Note
|
||||
// that the internal counter only actually uses 32 bits.
|
||||
type YubiKey struct {
|
||||
token yubikey.Token
|
||||
counter uint64
|
||||
key yubikey.Key
|
||||
public []byte
|
||||
}
|
||||
|
||||
// Public returns the public component of the token.
|
||||
func (yk *YubiKey) Public() []byte {
|
||||
return yk.public[:]
|
||||
}
|
||||
|
||||
// Counter returns the YubiKey's counter.
|
||||
func (yk *YubiKey) Counter() uint64 {
|
||||
return yk.counter
|
||||
}
|
||||
|
||||
// SetCounter sets the YubiKey's counter.
|
||||
func (yk *YubiKey) SetCounter(counter uint64) {
|
||||
yk.counter = counter & 0xffffffff
|
||||
}
|
||||
|
||||
// Key returns the YubiKey's secret key.
|
||||
func (yk *YubiKey) Key() []byte {
|
||||
return yk.key[:]
|
||||
}
|
||||
|
||||
// Size returns the length of the YubiKey's OTP output plus the length
|
||||
// of the public identifier.
|
||||
func (yk *YubiKey) Size() int {
|
||||
return yubikey.OTPSize + len(yk.public)
|
||||
}
|
||||
|
||||
// OTP returns a new one-time password from the YubiKey.
|
||||
func (yk *YubiKey) OTP() string {
|
||||
otp := yk.token.Generate(yk.key)
|
||||
if otp == nil {
|
||||
return ""
|
||||
}
|
||||
return modhex.StdEncoding.EncodeToString(otp.Bytes())
|
||||
}
|
||||
|
||||
// Hash always returns nil, as the YubiKey tokens do not use a hash
|
||||
// function.
|
||||
func (yk *YubiKey) Hash() func() hash.Hash {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Type returns YUBIKEY.
|
||||
func (yk *YubiKey) Type() Type {
|
||||
return YUBIKEY
|
||||
}
|
||||
Reference in New Issue
Block a user