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.
5
// Package xts implements the XTS cipher mode as specified in IEEE P1619/D16.
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.
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.
17
// XTS does not provide any authentication. An attacker can manipulate the
18
// ciphertext and randomise a block (16 bytes) of the plaintext.
20
// (Note: this package does not implement ciphertext-stealing so sectors must
21
// be a multiple of 16 bytes.)
29
// Cipher contains an expanded key structure. It doesn't contain mutable state
30
// and therefore can be used concurrently.
35
// blockSize is the block size that the underlying cipher must have. XTS is
36
// only defined for 16-byte ciphers.
39
// NewCipher creates a Cipher given a function for creating the underlying
40
// block cipher (which must have a block size of 16 bytes). The key must be
41
// twice the length of the underlying cipher's key.
42
func NewCipher(cipherFunc func([]byte) (cipher.Block, error), key []byte) (c *Cipher, err error) {
44
if c.k1, err = cipherFunc(key[:len(key)/2]); err != nil {
47
c.k2, err = cipherFunc(key[len(key)/2:])
49
if c.k1.BlockSize() != blockSize {
50
err = errors.New("xts: cipher does not have a block size of 16")
56
// Encrypt encrypts a sector of plaintext and puts the result into ciphertext.
57
// Plaintext and ciphertext may be the same slice but should not overlap.
58
// Sectors must be a multiple of 16 bytes and less than 2²⁴ bytes.
59
func (c *Cipher) Encrypt(ciphertext, plaintext []byte, sectorNum uint64) {
60
if len(ciphertext) < len(plaintext) {
61
panic("xts: ciphertext is smaller than plaintext")
63
if len(plaintext)%blockSize != 0 {
64
panic("xts: plaintext is not a multiple of the block size")
67
var tweak [blockSize]byte
68
for i := 0; i < 8; i++ {
69
tweak[i] = byte(sectorNum)
73
c.k2.Encrypt(tweak[:], tweak[:])
75
for i := 0; i < len(plaintext); i += blockSize {
76
for j := 0; j < blockSize; j++ {
77
ciphertext[i+j] = plaintext[i+j] ^ tweak[j]
79
c.k1.Encrypt(ciphertext[i:], ciphertext[i:])
80
for j := 0; j < blockSize; j++ {
81
ciphertext[i+j] ^= tweak[j]
88
// Decrypt decrypts a sector of ciphertext and puts the result into plaintext.
89
// Plaintext and ciphertext may be the same slice but should not overlap.
90
// Sectors must be a multiple of 16 bytes and less than 2²⁴ bytes.
91
func (c *Cipher) Decrypt(plaintext, ciphertext []byte, sectorNum uint64) {
92
if len(plaintext) < len(ciphertext) {
93
panic("xts: plaintext is smaller than ciphertext")
95
if len(ciphertext)%blockSize != 0 {
96
panic("xts: ciphertext is not a multiple of the block size")
99
var tweak [blockSize]byte
100
for i := 0; i < 8; i++ {
101
tweak[i] = byte(sectorNum)
105
c.k2.Encrypt(tweak[:], tweak[:])
107
for i := 0; i < len(plaintext); i += blockSize {
108
for j := 0; j < blockSize; j++ {
109
plaintext[i+j] = ciphertext[i+j] ^ tweak[j]
111
c.k1.Decrypt(plaintext[i:], plaintext[i:])
112
for j := 0; j < blockSize; j++ {
113
plaintext[i+j] ^= tweak[j]
120
// mul2 multiplies tweak by 2 in GF(2¹²⁸) with an irreducible polynomial of
121
// x¹²⁸ + x⁷ + x² + x + 1.
122
func mul2(tweak *[blockSize]byte) {
124
for j := range tweak {
125
carryOut := tweak[j] >> 7
126
tweak[j] = (tweak[j] << 1) + carryIn
130
// If we have a carry bit then we need to subtract a multiple
131
// of the irreducible polynomial (x¹²⁸ + x⁷ + x² + x + 1).
132
// By dropping the carry bit, we're subtracting the x^128 term
133
// so all that remains is to subtract x⁷ + x² + x + 1.
134
// Subtraction (and addition) in this representation is just
136
tweak[0] ^= 1<<7 | 1<<2 | 1<<1 | 1