hare

[hare] The Hare programming language
git clone https://git.torresjrjr.com/hare.git
Log | Files | Refs | README | LICENSE

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 };