hare

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

cbc.ha (3112B)


      1 // License: MPL-2.0
      2 // (c) 2021 Armin Preiml <apreiml@strohwolke.at>
      3 // (c) 2021 Drew DeVault <sir@cmpwn.com>
      4 use crypto::math;
      5 
      6 export type cbc_mode = struct {
      7 	b: *block,
      8 	encrypt: bool,
      9 	carry: []u8,
     10 	carrybuf: []u8,
     11 };
     12 
     13 // Creates a cipher block chaining (CBC) mode encryptor.
     14 //
     15 // The user must supply an initialization vector (IV) equal in length to the
     16 // block size of the underlying [[block]] cipher, and a temporary state buffer
     17 // whose size is equal to the block size times two. The module providing the
     18 // underlying block cipher usually provides constants which define the lengths
     19 // of these buffers for static allocation.
     20 export fn cbc_encryptor(b: *block, iv: []u8, buf: []u8) cbc_mode = {
     21 	assert(len(iv) == blocksz(b),
     22 		"len(iv) must be the same as the block size");
     23 	assert(len(buf) == blocksz(b) * 2,
     24 		"buffer needs to be two times of the block size");
     25 
     26 	const bsz = blocksz(b);
     27 	let carry = buf[0..bsz];
     28 	carry[..] = iv[..];
     29 
     30 	return cbc_mode {
     31 		b = b,
     32 		encrypt = true,
     33 		carry = carry,
     34 		carrybuf = buf[bsz..],
     35 	};
     36 };
     37 
     38 // Creates a cipher block chaining (CBC) mode decryptor.
     39 //
     40 // The user must supply an initialization vector (IV) equal in length to the
     41 // block size of the underlying [[block]] cipher, and a temporary state buffer
     42 // whose size is equal to the block size times two. The module providing the
     43 // underlying block cipher usually provides constants which define the lengths
     44 // of these buffers for static allocation.
     45 export fn cbc_decryptor(b: *block, iv: []u8, buf: []u8) cbc_mode = {
     46 	assert(len(iv) == blocksz(b),
     47 		"len(iv) must be the same as block length sz");
     48 	assert(len(buf) == blocksz(b) * 2,
     49 		"buffer needs to be two times of the block size");
     50 
     51 	const bsz = blocksz(b);
     52 	let carry = buf[0..bsz];
     53 	carry[..] = iv[..];
     54 
     55 	return cbc_mode {
     56 		b = b,
     57 		encrypt = false,
     58 		carry = carry,
     59 		carrybuf = buf[bsz..],
     60 	};
     61 };
     62 
     63 // Encrypts given blocks with a length that is a multiple of the block size.
     64 // In place encryption only works if dest and src point exactly at the
     65 // same range.
     66 export fn cbc_encrypt(c: *cbc_mode, dest: []u8, src: []u8) void = {
     67 	const sz = blocksz(c.b);
     68 	assert(c.encrypt);
     69 	assert(len(dest) % sz == 0 && len(src) == len(dest),
     70 		"size of dest and src needs to match and be a multiple of block size");
     71 
     72 	for (let i = 0z; i < len(dest); i += sz) {
     73 		let eb = i + sz;
     74 		crypto::math::xor(dest[i..eb], src[i..eb], c.carry);
     75 		encrypt(c.b, dest[i..eb], dest[i..eb]);
     76 		c.carry[..] = dest[i..eb];
     77 	};
     78 };
     79 
     80 // Decrypts given blocks with a length that is a multiple of the block size.
     81 // In place decryption only works if dest and src point exactly at the
     82 // same range.
     83 export fn cbc_decrypt(c: *cbc_mode, dest: []u8, src: []u8) void = {
     84 	const sz = blocksz(c.b);
     85 	assert(!c.encrypt);
     86 	assert(len(dest) % sz == 0 && len(src) == len(dest),
     87 		"size of dest and src needs to match and be a multiple of block size");
     88 
     89 	for (let i = 0z; i < len(dest); i += sz) {
     90 		let eb = i + sz;
     91 		c.carrybuf[..] = c.carry[..];
     92 		c.carry[..] = src[i..eb];
     93 		decrypt(c.b, dest[i..eb], src[i..eb]);
     94 		crypto::math::xor(dest[i..eb], dest[i..eb], c.carrybuf);
     95 	};
     96 };