1// Copyright 2012 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 xts implements the XTS cipher mode as specified in IEEE P1619/D16.
6//
7// XTS mode is typically used for disk encryption, which presents a number of
8// novel problems that make more common modes inapplicable. The disk is
9// conceptually an array of sectors and we must be able to encrypt and decrypt
10// a sector in isolation. However, an attacker must not be able to transpose
11// two sectors of plaintext by transposing their ciphertext.
12//
13// XTS wraps a block cipher with Rogaway's XEX mode in order to build a
14// tweakable block cipher. This allows each sector to have a unique tweak and
15// effectively create a unique key for each sector.
16//
17// XTS does not provide any authentication. An attacker can manipulate the
18// ciphertext and randomise a block (16 bytes) of the plaintext. This package
19// does not implement ciphertext-stealing so sectors must be a multiple of 16
20// bytes.
21//
22// Note that XTS is usually not appropriate for any use besides disk encryption.
23// Most users should use an AEAD mode like GCM (from crypto/cipher.NewGCM) instead.
24package xts // import "golang.org/x/crypto/xts"
25
26import (
27	"crypto/cipher"
28	"encoding/binary"
29	"errors"
30	"sync"
31
32	"golang.org/x/crypto/internal/subtle"
33)
34
35// Cipher contains an expanded key structure. It is safe for concurrent use if
36// the underlying block cipher is safe for concurrent use.
37type Cipher struct {
38	k1, k2 cipher.Block
39}
40
41// blockSize is the block size that the underlying cipher must have. XTS is
42// only defined for 16-byte ciphers.
43const blockSize = 16
44
45var tweakPool = sync.Pool{
46	New: func() interface{} {
47		return new([blockSize]byte)
48	},
49}
50
51// NewCipher creates a Cipher given a function for creating the underlying
52// block cipher (which must have a block size of 16 bytes). The key must be
53// twice the length of the underlying cipher's key.
54func 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// Encrypt encrypts a sector of plaintext and puts the result into ciphertext.
69// Plaintext and ciphertext must overlap entirely or not at all.
70// Sectors must be a multiple of 16 bytes and less than 2²⁴ bytes.
71func (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 subtle.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// Decrypt decrypts a sector of ciphertext and puts the result into plaintext.
108// Plaintext and ciphertext must overlap entirely or not at all.
109// Sectors must be a multiple of 16 bytes and less than 2²⁴ bytes.
110func (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 subtle.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// mul2 multiplies tweak by 2 in GF(2¹²⁸) with an irreducible polynomial of
147// x¹²⁸ + x⁷ + x² + x + 1.
148func 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		// If we have a carry bit then we need to subtract a multiple
157		// of the irreducible polynomial (x¹²⁸ + x⁷ + x² + x + 1).
158		// By dropping the carry bit, we're subtracting the x^128 term
159		// so all that remains is to subtract x⁷ + x² + x + 1.
160		// Subtraction (and addition) in this representation is just
161		// XOR.
162		tweak[0] ^= 1<<7 | 1<<2 | 1<<1 | 1
163	}
164}
165