1// Copyright 2015 The Go Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style
3// license that can be found in the LICENSE file.
4
5// Package tea implements the TEA algorithm, as defined in Needham and
6// Wheeler's 1994 technical report, “TEA, a Tiny Encryption Algorithm”. See
7// http://www.cix.co.uk/~klockstone/tea.pdf for details.
8//
9// TEA is a legacy cipher and its short block size makes it vulnerable to
10// birthday bound attacks (see https://sweet32.info). It should only be used
11// where compatibility with legacy systems, not security, is the goal.
12//
13// Deprecated: any new system should use AES (from crypto/aes, if necessary in
14// an AEAD mode like crypto/cipher.NewGCM) or XChaCha20-Poly1305 (from
15// golang.org/x/crypto/chacha20poly1305).
16package tea
17
18import (
19	"crypto/cipher"
20	"encoding/binary"
21	"errors"
22)
23
24const (
25	// BlockSize is the size of a TEA block, in bytes.
26	BlockSize = 8
27
28	// KeySize is the size of a TEA key, in bytes.
29	KeySize = 16
30
31	// delta is the TEA key schedule constant.
32	delta = 0x9e3779b9
33
34	// numRounds is the standard number of rounds in TEA.
35	numRounds = 64
36)
37
38// tea is an instance of the TEA cipher with a particular key.
39type tea struct {
40	key    [16]byte
41	rounds int
42}
43
44// NewCipher returns an instance of the TEA cipher with the standard number of
45// rounds. The key argument must be 16 bytes long.
46func NewCipher(key []byte) (cipher.Block, error) {
47	return NewCipherWithRounds(key, numRounds)
48}
49
50// NewCipherWithRounds returns an instance of the TEA cipher with a given
51// number of rounds, which must be even. The key argument must be 16 bytes
52// long.
53func NewCipherWithRounds(key []byte, rounds int) (cipher.Block, error) {
54	if len(key) != 16 {
55		return nil, errors.New("tea: incorrect key size")
56	}
57
58	if rounds&1 != 0 {
59		return nil, errors.New("tea: odd number of rounds specified")
60	}
61
62	c := &tea{
63		rounds: rounds,
64	}
65	copy(c.key[:], key)
66
67	return c, nil
68}
69
70// BlockSize returns the TEA block size, which is eight bytes. It is necessary
71// to satisfy the Block interface in the package "crypto/cipher".
72func (*tea) BlockSize() int {
73	return BlockSize
74}
75
76// Encrypt encrypts the 8 byte buffer src using the key in t and stores the
77// result in dst. Note that for amounts of data larger than a block, it is not
78// safe to just call Encrypt on successive blocks; instead, use an encryption
79// mode like CBC (see crypto/cipher/cbc.go).
80func (t *tea) Encrypt(dst, src []byte) {
81	e := binary.BigEndian
82	v0, v1 := e.Uint32(src), e.Uint32(src[4:])
83	k0, k1, k2, k3 := e.Uint32(t.key[0:]), e.Uint32(t.key[4:]), e.Uint32(t.key[8:]), e.Uint32(t.key[12:])
84
85	sum := uint32(0)
86	delta := uint32(delta)
87
88	for i := 0; i < t.rounds/2; i++ {
89		sum += delta
90		v0 += ((v1 << 4) + k0) ^ (v1 + sum) ^ ((v1 >> 5) + k1)
91		v1 += ((v0 << 4) + k2) ^ (v0 + sum) ^ ((v0 >> 5) + k3)
92	}
93
94	e.PutUint32(dst, v0)
95	e.PutUint32(dst[4:], v1)
96}
97
98// Decrypt decrypts the 8 byte buffer src using the key in t and stores the
99// result in dst.
100func (t *tea) Decrypt(dst, src []byte) {
101	e := binary.BigEndian
102	v0, v1 := e.Uint32(src), e.Uint32(src[4:])
103	k0, k1, k2, k3 := e.Uint32(t.key[0:]), e.Uint32(t.key[4:]), e.Uint32(t.key[8:]), e.Uint32(t.key[12:])
104
105	delta := uint32(delta)
106	sum := delta * uint32(t.rounds/2) // in general, sum = delta * n
107
108	for i := 0; i < t.rounds/2; i++ {
109		v1 -= ((v0 << 4) + k2) ^ (v0 + sum) ^ ((v0 >> 5) + k3)
110		v0 -= ((v1 << 4) + k0) ^ (v1 + sum) ^ ((v1 >> 5) + k1)
111		sum -= delta
112	}
113
114	e.PutUint32(dst, v0)
115	e.PutUint32(dst[4:], v1)
116}
117