Stream Cipher

假如我们有一份很重要的文件想要从本地传输到远程客户端,因为并不想让别人看见我们传输的信息,所以需要使用某种手段将传输的数据保护起来,我们可以选择先将文件加密后再进行传输,别人收到之后再进行相应的解密操作。这种方式对于小文件来说问题倒不是很大,但是如果文件体积非常大,本地对文件进行加密和远程对文件进行解密花费的时间就会很长,这样的话时间效率就非常低了,如果我们可以对该文件边加密边传输,远程客户端也可以边接收边解密的话,时间效率就可以大幅度提升了。

下面我们来引入流加密解决上述问题,流加密有很多模式,例如 CFBCTROFB 等。而流加密的核心就是异或操作,使用 XORKeyStream 就可以进行加解密了。

1
2
3
4
5
package cipher

type Stream interface {
XORKeyStream(dst, src []byte)
}

因为加密解密肯定涉及到读写操作,所以我们用一个结构体 writer 实现 io.Writer 这个接口,里面封装了一个 io.Writercipher.Stream ,基本的思路就是将数据经过 cipher.StreamXORKeyStream 方法写入 io.Writer 中。这里 buf 作为中间读操作和加密操作的缓存。

考虑到通用性,这里和下面我们使用 io.Writerio.Writer 这样的接口进行抽象操作,而非使用具体的 Writer 或者 Reader 来代替。

1
2
3
4
5
6
7
8
9
10
11
const bufSize = 32 * 1024

type writer struct {
io.Writer
cipher.Stream
buf []byte
}

func NewWriter(w io.Writer, s cipher.Stream) io.Writer {
return &writer{Writer: w, Stream: s, buf: make([]byte, bufSize)}
}
1
2
3
4
func (w *writer) Write(b []byte) (int, error) {
n, err := w.ReadFrom(bytes.NewBuffer(b))
return int(n), err
}

ReadFrom 方法使我们的 writer 不断从未加密的 io.Reader 中读取数据到 buf 中,再利用 XORKeyStream 将数据加密后写入自己的 io.Writer 中。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
func (w *writer) ReadFrom(r io.Reader) (n int64, err error) {
for {
buf := w.buf
nr, er := r.Read(buf)
if nr > 0 {
n += int64(nr)
buf = buf[:nr]
w.XORKeyStream(buf, buf)
_, ew := w.Writer.Write(buf)
if ew != nil {
err = ew
return
}
}

if er != nil {
if er != io.EOF {
err = err
}
return
}
}
}

在读方面,和写的时候类似,我们也在自己定义的结构体 reader 中包含一个 io.Readercipher.Stream ,基本思路也是从 io.Reader 中读取经过加密的数据,然后再用 cipher.StreamXORKeyStream 方法解密。

1
2
3
4
5
6
7
8
9
type reader struct {
io.Reader
cipher.Stream
buf []byte
}

func NewReader(r io.Reader, s cipher.Stream) io.Reader {
return &reader{Reader: r, Stream: s, buf: make([]byte, bufSize)}
}

下面实现的 Read 方法利用 io.Reader 读取经过加密后的数据,再利用XORKeyStream 进行解密。

1
2
3
4
5
6
7
8
9
func (r *reader) Read(b []byte) (int, error) {
n, err := r.Reader.Read(b)
if err != nil {
return 0, err
}
b = b[:n]
r.XORKeyStream(b, b)
return n, nil
}

WriteTo 方法反复使用上面的 Read 方法将数据解密后写入 io.Writer 中直到结束。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
func (r *reader) WriteTo(w io.Writer) (n int64, err error) {
for {
buf := r.buf
nr, er := r.Read(buf)
if nr > 0 {
nw, ew := w.Write(buf[:nr])
n += int64(nw)

if ew != nil {
err = ew
return
}
}
if er != nil {
if er != io.EOF {
err = er
}
return
}
}
}
Pieces of Valuable Programming Knowledges