blob: 9d8b1722400ded5d2980153a848298585cd1d48d (
plain)
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
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
|
// Copyright 2009 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// Encrypt/decrypt data by xor with a pseudo-random data stream.
package block
import (
"io"
"os"
)
// A dataStream is an interface to an unending stream of data,
// used by XorReader and XorWriter to model a pseudo-random generator.
// Calls to Next() return sequential blocks of data from the stream.
// Each call must return at least one byte: there is no EOF.
type dataStream interface {
Next() []byte
}
type xorReader struct {
r io.Reader
rand dataStream // pseudo-random
buf []byte // data available from last call to rand
}
func newXorReader(rand dataStream, r io.Reader) io.Reader {
x := new(xorReader)
x.r = r
x.rand = rand
return x
}
func (x *xorReader) Read(p []byte) (n int, err os.Error) {
n, err = x.r.Read(p)
// xor input with stream.
bp := 0
buf := x.buf
for i := 0; i < n; i++ {
if bp >= len(buf) {
buf = x.rand.Next()
bp = 0
}
p[i] ^= buf[bp]
bp++
}
x.buf = buf[bp:]
return n, err
}
type xorWriter struct {
w io.Writer
rand dataStream // pseudo-random
buf []byte // last buffer returned by rand
extra []byte // extra random data (use before buf)
work []byte // work space
}
func newXorWriter(rand dataStream, w io.Writer) io.Writer {
x := new(xorWriter)
x.w = w
x.rand = rand
x.work = make([]byte, 4096)
return x
}
func (x *xorWriter) Write(p []byte) (n int, err os.Error) {
for len(p) > 0 {
// Determine next chunk of random data
// and xor with p into x.work.
var chunk []byte
m := len(p)
if nn := len(x.extra); nn > 0 {
// extra points into work, so edit directly
if m > nn {
m = nn
}
for i := 0; i < m; i++ {
x.extra[i] ^= p[i]
}
chunk = x.extra[0:m]
} else {
// xor p ^ buf into work, refreshing buf as needed
if nn := len(x.work); m > nn {
m = nn
}
bp := 0
buf := x.buf
for i := 0; i < m; i++ {
if bp >= len(buf) {
buf = x.rand.Next()
bp = 0
}
x.work[i] = buf[bp] ^ p[i]
bp++
}
x.buf = buf[bp:]
chunk = x.work[0:m]
}
// Write chunk.
var nn int
nn, err = x.w.Write(chunk)
if nn != len(chunk) && err == nil {
err = io.ErrShortWrite
}
if nn < len(chunk) {
// Reconstruct the random bits from the unwritten
// data and save them for next time.
for i := nn; i < m; i++ {
chunk[i] ^= p[i]
}
x.extra = chunk[nn:]
}
n += nn
if err != nil {
return
}
p = p[m:]
}
return
}
|