xts.ha (2984B)
1 // SPDX-License-Identifier: MPL-2.0 2 // (c) Hare authors <https://harelang.org> 3 4 use bytes; 5 use crypto::aes; 6 use crypto::cipher; 7 8 export type block = struct { 9 b1: aes::block, 10 b2: aes::block, 11 x: [aes::BLOCKSZ]u8, 12 }; 13 14 // Creates a AES-XTS instance. Must be initialized with [[init]] and always be 15 // finished using [[finish]] to erase sensitive state from memory. 16 export fn xts() block = block { 17 b1 = aes::aes(), 18 b2 = aes::aes(), 19 ... 20 }; 21 22 // Initializes the AES-XTS instance. The key length must be 64, 48, or 32 bytes 23 // (the size of two valid AES keys). 24 export fn init(b: *block, key: []u8) void = { 25 assert(len(key) == 64 || len(key) == 48 || len(key) == 32, 26 "invalid key size"); 27 let sep: size = len(key) / 2; 28 29 aes::init(&b.b1, key[..sep]); 30 aes::init(&b.b2, key[sep..]); 31 }; 32 33 def GF_128_FDBK: u8 = 0x87; 34 35 // Encrypts a block given its 'sector' number. The block must be a multiple of 36 // [[crypto::aes::BLOCKSZ]] (16 bytes) in length. 37 export fn encrypt(b: *block, dest: []u8, src: []u8, sector: u64) void = { 38 assert(len(src) == len(dest) && len(src) % aes::BLOCKSZ == 0); 39 40 let tweak: [aes::BLOCKSZ]u8 = [0...]; 41 let carryin: u8 = 0; 42 let carryout: u8 = 0; 43 44 for (let j = 0z; j < len(tweak); j += 1) { 45 tweak[j] = (sector & 0xFF): u8; 46 sector >>= 8; 47 }; 48 49 cipher::encrypt(&b.b2, tweak, tweak); 50 51 let i = 0z; 52 for (i + aes::BLOCKSZ <= len(src); i += aes::BLOCKSZ) { 53 for (let j = 0z; j < aes::BLOCKSZ; j += 1) { 54 b.x[j] = src[i + j] ^ tweak[j]; 55 }; 56 57 cipher::encrypt(&b.b1, b.x, b.x); 58 59 for (let j = 0z; j < aes::BLOCKSZ; j += 1) { 60 dest[i + j] = b.x[j] ^ tweak[j]; 61 }; 62 63 // multiply primitive 64 carryin = 0; 65 for (let j = 0z; j < aes::BLOCKSZ; j += 1) { 66 carryout = (tweak[j] >> 7) & 1; 67 tweak[j] = ((tweak[j] << 1) + carryin) & 0xff; 68 carryin = carryout; 69 }; 70 71 if (carryout != 0) { 72 tweak[0] ^= GF_128_FDBK; 73 }; 74 }; 75 }; 76 77 // Decrypts a block given its 'sector' number. 78 export fn decrypt(b: *block, dest: []u8, src: []u8, sector: u64) void = { 79 assert(len(src) == len(dest) && len(src) % aes::BLOCKSZ == 0); 80 81 let tweak: [aes::BLOCKSZ]u8 = [0...]; 82 let carryin: u8 = 0; 83 let carryout: u8 = 0; 84 85 for (let j = 0z; j < len(tweak); j += 1) { 86 tweak[j] = (sector & 0xFF): u8; 87 sector >>= 8; 88 }; 89 90 cipher::encrypt(&b.b2, tweak, tweak); 91 92 let i = 0z; 93 for (i + aes::BLOCKSZ <= len(src); i += aes::BLOCKSZ) { 94 for (let j = 0z; j < aes::BLOCKSZ; j += 1) { 95 b.x[j] = src[i + j] ^ tweak[j]; 96 }; 97 98 cipher::decrypt(&b.b1, b.x, b.x); 99 100 for (let j = 0z; j < aes::BLOCKSZ; j += 1) { 101 dest[i + j] = b.x[j] ^ tweak[j]; 102 }; 103 104 105 // multiply primitive 106 carryin = 0; 107 for (let j = 0z; j < aes::BLOCKSZ; j += 1) { 108 carryout = (tweak[j] >> 7) & 1; 109 tweak[j] = ((tweak[j] << 1) + carryin) & 0xff; 110 carryin = carryout; 111 }; 112 113 if (carryout != 0) { 114 tweak[0] ^= GF_128_FDBK; 115 }; 116 }; 117 }; 118 119 // Clears the sensible data of AES-XTS instance off the memory. 120 export fn finish(b: *block) void = { 121 cipher::finish(&b.b1); 122 cipher::finish(&b.b2); 123 bytes::zero(b.x); 124 };