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