hare

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

xts.ha (3027B)


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