v2 / vlib / crypto / cipher / ctr.v
85 lines · 76 sloc · 1.97 KB · 0a143f61dcc7fa25b2c44b285c3cf736f14a3abc
Raw
1// The source code refers to the go standard library, which will be combined with AES in the future.
2// Use of this source code is governed by an MIT license
3// that can be found in the LICENSE file.
4//
5// Counter (CTR) mode.
6//
7// CTR converts a block cipher into a stream cipher by
8// repeatedly encrypting an incrementing counter and
9// xoring the resulting stream of data with the input.
10//
11// See NIST SP 800-38A, pp 13-15
12module cipher
13
14import crypto.internal.subtle
15
16struct Ctr {
17mut:
18 b Block
19 next []u8
20 out []u8
21 out_used int
22}
23
24// free the resources taken by the Ctr `c`
25@[unsafe]
26pub fn (mut x Ctr) free() {
27 $if prealloc {
28 return
29 }
30 unsafe {
31 // x.b.free() TODO add?
32 x.out.free()
33 x.next.free()
34 }
35}
36
37// new_ctr returns a Ctr which encrypts/decrypts using the given Block in
38// counter mode. The length of iv must be the same as the Block's block size.
39pub fn new_ctr(b Block, iv []u8) Ctr {
40 block_size := b.block_size
41 if iv.len != block_size {
42 panic('cipher.new_cfb: IV length must be equal block size')
43 }
44 return Ctr{
45 b: b
46 out: []u8{len: b.block_size}
47 next: iv.clone()
48 out_used: block_size
49 }
50}
51
52// xor_key_stream xors each byte in the given slice with a byte from the key stream.
53pub fn (mut x Ctr) xor_key_stream(mut dst []u8, src []u8) {
54 unsafe {
55 mut local_dst := *dst
56 mut local_src := src
57 if local_dst.len < local_src.len {
58 panic('crypto.cipher.xor_key_stream: output smaller than input')
59 }
60
61 if subtle.inexact_overlap(local_dst[..local_src.len], local_src) {
62 panic('crypto.cipher.xor_key_stream: invalid buffer overlap')
63 }
64
65 for local_src.len > 0 {
66 if x.out_used == x.out.len {
67 x.b.encrypt(mut x.out, x.next)
68 x.out_used = 0
69 // increment counter
70 for i := x.next.len - 1; i >= 0; i-- {
71 x.next[i]++
72 if x.next[i] != 0 {
73 break
74 }
75 }
76 }
77
78 n := xor_bytes(mut local_dst, local_src, x.out[x.out_used..])
79
80 local_dst = local_dst[n..]
81 local_src = local_src[n..]
82 x.out_used += n
83 }
84 }
85}
86