cipher.go 3.4 KB

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