This repository has been archived by the owner on Jul 7, 2020. It is now read-only.
forked from keybase/client
/
paperkey_phrase.go
106 lines (92 loc) · 2.9 KB
/
paperkey_phrase.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
// Copyright 2015 Keybase, Inc. All rights reserved. Use of
// this source code is governed by the included BSD license.
package libkb
import (
"crypto/sha256"
"errors"
"strings"
)
// PaperKeyPhrase is the string that can generate a paper key. It
// is versioned and forced to be lowercase. To make a new random
// phrase, use MakePaperKeyPhrase. To convert a string to a
// PaperKeyPhrase, use NewPaperKeyPhrase.
type PaperKeyPhrase string
// MakePaperKeyPhrase creates a new, random paper key phrase for
// the given version.
func MakePaperKeyPhrase(version uint8) (PaperKeyPhrase, error) {
nbits := PaperKeySecretEntropy + PaperKeyIDBits + PaperKeyVersionBits
for i := 0; i < 1000; i++ {
words, err := SecWordList(nbits)
if err != nil {
return "", err
}
if wordVersion(words[len(words)-1]) != version {
continue
}
return NewPaperKeyPhrase(strings.Join(words, " ")), nil
}
return "", KeyGenError{Msg: "exhausted attempts to generate valid paper key"}
}
// NewPaperKeyPhrase converts a string into a PaperKeyPhrase.
func NewPaperKeyPhrase(phrase string) PaperKeyPhrase {
phrase = strings.TrimSpace(strings.ToLower(phrase))
return PaperKeyPhrase(strings.Join(strings.Fields(phrase), " "))
}
// String returns a string representation of the phrase.
func (p PaperKeyPhrase) String() string {
return string(p)
}
// Bytes returns a byte slice of the phrase.
func (p PaperKeyPhrase) Bytes() []byte {
return []byte(p)
}
// Version calculates the phrase version. 0-15 are possible
// versions.
func (p PaperKeyPhrase) Version() (uint8, error) {
words := p.words()
if len(words) == 0 {
return 0, errors.New("empty paper key phrase")
}
return wordVersion(words[len(words)-1]), nil
}
func (p PaperKeyPhrase) InvalidWords() (words []string) {
for _, w := range p.words() {
// in secwords.go:
if !validWord(w) {
words = append(words, w)
}
}
return words
}
// Prefix returns the first two words in the phrase.
func (p PaperKeyPhrase) Prefix() string {
return strings.Join(p.words()[0:2], " ")
}
// words returns the phrase as a slice of words.
func (p PaperKeyPhrase) words() []string {
return strings.Fields(p.String())
}
func (p PaperKeyPhrase) NumWords() int {
return len(p.words())
}
// wordVersion calculates the paper key phrase version based on a
// word.
func wordVersion(word string) uint8 {
h := sha256.Sum256([]byte(word))
if PaperKeyVersionBits > 8 {
panic("PaperKeyVersionBits must be 8 bits or fewer")
}
return h[len(h)-1] & ((1 << PaperKeyVersionBits) - 1)
}
func NewPaperKeyPhraseCheckVersion(m MetaContext, passphrase string) (ret PaperKeyPhrase, err error) {
paperPhrase := NewPaperKeyPhrase(passphrase)
version, err := paperPhrase.Version()
if err != nil {
return ret, err
}
if version != PaperKeyVersion {
m.CDebugf("paper version mismatch: generated paper key version = %d, libkb version = %d", version, PaperKeyVersion)
return ret, KeyVersionError{}
}
return paperPhrase, nil
}