v2 / vlib / crypto / cipher / cbc.v
133 lines · 124 sloc · 3.74 KB · 43c45d95824f378b9edc46017e3c2382ccb54bc9
Raw
1// The source code refers to the go standard library, which will be combined with AES in the future.
2
3// Use of this source code is governed by an MIT license
4// that can be found in the LICENSE file.
5// Cipher block chaining (CBC) mode.
6// CBC provides confidentiality by xoring (chaining) each plaintext block
7// with the previous ciphertext block before applying the block cipher.
8// See NIST SP 800-38A, pp 10-11
9// NOTE this will be moved to crypto.cipher interface (joe-c)
10module cipher
11
12import crypto.internal.subtle
13
14struct Cbc {
15mut:
16 b Block
17 block_size int
18 iv []u8
19 tmp []u8
20}
21
22// free the resources taken by the Cbc `x`
23@[unsafe]
24pub fn (mut x Cbc) free() {
25 $if prealloc {
26 return
27 }
28 unsafe {
29 // x.b.free() TODO add?
30 x.iv.free()
31 x.tmp.free()
32 }
33}
34
35// internal
36fn new_des_cbc(b Block, iv []u8) Cbc {
37 return Cbc{
38 b: b
39 block_size: b.block_size
40 iv: iv.clone()
41 tmp: []u8{len: b.block_size}
42 }
43}
44
45// new_cbc returns a `DesCbc` which encrypts in cipher block chaining
46// mode, using the given Block. The length of iv must be the same as the
47// Block's block size.
48pub fn new_cbc(b Block, iv []u8) Cbc {
49 if iv.len != b.block_size {
50 panic('crypto.cipher.new_cbc_encrypter: IV length must equal block size')
51 }
52 return new_des_cbc(b, iv)
53}
54
55// encrypt_blocks encrypts the blocks in `src_` to `dst_`.
56// Please note: `dst_` is mutable for performance reasons.
57pub fn (mut x Cbc) encrypt_blocks(mut dst_ []u8, src_ []u8) {
58 unsafe {
59 mut dst := *dst_
60 mut src := src_
61 if src.len % x.block_size != 0 {
62 panic('crypto.cipher: input not full blocks')
63 }
64 if dst.len < src.len {
65 panic('crypto.cipher: output smaller than input')
66 }
67 if subtle.inexact_overlap(dst[..src.len], src_) {
68 panic('crypto.cipher: invalid buffer overlap')
69 }
70 mut iv := x.iv
71 for src.len > 0 {
72 // Write the xor to dst, then encrypt in place.
73 xor_bytes(mut dst[..x.block_size], src[..x.block_size], iv)
74 x.b.encrypt(mut dst[..x.block_size], dst[..x.block_size])
75 // Move to the next block with this block as the next iv.
76 iv = dst[..x.block_size]
77 if x.block_size >= src.len {
78 src = []
79 } else {
80 src = src[x.block_size..]
81 }
82 dst = dst[x.block_size..]
83 }
84 // Save the iv for the next crypt_blocks call.
85 copy(mut x.iv, iv)
86 }
87}
88
89// decrypt_blocks decrypts the blocks in `src` to `dst`.
90// Please note: `dst` is mutable for performance reasons.
91pub fn (mut x Cbc) decrypt_blocks(mut dst []u8, src []u8) {
92 if src.len % x.block_size != 0 {
93 panic('crypto.cipher: input not full blocks')
94 }
95 if dst.len < src.len {
96 panic('crypto.cipher: output smaller than input')
97 }
98 if subtle.inexact_overlap((*dst)[..src.len], src) {
99 panic('crypto.cipher: invalid buffer overlap')
100 }
101 if src.len == 0 {
102 return
103 }
104 // For each block, we need to xor the decrypted data with the previous block's ciphertext (the iv).
105 // To avoid making a copy each time, we loop over the blocks BACKWARDS.
106 mut end := src.len
107 mut start := end - x.block_size
108 mut prev := start - x.block_size
109 // Copy the last block of ciphertext in preparation as the new iv.
110 copy(mut x.tmp, src[start..end])
111 // Loop over all but the first block.
112 for start > 0 {
113 src_chunk := src[start..end]
114 x.b.decrypt(mut (*dst)[start..end], src_chunk)
115 xor_bytes(mut (*dst)[start..end], (*dst)[start..end], src[prev..start])
116 end = start
117 start = prev
118 prev -= x.block_size
119 }
120 // The first block is special because it uses the saved iv.
121 src_chunk := src[start..end]
122 x.b.decrypt(mut (*dst)[start..end], src_chunk)
123 xor_bytes(mut (*dst)[start..end], (*dst)[start..end], x.iv)
124 // Set the new iv to the first block we copied earlier.
125 x.iv, x.tmp = x.tmp, x.iv
126}
127
128fn (mut x Cbc) set_iv(iv []u8) {
129 if iv.len != x.iv.len {
130 panic('cipher: incorrect length IV')
131 }
132 copy(mut x.iv, iv)
133}
134