blob: ffb76c5c4a2f4ef88db05886e1d059c30ea6a80b (
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;
}
|