From 8debdc1501147bb2980909fe854918946f2ad95b Mon Sep 17 00:00:00 2001 From: Eric Chiang Date: Mon, 8 Jan 2018 17:19:12 -0800 Subject: [PATCH] kubeadm: more random tokens The strategy of hex encoding a random byte array only uses the following characters: 0123456789abcdef Instead of the entire bootstrapping token character set: 0123456789abcdefghijklmnopqrstuvwxyz Update the token generation to use the entire character set. This increases the token secret from 48 bits of entropy to ~82 bits. 256^8 (1.8e+19) vs. 36^16 (7.9e+24). --- cmd/kubeadm/app/util/token/tokens.go | 38 ++++++++++++++++++----- cmd/kubeadm/app/util/token/tokens_test.go | 4 +-- 2 files changed, 32 insertions(+), 10 deletions(-) diff --git a/cmd/kubeadm/app/util/token/tokens.go b/cmd/kubeadm/app/util/token/tokens.go index 18d886f533f..6be9260005e 100644 --- a/cmd/kubeadm/app/util/token/tokens.go +++ b/cmd/kubeadm/app/util/token/tokens.go @@ -17,8 +17,8 @@ limitations under the License. package token import ( + "bufio" "crypto/rand" - "encoding/hex" "fmt" "regexp" @@ -27,9 +27,9 @@ import ( const ( // TokenIDBytes defines a number of bytes used for a token id - TokenIDBytes = 3 + TokenIDBytes = 6 // TokenSecretBytes defines a number of bytes used for a secret - TokenSecretBytes = 8 + TokenSecretBytes = 16 ) var ( @@ -43,13 +43,35 @@ var ( TokenRegexp = regexp.MustCompile(TokenRegexpString) ) +const validBootstrapTokenChars = "0123456789abcdefghijklmnopqrstuvwxyz" + func randBytes(length int) (string, error) { - b := make([]byte, length) - _, err := rand.Read(b) - if err != nil { - return "", err + // len("0123456789abcdefghijklmnopqrstuvwxyz") = 36 which doesn't evenly divide + // the possible values of a byte: 256 mod 36 = 4. Discard any random bytes we + // read that are >= 252 so the bytes we evenly divide the character set. + const maxByteValue = 252 + + var ( + b byte + err error + token = make([]byte, length) + ) + + reader := bufio.NewReaderSize(rand.Reader, length*2) + for i := range token { + for { + if b, err = reader.ReadByte(); err != nil { + return "", err + } + if b < maxByteValue { + break + } + } + + token[i] = validBootstrapTokenChars[int(b)%len(validBootstrapTokenChars)] } - return hex.EncodeToString(b), nil + + return string(token), nil } // GenerateToken generates a new token with a token ID that is valid as a diff --git a/cmd/kubeadm/app/util/token/tokens_test.go b/cmd/kubeadm/app/util/token/tokens_test.go index b9b617c20a7..4146a027036 100644 --- a/cmd/kubeadm/app/util/token/tokens_test.go +++ b/cmd/kubeadm/app/util/token/tokens_test.go @@ -147,8 +147,8 @@ func TestRandBytes(t *testing.T) { if err != nil { t.Errorf("failed randBytes: %v", err) } - if len(actual) != rt*2 { - t.Errorf("failed randBytes:\n\texpected: %d\n\t actual: %d\n", rt*2, len(actual)) + if len(actual) != rt { + t.Errorf("failed randBytes:\n\texpected: %d\n\t actual: %d\n", rt, len(actual)) } } }