...
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24 package xts
25
26 import (
27 "crypto/cipher"
28 "encoding/binary"
29 "errors"
30 "sync"
31
32 "golang.org/x/crypto/internal/alias"
33 )
34
35
36
37 type Cipher struct {
38 k1, k2 cipher.Block
39 }
40
41
42
43 const blockSize = 16
44
45 var tweakPool = sync.Pool{
46 New: func() interface{} {
47 return new([blockSize]byte)
48 },
49 }
50
51
52
53
54 func NewCipher(cipherFunc func([]byte) (cipher.Block, error), key []byte) (c *Cipher, err error) {
55 c = new(Cipher)
56 if c.k1, err = cipherFunc(key[:len(key)/2]); err != nil {
57 return
58 }
59 c.k2, err = cipherFunc(key[len(key)/2:])
60
61 if c.k1.BlockSize() != blockSize {
62 err = errors.New("xts: cipher does not have a block size of 16")
63 }
64
65 return
66 }
67
68
69
70
71 func (c *Cipher) Encrypt(ciphertext, plaintext []byte, sectorNum uint64) {
72 if len(ciphertext) < len(plaintext) {
73 panic("xts: ciphertext is smaller than plaintext")
74 }
75 if len(plaintext)%blockSize != 0 {
76 panic("xts: plaintext is not a multiple of the block size")
77 }
78 if alias.InexactOverlap(ciphertext[:len(plaintext)], plaintext) {
79 panic("xts: invalid buffer overlap")
80 }
81
82 tweak := tweakPool.Get().(*[blockSize]byte)
83 for i := range tweak {
84 tweak[i] = 0
85 }
86 binary.LittleEndian.PutUint64(tweak[:8], sectorNum)
87
88 c.k2.Encrypt(tweak[:], tweak[:])
89
90 for len(plaintext) > 0 {
91 for j := range tweak {
92 ciphertext[j] = plaintext[j] ^ tweak[j]
93 }
94 c.k1.Encrypt(ciphertext, ciphertext)
95 for j := range tweak {
96 ciphertext[j] ^= tweak[j]
97 }
98 plaintext = plaintext[blockSize:]
99 ciphertext = ciphertext[blockSize:]
100
101 mul2(tweak)
102 }
103
104 tweakPool.Put(tweak)
105 }
106
107
108
109
110 func (c *Cipher) Decrypt(plaintext, ciphertext []byte, sectorNum uint64) {
111 if len(plaintext) < len(ciphertext) {
112 panic("xts: plaintext is smaller than ciphertext")
113 }
114 if len(ciphertext)%blockSize != 0 {
115 panic("xts: ciphertext is not a multiple of the block size")
116 }
117 if alias.InexactOverlap(plaintext[:len(ciphertext)], ciphertext) {
118 panic("xts: invalid buffer overlap")
119 }
120
121 tweak := tweakPool.Get().(*[blockSize]byte)
122 for i := range tweak {
123 tweak[i] = 0
124 }
125 binary.LittleEndian.PutUint64(tweak[:8], sectorNum)
126
127 c.k2.Encrypt(tweak[:], tweak[:])
128
129 for len(ciphertext) > 0 {
130 for j := range tweak {
131 plaintext[j] = ciphertext[j] ^ tweak[j]
132 }
133 c.k1.Decrypt(plaintext, plaintext)
134 for j := range tweak {
135 plaintext[j] ^= tweak[j]
136 }
137 plaintext = plaintext[blockSize:]
138 ciphertext = ciphertext[blockSize:]
139
140 mul2(tweak)
141 }
142
143 tweakPool.Put(tweak)
144 }
145
146
147
148 func mul2(tweak *[blockSize]byte) {
149 var carryIn byte
150 for j := range tweak {
151 carryOut := tweak[j] >> 7
152 tweak[j] = (tweak[j] << 1) + carryIn
153 carryIn = carryOut
154 }
155 if carryIn != 0 {
156
157
158
159
160
161
162 tweak[0] ^= 1<<7 | 1<<2 | 1<<1 | 1
163 }
164 }
165
View as plain text