<commit_before>package teams

import (
	"fmt"

	"crypto/hmac"
	"crypto/rand"
	"crypto/sha512"
	"encoding/base64"
	"encoding/hex"
	"errors"

	"golang.org/x/crypto/nacl/secretbox"
	"golang.org/x/crypto/scrypt"
	"golang.org/x/net/context"

	libkb "github.com/keybase/client/go/libkb"
	keybase1 "github.com/keybase/client/go/protocol/keybase1"
	"github.com/keybase/saltpack/encoding/basex"
)

// How many random bytes are needed to create "Invite Key" token of
// chosen alphabet and length.
const SeitanRawIKeyLength = 10

// This is expected seitan token length, the secret "Invite Key" that
// is generated on one client and distributed to another via face-to-
// face meeting, use of a trusted courier etc.
//
// We only try to distinguish Seitan tokens from normal e-mail tokens
// via length so make sure they are never the same length. Right now
// server-trust e-mail tokens are 12 characters.
const SeitanEncodedIKeyLength = 16

// Key-Base 33 encoding. lower case letters except 'l' and digits except for '0' and '1'.
const KBase33EncodeStd = "abcdefghijkmnopqrstuvwxyz23456789"

var Base33Encoding = basex.NewEncoding(KBase33EncodeStd, SeitanRawIKeyLength, "")

// "Invite Key"
type SeitanIKey string

// "Packed Encrypted Invite Key"
// All following 3 structs should be considerd one. When any changes,
// Version in PEIKey has to be bumped up.
type SeitanPEIKey struct {
	_struct               bool `codec:",toarray"`
	Version               uint
	TeamKeyGeneration     keybase1.PerTeamKeyGeneration
	RandomNonce           keybase1.BoxNonce
	EncryptedIKeyAndLabel []byte // keybase1.SeitanIKeyAndLabel MsgPacked and encrypted
}

func GenerateIKey() (ikey SeitanIKey, err error) {
	rawKey, err := libkb.RandBytes(SeitanRawIKeyLength)
	if err != nil {
		return ikey, err
	}

	var encodedKey [SeitanEncodedIKeyLength]byte
	Base33Encoding.Encode(encodedKey[:], rawKey)

	var verify [SeitanRawIKeyLength]byte
	_, err = Base33Encoding.Decode(verify[:], encodedKey[:])
	if err != nil {
		return ikey, err
	}

	if !libkb.SecureByteArrayEq(verify[:], rawKey) {
		return ikey, errors.New("Internal error - ikey encoding failed")
	}

	ikey = SeitanIKey(encodedKey[:])
	return ikey, nil
}

// GenerateIKeyFromString safely creates SeitanIKey value from
// plaintext string. Only length is checked - any 16-character token<commit_msg>don't use 'I' in the seitan token alphabet (#9794)<commit_after>package teams

import (
	"fmt"

	"crypto/hmac"
	"crypto/rand"
	"crypto/sha512"
	"encoding/base64"
	"encoding/hex"
	"errors"

	"golang.org/x/crypto/nacl/secretbox"
	"golang.org/x/crypto/scrypt"
	"golang.org/x/net/context"

	libkb "github.com/keybase/client/go/libkb"
	keybase1 "github.com/keybase/client/go/protocol/keybase1"
	"github.com/keybase/saltpack/encoding/basex"
)

// How many random bytes are needed to create "Invite Key" token of
// chosen alphabet and length.
const SeitanRawIKeyLength = 10

// This is expected seitan token length, the secret "Invite Key" that
// is generated on one client and distributed to another via face-to-
// face meeting, use of a trusted courier etc.
//
// We only try to distinguish Seitan tokens from normal e-mail tokens
// via length so make sure they are never the same length. Right now
// server-trust e-mail tokens are 12 characters.
const SeitanEncodedIKeyLength = 16

// Key-Base 32 encoding. lower case letters except 'l', 'i' and digits except for '0' and '1'.
const KBase32EncodeStd = "abcdefghjkmnopqrstuvwxyz23456789"

var Base32Encoding = basex.NewEncoding(KBase32EncodeStd, SeitanRawIKeyLength, "")

// "Invite Key"
type SeitanIKey string

// "Packed Encrypted Invite Key"
// All following 3 structs should be considerd one. When any changes,
// Version in PEIKey has to be bumped up.
type SeitanPEIKey struct {
	_struct               bool `codec:",toarray"`
	Version               uint
	TeamKeyGeneration     keybase1.PerTeamKeyGeneration
	RandomNonce           keybase1.BoxNonce
	EncryptedIKeyAndLabel []byte // keybase1.SeitanIKeyAndLabel MsgPacked and encrypted
}

func GenerateIKey() (ikey SeitanIKey, err error) {
	rawKey, err := libkb.RandBytes(SeitanRawIKeyLength)
	if err != nil {
		return ikey, err
	}

	var encodedKey [SeitanEncodedIKeyLength]byte
	Base32Encoding.Encode(encodedKey[:], rawKey)

	var verify [SeitanRawIKeyLength]byte
	_, err = Base32Encoding.Decode(verify[:], encodedKey[:])
	if err != nil {
		return ikey, err
	}

	if !libkb.SecureByteArrayEq(verify[:], rawKey) {
		return ikey, errors.New("Internal error - ikey encoding failed")
	}

	ikey = SeitanIKey(encodedKey[:])
	return ikey, nil
}

// GenerateIKeyFromString safely creates SeitanIKey value from
// plaintext string. Only length is checked - any 16-character token
{'fraction_non_alphanumeric': 0.09934056583705594, 'fraction_numerical': 0.018293980004254414, 'mean_word_length': 4.045064377682404, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 3, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '7615089', 'n_tokens_mistral': 1636, 'n_tokens_neox': 1529, 'n_words': 468}