mirror of
https://github.com/golang/go
synced 2024-11-21 18:34:44 -07:00
crypto/cipher: add package
cipher is intended to replace crypto/block over time. This change only adds basic parts: CBC and CTR mode and doesn't add the package to the top-level Makefile. R=r, rsc CC=golang-dev https://golang.org/cl/3069041
This commit is contained in:
parent
ad21c42f05
commit
07791d04d6
14
src/pkg/crypto/cipher/Makefile
Normal file
14
src/pkg/crypto/cipher/Makefile
Normal file
@ -0,0 +1,14 @@
|
||||
# Copyright 2010 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.
|
||||
|
||||
include ../../../Make.inc
|
||||
|
||||
TARG=crypto/cipher
|
||||
GOFILES=\
|
||||
cbc.go\
|
||||
cipher.go\
|
||||
ctr.go\
|
||||
io.go
|
||||
|
||||
include ../../../Make.pkg
|
78
src/pkg/crypto/cipher/cbc.go
Normal file
78
src/pkg/crypto/cipher/cbc.go
Normal file
@ -0,0 +1,78 @@
|
||||
// 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.
|
||||
|
||||
// Cipher block chaining (CBC) mode.
|
||||
|
||||
// CBC provides confidentiality by xoring (chaining) each plaintext block
|
||||
// with the previous ciphertext block before applying the block cipher.
|
||||
|
||||
// See NIST SP 800-38A, pp 10-11
|
||||
|
||||
package cipher
|
||||
|
||||
type cbc struct {
|
||||
b Block
|
||||
blockSize int
|
||||
iv []byte
|
||||
tmp []byte
|
||||
}
|
||||
|
||||
func newCBC(b Block, iv []byte) *cbc {
|
||||
return &cbc{
|
||||
b: b,
|
||||
blockSize: b.BlockSize(),
|
||||
iv: dup(iv),
|
||||
tmp: make([]byte, b.BlockSize()),
|
||||
}
|
||||
}
|
||||
|
||||
type cbcEncrypter cbc
|
||||
|
||||
// NewCBCEncrypter returns a BlockMode which encrypts in cipher block chaining
|
||||
// mode, using the given Block. The length of iv must be the same as the
|
||||
// Block's block size.
|
||||
func NewCBCEncrypter(b Block, iv []byte) BlockMode {
|
||||
return (*cbcEncrypter)(newCBC(b, iv))
|
||||
}
|
||||
|
||||
func (x *cbcEncrypter) BlockSize() int { return x.blockSize }
|
||||
|
||||
func (x *cbcEncrypter) CryptBlocks(dst, src []byte) {
|
||||
for len(src) > 0 {
|
||||
for i := 0; i < x.blockSize; i++ {
|
||||
x.iv[i] ^= src[i]
|
||||
}
|
||||
x.b.Encrypt(x.iv, x.iv)
|
||||
for i := 0; i < x.blockSize; i++ {
|
||||
dst[i] = x.iv[i]
|
||||
}
|
||||
src = src[x.blockSize:]
|
||||
dst = dst[x.blockSize:]
|
||||
}
|
||||
}
|
||||
|
||||
type cbcDecrypter cbc
|
||||
|
||||
// NewCBCDecrypter returns a BlockMode which decrypts in cipher block chaining
|
||||
// mode, using the given Block. The length of iv must be the same as the
|
||||
// Block's block size as must match the iv used to encrypt the data.
|
||||
func NewCBCDecrypter(b Block, iv []byte) *cbcDecrypter {
|
||||
return (*cbcDecrypter)(newCBC(b, iv))
|
||||
}
|
||||
|
||||
func (x *cbcDecrypter) BlockSize() int { return x.blockSize }
|
||||
|
||||
func (x *cbcDecrypter) CryptBlocks(dst, src []byte) {
|
||||
for len(src) > 0 {
|
||||
x.b.Decrypt(x.tmp, src[:x.blockSize])
|
||||
for i := 0; i < x.blockSize; i++ {
|
||||
x.tmp[i] ^= x.iv[i]
|
||||
x.iv[i] = src[i]
|
||||
dst[i] = x.tmp[i]
|
||||
}
|
||||
|
||||
src = src[x.blockSize:]
|
||||
dst = dst[x.blockSize:]
|
||||
}
|
||||
}
|
89
src/pkg/crypto/cipher/cbc_aes_test.go
Normal file
89
src/pkg/crypto/cipher/cbc_aes_test.go
Normal file
@ -0,0 +1,89 @@
|
||||
// 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.
|
||||
|
||||
// CBC AES test vectors.
|
||||
|
||||
// See U.S. National Institute of Standards and Technology (NIST)
|
||||
// Special Publication 800-38A, ``Recommendation for Block Cipher
|
||||
// Modes of Operation,'' 2001 Edition, pp. 24-29.
|
||||
|
||||
package cipher
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"crypto/aes"
|
||||
"testing"
|
||||
)
|
||||
|
||||
var cbcAESTests = []struct {
|
||||
name string
|
||||
key []byte
|
||||
iv []byte
|
||||
in []byte
|
||||
out []byte
|
||||
}{
|
||||
// NIST SP 800-38A pp 27-29
|
||||
{
|
||||
"CBC-AES128",
|
||||
commonKey128,
|
||||
commonIV,
|
||||
commonInput,
|
||||
[]byte{
|
||||
0x76, 0x49, 0xab, 0xac, 0x81, 0x19, 0xb2, 0x46, 0xce, 0xe9, 0x8e, 0x9b, 0x12, 0xe9, 0x19, 0x7d,
|
||||
0x50, 0x86, 0xcb, 0x9b, 0x50, 0x72, 0x19, 0xee, 0x95, 0xdb, 0x11, 0x3a, 0x91, 0x76, 0x78, 0xb2,
|
||||
0x73, 0xbe, 0xd6, 0xb8, 0xe3, 0xc1, 0x74, 0x3b, 0x71, 0x16, 0xe6, 0x9e, 0x22, 0x22, 0x95, 0x16,
|
||||
0x3f, 0xf1, 0xca, 0xa1, 0x68, 0x1f, 0xac, 0x09, 0x12, 0x0e, 0xca, 0x30, 0x75, 0x86, 0xe1, 0xa7,
|
||||
},
|
||||
},
|
||||
{
|
||||
"CBC-AES192",
|
||||
commonKey192,
|
||||
commonIV,
|
||||
commonInput,
|
||||
[]byte{
|
||||
0x4f, 0x02, 0x1d, 0xb2, 0x43, 0xbc, 0x63, 0x3d, 0x71, 0x78, 0x18, 0x3a, 0x9f, 0xa0, 0x71, 0xe8,
|
||||
0xb4, 0xd9, 0xad, 0xa9, 0xad, 0x7d, 0xed, 0xf4, 0xe5, 0xe7, 0x38, 0x76, 0x3f, 0x69, 0x14, 0x5a,
|
||||
0x57, 0x1b, 0x24, 0x20, 0x12, 0xfb, 0x7a, 0xe0, 0x7f, 0xa9, 0xba, 0xac, 0x3d, 0xf1, 0x02, 0xe0,
|
||||
0x08, 0xb0, 0xe2, 0x79, 0x88, 0x59, 0x88, 0x81, 0xd9, 0x20, 0xa9, 0xe6, 0x4f, 0x56, 0x15, 0xcd,
|
||||
},
|
||||
},
|
||||
{
|
||||
"CBC-AES256",
|
||||
commonKey256,
|
||||
commonIV,
|
||||
commonInput,
|
||||
[]byte{
|
||||
0xf5, 0x8c, 0x4c, 0x04, 0xd6, 0xe5, 0xf1, 0xba, 0x77, 0x9e, 0xab, 0xfb, 0x5f, 0x7b, 0xfb, 0xd6,
|
||||
0x9c, 0xfc, 0x4e, 0x96, 0x7e, 0xdb, 0x80, 0x8d, 0x67, 0x9f, 0x77, 0x7b, 0xc6, 0x70, 0x2c, 0x7d,
|
||||
0x39, 0xf2, 0x33, 0x69, 0xa9, 0xd9, 0xba, 0xcf, 0xa5, 0x30, 0xe2, 0x63, 0x04, 0x23, 0x14, 0x61,
|
||||
0xb2, 0xeb, 0x05, 0xe2, 0xc3, 0x9b, 0xe9, 0xfc, 0xda, 0x6c, 0x19, 0x07, 0x8c, 0x6a, 0x9d, 0x1b,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
func TestCBC_AES(t *testing.T) {
|
||||
for _, tt := range cbcAESTests {
|
||||
test := tt.name
|
||||
|
||||
c, err := aes.NewCipher(tt.key)
|
||||
if err != nil {
|
||||
t.Errorf("%s: NewCipher(%d bytes) = %s", test, len(tt.key), err)
|
||||
continue
|
||||
}
|
||||
|
||||
encrypter := NewCBCEncrypter(c, tt.iv)
|
||||
d := make([]byte, len(tt.in))
|
||||
encrypter.CryptBlocks(d, tt.in)
|
||||
if !bytes.Equal(tt.out, d) {
|
||||
t.Errorf("%s: CBCEncrypter\nhave %x\nwant %x", test, d, tt.out)
|
||||
}
|
||||
|
||||
decrypter := NewCBCDecrypter(c, tt.iv)
|
||||
p := make([]byte, len(d))
|
||||
decrypter.CryptBlocks(p, d)
|
||||
if !bytes.Equal(tt.in, p) {
|
||||
t.Errorf("%s: CBCDecrypter\nhave %x\nwant %x", test, d, tt.in)
|
||||
}
|
||||
}
|
||||
}
|
63
src/pkg/crypto/cipher/cipher.go
Normal file
63
src/pkg/crypto/cipher/cipher.go
Normal file
@ -0,0 +1,63 @@
|
||||
// Copyright 2010 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.
|
||||
|
||||
// The cipher package implements standard block cipher modes
|
||||
// that can be wrapped around low-level block cipher implementations.
|
||||
// See http://csrc.nist.gov/groups/ST/toolkit/BCM/current_modes.html
|
||||
// and NIST Special Publication 800-38A.
|
||||
package cipher
|
||||
|
||||
// A Block represents an implementation of block cipher
|
||||
// using a given key. It provides the capability to encrypt
|
||||
// or decrypt individual blocks. The mode implementations
|
||||
// extend that capability to streams of blocks.
|
||||
type Block interface {
|
||||
// BlockSize returns the cipher's block size.
|
||||
BlockSize() int
|
||||
|
||||
// Encrypt encrypts the first block in src into dst.
|
||||
// Dst and src may point at the same memory.
|
||||
Encrypt(dst, src []byte)
|
||||
|
||||
// Decrypt decrypts the first block in src into dst.
|
||||
// Dst and src may point at the same memory.
|
||||
Decrypt(dst, src []byte)
|
||||
}
|
||||
|
||||
// A Stream represents a stream cipher.
|
||||
type Stream interface {
|
||||
// XORKeyStream XORs each byte in the given slice with a byte from the
|
||||
// cipher's key stream. Dst and src may point to the same memory.
|
||||
XORKeyStream(dst, src []byte)
|
||||
}
|
||||
|
||||
// A BlockMode represents a block cipher running in a block-based mode (CBC,
|
||||
// ECB etc).
|
||||
type BlockMode interface {
|
||||
// BlockSize returns the mode's block size.
|
||||
BlockSize() int
|
||||
|
||||
// CryptBlocks encrypts or decrypts a number of blocks. The length of
|
||||
// src must be a multiple of the block size. Dst and src may point to
|
||||
// the same memory.
|
||||
CryptBlocks(dst, src []byte)
|
||||
}
|
||||
|
||||
// Utility routines
|
||||
|
||||
func shift1(dst, src []byte) byte {
|
||||
var b byte
|
||||
for i := len(src) - 1; i >= 0; i-- {
|
||||
bb := src[i] >> 7
|
||||
dst[i] = src[i]<<1 | b
|
||||
b = bb
|
||||
}
|
||||
return b
|
||||
}
|
||||
|
||||
func dup(p []byte) []byte {
|
||||
q := make([]byte, len(p))
|
||||
copy(q, p)
|
||||
return q
|
||||
}
|
28
src/pkg/crypto/cipher/common_test.go
Normal file
28
src/pkg/crypto/cipher/common_test.go
Normal file
@ -0,0 +1,28 @@
|
||||
// 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.
|
||||
|
||||
package cipher
|
||||
|
||||
// Common values for tests.
|
||||
|
||||
var commonInput = []byte{
|
||||
0x6b, 0xc1, 0xbe, 0xe2, 0x2e, 0x40, 0x9f, 0x96, 0xe9, 0x3d, 0x7e, 0x11, 0x73, 0x93, 0x17, 0x2a,
|
||||
0xae, 0x2d, 0x8a, 0x57, 0x1e, 0x03, 0xac, 0x9c, 0x9e, 0xb7, 0x6f, 0xac, 0x45, 0xaf, 0x8e, 0x51,
|
||||
0x30, 0xc8, 0x1c, 0x46, 0xa3, 0x5c, 0xe4, 0x11, 0xe5, 0xfb, 0xc1, 0x19, 0x1a, 0x0a, 0x52, 0xef,
|
||||
0xf6, 0x9f, 0x24, 0x45, 0xdf, 0x4f, 0x9b, 0x17, 0xad, 0x2b, 0x41, 0x7b, 0xe6, 0x6c, 0x37, 0x10,
|
||||
}
|
||||
|
||||
var commonKey128 = []byte{0x2b, 0x7e, 0x15, 0x16, 0x28, 0xae, 0xd2, 0xa6, 0xab, 0xf7, 0x15, 0x88, 0x09, 0xcf, 0x4f, 0x3c}
|
||||
|
||||
var commonKey192 = []byte{
|
||||
0x8e, 0x73, 0xb0, 0xf7, 0xda, 0x0e, 0x64, 0x52, 0xc8, 0x10, 0xf3, 0x2b, 0x80, 0x90, 0x79, 0xe5,
|
||||
0x62, 0xf8, 0xea, 0xd2, 0x52, 0x2c, 0x6b, 0x7b,
|
||||
}
|
||||
|
||||
var commonKey256 = []byte{
|
||||
0x60, 0x3d, 0xeb, 0x10, 0x15, 0xca, 0x71, 0xbe, 0x2b, 0x73, 0xae, 0xf0, 0x85, 0x7d, 0x77, 0x81,
|
||||
0x1f, 0x35, 0x2c, 0x07, 0x3b, 0x61, 0x08, 0xd7, 0x2d, 0x98, 0x10, 0xa3, 0x09, 0x14, 0xdf, 0xf4,
|
||||
}
|
||||
|
||||
var commonIV = []byte{0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f}
|
51
src/pkg/crypto/cipher/ctr.go
Normal file
51
src/pkg/crypto/cipher/ctr.go
Normal file
@ -0,0 +1,51 @@
|
||||
// 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.
|
||||
|
||||
// Counter (CTR) mode.
|
||||
|
||||
// CTR converts a block cipher into a stream cipher by
|
||||
// repeatedly encrypting an incrementing counter and
|
||||
// xoring the resulting stream of data with the input.
|
||||
|
||||
// See NIST SP 800-38A, pp 13-15
|
||||
|
||||
package cipher
|
||||
|
||||
type ctr struct {
|
||||
b Block
|
||||
ctr []byte
|
||||
out []byte
|
||||
outUsed int
|
||||
}
|
||||
|
||||
// NewCTR returns a Stream which encrypts/decrypts using the given Block in
|
||||
// counter mode. The length of iv must be the same as the Block's block size.
|
||||
func NewCTR(block Block, iv []byte) Stream {
|
||||
return &ctr{
|
||||
b: block,
|
||||
ctr: dup(iv),
|
||||
out: make([]byte, len(iv)),
|
||||
outUsed: len(iv),
|
||||
}
|
||||
}
|
||||
|
||||
func (x *ctr) XORKeyStream(dst, src []byte) {
|
||||
for i := 0; i < len(src); i++ {
|
||||
if x.outUsed == len(x.ctr) {
|
||||
x.b.Encrypt(x.out, x.ctr)
|
||||
x.outUsed = 0
|
||||
|
||||
// Increment counter
|
||||
for i := len(x.ctr) - 1; i >= 0; i-- {
|
||||
x.ctr[i]++
|
||||
if x.ctr[i] != 0 {
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
dst[i] = src[i] ^ x.out[x.outUsed]
|
||||
x.outUsed++
|
||||
}
|
||||
}
|
101
src/pkg/crypto/cipher/ctr_aes_test.go
Normal file
101
src/pkg/crypto/cipher/ctr_aes_test.go
Normal file
@ -0,0 +1,101 @@
|
||||
// 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.
|
||||
|
||||
// CTR AES test vectors.
|
||||
|
||||
// See U.S. National Institute of Standards and Technology (NIST)
|
||||
// Special Publication 800-38A, ``Recommendation for Block Cipher
|
||||
// Modes of Operation,'' 2001 Edition, pp. 55-58.
|
||||
|
||||
package cipher
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"crypto/aes"
|
||||
"testing"
|
||||
)
|
||||
|
||||
var commonCounter = []byte{0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff}
|
||||
|
||||
var ctrAESTests = []struct {
|
||||
name string
|
||||
key []byte
|
||||
iv []byte
|
||||
in []byte
|
||||
out []byte
|
||||
}{
|
||||
// NIST SP 800-38A pp 55-58
|
||||
{
|
||||
"CTR-AES128",
|
||||
commonKey128,
|
||||
commonCounter,
|
||||
commonInput,
|
||||
[]byte{
|
||||
0x87, 0x4d, 0x61, 0x91, 0xb6, 0x20, 0xe3, 0x26, 0x1b, 0xef, 0x68, 0x64, 0x99, 0x0d, 0xb6, 0xce,
|
||||
0x98, 0x06, 0xf6, 0x6b, 0x79, 0x70, 0xfd, 0xff, 0x86, 0x17, 0x18, 0x7b, 0xb9, 0xff, 0xfd, 0xff,
|
||||
0x5a, 0xe4, 0xdf, 0x3e, 0xdb, 0xd5, 0xd3, 0x5e, 0x5b, 0x4f, 0x09, 0x02, 0x0d, 0xb0, 0x3e, 0xab,
|
||||
0x1e, 0x03, 0x1d, 0xda, 0x2f, 0xbe, 0x03, 0xd1, 0x79, 0x21, 0x70, 0xa0, 0xf3, 0x00, 0x9c, 0xee,
|
||||
},
|
||||
},
|
||||
{
|
||||
"CTR-AES192",
|
||||
commonKey192,
|
||||
commonCounter,
|
||||
commonInput,
|
||||
[]byte{
|
||||
0x1a, 0xbc, 0x93, 0x24, 0x17, 0x52, 0x1c, 0xa2, 0x4f, 0x2b, 0x04, 0x59, 0xfe, 0x7e, 0x6e, 0x0b,
|
||||
0x09, 0x03, 0x39, 0xec, 0x0a, 0xa6, 0xfa, 0xef, 0xd5, 0xcc, 0xc2, 0xc6, 0xf4, 0xce, 0x8e, 0x94,
|
||||
0x1e, 0x36, 0xb2, 0x6b, 0xd1, 0xeb, 0xc6, 0x70, 0xd1, 0xbd, 0x1d, 0x66, 0x56, 0x20, 0xab, 0xf7,
|
||||
0x4f, 0x78, 0xa7, 0xf6, 0xd2, 0x98, 0x09, 0x58, 0x5a, 0x97, 0xda, 0xec, 0x58, 0xc6, 0xb0, 0x50,
|
||||
},
|
||||
},
|
||||
{
|
||||
"CTR-AES256",
|
||||
commonKey256,
|
||||
commonCounter,
|
||||
commonInput,
|
||||
[]byte{
|
||||
0x60, 0x1e, 0xc3, 0x13, 0x77, 0x57, 0x89, 0xa5, 0xb7, 0xa7, 0xf5, 0x04, 0xbb, 0xf3, 0xd2, 0x28,
|
||||
0xf4, 0x43, 0xe3, 0xca, 0x4d, 0x62, 0xb5, 0x9a, 0xca, 0x84, 0xe9, 0x90, 0xca, 0xca, 0xf5, 0xc5,
|
||||
0x2b, 0x09, 0x30, 0xda, 0xa2, 0x3d, 0xe9, 0x4c, 0xe8, 0x70, 0x17, 0xba, 0x2d, 0x84, 0x98, 0x8d,
|
||||
0xdf, 0xc9, 0xc5, 0x8d, 0xb6, 0x7a, 0xad, 0xa6, 0x13, 0xc2, 0xdd, 0x08, 0x45, 0x79, 0x41, 0xa6,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
func TestCTR_AES(t *testing.T) {
|
||||
for _, tt := range ctrAESTests {
|
||||
test := tt.name
|
||||
|
||||
c, err := aes.NewCipher(tt.key)
|
||||
if err != nil {
|
||||
t.Errorf("%s: NewCipher(%d bytes) = %s", test, len(tt.key), err)
|
||||
continue
|
||||
}
|
||||
|
||||
for j := 0; j <= 5; j += 5 {
|
||||
in := tt.in[0 : len(tt.in)-j]
|
||||
ctr := NewCTR(c, tt.iv)
|
||||
encrypted := make([]byte, len(in))
|
||||
ctr.XORKeyStream(encrypted, in)
|
||||
if out := tt.out[0:len(in)]; !bytes.Equal(out, encrypted) {
|
||||
t.Errorf("%s/%d: CTR\ninpt %x\nhave %x\nwant %x", test, len(in), in, encrypted, out)
|
||||
}
|
||||
}
|
||||
|
||||
for j := 0; j <= 7; j += 7 {
|
||||
in := tt.out[0 : len(tt.out)-j]
|
||||
ctr := NewCTR(c, tt.iv)
|
||||
plain := make([]byte, len(in))
|
||||
ctr.XORKeyStream(plain, in)
|
||||
if out := tt.in[0:len(in)]; !bytes.Equal(out, plain) {
|
||||
t.Errorf("%s/%d: CTRReader\nhave %x\nwant %x", test, len(out), plain, out)
|
||||
}
|
||||
}
|
||||
|
||||
if t.Failed() {
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
57
src/pkg/crypto/cipher/io.go
Normal file
57
src/pkg/crypto/cipher/io.go
Normal file
@ -0,0 +1,57 @@
|
||||
// Copyright 2010 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.
|
||||
|
||||
package cipher
|
||||
|
||||
import (
|
||||
"os"
|
||||
"io"
|
||||
)
|
||||
|
||||
// The Stream* objects are so simple that all their members are public. Users
|
||||
// can create them themselves.
|
||||
|
||||
// StreamReader wraps a Stream into an io.Reader. It simply calls XORKeyStream
|
||||
// to process each slice of data which passes through.
|
||||
type StreamReader struct {
|
||||
S Stream
|
||||
R io.Reader
|
||||
}
|
||||
|
||||
func (r StreamReader) Read(dst []byte) (n int, err os.Error) {
|
||||
n, err = r.R.Read(dst)
|
||||
r.S.XORKeyStream(dst[:n], dst[:n])
|
||||
return
|
||||
}
|
||||
|
||||
// StreamWriter wraps a Stream into an io.Writer. It simply calls XORKeyStream
|
||||
// to process each slice of data which passes through. If any Write call
|
||||
// returns short then the StreamWriter is out of sync and must be discarded.
|
||||
type StreamWriter struct {
|
||||
S Stream
|
||||
W io.Writer
|
||||
Err os.Error
|
||||
}
|
||||
|
||||
func (w StreamWriter) Write(src []byte) (n int, err os.Error) {
|
||||
if w.Err != nil {
|
||||
return 0, w.Err
|
||||
}
|
||||
c := make([]byte, len(src))
|
||||
w.S.XORKeyStream(c, src)
|
||||
n, err = w.W.Write(c)
|
||||
if n != len(src) {
|
||||
if err == nil { // should never happen
|
||||
err = io.ErrShortWrite
|
||||
}
|
||||
w.Err = err
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (w StreamWriter) Close() os.Error {
|
||||
// This saves us from either requiring a WriteCloser or having a
|
||||
// StreamWriterCloser.
|
||||
return w.W.(io.Closer).Close()
|
||||
}
|
Loading…
Reference in New Issue
Block a user