Makefile: Fix order of arguments in linker call
[dmsetup-tc.git] / xts.c
blobf036ecac9b91a75ddfb207bcedd0e86ca283a35d
1 /*
2 * xts.c: AES-XTS implementation
4 * Copyright (C) 2008 Jan Krueger <jk@jk.gs>
6 * This file is part of dmsetup-tc.
8 * dmsetup-tc is free software: you can redistribute it and/or
9 * modify it under the terms of the GNU General Public License as
10 * published by the Free Software Foundation, either version 3 of the
11 * License, or (at your option) any later version.
13 * dmsetup-tc is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * General Public License for more details.
18 * You should have received a copy of the GNU General Public License along
19 * with dmsetup-tc. If not, see <http://www.gnu.org/licenses/>.
22 #include <errno.h>
23 #include <gcrypt.h>
24 #include <string.h>
26 #include "xts.h"
29 * This is a partial implementation of AES-XTS (using libgcrypt for
30 * AES-256). Care was taken to keep the code readable. The algorithm is
31 * explained in various comments.
33 * GLOSSARY
34 * ========
36 * Block
37 * "Chain-encrypted" blocks of data inside a _data unit_.
39 * Data unit
40 * Separately encrypted units of data, e.g. disk sectors. Each data unit
41 * uses a different _tweak_ for decryption to prevent a variety of
42 * attacks.
44 * Tweak
45 * Usually something like a sector number. More generally, a series of
46 * positive numbers starting at a certain point and increasing by one
47 * for each new data unit.
49 * CAVEATS
50 * =======
52 * This code only works on little-endian systems. Fix xts_shift if you care.
54 * Ciphertext stealing is not supported, i.e. the data unit size better be
55 * divisible by the block size.
57 * For simplicity, we limit the tweak to 32 bit values. This is sufficient
58 * for disk encryption for disk sectors below 2 terabytes.
60 * We always assume we're starting to decrypt at the first block, i.e. block
61 * index = 0.
64 #define XTS_BLOCKSIZE 16
66 typedef unsigned int *xts_block32;
68 const char *aes_xts_err;
69 const char *aes_xts_errsrc;
72 * Performs one left shift of the encrypted tweak. We call this after each
73 * round of block decryption so that the value gets shifted further each
74 * time.
76 static void xts_shift(xts_block32 b)
78 unsigned int x = (b[3] & 0x80000000) ? 135 : 0;
79 b[3] <<= 1; if (b[2] & 0x80000000) b[3] |= 1;
80 b[2] <<= 1; if (b[1] & 0x80000000) b[2] |= 1;
81 b[1] <<= 1; if (b[0] & 0x80000000) b[1] |= 1;
82 b[0] <<= 1; b[0] ^= x;
84 static void xts_xor(xts_block32 dst, xts_block32 src)
86 dst[3] ^= src[3];
87 dst[2] ^= src[2];
88 dst[1] ^= src[1];
89 dst[0] ^= src[0];
93 * Decrypts a series of blocks. Works in-place if so desired by setting
94 * cipher to NULL (in which case existing ciphertext will be taken from
95 * plain). Of course, overlapping buffers are evil scary verboten). Be sure
96 * to initialize libgcrypt beforehand, too (and have it init secure memory).
98 int aes_xts_decrypt(unsigned char *key, unsigned char *cipher, int numblocks,
99 unsigned int tweak, unsigned char *plain)
101 char buf[16];
102 xts_block32 etweak;
103 gcry_cipher_hd_t hd;
104 gcry_error_t err;
105 int i;
108 * XTS actually uses twice the key size of the underlying cipher.
109 * The second half of the key is used to encrypt the tweak.
111 char *key2 = (char *) &key[32];
113 etweak = (xts_block32) buf;
114 memset(etweak, 0, 16);
115 etweak[0] = tweak;
117 #define _xts_checkerr(c, x) {err = c;\
118 if (0 != gcry_err_code(err)) {\
119 errno = gcry_err_code_to_errno(err);\
120 aes_xts_err = gcry_strerror(err);\
121 aes_xts_errsrc = gcry_strsource(err);\
122 if (x) gcry_cipher_close(x);\
123 return -1;\
126 _xts_checkerr(gcry_cipher_open(&hd, GCRY_CIPHER_AES256,
127 GCRY_CIPHER_MODE_ECB, GCRY_CIPHER_SECURE), 0);
128 _xts_checkerr(gcry_cipher_setkey(hd, key2, 32), hd);
129 _xts_checkerr(gcry_cipher_encrypt(hd, etweak, XTS_BLOCKSIZE, NULL,
130 0), hd);
132 /* For the rest we use the main key, i.e. the first half. */
133 _xts_checkerr(gcry_cipher_setkey(hd, key, 32), hd);
135 for (i = 0; i < numblocks; i++) {
136 if (cipher) {
137 xts_xor((xts_block32) cipher, etweak);
138 _xts_checkerr(gcry_cipher_decrypt(hd, plain,
139 XTS_BLOCKSIZE, cipher, XTS_BLOCKSIZE), hd);
140 cipher += XTS_BLOCKSIZE;
141 } else {
142 xts_xor((xts_block32) plain, etweak);
143 _xts_checkerr(gcry_cipher_decrypt(hd, plain,
144 XTS_BLOCKSIZE, NULL, 0), hd);
146 xts_xor((xts_block32) plain, etweak);
147 plain += XTS_BLOCKSIZE;
148 xts_shift(etweak);
151 gcry_cipher_close(hd);
152 return 0;