File: cbc.ha

package info (click to toggle)
hare 0.25.2-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 6,948 kB
  • sloc: asm: 1,264; makefile: 123; sh: 114; lisp: 101
file content (96 lines) | stat: -rw-r--r-- 3,066 bytes parent folder | download | duplicates (2)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
// SPDX-License-Identifier: MPL-2.0
// (c) Hare authors <https://harelang.org>

use crypto::math;

export type cbc_mode = struct {
	b: *block,
	encrypt: bool,
	carry: []u8,
	carrybuf: []u8,
};

// Creates a cipher block chaining (CBC) mode encryptor.
//
// The user must supply an initialization vector (IV) equal in length to the
// block size of the underlying [[block]] cipher, and a temporary state buffer
// whose size is equal to the block size times two. The module providing the
// underlying block cipher usually provides constants which define the lengths
// of these buffers for static allocation.
export fn cbc_encryptor(b: *block, iv: []u8, buf: []u8) cbc_mode = {
	assert(len(iv) == blocksz(b),
		"len(iv) must be the same as the block size");
	assert(len(buf) == blocksz(b) * 2,
		"buffer needs to be two times of the block size");

	const bsz = blocksz(b);
	let carry = buf[0..bsz];
	carry[..] = iv[..];

	return cbc_mode {
		b = b,
		encrypt = true,
		carry = carry,
		carrybuf = buf[bsz..],
	};
};

// Creates a cipher block chaining (CBC) mode decryptor.
//
// The user must supply an initialization vector (IV) equal in length to the
// block size of the underlying [[block]] cipher, and a temporary state buffer
// whose size is equal to the block size times two. The module providing the
// underlying block cipher usually provides constants which define the lengths
// of these buffers for static allocation.
export fn cbc_decryptor(b: *block, iv: []u8, buf: []u8) cbc_mode = {
	assert(len(iv) == blocksz(b),
		"len(iv) must be the same as block length sz");
	assert(len(buf) == blocksz(b) * 2,
		"buffer needs to be two times of the block size");

	const bsz = blocksz(b);
	let carry = buf[0..bsz];
	carry[..] = iv[..];

	return cbc_mode {
		b = b,
		encrypt = false,
		carry = carry,
		carrybuf = buf[bsz..],
	};
};

// Encrypts given blocks with a length that is a multiple of the block size.
// In place encryption only works if dest and src point exactly at the
// same range.
export fn cbc_encrypt(c: *cbc_mode, dest: []u8, src: []u8) void = {
	const sz = blocksz(c.b);
	assert(c.encrypt);
	assert(len(dest) % sz == 0 && len(src) == len(dest),
		"size of dest and src needs to match and be a multiple of block size");

	for (let i = 0z; i < len(dest); i += sz) {
		let eb = i + sz;
		math::xor(dest[i..eb], src[i..eb], c.carry);
		encrypt(c.b, dest[i..eb], dest[i..eb]);
		c.carry[..] = dest[i..eb];
	};
};

// Decrypts given blocks with a length that is a multiple of the block size.
// In place decryption only works if dest and src point exactly at the
// same range.
export fn cbc_decrypt(c: *cbc_mode, dest: []u8, src: []u8) void = {
	const sz = blocksz(c.b);
	assert(!c.encrypt);
	assert(len(dest) % sz == 0 && len(src) == len(dest),
		"size of dest and src needs to match and be a multiple of block size");

	for (let i = 0z; i < len(dest); i += sz) {
		let eb = i + sz;
		c.carrybuf[..] = c.carry[..];
		c.carry[..] = src[i..eb];
		decrypt(c.b, dest[i..eb], src[i..eb]);
		math::xor(dest[i..eb], dest[i..eb], c.carrybuf);
	};
};