diff options
Diffstat (limited to 'vendor/github.com/pquerna/otp/hotp/hotp.go')
| -rw-r--r-- | vendor/github.com/pquerna/otp/hotp/hotp.go | 237 |
1 files changed, 0 insertions, 237 deletions
diff --git a/vendor/github.com/pquerna/otp/hotp/hotp.go b/vendor/github.com/pquerna/otp/hotp/hotp.go deleted file mode 100644 index bc23b660b..000000000 --- a/vendor/github.com/pquerna/otp/hotp/hotp.go +++ /dev/null @@ -1,237 +0,0 @@ -/** - * Copyright 2014 Paul Querna - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ - -package hotp - -import ( - "github.com/pquerna/otp" - "github.com/pquerna/otp/internal" - "io" - - "crypto/hmac" - "crypto/rand" - "crypto/subtle" - "encoding/base32" - "encoding/binary" - "fmt" - "math" - "net/url" - "strings" -) - -const debug = false - -// Validate a HOTP passcode given a counter and secret. -// This is a shortcut for ValidateCustom, with parameters that -// are compataible with Google-Authenticator. -func Validate(passcode string, counter uint64, secret string) bool { - rv, _ := ValidateCustom( - passcode, - counter, - secret, - ValidateOpts{ - Digits: otp.DigitsSix, - Algorithm: otp.AlgorithmSHA1, - }, - ) - return rv -} - -// ValidateOpts provides options for ValidateCustom(). -type ValidateOpts struct { - // Digits as part of the input. Defaults to 6. - Digits otp.Digits - // Algorithm to use for HMAC. Defaults to SHA1. - Algorithm otp.Algorithm - // Encoder to use for output code. - Encoder otp.Encoder -} - -// GenerateCode creates a HOTP passcode given a counter and secret. -// This is a shortcut for GenerateCodeCustom, with parameters that -// are compataible with Google-Authenticator. -func GenerateCode(secret string, counter uint64) (string, error) { - return GenerateCodeCustom(secret, counter, ValidateOpts{ - Digits: otp.DigitsSix, - Algorithm: otp.AlgorithmSHA1, - }) -} - -// GenerateCodeCustom uses a counter and secret value and options struct to -// create a passcode. -func GenerateCodeCustom(secret string, counter uint64, opts ValidateOpts) (passcode string, err error) { - //Set default value - if opts.Digits == 0 { - opts.Digits = otp.DigitsSix - } - // As noted in issue #10 and #17 this adds support for TOTP secrets that are - // missing their padding. - secret = strings.TrimSpace(secret) - if n := len(secret) % 8; n != 0 { - secret = secret + strings.Repeat("=", 8-n) - } - - // As noted in issue #24 Google has started producing base32 in lower case, - // but the StdEncoding (and the RFC), expect a dictionary of only upper case letters. - secret = strings.ToUpper(secret) - - secretBytes, err := base32.StdEncoding.DecodeString(secret) - if err != nil { - return "", otp.ErrValidateSecretInvalidBase32 - } - - buf := make([]byte, 8) - mac := hmac.New(opts.Algorithm.Hash, secretBytes) - binary.BigEndian.PutUint64(buf, counter) - if debug { - fmt.Printf("counter=%v\n", counter) - fmt.Printf("buf=%v\n", buf) - } - - mac.Write(buf) - sum := mac.Sum(nil) - - // "Dynamic truncation" in RFC 4226 - // http://tools.ietf.org/html/rfc4226#section-5.4 - offset := sum[len(sum)-1] & 0xf - value := int64(((int(sum[offset]) & 0x7f) << 24) | - ((int(sum[offset+1] & 0xff)) << 16) | - ((int(sum[offset+2] & 0xff)) << 8) | - (int(sum[offset+3]) & 0xff)) - - l := opts.Digits.Length() - switch opts.Encoder { - case otp.EncoderDefault: - mod := int32(value % int64(math.Pow10(l))) - - if debug { - fmt.Printf("offset=%v\n", offset) - fmt.Printf("value=%v\n", value) - fmt.Printf("mod'ed=%v\n", mod) - } - passcode = opts.Digits.Format(mod) - case otp.EncoderSteam: - // Define the character set used by Steam Guard codes. - alphabet := []byte{ - '2', '3', '4', '5', '6', '7', '8', '9', 'B', 'C', - 'D', 'F', 'G', 'H', 'J', 'K', 'M', 'N', 'P', 'Q', - 'R', 'T', 'V', 'W', 'X', 'Y', - } - radix := int64(len(alphabet)) - - for i := 0; i < l; i++ { - digit := value % radix - value /= radix - c := alphabet[digit] - passcode += string(c) - } - } - - return -} - -// ValidateCustom validates an HOTP with customizable options. Most users should -// use Validate(). -func ValidateCustom(passcode string, counter uint64, secret string, opts ValidateOpts) (bool, error) { - passcode = strings.TrimSpace(passcode) - - if len(passcode) != opts.Digits.Length() { - return false, otp.ErrValidateInputInvalidLength - } - - otpstr, err := GenerateCodeCustom(secret, counter, opts) - if err != nil { - return false, err - } - - if subtle.ConstantTimeCompare([]byte(otpstr), []byte(passcode)) == 1 { - return true, nil - } - - return false, nil -} - -// GenerateOpts provides options for .Generate() -type GenerateOpts struct { - // Name of the issuing Organization/Company. - Issuer string - // Name of the User's Account (eg, email address) - AccountName string - // Size in size of the generated Secret. Defaults to 10 bytes. - SecretSize uint - // Secret to store. Defaults to a randomly generated secret of SecretSize. You should generally leave this empty. - Secret []byte - // Digits to request. Defaults to 6. - Digits otp.Digits - // Algorithm to use for HMAC. Defaults to SHA1. - Algorithm otp.Algorithm - // Reader to use for generating HOTP Key. - Rand io.Reader -} - -var b32NoPadding = base32.StdEncoding.WithPadding(base32.NoPadding) - -// Generate creates a new HOTP Key. -func Generate(opts GenerateOpts) (*otp.Key, error) { - // url encode the Issuer/AccountName - if opts.Issuer == "" { - return nil, otp.ErrGenerateMissingIssuer - } - - if opts.AccountName == "" { - return nil, otp.ErrGenerateMissingAccountName - } - - if opts.SecretSize == 0 { - opts.SecretSize = 10 - } - - if opts.Digits == 0 { - opts.Digits = otp.DigitsSix - } - - if opts.Rand == nil { - opts.Rand = rand.Reader - } - - // otpauth://hotp/Example:alice@google.com?secret=JBSWY3DPEHPK3PXP&issuer=Example - - v := url.Values{} - if len(opts.Secret) != 0 { - v.Set("secret", b32NoPadding.EncodeToString(opts.Secret)) - } else { - secret := make([]byte, opts.SecretSize) - _, err := io.ReadFull(opts.Rand, secret) - if err != nil { - return nil, err - } - v.Set("secret", b32NoPadding.EncodeToString(secret)) - } - - v.Set("issuer", opts.Issuer) - v.Set("algorithm", opts.Algorithm.String()) - v.Set("digits", opts.Digits.String()) - - u := url.URL{ - Scheme: "otpauth", - Host: "hotp", - Path: "/" + opts.Issuer + ":" + opts.AccountName, - RawQuery: internal.EncodeQuery(v), - } - - return otp.NewKeyFromURL(u.String()) -} |
