Dhiru Kholia | e7913d6 | 2015-05-31 10:48:25 +0200 | [diff] [blame] | 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. |
Filippo Valsorda | a573983 | 2019-02-22 18:23:34 -0500 | [diff] [blame] | 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). |
Dhiru Kholia | e7913d6 | 2015-05-31 10:48:25 +0200 | [diff] [blame] | 16 | package tea |
| 17 | |
| 18 | import ( |
| 19 | "crypto/cipher" |
| 20 | "encoding/binary" |
| 21 | "errors" |
| 22 | ) |
| 23 | |
| 24 | const ( |
| 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. |
| 39 | type 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. |
| 46 | func 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. |
| 53 | func 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". |
| 72 | func (*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). |
| 80 | func (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. |
| 100 | func (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 | } |