Commit 405ca104 by Ian Lance Taylor

libgo: Update to current Go library.

From-SVN: r172106
parent a751005d
342e3b11f21a f618e5e0991d
The first line of this file holds the Mercurial revision number of the The first line of this file holds the Mercurial revision number of the
last merge done from the master library sources. last merge done from the master library sources.
...@@ -177,10 +177,10 @@ toolexeclibgocryptodir = $(toolexeclibgodir)/crypto ...@@ -177,10 +177,10 @@ toolexeclibgocryptodir = $(toolexeclibgodir)/crypto
toolexeclibgocrypto_DATA = \ toolexeclibgocrypto_DATA = \
crypto/aes.gox \ crypto/aes.gox \
crypto/block.gox \
crypto/blowfish.gox \ crypto/blowfish.gox \
crypto/cast5.gox \ crypto/cast5.gox \
crypto/cipher.gox \ crypto/cipher.gox \
crypto/des.gox \
crypto/dsa.gox \ crypto/dsa.gox \
crypto/ecdsa.gox \ crypto/ecdsa.gox \
crypto/elliptic.gox \ crypto/elliptic.gox \
...@@ -727,9 +727,12 @@ go_os_files = \ ...@@ -727,9 +727,12 @@ go_os_files = \
go/os/env.go \ go/os/env.go \
go/os/env_unix.go \ go/os/env_unix.go \
go/os/error.go \ go/os/error.go \
go/os/error_posix.go \
go/os/exec.go \ go/os/exec.go \
go/os/exec_posix.go \
go/os/exec_unix.go \ go/os/exec_unix.go \
go/os/file.go \ go/os/file.go \
go/os/file_posix.go \
go/os/file_unix.go \ go/os/file_unix.go \
go/os/getwd.go \ go/os/getwd.go \
go/os/path.go \ go/os/path.go \
...@@ -932,16 +935,6 @@ go_crypto_aes_files = \ ...@@ -932,16 +935,6 @@ go_crypto_aes_files = \
go/crypto/aes/block.go \ go/crypto/aes/block.go \
go/crypto/aes/cipher.go \ go/crypto/aes/cipher.go \
go/crypto/aes/const.go go/crypto/aes/const.go
go_crypto_block_files = \
go/crypto/block/cbc.go \
go/crypto/block/cfb.go \
go/crypto/block/cmac.go \
go/crypto/block/cipher.go \
go/crypto/block/ctr.go \
go/crypto/block/eax.go \
go/crypto/block/ecb.go \
go/crypto/block/ofb.go \
go/crypto/block/xor.go
go_crypto_blowfish_files = \ go_crypto_blowfish_files = \
go/crypto/blowfish/block.go \ go/crypto/blowfish/block.go \
go/crypto/blowfish/const.go \ go/crypto/blowfish/const.go \
...@@ -956,6 +949,10 @@ go_crypto_cipher_files = \ ...@@ -956,6 +949,10 @@ go_crypto_cipher_files = \
go/crypto/cipher/io.go \ go/crypto/cipher/io.go \
go/crypto/cipher/ocfb.go \ go/crypto/cipher/ocfb.go \
go/crypto/cipher/ofb.go go/crypto/cipher/ofb.go
go_crypto_des_files = \
go/crypto/des/block.go \
go/crypto/des/cipher.go \
go/crypto/des/const.go
go_crypto_dsa_files = \ go_crypto_dsa_files = \
go/crypto/dsa/dsa.go go/crypto/dsa/dsa.go
go_crypto_ecdsa_files = \ go_crypto_ecdsa_files = \
...@@ -1428,10 +1425,10 @@ libgo_go_objs = \ ...@@ -1428,10 +1425,10 @@ libgo_go_objs = \
container/ring.lo \ container/ring.lo \
container/vector.lo \ container/vector.lo \
crypto/aes.lo \ crypto/aes.lo \
crypto/block.lo \
crypto/blowfish.lo \ crypto/blowfish.lo \
crypto/cast5.lo \ crypto/cast5.lo \
crypto/cipher.lo \ crypto/cipher.lo \
crypto/des.lo \
crypto/dsa.lo \ crypto/dsa.lo \
crypto/ecdsa.lo \ crypto/ecdsa.lo \
crypto/elliptic.lo \ crypto/elliptic.lo \
...@@ -2026,13 +2023,6 @@ crypto/aes/check: $(CHECK_DEPS) ...@@ -2026,13 +2023,6 @@ crypto/aes/check: $(CHECK_DEPS)
@$(CHECK) @$(CHECK)
.PHONY: crypto/aes/check .PHONY: crypto/aes/check
crypto/block.lo: $(go_crypto_block_files) fmt.gox io.gox os.gox strconv.gox
$(BUILDPACKAGE)
crypto/block/check: $(CHECK_DEPS)
@$(MKDIR_P) crypto/block
@$(CHECK)
.PHONY: crypto/block/check
crypto/blowfish.lo: $(go_crypto_blowfish_files) os.gox strconv.gox crypto/blowfish.lo: $(go_crypto_blowfish_files) os.gox strconv.gox
$(BUILDPACKAGE) $(BUILDPACKAGE)
crypto/blowfish/check: $(CHECK_DEPS) crypto/blowfish/check: $(CHECK_DEPS)
...@@ -2054,6 +2044,13 @@ crypto/cipher/check: $(CHECK_DEPS) ...@@ -2054,6 +2044,13 @@ crypto/cipher/check: $(CHECK_DEPS)
@$(CHECK) @$(CHECK)
.PHONY: crypto/cipher/check .PHONY: crypto/cipher/check
crypto/des.lo: $(go_crypto_des_files) encoding/binary.gox os.gox strconv.gox
$(BUILDPACKAGE)
crypto/des/check: $(CHECK_DEPS)
@$(MKDIR_P) crypto/des
@$(CHECK)
.PHONY: crypto/des/check
crypto/dsa.lo: $(go_crypto_dsa_files) big.gox io.gox os.gox crypto/dsa.lo: $(go_crypto_dsa_files) big.gox io.gox os.gox
$(BUILDPACKAGE) $(BUILDPACKAGE)
crypto/dsa/check: $(CHECK_DEPS) crypto/dsa/check: $(CHECK_DEPS)
...@@ -2139,7 +2136,8 @@ crypto/ripemd160/check: $(CHECK_DEPS) ...@@ -2139,7 +2136,8 @@ crypto/ripemd160/check: $(CHECK_DEPS)
.PHONY: crypto/ripemd160/check .PHONY: crypto/ripemd160/check
crypto/rsa.lo: $(go_crypto_rsa_files) big.gox crypto.gox crypto/sha1.gox \ crypto/rsa.lo: $(go_crypto_rsa_files) big.gox crypto.gox crypto/sha1.gox \
crypto/subtle.gox encoding/hex.gox hash.gox io.gox os.gox crypto/subtle.gox encoding/hex.gox hash.gox io.gox os.gox \
sync.gox
$(BUILDPACKAGE) $(BUILDPACKAGE)
crypto/rsa/check: $(CHECK_DEPS) crypto/rsa/check: $(CHECK_DEPS)
@$(MKDIR_P) crypto/rsa @$(MKDIR_P) crypto/rsa
...@@ -2475,8 +2473,8 @@ http/cgi/check: $(CHECK_DEPS) ...@@ -2475,8 +2473,8 @@ http/cgi/check: $(CHECK_DEPS)
@$(CHECK) @$(CHECK)
.PHONY: http/cgi/check .PHONY: http/cgi/check
http/httptest.lo: $(go_http_httptest_files) bytes.gox fmt.gox http.gox \ http/httptest.lo: $(go_http_httptest_files) bytes.gox crypto/rand.gox \
net.gox os.gox crypto/tls.gox fmt.gox http.gox net.gox os.gox time.gox
$(BUILDPACKAGE) $(BUILDPACKAGE)
http/httptest/check: $(CHECK_DEPS) http/httptest/check: $(CHECK_DEPS)
@$(MKDIR_P) http/httptest @$(MKDIR_P) http/httptest
...@@ -2767,14 +2765,14 @@ container/vector.gox: container/vector.lo ...@@ -2767,14 +2765,14 @@ container/vector.gox: container/vector.lo
crypto/aes.gox: crypto/aes.lo crypto/aes.gox: crypto/aes.lo
$(BUILDGOX) $(BUILDGOX)
crypto/block.gox: crypto/block.lo
$(BUILDGOX)
crypto/blowfish.gox: crypto/blowfish.lo crypto/blowfish.gox: crypto/blowfish.lo
$(BUILDGOX) $(BUILDGOX)
crypto/cast5.gox: crypto/cast5.lo crypto/cast5.gox: crypto/cast5.lo
$(BUILDGOX) $(BUILDGOX)
crypto/cipher.gox: crypto/cipher.lo crypto/cipher.gox: crypto/cipher.lo
$(BUILDGOX) $(BUILDGOX)
crypto/des.gox: crypto/des.lo
$(BUILDGOX)
crypto/dsa.gox: crypto/dsa.lo crypto/dsa.gox: crypto/dsa.lo
$(BUILDGOX) $(BUILDGOX)
crypto/ecdsa.gox: crypto/ecdsa.lo crypto/ecdsa.gox: crypto/ecdsa.lo
...@@ -3002,10 +3000,10 @@ TEST_PACKAGES = \ ...@@ -3002,10 +3000,10 @@ TEST_PACKAGES = \
container/ring/check \ container/ring/check \
container/vector/check \ container/vector/check \
crypto/aes/check \ crypto/aes/check \
crypto/block/check \
crypto/blowfish/check \ crypto/blowfish/check \
crypto/cast5/check \ crypto/cast5/check \
crypto/cipher/check \ crypto/cipher/check \
crypto/des/check \
crypto/dsa/check \ crypto/dsa/check \
crypto/ecdsa/check \ crypto/ecdsa/check \
crypto/elliptic/check \ crypto/elliptic/check \
......
...@@ -140,31 +140,30 @@ am__DEPENDENCIES_2 = asn1/asn1.lo big/big.lo bufio/bufio.lo \ ...@@ -140,31 +140,30 @@ am__DEPENDENCIES_2 = asn1/asn1.lo big/big.lo bufio/bufio.lo \
archive/zip.lo compress/bzip2.lo compress/flate.lo \ archive/zip.lo compress/bzip2.lo compress/flate.lo \
compress/gzip.lo compress/lzw.lo compress/zlib.lo \ compress/gzip.lo compress/lzw.lo compress/zlib.lo \
container/heap.lo container/list.lo container/ring.lo \ container/heap.lo container/list.lo container/ring.lo \
container/vector.lo crypto/aes.lo crypto/block.lo \ container/vector.lo crypto/aes.lo crypto/blowfish.lo \
crypto/blowfish.lo crypto/cast5.lo crypto/cipher.lo \ crypto/cast5.lo crypto/cipher.lo crypto/des.lo crypto/dsa.lo \
crypto/dsa.lo crypto/ecdsa.lo crypto/elliptic.lo \ crypto/ecdsa.lo crypto/elliptic.lo crypto/hmac.lo \
crypto/hmac.lo crypto/md4.lo crypto/md5.lo crypto/ocsp.lo \ crypto/md4.lo crypto/md5.lo crypto/ocsp.lo crypto/openpgp.lo \
crypto/openpgp.lo crypto/rand.lo crypto/rc4.lo \ crypto/rand.lo crypto/rc4.lo crypto/ripemd160.lo crypto/rsa.lo \
crypto/ripemd160.lo crypto/rsa.lo crypto/sha1.lo \ crypto/sha1.lo crypto/sha256.lo crypto/sha512.lo \
crypto/sha256.lo crypto/sha512.lo crypto/subtle.lo \ crypto/subtle.lo crypto/tls.lo crypto/twofish.lo \
crypto/tls.lo crypto/twofish.lo crypto/x509.lo crypto/xtea.lo \ crypto/x509.lo crypto/xtea.lo crypto/openpgp/armor.lo \
crypto/openpgp/armor.lo crypto/openpgp/error.lo \ crypto/openpgp/error.lo crypto/openpgp/packet.lo \
crypto/openpgp/packet.lo crypto/openpgp/s2k.lo debug/dwarf.lo \ crypto/openpgp/s2k.lo debug/dwarf.lo debug/elf.lo \
debug/elf.lo debug/gosym.lo debug/macho.lo debug/pe.lo \ debug/gosym.lo debug/macho.lo debug/pe.lo debug/proc.lo \
debug/proc.lo encoding/ascii85.lo encoding/base32.lo \ encoding/ascii85.lo encoding/base32.lo encoding/base64.lo \
encoding/base64.lo encoding/binary.lo encoding/git85.lo \ encoding/binary.lo encoding/git85.lo encoding/hex.lo \
encoding/hex.lo encoding/line.lo encoding/pem.lo \ encoding/line.lo encoding/pem.lo exp/datafmt.lo exp/draw.lo \
exp/datafmt.lo exp/draw.lo exp/eval.lo go/ast.lo go/doc.lo \ exp/eval.lo go/ast.lo go/doc.lo go/parser.lo go/printer.lo \
go/parser.lo go/printer.lo go/scanner.lo go/token.lo \ go/scanner.lo go/token.lo go/typechecker.lo hash/adler32.lo \
go/typechecker.lo hash/adler32.lo hash/crc32.lo hash/crc64.lo \ hash/crc32.lo hash/crc64.lo hash/fnv.lo http/cgi.lo \
hash/fnv.lo http/cgi.lo http/httptest.lo http/pprof.lo \ http/httptest.lo http/pprof.lo image/jpeg.lo image/png.lo \
image/jpeg.lo image/png.lo index/suffixarray.lo io/ioutil.lo \ index/suffixarray.lo io/ioutil.lo mime/multipart.lo \
mime/multipart.lo net/dict.lo net/textproto.lo \ net/dict.lo net/textproto.lo $(am__DEPENDENCIES_1) \
$(am__DEPENDENCIES_1) os/signal.lo path/filepath.lo \ os/signal.lo path/filepath.lo rpc/jsonrpc.lo runtime/debug.lo \
rpc/jsonrpc.lo runtime/debug.lo runtime/pprof.lo \ runtime/pprof.lo sync/atomic.lo sync/atomic_c.lo \
sync/atomic.lo sync/atomic_c.lo syscalls/syscall.lo \ syscalls/syscall.lo syscalls/errno.lo testing/testing.lo \
syscalls/errno.lo testing/testing.lo testing/iotest.lo \ testing/iotest.lo testing/quick.lo testing/script.lo
testing/quick.lo testing/script.lo
libgo_la_DEPENDENCIES = $(am__DEPENDENCIES_2) $(am__DEPENDENCIES_1) \ libgo_la_DEPENDENCIES = $(am__DEPENDENCIES_2) $(am__DEPENDENCIES_1) \
$(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) \ $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) \
$(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1)
...@@ -624,10 +623,10 @@ toolexeclibgocontainer_DATA = \ ...@@ -624,10 +623,10 @@ toolexeclibgocontainer_DATA = \
toolexeclibgocryptodir = $(toolexeclibgodir)/crypto toolexeclibgocryptodir = $(toolexeclibgodir)/crypto
toolexeclibgocrypto_DATA = \ toolexeclibgocrypto_DATA = \
crypto/aes.gox \ crypto/aes.gox \
crypto/block.gox \
crypto/blowfish.gox \ crypto/blowfish.gox \
crypto/cast5.gox \ crypto/cast5.gox \
crypto/cipher.gox \ crypto/cipher.gox \
crypto/des.gox \
crypto/dsa.gox \ crypto/dsa.gox \
crypto/ecdsa.gox \ crypto/ecdsa.gox \
crypto/elliptic.gox \ crypto/elliptic.gox \
...@@ -1087,9 +1086,12 @@ go_os_files = \ ...@@ -1087,9 +1086,12 @@ go_os_files = \
go/os/env.go \ go/os/env.go \
go/os/env_unix.go \ go/os/env_unix.go \
go/os/error.go \ go/os/error.go \
go/os/error_posix.go \
go/os/exec.go \ go/os/exec.go \
go/os/exec_posix.go \
go/os/exec_unix.go \ go/os/exec_unix.go \
go/os/file.go \ go/os/file.go \
go/os/file_posix.go \
go/os/file_unix.go \ go/os/file_unix.go \
go/os/getwd.go \ go/os/getwd.go \
go/os/path.go \ go/os/path.go \
...@@ -1279,17 +1281,6 @@ go_crypto_aes_files = \ ...@@ -1279,17 +1281,6 @@ go_crypto_aes_files = \
go/crypto/aes/cipher.go \ go/crypto/aes/cipher.go \
go/crypto/aes/const.go go/crypto/aes/const.go
go_crypto_block_files = \
go/crypto/block/cbc.go \
go/crypto/block/cfb.go \
go/crypto/block/cmac.go \
go/crypto/block/cipher.go \
go/crypto/block/ctr.go \
go/crypto/block/eax.go \
go/crypto/block/ecb.go \
go/crypto/block/ofb.go \
go/crypto/block/xor.go
go_crypto_blowfish_files = \ go_crypto_blowfish_files = \
go/crypto/blowfish/block.go \ go/crypto/blowfish/block.go \
go/crypto/blowfish/const.go \ go/crypto/blowfish/const.go \
...@@ -1307,6 +1298,11 @@ go_crypto_cipher_files = \ ...@@ -1307,6 +1298,11 @@ go_crypto_cipher_files = \
go/crypto/cipher/ocfb.go \ go/crypto/cipher/ocfb.go \
go/crypto/cipher/ofb.go go/crypto/cipher/ofb.go
go_crypto_des_files = \
go/crypto/des/block.go \
go/crypto/des/cipher.go \
go/crypto/des/const.go
go_crypto_dsa_files = \ go_crypto_dsa_files = \
go/crypto/dsa/dsa.go go/crypto/dsa/dsa.go
...@@ -1766,10 +1762,10 @@ libgo_go_objs = \ ...@@ -1766,10 +1762,10 @@ libgo_go_objs = \
container/ring.lo \ container/ring.lo \
container/vector.lo \ container/vector.lo \
crypto/aes.lo \ crypto/aes.lo \
crypto/block.lo \
crypto/blowfish.lo \ crypto/blowfish.lo \
crypto/cast5.lo \ crypto/cast5.lo \
crypto/cipher.lo \ crypto/cipher.lo \
crypto/des.lo \
crypto/dsa.lo \ crypto/dsa.lo \
crypto/ecdsa.lo \ crypto/ecdsa.lo \
crypto/elliptic.lo \ crypto/elliptic.lo \
...@@ -2008,10 +2004,10 @@ TEST_PACKAGES = \ ...@@ -2008,10 +2004,10 @@ TEST_PACKAGES = \
container/ring/check \ container/ring/check \
container/vector/check \ container/vector/check \
crypto/aes/check \ crypto/aes/check \
crypto/block/check \
crypto/blowfish/check \ crypto/blowfish/check \
crypto/cast5/check \ crypto/cast5/check \
crypto/cipher/check \ crypto/cipher/check \
crypto/des/check \
crypto/dsa/check \ crypto/dsa/check \
crypto/ecdsa/check \ crypto/ecdsa/check \
crypto/elliptic/check \ crypto/elliptic/check \
...@@ -4436,13 +4432,6 @@ crypto/aes/check: $(CHECK_DEPS) ...@@ -4436,13 +4432,6 @@ crypto/aes/check: $(CHECK_DEPS)
@$(CHECK) @$(CHECK)
.PHONY: crypto/aes/check .PHONY: crypto/aes/check
crypto/block.lo: $(go_crypto_block_files) fmt.gox io.gox os.gox strconv.gox
$(BUILDPACKAGE)
crypto/block/check: $(CHECK_DEPS)
@$(MKDIR_P) crypto/block
@$(CHECK)
.PHONY: crypto/block/check
crypto/blowfish.lo: $(go_crypto_blowfish_files) os.gox strconv.gox crypto/blowfish.lo: $(go_crypto_blowfish_files) os.gox strconv.gox
$(BUILDPACKAGE) $(BUILDPACKAGE)
crypto/blowfish/check: $(CHECK_DEPS) crypto/blowfish/check: $(CHECK_DEPS)
...@@ -4464,6 +4453,13 @@ crypto/cipher/check: $(CHECK_DEPS) ...@@ -4464,6 +4453,13 @@ crypto/cipher/check: $(CHECK_DEPS)
@$(CHECK) @$(CHECK)
.PHONY: crypto/cipher/check .PHONY: crypto/cipher/check
crypto/des.lo: $(go_crypto_des_files) encoding/binary.gox os.gox strconv.gox
$(BUILDPACKAGE)
crypto/des/check: $(CHECK_DEPS)
@$(MKDIR_P) crypto/des
@$(CHECK)
.PHONY: crypto/des/check
crypto/dsa.lo: $(go_crypto_dsa_files) big.gox io.gox os.gox crypto/dsa.lo: $(go_crypto_dsa_files) big.gox io.gox os.gox
$(BUILDPACKAGE) $(BUILDPACKAGE)
crypto/dsa/check: $(CHECK_DEPS) crypto/dsa/check: $(CHECK_DEPS)
...@@ -4549,7 +4545,8 @@ crypto/ripemd160/check: $(CHECK_DEPS) ...@@ -4549,7 +4545,8 @@ crypto/ripemd160/check: $(CHECK_DEPS)
.PHONY: crypto/ripemd160/check .PHONY: crypto/ripemd160/check
crypto/rsa.lo: $(go_crypto_rsa_files) big.gox crypto.gox crypto/sha1.gox \ crypto/rsa.lo: $(go_crypto_rsa_files) big.gox crypto.gox crypto/sha1.gox \
crypto/subtle.gox encoding/hex.gox hash.gox io.gox os.gox crypto/subtle.gox encoding/hex.gox hash.gox io.gox os.gox \
sync.gox
$(BUILDPACKAGE) $(BUILDPACKAGE)
crypto/rsa/check: $(CHECK_DEPS) crypto/rsa/check: $(CHECK_DEPS)
@$(MKDIR_P) crypto/rsa @$(MKDIR_P) crypto/rsa
...@@ -4885,8 +4882,8 @@ http/cgi/check: $(CHECK_DEPS) ...@@ -4885,8 +4882,8 @@ http/cgi/check: $(CHECK_DEPS)
@$(CHECK) @$(CHECK)
.PHONY: http/cgi/check .PHONY: http/cgi/check
http/httptest.lo: $(go_http_httptest_files) bytes.gox fmt.gox http.gox \ http/httptest.lo: $(go_http_httptest_files) bytes.gox crypto/rand.gox \
net.gox os.gox crypto/tls.gox fmt.gox http.gox net.gox os.gox time.gox
$(BUILDPACKAGE) $(BUILDPACKAGE)
http/httptest/check: $(CHECK_DEPS) http/httptest/check: $(CHECK_DEPS)
@$(MKDIR_P) http/httptest @$(MKDIR_P) http/httptest
...@@ -5172,14 +5169,14 @@ container/vector.gox: container/vector.lo ...@@ -5172,14 +5169,14 @@ container/vector.gox: container/vector.lo
crypto/aes.gox: crypto/aes.lo crypto/aes.gox: crypto/aes.lo
$(BUILDGOX) $(BUILDGOX)
crypto/block.gox: crypto/block.lo
$(BUILDGOX)
crypto/blowfish.gox: crypto/blowfish.lo crypto/blowfish.gox: crypto/blowfish.lo
$(BUILDGOX) $(BUILDGOX)
crypto/cast5.gox: crypto/cast5.lo crypto/cast5.gox: crypto/cast5.lo
$(BUILDGOX) $(BUILDGOX)
crypto/cipher.gox: crypto/cipher.lo crypto/cipher.gox: crypto/cipher.lo
$(BUILDGOX) $(BUILDGOX)
crypto/des.gox: crypto/des.lo
$(BUILDGOX)
crypto/dsa.gox: crypto/dsa.lo crypto/dsa.gox: crypto/dsa.lo
$(BUILDGOX) $(BUILDGOX)
crypto/ecdsa.gox: crypto/ecdsa.lo crypto/ecdsa.gox: crypto/ecdsa.lo
......
...@@ -95,7 +95,7 @@ func (tr *Reader) skipUnread() { ...@@ -95,7 +95,7 @@ func (tr *Reader) skipUnread() {
nr := tr.nb + tr.pad // number of bytes to skip nr := tr.nb + tr.pad // number of bytes to skip
tr.nb, tr.pad = 0, 0 tr.nb, tr.pad = 0, 0
if sr, ok := tr.r.(io.Seeker); ok { if sr, ok := tr.r.(io.Seeker); ok {
if _, err := sr.Seek(nr, 1); err == nil { if _, err := sr.Seek(nr, os.SEEK_CUR); err == nil {
return return
} }
} }
......
...@@ -113,7 +113,7 @@ var untarTests = []*untarTest{ ...@@ -113,7 +113,7 @@ var untarTests = []*untarTest{
func TestReader(t *testing.T) { func TestReader(t *testing.T) {
testLoop: testLoop:
for i, test := range untarTests { for i, test := range untarTests {
f, err := os.Open(test.file, os.O_RDONLY, 0444) f, err := os.Open(test.file)
if err != nil { if err != nil {
t.Errorf("test %d: Unexpected error: %v", i, err) t.Errorf("test %d: Unexpected error: %v", i, err)
continue continue
...@@ -143,7 +143,7 @@ testLoop: ...@@ -143,7 +143,7 @@ testLoop:
} }
func TestPartialRead(t *testing.T) { func TestPartialRead(t *testing.T) {
f, err := os.Open("testdata/gnu.tar", os.O_RDONLY, 0444) f, err := os.Open("testdata/gnu.tar")
if err != nil { if err != nil {
t.Fatalf("Unexpected error: %v", err) t.Fatalf("Unexpected error: %v", err)
} }
...@@ -181,7 +181,7 @@ func TestPartialRead(t *testing.T) { ...@@ -181,7 +181,7 @@ func TestPartialRead(t *testing.T) {
func TestIncrementalRead(t *testing.T) { func TestIncrementalRead(t *testing.T) {
test := gnuTarTest test := gnuTarTest
f, err := os.Open(test.file, os.O_RDONLY, 0444) f, err := os.Open(test.file)
if err != nil { if err != nil {
t.Fatalf("Unexpected error: %v", err) t.Fatalf("Unexpected error: %v", err)
} }
...@@ -235,7 +235,7 @@ func TestIncrementalRead(t *testing.T) { ...@@ -235,7 +235,7 @@ func TestIncrementalRead(t *testing.T) {
func TestNonSeekable(t *testing.T) { func TestNonSeekable(t *testing.T) {
test := gnuTarTest test := gnuTarTest
f, err := os.Open(test.file, os.O_RDONLY, 0444) f, err := os.Open(test.file)
if err != nil { if err != nil {
t.Fatalf("Unexpected error: %v", err) t.Fatalf("Unexpected error: %v", err)
} }
......
...@@ -49,7 +49,7 @@ func (f *File) hasDataDescriptor() bool { ...@@ -49,7 +49,7 @@ func (f *File) hasDataDescriptor() bool {
// OpenReader will open the Zip file specified by name and return a Reader. // OpenReader will open the Zip file specified by name and return a Reader.
func OpenReader(name string) (*Reader, os.Error) { func OpenReader(name string) (*Reader, os.Error) {
f, err := os.Open(name, os.O_RDONLY, 0644) f, err := os.Open(name)
if err != nil { if err != nil {
return nil, err return nil, err
} }
...@@ -73,7 +73,7 @@ func NewReader(r io.ReaderAt, size int64) (*Reader, os.Error) { ...@@ -73,7 +73,7 @@ func NewReader(r io.ReaderAt, size int64) (*Reader, os.Error) {
Comment: end.comment, Comment: end.comment,
} }
rs := io.NewSectionReader(r, 0, size) rs := io.NewSectionReader(r, 0, size)
if _, err = rs.Seek(int64(end.directoryOffset), 0); err != nil { if _, err = rs.Seek(int64(end.directoryOffset), os.SEEK_SET); err != nil {
return nil, err return nil, err
} }
buf := bufio.NewReader(rs) buf := bufio.NewReader(rs)
...@@ -94,7 +94,7 @@ func (f *File) Open() (rc io.ReadCloser, err os.Error) { ...@@ -94,7 +94,7 @@ func (f *File) Open() (rc io.ReadCloser, err os.Error) {
if err = readFileHeader(f, r); err != nil { if err = readFileHeader(f, r); err != nil {
return return
} }
if f.bodyOffset, err = r.Seek(0, 1); err != nil { if f.bodyOffset, err = r.Seek(0, os.SEEK_CUR); err != nil {
return return
} }
} }
......
...@@ -415,38 +415,27 @@ func (b *Writer) Buffered() int { return b.n } ...@@ -415,38 +415,27 @@ func (b *Writer) Buffered() int { return b.n }
// If nn < len(p), it also returns an error explaining // If nn < len(p), it also returns an error explaining
// why the write is short. // why the write is short.
func (b *Writer) Write(p []byte) (nn int, err os.Error) { func (b *Writer) Write(p []byte) (nn int, err os.Error) {
if b.err != nil { for len(p) > b.Available() && b.err == nil {
return 0, b.err var n int
} if b.Buffered() == 0 {
nn = 0
for len(p) > 0 {
n := b.Available()
if n <= 0 {
if b.Flush(); b.err != nil {
break
}
n = b.Available()
}
if b.Buffered() == 0 && len(p) >= len(b.buf) {
// Large write, empty buffer. // Large write, empty buffer.
// Write directly from p to avoid copy. // Write directly from p to avoid copy.
n, b.err = b.wr.Write(p) n, b.err = b.wr.Write(p)
} else {
n = copy(b.buf[b.n:], p)
b.n += n
b.Flush()
}
nn += n nn += n
p = p[n:] p = p[n:]
if b.err != nil {
break
}
continue
} }
if n > len(p) { if b.err != nil {
n = len(p) return nn, b.err
} }
copy(b.buf[b.n:b.n+n], p[0:n]) n := copy(b.buf[b.n:], p)
b.n += n b.n += n
nn += n nn += n
p = p[n:] return nn, nil
}
return nn, b.err
} }
// WriteByte writes a single byte. // WriteByte writes a single byte.
...@@ -496,24 +485,21 @@ func (b *Writer) WriteRune(rune int) (size int, err os.Error) { ...@@ -496,24 +485,21 @@ func (b *Writer) WriteRune(rune int) (size int, err os.Error) {
// If the count is less than len(s), it also returns an error explaining // If the count is less than len(s), it also returns an error explaining
// why the write is short. // why the write is short.
func (b *Writer) WriteString(s string) (int, os.Error) { func (b *Writer) WriteString(s string) (int, os.Error) {
if b.err != nil { nn := 0
return 0, b.err for len(s) > b.Available() && b.err == nil {
} n := copy(b.buf[b.n:], s)
// Common case, worth making fast. b.n += n
if b.Available() >= len(s) || len(b.buf) >= len(s) && b.Flush() == nil { nn += n
for i := 0; i < len(s); i++ { // loop over bytes, not runes. s = s[n:]
b.buf[b.n] = s[i] b.Flush()
b.n++
}
return len(s), nil
} }
for i := 0; i < len(s); i++ { // loop over bytes, not runes.
b.WriteByte(s[i])
if b.err != nil { if b.err != nil {
return i, b.err return nn, b.err
}
} }
return len(s), nil n := copy(b.buf[b.n:], s)
b.n += n
nn += n
return nn, nil
} }
// buffered input and output // buffered input and output
......
...@@ -21,7 +21,7 @@ var filenames = []string{ ...@@ -21,7 +21,7 @@ var filenames = []string{
// the given options yields equivalent bytes to the original file. // the given options yields equivalent bytes to the original file.
func testFile(t *testing.T, fn string, order Order, litWidth int) { func testFile(t *testing.T, fn string, order Order, litWidth int) {
// Read the file, as golden output. // Read the file, as golden output.
golden, err := os.Open(fn, os.O_RDONLY, 0400) golden, err := os.Open(fn)
if err != nil { if err != nil {
t.Errorf("%s (order=%d litWidth=%d): %v", fn, order, litWidth, err) t.Errorf("%s (order=%d litWidth=%d): %v", fn, order, litWidth, err)
return return
...@@ -29,7 +29,7 @@ func testFile(t *testing.T, fn string, order Order, litWidth int) { ...@@ -29,7 +29,7 @@ func testFile(t *testing.T, fn string, order Order, litWidth int) {
defer golden.Close() defer golden.Close()
// Read the file again, and push it through a pipe that compresses at the write end, and decompresses at the read end. // Read the file again, and push it through a pipe that compresses at the write end, and decompresses at the read end.
raw, err := os.Open(fn, os.O_RDONLY, 0400) raw, err := os.Open(fn)
if err != nil { if err != nil {
t.Errorf("%s (order=%d litWidth=%d): %v", fn, order, litWidth, err) t.Errorf("%s (order=%d litWidth=%d): %v", fn, order, litWidth, err)
return return
......
...@@ -20,7 +20,7 @@ var filenames = []string{ ...@@ -20,7 +20,7 @@ var filenames = []string{
// yields equivalent bytes to the original file. // yields equivalent bytes to the original file.
func testFileLevel(t *testing.T, fn string, level int) { func testFileLevel(t *testing.T, fn string, level int) {
// Read the file, as golden output. // Read the file, as golden output.
golden, err := os.Open(fn, os.O_RDONLY, 0444) golden, err := os.Open(fn)
if err != nil { if err != nil {
t.Errorf("%s (level=%d): %v", fn, level, err) t.Errorf("%s (level=%d): %v", fn, level, err)
return return
...@@ -28,7 +28,7 @@ func testFileLevel(t *testing.T, fn string, level int) { ...@@ -28,7 +28,7 @@ func testFileLevel(t *testing.T, fn string, level int) {
defer golden.Close() defer golden.Close()
// Read the file again, and push it through a pipe that compresses at the write end, and decompresses at the read end. // Read the file again, and push it through a pipe that compresses at the write end, and decompresses at the read end.
raw, err := os.Open(fn, os.O_RDONLY, 0444) raw, err := os.Open(fn)
if err != nil { if err != nil {
t.Errorf("%s (level=%d): %v", fn, level, err) t.Errorf("%s (level=%d): %v", fn, level, err)
return return
......
// 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 block
import (
"io"
)
type cbcCipher struct {
c Cipher
blockSize int
iv []byte
tmp []byte
}
func newCBC(c Cipher, iv []byte) *cbcCipher {
n := c.BlockSize()
x := new(cbcCipher)
x.c = c
x.blockSize = n
x.iv = dup(iv)
x.tmp = make([]byte, n)
return x
}
func (x *cbcCipher) BlockSize() int { return x.blockSize }
func (x *cbcCipher) Encrypt(dst, src []byte) {
for i := 0; i < x.blockSize; i++ {
x.iv[i] ^= src[i]
}
x.c.Encrypt(x.iv, x.iv)
for i := 0; i < x.blockSize; i++ {
dst[i] = x.iv[i]
}
}
func (x *cbcCipher) Decrypt(dst, src []byte) {
x.c.Decrypt(x.tmp, src)
for i := 0; i < x.blockSize; i++ {
x.tmp[i] ^= x.iv[i]
x.iv[i] = src[i]
dst[i] = x.tmp[i]
}
}
// NewCBCDecrypter returns a reader that reads data from r and decrypts it using c
// in cipher block chaining (CBC) mode with the initialization vector iv.
// The returned Reader does not buffer or read ahead except
// as required by the cipher's block size.
func NewCBCDecrypter(c Cipher, iv []byte, r io.Reader) io.Reader {
return NewECBDecrypter(newCBC(c, iv), r)
}
// NewCBCEncrypter returns a writer that encrypts data using c
// in cipher block chaining (CBC) mode with the initialization vector iv
// and writes the encrypted data to w.
// The returned Writer does no buffering except as required
// by the cipher's block size, so there is no need for a Flush method.
func NewCBCEncrypter(c Cipher, iv []byte, w io.Writer) io.Writer {
return NewECBEncrypter(newCBC(c, iv), w)
}
// 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 feedback (CFB) mode.
// CFB provides confidentiality by feeding a fraction of
// the previous ciphertext in as the plaintext for the next
// block operation.
// See NIST SP 800-38A, pp 11-13
package block
import (
"io"
)
type cfbCipher struct {
c Cipher
blockSize int // our block size (s/8)
cipherSize int // underlying cipher block size
iv []byte
tmp []byte
}
func newCFB(c Cipher, s int, iv []byte) *cfbCipher {
if s == 0 || s%8 != 0 {
panic("crypto/block: invalid CFB mode")
}
b := c.BlockSize()
x := new(cfbCipher)
x.c = c
x.blockSize = s / 8
x.cipherSize = b
x.iv = dup(iv)
x.tmp = make([]byte, b)
return x
}
func (x *cfbCipher) BlockSize() int { return x.blockSize }
func (x *cfbCipher) Encrypt(dst, src []byte) {
// Encrypt old IV and xor prefix with src to make dst.
x.c.Encrypt(x.tmp, x.iv)
for i := 0; i < x.blockSize; i++ {
dst[i] = src[i] ^ x.tmp[i]
}
// Slide unused IV pieces down and insert dst at end.
for i := 0; i < x.cipherSize-x.blockSize; i++ {
x.iv[i] = x.iv[i+x.blockSize]
}
off := x.cipherSize - x.blockSize
for i := off; i < x.cipherSize; i++ {
x.iv[i] = dst[i-off]
}
}
func (x *cfbCipher) Decrypt(dst, src []byte) {
// Encrypt [sic] old IV and xor prefix with src to make dst.
x.c.Encrypt(x.tmp, x.iv)
for i := 0; i < x.blockSize; i++ {
dst[i] = src[i] ^ x.tmp[i]
}
// Slide unused IV pieces down and insert src at top.
for i := 0; i < x.cipherSize-x.blockSize; i++ {
x.iv[i] = x.iv[i+x.blockSize]
}
off := x.cipherSize - x.blockSize
for i := off; i < x.cipherSize; i++ {
// Reconstruct src = dst ^ x.tmp
// in case we overwrote src (src == dst).
x.iv[i] = dst[i-off] ^ x.tmp[i-off]
}
}
// NewCFBDecrypter returns a reader that reads data from r and decrypts it using c
// in s-bit cipher feedback (CFB) mode with the initialization vector iv.
// The returned Reader does not buffer or read ahead except
// as required by the cipher's block size.
// Modes for s not a multiple of 8 are unimplemented.
func NewCFBDecrypter(c Cipher, s int, iv []byte, r io.Reader) io.Reader {
return NewECBDecrypter(newCFB(c, s, iv), r)
}
// NewCFBEncrypter returns a writer that encrypts data using c
// in s-bit cipher feedback (CFB) mode with the initialization vector iv
// and writes the encrypted data to w.
// The returned Writer does no buffering except as required
// by the cipher's block size, so there is no need for a Flush method.
// Modes for s not a multiple of 8 are unimplemented.
func NewCFBEncrypter(c Cipher, s int, iv []byte, w io.Writer) io.Writer {
return NewECBEncrypter(newCFB(c, s, iv), w)
}
// 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.
// CFB 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. 29-52.
package block
import (
"bytes"
"crypto/aes"
"io"
"testing"
)
type cfbTest struct {
name string
s int
key []byte
iv []byte
in []byte
out []byte
}
var cfbAESTests = []cfbTest{
{
"CFB1-AES128",
1,
commonKey128,
commonIV,
[]byte{
0<<7 | 1<<6 | 1<<5 | 0<<4 | 1<<3 | 0<<2 | 1<<1,
1<<7 | 1<<6 | 0<<5 | 0<<4 | 0<<3 | 0<<2 | 0<<1,
},
[]byte{
0<<7 | 1<<6 | 1<<5 | 0<<4 | 1<<3 | 0<<2 | 0<<1,
1<<7 | 0<<6 | 1<<5 | 1<<4 | 0<<3 | 0<<2 | 1<<1,
},
},
{
"CFB1-AES192",
1,
commonKey192,
commonIV,
[]byte{
0<<7 | 1<<6 | 1<<5 | 0<<4 | 1<<3 | 0<<2 | 1<<1,
1<<7 | 1<<6 | 0<<5 | 0<<4 | 0<<3 | 0<<2 | 0<<1,
},
[]byte{
1<<7 | 0<<6 | 0<<5 | 1<<4 | 0<<3 | 0<<2 | 1<<1,
0<<7 | 1<<6 | 0<<5 | 1<<4 | 1<<3 | 0<<2 | 0<<1,
},
},
{
"CFB1-AES256",
1,
commonKey256,
commonIV,
[]byte{
0<<7 | 1<<6 | 1<<5 | 0<<4 | 1<<3 | 0<<2 | 1<<1,
1<<7 | 1<<6 | 0<<5 | 0<<4 | 0<<3 | 0<<2 | 0<<1,
},
[]byte{
1<<7 | 0<<6 | 0<<5 | 1<<4 | 0<<3 | 0<<2 | 0<<1,
0<<7 | 0<<6 | 1<<5 | 0<<4 | 1<<3 | 0<<2 | 0<<1,
},
},
{
"CFB8-AES128",
8,
commonKey128,
commonIV,
[]byte{
0x6b,
0xc1,
0xbe,
0xe2,
0x2e,
0x40,
0x9f,
0x96,
0xe9,
0x3d,
0x7e,
0x11,
0x73,
0x93,
0x17,
0x2a,
0xae,
0x2d,
},
[]byte{
0x3b,
0x79,
0x42,
0x4c,
0x9c,
0x0d,
0xd4,
0x36,
0xba,
0xce,
0x9e,
0x0e,
0xd4,
0x58,
0x6a,
0x4f,
0x32,
0xb9,
},
},
{
"CFB8-AES192",
8,
commonKey192,
commonIV,
[]byte{
0x6b,
0xc1,
0xbe,
0xe2,
0x2e,
0x40,
0x9f,
0x96,
0xe9,
0x3d,
0x7e,
0x11,
0x73,
0x93,
0x17,
0x2a,
0xae,
0x2d,
},
[]byte{
0xcd,
0xa2,
0x52,
0x1e,
0xf0,
0xa9,
0x05,
0xca,
0x44,
0xcd,
0x05,
0x7c,
0xbf,
0x0d,
0x47,
0xa0,
0x67,
0x8a,
},
},
{
"CFB8-AES256",
8,
commonKey256,
commonIV,
[]byte{
0x6b,
0xc1,
0xbe,
0xe2,
0x2e,
0x40,
0x9f,
0x96,
0xe9,
0x3d,
0x7e,
0x11,
0x73,
0x93,
0x17,
0x2a,
0xae,
0x2d,
},
[]byte{
0xdc,
0x1f,
0x1a,
0x85,
0x20,
0xa6,
0x4d,
0xb5,
0x5f,
0xcc,
0x8a,
0xc5,
0x54,
0x84,
0x4e,
0x88,
0x97,
0x00,
},
},
{
"CFB128-AES128",
128,
commonKey128,
commonIV,
[]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,
},
[]byte{
0x3b, 0x3f, 0xd9, 0x2e, 0xb7, 0x2d, 0xad, 0x20, 0x33, 0x34, 0x49, 0xf8, 0xe8, 0x3c, 0xfb, 0x4a,
0xc8, 0xa6, 0x45, 0x37, 0xa0, 0xb3, 0xa9, 0x3f, 0xcd, 0xe3, 0xcd, 0xad, 0x9f, 0x1c, 0xe5, 0x8b,
0x26, 0x75, 0x1f, 0x67, 0xa3, 0xcb, 0xb1, 0x40, 0xb1, 0x80, 0x8c, 0xf1, 0x87, 0xa4, 0xf4, 0xdf,
0xc0, 0x4b, 0x05, 0x35, 0x7c, 0x5d, 0x1c, 0x0e, 0xea, 0xc4, 0xc6, 0x6f, 0x9f, 0xf7, 0xf2, 0xe6,
},
},
{
"CFB128-AES192",
128,
commonKey192,
commonIV,
[]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,
},
[]byte{
0xcd, 0xc8, 0x0d, 0x6f, 0xdd, 0xf1, 0x8c, 0xab, 0x34, 0xc2, 0x59, 0x09, 0xc9, 0x9a, 0x41, 0x74,
0x67, 0xce, 0x7f, 0x7f, 0x81, 0x17, 0x36, 0x21, 0x96, 0x1a, 0x2b, 0x70, 0x17, 0x1d, 0x3d, 0x7a,
0x2e, 0x1e, 0x8a, 0x1d, 0xd5, 0x9b, 0x88, 0xb1, 0xc8, 0xe6, 0x0f, 0xed, 0x1e, 0xfa, 0xc4, 0xc9,
0xc0, 0x5f, 0x9f, 0x9c, 0xa9, 0x83, 0x4f, 0xa0, 0x42, 0xae, 0x8f, 0xba, 0x58, 0x4b, 0x09, 0xff,
},
},
{
"CFB128-AES256",
128,
commonKey256,
commonIV,
[]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,
},
[]byte{
0xdc, 0x7e, 0x84, 0xbf, 0xda, 0x79, 0x16, 0x4b, 0x7e, 0xcd, 0x84, 0x86, 0x98, 0x5d, 0x38, 0x60,
0x39, 0xff, 0xed, 0x14, 0x3b, 0x28, 0xb1, 0xc8, 0x32, 0x11, 0x3c, 0x63, 0x31, 0xe5, 0x40, 0x7b,
0xdf, 0x10, 0x13, 0x24, 0x15, 0xe5, 0x4b, 0x92, 0xa1, 0x3e, 0xd0, 0xa8, 0x26, 0x7a, 0xe2, 0xf9,
0x75, 0xa3, 0x85, 0x74, 0x1a, 0xb9, 0xce, 0xf8, 0x20, 0x31, 0x62, 0x3d, 0x55, 0xb1, 0xe4, 0x71,
},
},
}
func TestCFB_AES(t *testing.T) {
for _, tt := range cfbAESTests {
test := tt.name
if tt.s == 1 {
// 1-bit CFB not implemented
continue
}
c, err := aes.NewCipher(tt.key)
if err != nil {
t.Errorf("%s: NewCipher(%d bytes) = %s", test, len(tt.key), err)
continue
}
var crypt bytes.Buffer
w := NewCFBEncrypter(c, tt.s, tt.iv, &crypt)
var r io.Reader = bytes.NewBuffer(tt.in)
n, err := io.Copy(w, r)
if n != int64(len(tt.in)) || err != nil {
t.Errorf("%s: CFBEncrypter io.Copy = %d, %v want %d, nil", test, n, err, len(tt.in))
} else if d := crypt.Bytes(); !same(tt.out, d) {
t.Errorf("%s: CFBEncrypter\nhave %x\nwant %x", test, d, tt.out)
}
var plain bytes.Buffer
r = NewCFBDecrypter(c, tt.s, tt.iv, bytes.NewBuffer(tt.out))
w = &plain
n, err = io.Copy(w, r)
if n != int64(len(tt.out)) || err != nil {
t.Errorf("%s: CFBDecrypter io.Copy = %d, %v want %d, nil", test, n, err, len(tt.out))
} else if d := plain.Bytes(); !same(tt.in, d) {
t.Errorf("%s: CFBDecrypter\nhave %x\nwant %x", test, d, tt.in)
}
if t.Failed() {
break
}
}
}
// 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.
// The block package is deprecated, use cipher instead.
// The block 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 block
// A Cipher 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 Cipher interface {
// BlockSize returns the cipher's block size.
BlockSize() int
// Encrypt encrypts the first block in src into dst.
// Src and dst may point at the same memory.
Encrypt(dst, src []byte)
// Decrypt decrypts the first block in src into dst.
// Src and dst may point at the same memory.
Decrypt(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 same(p, q []byte) bool {
if len(p) != len(q) {
return false
}
for i := 0; i < len(p); i++ {
if p[i] != q[i] {
return false
}
}
return true
}
func dup(p []byte) []byte {
q := make([]byte, len(p))
copy(q, p)
return q
}
// 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.
// CMAC message authentication code, defined in
// NIST Special Publication SP 800-38B.
package block
import (
"hash"
"os"
)
const (
// minimal irreducible polynomial of degree b
r64 = 0x1b
r128 = 0x87
)
type cmac struct {
k1, k2, ci, digest []byte
p int // position in ci
c Cipher
}
// TODO(rsc): Should this return an error instead of panic?
// NewCMAC returns a new instance of a CMAC message authentication code
// digest using the given Cipher.
func NewCMAC(c Cipher) hash.Hash {
var r byte
n := c.BlockSize()
switch n {
case 64 / 8:
r = r64
case 128 / 8:
r = r128
default:
panic("crypto/block: NewCMAC: invalid cipher block size")
}
d := new(cmac)
d.c = c
d.k1 = make([]byte, n)
d.k2 = make([]byte, n)
d.ci = make([]byte, n)
d.digest = make([]byte, n)
// Subkey generation, p. 7
c.Encrypt(d.k1, d.k1)
if shift1(d.k1, d.k1) != 0 {
d.k1[n-1] ^= r
}
if shift1(d.k2, d.k1) != 0 {
d.k2[n-1] ^= r
}
return d
}
// Reset clears the digest state, starting a new digest.
func (d *cmac) Reset() {
for i := range d.ci {
d.ci[i] = 0
}
d.p = 0
}
// Write adds the given data to the digest state.
func (d *cmac) Write(p []byte) (n int, err os.Error) {
// Xor input into ci.
for _, c := range p {
// If ci is full, encrypt and start over.
if d.p >= len(d.ci) {
d.c.Encrypt(d.ci, d.ci)
d.p = 0
}
d.ci[d.p] ^= c
d.p++
}
return len(p), nil
}
// Sum returns the CMAC digest, one cipher block in length,
// of the data written with Write.
func (d *cmac) Sum() []byte {
// Finish last block, mix in key, encrypt.
// Don't edit ci, in case caller wants
// to keep digesting after call to Sum.
k := d.k1
if d.p < len(d.digest) {
k = d.k2
}
for i := 0; i < len(d.ci); i++ {
d.digest[i] = d.ci[i] ^ k[i]
}
if d.p < len(d.digest) {
d.digest[d.p] ^= 0x80
}
d.c.Encrypt(d.digest, d.digest)
return d.digest
}
func (d *cmac) Size() int { return len(d.digest) }
// 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.
// CMAC test vectors. See NIST SP 800-38B, Appendix D.
package block
import (
"crypto/aes"
"testing"
)
type cmacAESTest struct {
key []byte
in []byte
digest []byte
}
var cmacAESTests = []cmacAESTest{
{
commonKey128,
nil,
[]byte{0xbb, 0x1d, 0x69, 0x29, 0xe9, 0x59, 0x37, 0x28, 0x7f, 0xa3, 0x7d, 0x12, 0x9b, 0x75, 0x67, 0x46},
},
{
commonKey128,
[]byte{0x6b, 0xc1, 0xbe, 0xe2, 0x2e, 0x40, 0x9f, 0x96, 0xe9, 0x3d, 0x7e, 0x11, 0x73, 0x93, 0x17, 0x2a},
[]byte{0x07, 0x0a, 0x16, 0xb4, 0x6b, 0x4d, 0x41, 0x44, 0xf7, 0x9b, 0xdd, 0x9d, 0xd0, 0x4a, 0x28, 0x7c},
},
{
commonKey128,
[]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,
},
[]byte{0xdf, 0xa6, 0x67, 0x47, 0xde, 0x9a, 0xe6, 0x30, 0x30, 0xca, 0x32, 0x61, 0x14, 0x97, 0xc8, 0x27},
},
{
commonKey128,
[]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,
},
[]byte{0x51, 0xf0, 0xbe, 0xbf, 0x7e, 0x3b, 0x9d, 0x92, 0xfc, 0x49, 0x74, 0x17, 0x79, 0x36, 0x3c, 0xfe},
},
{
commonKey192,
nil,
[]byte{0xd1, 0x7d, 0xdf, 0x46, 0xad, 0xaa, 0xcd, 0xe5, 0x31, 0xca, 0xc4, 0x83, 0xde, 0x7a, 0x93, 0x67},
},
{
commonKey192,
[]byte{0x6b, 0xc1, 0xbe, 0xe2, 0x2e, 0x40, 0x9f, 0x96, 0xe9, 0x3d, 0x7e, 0x11, 0x73, 0x93, 0x17, 0x2a},
[]byte{0x9e, 0x99, 0xa7, 0xbf, 0x31, 0xe7, 0x10, 0x90, 0x06, 0x62, 0xf6, 0x5e, 0x61, 0x7c, 0x51, 0x84},
},
{
commonKey192,
[]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,
},
[]byte{0x8a, 0x1d, 0xe5, 0xbe, 0x2e, 0xb3, 0x1a, 0xad, 0x08, 0x9a, 0x82, 0xe6, 0xee, 0x90, 0x8b, 0x0e},
},
{
commonKey192,
[]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,
},
[]byte{0xa1, 0xd5, 0xdf, 0x0e, 0xed, 0x79, 0x0f, 0x79, 0x4d, 0x77, 0x58, 0x96, 0x59, 0xf3, 0x9a, 0x11},
},
{
commonKey256,
nil,
[]byte{0x02, 0x89, 0x62, 0xf6, 0x1b, 0x7b, 0xf8, 0x9e, 0xfc, 0x6b, 0x55, 0x1f, 0x46, 0x67, 0xd9, 0x83},
},
{
commonKey256,
[]byte{0x6b, 0xc1, 0xbe, 0xe2, 0x2e, 0x40, 0x9f, 0x96, 0xe9, 0x3d, 0x7e, 0x11, 0x73, 0x93, 0x17, 0x2a},
[]byte{0x28, 0xa7, 0x02, 0x3f, 0x45, 0x2e, 0x8f, 0x82, 0xbd, 0x4b, 0xf2, 0x8d, 0x8c, 0x37, 0xc3, 0x5c},
},
{
commonKey256,
[]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,
},
[]byte{0xaa, 0xf3, 0xd8, 0xf1, 0xde, 0x56, 0x40, 0xc2, 0x32, 0xf5, 0xb1, 0x69, 0xb9, 0xc9, 0x11, 0xe6},
},
{
commonKey256,
[]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,
},
[]byte{0xe1, 0x99, 0x21, 0x90, 0x54, 0x9f, 0x6e, 0xd5, 0x69, 0x6a, 0x2c, 0x05, 0x6c, 0x31, 0x54, 0x10},
},
}
func TestCMAC_AES(t *testing.T) {
for i, tt := range cmacAESTests {
c, err := aes.NewCipher(tt.key)
if err != nil {
t.Errorf("test %d: NewCipher: %s", i, err)
continue
}
d := NewCMAC(c)
n, err := d.Write(tt.in)
if err != nil || n != len(tt.in) {
t.Errorf("test %d: Write %d: %d, %s", i, len(tt.in), n, err)
continue
}
sum := d.Sum()
if !same(sum, tt.digest) {
x := d.(*cmac)
t.Errorf("test %d: digest mismatch\n\twant %x\n\thave %x\n\tk1 %x\n\tk2 %x", i, tt.digest, sum, x.k1, x.k2)
continue
}
}
}
// 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 block
import (
"io"
)
type ctrStream struct {
c Cipher
ctr []byte
out []byte
}
func newCTRStream(c Cipher, ctr []byte) *ctrStream {
x := new(ctrStream)
x.c = c
x.ctr = dup(ctr)
x.out = make([]byte, len(ctr))
return x
}
func (x *ctrStream) Next() []byte {
// Next block is encryption of counter.
x.c.Encrypt(x.out, x.ctr)
// Increment counter
for i := len(x.ctr) - 1; i >= 0; i-- {
x.ctr[i]++
if x.ctr[i] != 0 {
break
}
}
return x.out
}
// NewCTRReader returns a reader that reads data from r, decrypts (or encrypts)
// it using c in counter (CTR) mode with the initialization vector iv.
// The returned Reader does not buffer and has no block size.
// In CTR mode, encryption and decryption are the same operation:
// a CTR reader applied to an encrypted stream produces a decrypted
// stream and vice versa.
func NewCTRReader(c Cipher, iv []byte, r io.Reader) io.Reader {
return newXorReader(newCTRStream(c, iv), r)
}
// NewCTRWriter returns a writer that encrypts (or decrypts) data using c
// in counter (CTR) mode with the initialization vector iv
// and writes the encrypted data to w.
// The returned Writer does not buffer and has no block size.
// In CTR mode, encryption and decryption are the same operation:
// a CTR writer applied to an decrypted stream produces an encrypted
// stream and vice versa.
func NewCTRWriter(c Cipher, iv []byte, w io.Writer) io.Writer {
return newXorWriter(newCTRStream(c, iv), w)
}
// 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.
// EAX mode, not a NIST standard (yet).
// EAX provides encryption and authentication.
// EAX targets the same uses as NIST's CCM mode,
// but EAX adds the ability to run in streaming mode.
// See
// http://csrc.nist.gov/groups/ST/toolkit/BCM/documents/proposedmodes/eax/eax-spec.pdf
// http://www.cs.ucdavis.edu/~rogaway/papers/eax.pdf
// What those papers call OMAC is now called CMAC.
package block
import (
"fmt"
"hash"
"io"
"os"
)
// An EAXTagError is returned when the message has failed to authenticate,
// because the tag at the end of the message stream (Read) does not match
// the tag computed from the message itself (Computed).
type EAXTagError struct {
Read []byte
Computed []byte
}
func (e *EAXTagError) String() string {
return fmt.Sprintf("crypto/block: EAX tag mismatch: read %x but computed %x", e.Read, e.Computed)
}
func setupEAX(c Cipher, iv, hdr []byte, tagBytes int) (ctrIV, tag []byte, cmac hash.Hash) {
n := len(iv)
if n != c.BlockSize() {
panic(fmt.Sprintln("crypto/block: EAX: iv length", n, "!=", c.BlockSize()))
}
buf := make([]byte, n) // zeroed
// tag = CMAC(0 + iv) ^ CMAC(1 + hdr) ^ CMAC(2 + data)
cmac = NewCMAC(c)
cmac.Write(buf) // 0
cmac.Write(iv)
sum := cmac.Sum()
ctrIV = dup(sum)
tag = dup(sum[0:tagBytes])
cmac.Reset()
buf[n-1] = 1
cmac.Write(buf) // 1
cmac.Write(hdr)
sum = cmac.Sum()
for i := 0; i < tagBytes; i++ {
tag[i] ^= sum[i]
}
cmac.Reset()
buf[n-1] = 2 // 2
cmac.Write(buf)
return
}
func finishEAX(tag []byte, cmac hash.Hash) {
// Finish CMAC #2 and xor into tag.
sum := cmac.Sum()
for i := range tag {
tag[i] ^= sum[i]
}
}
// Writer adapter. Tees writes into both w and cmac.
// Knows that cmac never returns write errors.
type cmacWriter struct {
w io.Writer
cmac hash.Hash
}
func (cw *cmacWriter) Write(p []byte) (n int, err os.Error) {
n, err = cw.w.Write(p)
cw.cmac.Write(p[0:n])
return
}
// An eaxEncrypter implements the EAX encryption mode.
type eaxEncrypter struct {
ctr io.Writer // CTR encrypter
cw cmacWriter // CTR's output stream
tag []byte
}
// NewEAXEncrypter creates and returns a new EAX encrypter
// using the given cipher c, initialization vector iv, associated data hdr,
// and tag length tagBytes. The encrypter's Write method encrypts
// the data it receives and writes that data to w.
// The encrypter's Close method writes a final authenticating tag to w.
func NewEAXEncrypter(c Cipher, iv []byte, hdr []byte, tagBytes int, w io.Writer) io.WriteCloser {
x := new(eaxEncrypter)
// Create new CTR instance writing to both
// w for encrypted output and cmac for digesting.
x.cw.w = w
var ctrIV []byte
ctrIV, x.tag, x.cw.cmac = setupEAX(c, iv, hdr, tagBytes)
x.ctr = NewCTRWriter(c, ctrIV, &x.cw)
return x
}
func (x *eaxEncrypter) Write(p []byte) (n int, err os.Error) {
return x.ctr.Write(p)
}
func (x *eaxEncrypter) Close() os.Error {
x.ctr = nil // crash if Write is called again
// Write tag.
finishEAX(x.tag, x.cw.cmac)
n, err := x.cw.w.Write(x.tag)
if n != len(x.tag) && err == nil {
err = io.ErrShortWrite
}
return err
}
// Reader adapter. Returns data read from r but hangs
// on to the last len(tag) bytes for itself (returns EOF len(tag)
// bytes early). Also tees all data returned from Read into
// the cmac digest. The "don't return the last t bytes"
// and the "tee into digest" functionality could be separated,
// but the latter half is trivial.
type cmacReader struct {
r io.Reader
cmac hash.Hash
tag []byte
tmp []byte
}
func (cr *cmacReader) Read(p []byte) (n int, err os.Error) {
// TODO(rsc): Maybe fall back to simpler code if
// we recognize the underlying r as a ByteBuffer
// or ByteReader. Then we can just take the last piece
// off at the start.
// First, read a tag-sized chunk.
// It's probably not the tag (unless there's no data).
tag := cr.tag
if len(tag) < cap(tag) {
nt := len(tag)
nn, err1 := io.ReadFull(cr.r, tag[nt:cap(tag)])
tag = tag[0 : nt+nn]
cr.tag = tag
if err1 != nil {
return 0, err1
}
}
tagBytes := len(tag)
if len(p) > 4*tagBytes {
// If p is big, try to read directly into p to avoid a copy.
n, err = cr.r.Read(p[tagBytes:])
if n == 0 {
goto out
}
// copy old tag into p
for i := 0; i < tagBytes; i++ {
p[i] = tag[i]
}
// copy new tag out of p
for i := 0; i < tagBytes; i++ {
tag[i] = p[n+i]
}
goto out
}
// Otherwise, read into p and then slide data
n, err = cr.r.Read(p)
if n == 0 {
goto out
}
// copy tag+p into p+tmp and then swap tmp, tag
tmp := cr.tmp
for i := n + tagBytes - 1; i >= 0; i-- {
var c byte
if i < tagBytes {
c = tag[i]
} else {
c = p[i-tagBytes]
}
if i < n {
p[i] = c
} else {
tmp[i] = c
}
}
cr.tmp, cr.tag = tag, tmp
out:
cr.cmac.Write(p[0:n])
return
}
type eaxDecrypter struct {
ctr io.Reader
cr cmacReader
tag []byte
}
// NewEAXDecrypter creates and returns a new EAX decrypter
// using the given cipher c, initialization vector iv, associated data hdr,
// and tag length tagBytes. The encrypter's Read method decrypts and
// returns data read from r. At r's EOF, the encrypter checks the final
// authenticating tag and returns an EAXTagError if the tag is invalid.
// In that case, the message should be discarded.
// Note that the data stream returned from Read cannot be
// assumed to be valid, authenticated data until Read returns
// 0, nil to signal the end of the data.
func NewEAXDecrypter(c Cipher, iv []byte, hdr []byte, tagBytes int, r io.Reader) io.Reader {
x := new(eaxDecrypter)
x.cr.r = r
x.cr.tag = make([]byte, 0, tagBytes)
x.cr.tmp = make([]byte, 0, tagBytes)
var ctrIV []byte
ctrIV, x.tag, x.cr.cmac = setupEAX(c, iv, hdr, tagBytes)
x.ctr = NewCTRReader(c, ctrIV, &x.cr)
return x
}
func (x *eaxDecrypter) checkTag() os.Error {
x.ctr = nil // crash if Read is called again
finishEAX(x.tag, x.cr.cmac)
if !same(x.tag, x.cr.tag) {
e := new(EAXTagError)
e.Computed = dup(x.tag)
e.Read = dup(x.cr.tag)
return e
}
return nil
}
func (x *eaxDecrypter) Read(p []byte) (n int, err os.Error) {
n, err = x.ctr.Read(p)
if n == 0 && err == nil {
err = x.checkTag()
}
return n, err
}
// 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 block
import (
"bytes"
"crypto/aes"
"fmt"
"io"
"testing"
)
// Test vectors from http://www.cs.ucdavis.edu/~rogaway/papers/eax.pdf
type eaxAESTest struct {
msg []byte
key []byte
nonce []byte
header []byte
cipher []byte
}
var eaxAESTests = []eaxAESTest{
{
[]byte{},
[]byte{0x23, 0x39, 0x52, 0xDE, 0xE4, 0xD5, 0xED, 0x5F, 0x9B, 0x9C, 0x6D, 0x6F, 0xF8, 0x0F, 0xF4, 0x78},
[]byte{0x62, 0xEC, 0x67, 0xF9, 0xC3, 0xA4, 0xA4, 0x07, 0xFC, 0xB2, 0xA8, 0xC4, 0x90, 0x31, 0xA8, 0xB3},
[]byte{0x6B, 0xFB, 0x91, 0x4F, 0xD0, 0x7E, 0xAE, 0x6B},
[]byte{0xE0, 0x37, 0x83, 0x0E, 0x83, 0x89, 0xF2, 0x7B, 0x02, 0x5A, 0x2D, 0x65, 0x27, 0xE7, 0x9D, 0x01},
},
{
[]byte{0xF7, 0xFB},
[]byte{0x91, 0x94, 0x5D, 0x3F, 0x4D, 0xCB, 0xEE, 0x0B, 0xF4, 0x5E, 0xF5, 0x22, 0x55, 0xF0, 0x95, 0xA4},
[]byte{0xBE, 0xCA, 0xF0, 0x43, 0xB0, 0xA2, 0x3D, 0x84, 0x31, 0x94, 0xBA, 0x97, 0x2C, 0x66, 0xDE, 0xBD},
[]byte{0xFA, 0x3B, 0xFD, 0x48, 0x06, 0xEB, 0x53, 0xFA},
[]byte{0x19, 0xDD, 0x5C, 0x4C, 0x93, 0x31, 0x04, 0x9D, 0x0B, 0xDA, 0xB0, 0x27, 0x74, 0x08, 0xF6, 0x79, 0x67, 0xE5},
},
{
[]byte{0x1A, 0x47, 0xCB, 0x49, 0x33},
[]byte{0x01, 0xF7, 0x4A, 0xD6, 0x40, 0x77, 0xF2, 0xE7, 0x04, 0xC0, 0xF6, 0x0A, 0xDA, 0x3D, 0xD5, 0x23},
[]byte{0x70, 0xC3, 0xDB, 0x4F, 0x0D, 0x26, 0x36, 0x84, 0x00, 0xA1, 0x0E, 0xD0, 0x5D, 0x2B, 0xFF, 0x5E},
[]byte{0x23, 0x4A, 0x34, 0x63, 0xC1, 0x26, 0x4A, 0xC6},
[]byte{0xD8, 0x51, 0xD5, 0xBA, 0xE0, 0x3A, 0x59, 0xF2, 0x38, 0xA2, 0x3E, 0x39, 0x19, 0x9D, 0xC9, 0x26, 0x66, 0x26, 0xC4, 0x0F, 0x80},
},
{
[]byte{0x48, 0x1C, 0x9E, 0x39, 0xB1},
[]byte{0xD0, 0x7C, 0xF6, 0xCB, 0xB7, 0xF3, 0x13, 0xBD, 0xDE, 0x66, 0xB7, 0x27, 0xAF, 0xD3, 0xC5, 0xE8},
[]byte{0x84, 0x08, 0xDF, 0xFF, 0x3C, 0x1A, 0x2B, 0x12, 0x92, 0xDC, 0x19, 0x9E, 0x46, 0xB7, 0xD6, 0x17},
[]byte{0x33, 0xCC, 0xE2, 0xEA, 0xBF, 0xF5, 0xA7, 0x9D},
[]byte{0x63, 0x2A, 0x9D, 0x13, 0x1A, 0xD4, 0xC1, 0x68, 0xA4, 0x22, 0x5D, 0x8E, 0x1F, 0xF7, 0x55, 0x93, 0x99, 0x74, 0xA7, 0xBE, 0xDE},
},
{
[]byte{0x40, 0xD0, 0xC0, 0x7D, 0xA5, 0xE4},
[]byte{0x35, 0xB6, 0xD0, 0x58, 0x00, 0x05, 0xBB, 0xC1, 0x2B, 0x05, 0x87, 0x12, 0x45, 0x57, 0xD2, 0xC2},
[]byte{0xFD, 0xB6, 0xB0, 0x66, 0x76, 0xEE, 0xDC, 0x5C, 0x61, 0xD7, 0x42, 0x76, 0xE1, 0xF8, 0xE8, 0x16},
[]byte{0xAE, 0xB9, 0x6E, 0xAE, 0xBE, 0x29, 0x70, 0xE9},
[]byte{0x07, 0x1D, 0xFE, 0x16, 0xC6, 0x75, 0xCB, 0x06, 0x77, 0xE5, 0x36, 0xF7, 0x3A, 0xFE, 0x6A, 0x14, 0xB7, 0x4E, 0xE4, 0x98, 0x44, 0xDD},
},
{
[]byte{0x4D, 0xE3, 0xB3, 0x5C, 0x3F, 0xC0, 0x39, 0x24, 0x5B, 0xD1, 0xFB, 0x7D},
[]byte{0xBD, 0x8E, 0x6E, 0x11, 0x47, 0x5E, 0x60, 0xB2, 0x68, 0x78, 0x4C, 0x38, 0xC6, 0x2F, 0xEB, 0x22},
[]byte{0x6E, 0xAC, 0x5C, 0x93, 0x07, 0x2D, 0x8E, 0x85, 0x13, 0xF7, 0x50, 0x93, 0x5E, 0x46, 0xDA, 0x1B},
[]byte{0xD4, 0x48, 0x2D, 0x1C, 0xA7, 0x8D, 0xCE, 0x0F},
[]byte{0x83, 0x5B, 0xB4, 0xF1, 0x5D, 0x74, 0x3E, 0x35, 0x0E, 0x72, 0x84, 0x14, 0xAB, 0xB8, 0x64, 0x4F, 0xD6, 0xCC, 0xB8, 0x69, 0x47, 0xC5, 0xE1, 0x05, 0x90, 0x21, 0x0A, 0x4F},
},
{
[]byte{0x8B, 0x0A, 0x79, 0x30, 0x6C, 0x9C, 0xE7, 0xED, 0x99, 0xDA, 0xE4, 0xF8, 0x7F, 0x8D, 0xD6, 0x16, 0x36},
[]byte{0x7C, 0x77, 0xD6, 0xE8, 0x13, 0xBE, 0xD5, 0xAC, 0x98, 0xBA, 0xA4, 0x17, 0x47, 0x7A, 0x2E, 0x7D},
[]byte{0x1A, 0x8C, 0x98, 0xDC, 0xD7, 0x3D, 0x38, 0x39, 0x3B, 0x2B, 0xF1, 0x56, 0x9D, 0xEE, 0xFC, 0x19},
[]byte{0x65, 0xD2, 0x01, 0x79, 0x90, 0xD6, 0x25, 0x28},
[]byte{0x02, 0x08, 0x3E, 0x39, 0x79, 0xDA, 0x01, 0x48, 0x12, 0xF5, 0x9F, 0x11, 0xD5, 0x26, 0x30, 0xDA, 0x30, 0x13, 0x73, 0x27, 0xD1, 0x06, 0x49, 0xB0, 0xAA, 0x6E, 0x1C, 0x18, 0x1D, 0xB6, 0x17, 0xD7, 0xF2},
},
{
[]byte{0x1B, 0xDA, 0x12, 0x2B, 0xCE, 0x8A, 0x8D, 0xBA, 0xF1, 0x87, 0x7D, 0x96, 0x2B, 0x85, 0x92, 0xDD, 0x2D, 0x56},
[]byte{0x5F, 0xFF, 0x20, 0xCA, 0xFA, 0xB1, 0x19, 0xCA, 0x2F, 0xC7, 0x35, 0x49, 0xE2, 0x0F, 0x5B, 0x0D},
[]byte{0xDD, 0xE5, 0x9B, 0x97, 0xD7, 0x22, 0x15, 0x6D, 0x4D, 0x9A, 0xFF, 0x2B, 0xC7, 0x55, 0x98, 0x26},
[]byte{0x54, 0xB9, 0xF0, 0x4E, 0x6A, 0x09, 0x18, 0x9A},
[]byte{0x2E, 0xC4, 0x7B, 0x2C, 0x49, 0x54, 0xA4, 0x89, 0xAF, 0xC7, 0xBA, 0x48, 0x97, 0xED, 0xCD, 0xAE, 0x8C, 0xC3, 0x3B, 0x60, 0x45, 0x05, 0x99, 0xBD, 0x02, 0xC9, 0x63, 0x82, 0x90, 0x2A, 0xEF, 0x7F, 0x83, 0x2A},
},
{
[]byte{0x6C, 0xF3, 0x67, 0x20, 0x87, 0x2B, 0x85, 0x13, 0xF6, 0xEA, 0xB1, 0xA8, 0xA4, 0x44, 0x38, 0xD5, 0xEF, 0x11},
[]byte{0xA4, 0xA4, 0x78, 0x2B, 0xCF, 0xFD, 0x3E, 0xC5, 0xE7, 0xEF, 0x6D, 0x8C, 0x34, 0xA5, 0x61, 0x23},
[]byte{0xB7, 0x81, 0xFC, 0xF2, 0xF7, 0x5F, 0xA5, 0xA8, 0xDE, 0x97, 0xA9, 0xCA, 0x48, 0xE5, 0x22, 0xEC},
[]byte{0x89, 0x9A, 0x17, 0x58, 0x97, 0x56, 0x1D, 0x7E},
[]byte{0x0D, 0xE1, 0x8F, 0xD0, 0xFD, 0xD9, 0x1E, 0x7A, 0xF1, 0x9F, 0x1D, 0x8E, 0xE8, 0x73, 0x39, 0x38, 0xB1, 0xE8, 0xE7, 0xF6, 0xD2, 0x23, 0x16, 0x18, 0x10, 0x2F, 0xDB, 0x7F, 0xE5, 0x5F, 0xF1, 0x99, 0x17, 0x00},
},
{
[]byte{0xCA, 0x40, 0xD7, 0x44, 0x6E, 0x54, 0x5F, 0xFA, 0xED, 0x3B, 0xD1, 0x2A, 0x74, 0x0A, 0x65, 0x9F, 0xFB, 0xBB, 0x3C, 0xEA, 0xB7},
[]byte{0x83, 0x95, 0xFC, 0xF1, 0xE9, 0x5B, 0xEB, 0xD6, 0x97, 0xBD, 0x01, 0x0B, 0xC7, 0x66, 0xAA, 0xC3},
[]byte{0x22, 0xE7, 0xAD, 0xD9, 0x3C, 0xFC, 0x63, 0x93, 0xC5, 0x7E, 0xC0, 0xB3, 0xC1, 0x7D, 0x6B, 0x44},
[]byte{0x12, 0x67, 0x35, 0xFC, 0xC3, 0x20, 0xD2, 0x5A},
[]byte{0xCB, 0x89, 0x20, 0xF8, 0x7A, 0x6C, 0x75, 0xCF, 0xF3, 0x96, 0x27, 0xB5, 0x6E, 0x3E, 0xD1, 0x97, 0xC5, 0x52, 0xD2, 0x95, 0xA7, 0xCF, 0xC4, 0x6A, 0xFC, 0x25, 0x3B, 0x46, 0x52, 0xB1, 0xAF, 0x37, 0x95, 0xB1, 0x24, 0xAB, 0x6E},
},
}
func TestEAXEncrypt_AES(t *testing.T) {
b := new(bytes.Buffer)
for i, tt := range eaxAESTests {
test := fmt.Sprintf("test %d", i)
c, err := aes.NewCipher(tt.key)
if err != nil {
t.Fatalf("%s: NewCipher(%d bytes) = %s", test, len(tt.key), err)
}
b.Reset()
enc := NewEAXEncrypter(c, tt.nonce, tt.header, 16, b)
n, err := io.Copy(enc, bytes.NewBuffer(tt.msg))
if n != int64(len(tt.msg)) || err != nil {
t.Fatalf("%s: io.Copy into encrypter: %d, %s", test, n, err)
}
err = enc.Close()
if err != nil {
t.Fatalf("%s: enc.Close: %s", test, err)
}
if d := b.Bytes(); !same(d, tt.cipher) {
t.Fatalf("%s: got %x want %x", test, d, tt.cipher)
}
}
}
func TestEAXDecrypt_AES(t *testing.T) {
b := new(bytes.Buffer)
for i, tt := range eaxAESTests {
test := fmt.Sprintf("test %d", i)
c, err := aes.NewCipher(tt.key)
if err != nil {
t.Fatalf("%s: NewCipher(%d bytes) = %s", test, len(tt.key), err)
}
b.Reset()
dec := NewEAXDecrypter(c, tt.nonce, tt.header, 16, bytes.NewBuffer(tt.cipher))
n, err := io.Copy(b, dec)
if n != int64(len(tt.msg)) || err != nil {
t.Fatalf("%s: io.Copy into decrypter: %d, %s", test, n, err)
}
if d := b.Bytes(); !same(d, tt.msg) {
t.Fatalf("%s: got %x want %x", test, d, tt.msg)
}
}
}
// 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.
// Electronic codebook (ECB) mode.
// ECB is a fancy name for ``encrypt and decrypt each block separately.''
// It's a pretty bad thing to do for any large amount of data (more than one block),
// because the individual blocks can still be identified, duplicated, and reordered.
// The ECB implementation exists mainly to provide buffering for
// the other modes, which wrap it by providing modified Ciphers.
// See NIST SP 800-38A, pp 9-10
package block
import (
"io"
"os"
"strconv"
)
type ecbDecrypter struct {
c Cipher
r io.Reader
blockSize int // block size
// Buffered data.
// The buffer buf is used as storage for both
// plain or crypt; at least one of those is nil at any given time.
buf []byte
plain []byte // plain text waiting to be read
crypt []byte // ciphertext waiting to be decrypted
}
// Read into x.crypt until it has a full block or EOF or an error happens.
func (x *ecbDecrypter) fillCrypt() os.Error {
var err os.Error
for len(x.crypt) < x.blockSize {
off := len(x.crypt)
var m int
m, err = x.r.Read(x.crypt[off:x.blockSize])
x.crypt = x.crypt[0 : off+m]
if m == 0 {
break
}
// If an error happened but we got enough
// data to do some decryption, we can decrypt
// first and report the error (with some data) later.
// But if we don't have enough to decrypt,
// have to stop now.
if err != nil && len(x.crypt) < x.blockSize {
break
}
}
return err
}
// Read from plain text buffer into p.
func (x *ecbDecrypter) readPlain(p []byte) int {
n := len(x.plain)
if n > len(p) {
n = len(p)
}
for i := 0; i < n; i++ {
p[i] = x.plain[i]
}
if n < len(x.plain) {
x.plain = x.plain[n:]
} else {
x.plain = nil
}
return n
}
type ecbFragmentError int
func (n ecbFragmentError) String() string {
return "crypto/block: " + strconv.Itoa(int(n)) + "-byte fragment at EOF"
}
func (x *ecbDecrypter) Read(p []byte) (n int, err os.Error) {
if len(p) == 0 {
return
}
// If there's no plaintext waiting and p is not big enough
// to hold a whole cipher block, we'll have to work in the
// cipher text buffer. Set it to non-nil so that the
// code below will fill it.
if x.plain == nil && len(p) < x.blockSize && x.crypt == nil {
x.crypt = x.buf[0:0]
}
// If there is a leftover cipher text buffer,
// try to accumulate a full block.
if x.crypt != nil {
err = x.fillCrypt()
if err != nil || len(x.crypt) == 0 {
return
}
x.c.Decrypt(x.crypt, x.crypt)
x.plain = x.crypt
x.crypt = nil
}
// If there is a leftover plain text buffer, read from it.
if x.plain != nil {
n = x.readPlain(p)
return
}
// Read and decrypt directly in caller's buffer.
n, err = io.ReadAtLeast(x.r, p, x.blockSize)
if err == os.EOF && n > 0 {
// EOF is only okay on block boundary
err = os.ErrorString("block fragment at EOF during decryption")
return
}
var i int
for i = 0; i+x.blockSize <= n; i += x.blockSize {
a := p[i : i+x.blockSize]
x.c.Decrypt(a, a)
}
// There might be an encrypted fringe remaining.
// Save it for next time.
if i < n {
p = p[i:n]
copy(x.buf, p)
x.crypt = x.buf[0:len(p)]
n = i
}
return
}
// NewECBDecrypter returns a reader that reads data from r and decrypts it using c.
// It decrypts by calling c.Decrypt on each block in sequence;
// this mode is known as electronic codebook mode, or ECB.
// The returned Reader does not buffer or read ahead except
// as required by the cipher's block size.
func NewECBDecrypter(c Cipher, r io.Reader) io.Reader {
x := new(ecbDecrypter)
x.c = c
x.r = r
x.blockSize = c.BlockSize()
x.buf = make([]byte, x.blockSize)
return x
}
type ecbEncrypter struct {
c Cipher
w io.Writer
blockSize int
// Buffered data.
// The buffer buf is used as storage for both
// plain or crypt. If both are non-nil, plain
// follows crypt in buf.
buf []byte
plain []byte // plain text waiting to be encrypted
crypt []byte // encrypted text waiting to be written
}
// Flush the x.crypt buffer to x.w.
func (x *ecbEncrypter) flushCrypt() os.Error {
if len(x.crypt) == 0 {
return nil
}
n, err := x.w.Write(x.crypt)
if n < len(x.crypt) {
x.crypt = x.crypt[n:]
if err == nil {
err = io.ErrShortWrite
}
}
if err != nil {
return err
}
x.crypt = nil
return nil
}
// Slide x.plain down to the beginning of x.buf.
// Plain is known to have less than one block of data,
// so this is cheap enough.
func (x *ecbEncrypter) slidePlain() {
if len(x.plain) == 0 {
x.plain = x.buf[0:0]
} else if cap(x.plain) < cap(x.buf) {
copy(x.buf, x.plain)
x.plain = x.buf[0:len(x.plain)]
}
}
// Fill x.plain from the data in p.
// Return the number of bytes copied.
func (x *ecbEncrypter) fillPlain(p []byte) int {
off := len(x.plain)
n := len(p)
if max := cap(x.plain) - off; n > max {
n = max
}
x.plain = x.plain[0 : off+n]
for i := 0; i < n; i++ {
x.plain[off+i] = p[i]
}
return n
}
// Encrypt x.plain; record encrypted range as x.crypt.
func (x *ecbEncrypter) encrypt() {
var i int
n := len(x.plain)
for i = 0; i+x.blockSize <= n; i += x.blockSize {
a := x.plain[i : i+x.blockSize]
x.c.Encrypt(a, a)
}
x.crypt = x.plain[0:i]
x.plain = x.plain[i:n]
}
func (x *ecbEncrypter) Write(p []byte) (n int, err os.Error) {
for {
// If there is data waiting to be written, write it.
// This can happen on the first iteration
// if a write failed in an earlier call.
if err = x.flushCrypt(); err != nil {
return
}
// Now that encrypted data is gone (flush ran),
// perhaps we need to slide the plaintext down.
x.slidePlain()
// Fill plaintext buffer from p.
m := x.fillPlain(p)
if m == 0 {
break
}
n += m
p = p[m:]
// Encrypt, adjusting crypt and plain.
x.encrypt()
// Write x.crypt.
if err = x.flushCrypt(); err != nil {
break
}
}
return
}
// NewECBEncrypter returns a writer that encrypts data using c and writes it to w.
// It encrypts by calling c.Encrypt on each block in sequence;
// this mode is known as electronic codebook mode, or ECB.
// The returned Writer does no buffering except as required
// by the cipher's block size, so there is no need for a Flush method.
func NewECBEncrypter(c Cipher, w io.Writer) io.Writer {
x := new(ecbEncrypter)
x.c = c
x.w = w
x.blockSize = c.BlockSize()
// Create a buffer that is an integral number of blocks.
x.buf = make([]byte, 8192/x.blockSize*x.blockSize)
return x
}
// 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.
// ECB 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-27.
package block
import (
"bytes"
"crypto/aes"
"io"
"testing"
)
type ecbTest struct {
name string
key []byte
in []byte
out []byte
}
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}
var ecbAESTests = []ecbTest{
// FIPS 197, Appendix B, C
{
"FIPS-197 Appendix B",
commonKey128,
[]byte{0x32, 0x43, 0xf6, 0xa8, 0x88, 0x5a, 0x30, 0x8d, 0x31, 0x31, 0x98, 0xa2, 0xe0, 0x37, 0x07, 0x34},
[]byte{0x39, 0x25, 0x84, 0x1d, 0x02, 0xdc, 0x09, 0xfb, 0xdc, 0x11, 0x85, 0x97, 0x19, 0x6a, 0x0b, 0x32},
},
// NIST SP 800-38A pp 24-27
{
"ECB-AES128",
commonKey128,
commonInput,
[]byte{
0x3a, 0xd7, 0x7b, 0xb4, 0x0d, 0x7a, 0x36, 0x60, 0xa8, 0x9e, 0xca, 0xf3, 0x24, 0x66, 0xef, 0x97,
0xf5, 0xd3, 0xd5, 0x85, 0x03, 0xb9, 0x69, 0x9d, 0xe7, 0x85, 0x89, 0x5a, 0x96, 0xfd, 0xba, 0xaf,
0x43, 0xb1, 0xcd, 0x7f, 0x59, 0x8e, 0xce, 0x23, 0x88, 0x1b, 0x00, 0xe3, 0xed, 0x03, 0x06, 0x88,
0x7b, 0x0c, 0x78, 0x5e, 0x27, 0xe8, 0xad, 0x3f, 0x82, 0x23, 0x20, 0x71, 0x04, 0x72, 0x5d, 0xd4,
},
},
{
"ECB-AES192",
commonKey192,
commonInput,
[]byte{
0xbd, 0x33, 0x4f, 0x1d, 0x6e, 0x45, 0xf2, 0x5f, 0xf7, 0x12, 0xa2, 0x14, 0x57, 0x1f, 0xa5, 0xcc,
0x97, 0x41, 0x04, 0x84, 0x6d, 0x0a, 0xd3, 0xad, 0x77, 0x34, 0xec, 0xb3, 0xec, 0xee, 0x4e, 0xef,
0xef, 0x7a, 0xfd, 0x22, 0x70, 0xe2, 0xe6, 0x0a, 0xdc, 0xe0, 0xba, 0x2f, 0xac, 0xe6, 0x44, 0x4e,
0x9a, 0x4b, 0x41, 0xba, 0x73, 0x8d, 0x6c, 0x72, 0xfb, 0x16, 0x69, 0x16, 0x03, 0xc1, 0x8e, 0x0e,
},
},
{
"ECB-AES256",
commonKey256,
commonInput,
[]byte{
0xf3, 0xee, 0xd1, 0xbd, 0xb5, 0xd2, 0xa0, 0x3c, 0x06, 0x4b, 0x5a, 0x7e, 0x3d, 0xb1, 0x81, 0xf8,
0x59, 0x1c, 0xcb, 0x10, 0xd4, 0x10, 0xed, 0x26, 0xdc, 0x5b, 0xa7, 0x4a, 0x31, 0x36, 0x28, 0x70,
0xb6, 0xed, 0x21, 0xb9, 0x9c, 0xa6, 0xf4, 0xf9, 0xf1, 0x53, 0xe7, 0xb1, 0xbe, 0xaf, 0xed, 0x1d,
0x23, 0x30, 0x4b, 0x7a, 0x39, 0xf9, 0xf3, 0xff, 0x06, 0x7d, 0x8d, 0x8f, 0x9e, 0x24, 0xec, 0xc7,
},
},
}
func TestECB_AES(t *testing.T) {
for _, tt := range ecbAESTests {
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
}
var crypt bytes.Buffer
w := NewECBEncrypter(c, &crypt)
var r io.Reader = bytes.NewBuffer(tt.in)
n, err := io.Copy(w, r)
if n != int64(len(tt.in)) || err != nil {
t.Errorf("%s: ECBReader io.Copy = %d, %v want %d, nil", test, n, err, len(tt.in))
} else if d := crypt.Bytes(); !same(tt.out, d) {
t.Errorf("%s: ECBReader\nhave %x\nwant %x", test, d, tt.out)
}
var plain bytes.Buffer
r = NewECBDecrypter(c, bytes.NewBuffer(tt.out))
w = &plain
n, err = io.Copy(w, r)
if n != int64(len(tt.out)) || err != nil {
t.Errorf("%s: ECBWriter io.Copy = %d, %v want %d, nil", test, n, err, len(tt.out))
} else if d := plain.Bytes(); !same(tt.in, d) {
t.Errorf("%s: ECBWriter\nhave %x\nwant %x", test, d, tt.in)
}
if t.Failed() {
break
}
}
}
// 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 block
import (
"bytes"
"fmt"
"io"
"testing"
"testing/iotest"
)
// Simple Cipher for testing: adds an incrementing amount
// to each byte in each
type IncCipher struct {
blockSize int
delta byte
encrypting bool
}
func (c *IncCipher) BlockSize() int { return c.blockSize }
func (c *IncCipher) Encrypt(dst, src []byte) {
if !c.encrypting {
panic("encrypt: not encrypting")
}
if len(src) != c.blockSize || len(dst) != c.blockSize {
panic(fmt.Sprintln("encrypt: wrong block size", c.blockSize, len(src), len(dst)))
}
c.delta++
for i, b := range src {
dst[i] = b + c.delta
}
}
func (c *IncCipher) Decrypt(dst, src []byte) {
if c.encrypting {
panic("decrypt: not decrypting")
}
if len(src) != c.blockSize || len(dst) != c.blockSize {
panic(fmt.Sprintln("decrypt: wrong block size ", c.blockSize, " ", len(src), " ", len(dst)))
}
c.delta--
for i, b := range src {
dst[i] = b + c.delta
}
}
func TestECBEncrypter(t *testing.T) {
var plain, crypt [256]byte
for i := 0; i < len(plain); i++ {
plain[i] = byte(i)
}
b := new(bytes.Buffer)
for block := 1; block <= 64; block *= 2 {
// compute encrypted version
delta := byte(0)
for i := 0; i < len(crypt); i++ {
if i%block == 0 {
delta++
}
crypt[i] = plain[i] + delta
}
for frag := 0; frag < 2; frag++ {
c := &IncCipher{block, 0, true}
b.Reset()
r := bytes.NewBuffer(plain[0:])
w := NewECBEncrypter(c, b)
// copy plain into w in increasingly large chunks: 1, 1, 2, 4, 8, ...
// if frag != 0, move the 1 to the end to cause fragmentation.
if frag == 0 {
_, err := io.Copyn(w, r, 1)
if err != nil {
t.Errorf("block=%d frag=0: first Copyn: %s", block, err)
continue
}
}
for n := 1; n <= len(plain)/2; n *= 2 {
_, err := io.Copyn(w, r, int64(n))
if err != nil {
t.Errorf("block=%d frag=%d: Copyn %d: %s", block, frag, n, err)
}
}
if frag != 0 {
_, err := io.Copyn(w, r, 1)
if err != nil {
t.Errorf("block=%d frag=1: last Copyn: %s", block, err)
continue
}
}
// check output
data := b.Bytes()
if len(data) != len(crypt) {
t.Errorf("block=%d frag=%d: want %d bytes, got %d", block, frag, len(crypt), len(data))
continue
}
if string(data) != string(crypt[0:]) {
t.Errorf("block=%d frag=%d: want %x got %x", block, frag, data, crypt)
}
}
}
}
func testECBDecrypter(t *testing.T, maxio int) {
var readers = []func(io.Reader) io.Reader{
func(r io.Reader) io.Reader { return r },
iotest.OneByteReader,
iotest.HalfReader,
}
var plain, crypt [256]byte
for i := 0; i < len(plain); i++ {
plain[i] = byte(255 - i)
}
b := new(bytes.Buffer)
for block := 1; block <= 64 && block <= maxio; block *= 2 {
// compute encrypted version
delta := byte(0)
for i := 0; i < len(crypt); i++ {
if i%block == 0 {
delta++
}
crypt[i] = plain[i] + delta
}
for mode := 0; mode < len(readers); mode++ {
for frag := 0; frag < 2; frag++ {
test := fmt.Sprintf("block=%d mode=%d frag=%d maxio=%d", block, mode, frag, maxio)
c := &IncCipher{block, 0, false}
b.Reset()
r := NewECBDecrypter(c, readers[mode](bytes.NewBuffer(crypt[0:maxio])))
// read from crypt in increasingly large chunks: 1, 1, 2, 4, 8, ...
// if frag == 1, move the 1 to the end to cause fragmentation.
if frag == 0 {
_, err := io.Copyn(b, r, 1)
if err != nil {
t.Errorf("%s: first Copyn: %s", test, err)
continue
}
}
for n := 1; n <= maxio/2; n *= 2 {
_, err := io.Copyn(b, r, int64(n))
if err != nil {
t.Errorf("%s: Copyn %d: %s", test, n, err)
}
}
if frag != 0 {
_, err := io.Copyn(b, r, 1)
if err != nil {
t.Errorf("%s: last Copyn: %s", test, err)
continue
}
}
// check output
data := b.Bytes()
if len(data) != maxio {
t.Errorf("%s: want %d bytes, got %d", test, maxio, len(data))
continue
}
if string(data) != string(plain[0:maxio]) {
t.Errorf("%s: input=%x want %x got %x", test, crypt[0:maxio], plain[0:maxio], data)
}
}
}
}
}
func TestECBDecrypter(t *testing.T) {
// Do shorter I/O sizes first; they're easier to debug.
for n := 1; n <= 256 && !t.Failed(); n *= 2 {
testECBDecrypter(t, n)
}
}
// 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.
// Output feedback (OFB) mode.
// OFB converts a block cipher into a stream cipher by
// repeatedly encrypting an initialization vector and
// xoring the resulting stream of data with the input.
// See NIST SP 800-38A, pp 13-15
package block
import (
"fmt"
"io"
)
type ofbStream struct {
c Cipher
iv []byte
}
func newOFBStream(c Cipher, iv []byte) *ofbStream {
x := new(ofbStream)
x.c = c
n := len(iv)
if n != c.BlockSize() {
panic(fmt.Sprintln("crypto/block: newOFBStream: invalid iv size", n, "!=", c.BlockSize()))
}
x.iv = dup(iv)
return x
}
func (x *ofbStream) Next() []byte {
x.c.Encrypt(x.iv, x.iv)
return x.iv
}
// NewOFBReader returns a reader that reads data from r, decrypts (or encrypts)
// it using c in output feedback (OFB) mode with the initialization vector iv.
// The returned Reader does not buffer and has no block size.
// In OFB mode, encryption and decryption are the same operation:
// an OFB reader applied to an encrypted stream produces a decrypted
// stream and vice versa.
func NewOFBReader(c Cipher, iv []byte, r io.Reader) io.Reader {
return newXorReader(newOFBStream(c, iv), r)
}
// NewOFBWriter returns a writer that encrypts (or decrypts) data using c
// in cipher feedback (OFB) mode with the initialization vector iv
// and writes the encrypted data to w.
// The returned Writer does not buffer and has no block size.
// In OFB mode, encryption and decryption are the same operation:
// an OFB writer applied to an decrypted stream produces an encrypted
// stream and vice versa.
func NewOFBWriter(c Cipher, iv []byte, w io.Writer) io.Writer {
return newXorWriter(newOFBStream(c, iv), w)
}
// 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.
// OFB 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. 52-55.
package block
import (
"bytes"
"crypto/aes"
"io"
"testing"
)
type ofbTest struct {
name string
key []byte
iv []byte
in []byte
out []byte
}
var ofbAESTests = []ofbTest{
// NIST SP 800-38A pp 52-55
{
"OFB-AES128",
commonKey128,
commonIV,
commonInput,
[]byte{
0x3b, 0x3f, 0xd9, 0x2e, 0xb7, 0x2d, 0xad, 0x20, 0x33, 0x34, 0x49, 0xf8, 0xe8, 0x3c, 0xfb, 0x4a,
0x77, 0x89, 0x50, 0x8d, 0x16, 0x91, 0x8f, 0x03, 0xf5, 0x3c, 0x52, 0xda, 0xc5, 0x4e, 0xd8, 0x25,
0x97, 0x40, 0x05, 0x1e, 0x9c, 0x5f, 0xec, 0xf6, 0x43, 0x44, 0xf7, 0xa8, 0x22, 0x60, 0xed, 0xcc,
0x30, 0x4c, 0x65, 0x28, 0xf6, 0x59, 0xc7, 0x78, 0x66, 0xa5, 0x10, 0xd9, 0xc1, 0xd6, 0xae, 0x5e,
},
},
{
"OFB-AES192",
commonKey192,
commonIV,
commonInput,
[]byte{
0xcd, 0xc8, 0x0d, 0x6f, 0xdd, 0xf1, 0x8c, 0xab, 0x34, 0xc2, 0x59, 0x09, 0xc9, 0x9a, 0x41, 0x74,
0xfc, 0xc2, 0x8b, 0x8d, 0x4c, 0x63, 0x83, 0x7c, 0x09, 0xe8, 0x17, 0x00, 0xc1, 0x10, 0x04, 0x01,
0x8d, 0x9a, 0x9a, 0xea, 0xc0, 0xf6, 0x59, 0x6f, 0x55, 0x9c, 0x6d, 0x4d, 0xaf, 0x59, 0xa5, 0xf2,
0x6d, 0x9f, 0x20, 0x08, 0x57, 0xca, 0x6c, 0x3e, 0x9c, 0xac, 0x52, 0x4b, 0xd9, 0xac, 0xc9, 0x2a,
},
},
{
"OFB-AES256",
commonKey256,
commonIV,
commonInput,
[]byte{
0xdc, 0x7e, 0x84, 0xbf, 0xda, 0x79, 0x16, 0x4b, 0x7e, 0xcd, 0x84, 0x86, 0x98, 0x5d, 0x38, 0x60,
0x4f, 0xeb, 0xdc, 0x67, 0x40, 0xd2, 0x0b, 0x3a, 0xc8, 0x8f, 0x6a, 0xd8, 0x2a, 0x4f, 0xb0, 0x8d,
0x71, 0xab, 0x47, 0xa0, 0x86, 0xe8, 0x6e, 0xed, 0xf3, 0x9d, 0x1c, 0x5b, 0xba, 0x97, 0xc4, 0x08,
0x01, 0x26, 0x14, 0x1d, 0x67, 0xf3, 0x7b, 0xe8, 0x53, 0x8f, 0x5a, 0x8b, 0xe7, 0x40, 0xe4, 0x84,
},
},
}
func TestOFB_AES(t *testing.T) {
for _, tt := range ofbAESTests {
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 {
var crypt bytes.Buffer
in := tt.in[0 : len(tt.in)-j]
w := NewOFBWriter(c, tt.iv, &crypt)
var r io.Reader = bytes.NewBuffer(in)
n, err := io.Copy(w, r)
if n != int64(len(in)) || err != nil {
t.Errorf("%s/%d: OFBWriter io.Copy = %d, %v want %d, nil", test, len(in), n, err, len(in))
} else if d, out := crypt.Bytes(), tt.out[0:len(in)]; !same(out, d) {
t.Errorf("%s/%d: OFBWriter\ninpt %x\nhave %x\nwant %x", test, len(in), in, d, out)
}
}
for j := 0; j <= 7; j += 7 {
var plain bytes.Buffer
out := tt.out[0 : len(tt.out)-j]
r := NewOFBReader(c, tt.iv, bytes.NewBuffer(out))
w := &plain
n, err := io.Copy(w, r)
if n != int64(len(out)) || err != nil {
t.Errorf("%s/%d: OFBReader io.Copy = %d, %v want %d, nil", test, len(out), n, err, len(out))
} else if d, in := plain.Bytes(), tt.in[0:len(out)]; !same(in, d) {
t.Errorf("%s/%d: OFBReader\nhave %x\nwant %x", test, len(out), d, in)
}
}
if t.Failed() {
break
}
}
}
// 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
}
// 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 block
import (
"bytes"
"fmt"
"io"
"testing"
"testing/iotest"
)
// Simple "pseudo-random" stream for testing.
type incStream struct {
buf []byte
n byte
}
func newIncStream(blockSize int) *incStream {
x := new(incStream)
x.buf = make([]byte, blockSize)
return x
}
func (x *incStream) Next() []byte {
x.n++
for i := range x.buf {
x.buf[i] = x.n
x.n++
}
return x.buf
}
func testXorWriter(t *testing.T, maxio int) {
var plain, crypt [256]byte
for i := 0; i < len(plain); i++ {
plain[i] = byte(i)
}
b := new(bytes.Buffer)
for block := 1; block <= 64 && block <= maxio; block *= 2 {
// compute encrypted version
n := byte(0)
for i := 0; i < len(crypt); i++ {
if i%block == 0 {
n++
}
crypt[i] = plain[i] ^ n
n++
}
for frag := 0; frag < 2; frag++ {
test := fmt.Sprintf("block=%d frag=%d maxio=%d", block, frag, maxio)
b.Reset()
r := bytes.NewBuffer(plain[0:])
s := newIncStream(block)
w := newXorWriter(s, b)
// copy plain into w in increasingly large chunks: 1, 1, 2, 4, 8, ...
// if frag != 0, move the 1 to the end to cause fragmentation.
if frag == 0 {
_, err := io.Copyn(w, r, 1)
if err != nil {
t.Errorf("%s: first Copyn: %s", test, err)
continue
}
}
for n := 1; n <= len(plain)/2; n *= 2 {
_, err := io.Copyn(w, r, int64(n))
if err != nil {
t.Errorf("%s: Copyn %d: %s", test, n, err)
}
}
// check output
crypt := crypt[0 : len(crypt)-frag]
data := b.Bytes()
if len(data) != len(crypt) {
t.Errorf("%s: want %d bytes, got %d", test, len(crypt), len(data))
continue
}
if string(data) != string(crypt) {
t.Errorf("%s: want %x got %x", test, data, crypt)
}
}
}
}
func TestXorWriter(t *testing.T) {
// Do shorter I/O sizes first; they're easier to debug.
for n := 1; n <= 256 && !t.Failed(); n *= 2 {
testXorWriter(t, n)
}
}
func testXorReader(t *testing.T, maxio int) {
var readers = []func(io.Reader) io.Reader{
func(r io.Reader) io.Reader { return r },
iotest.OneByteReader,
iotest.HalfReader,
}
var plain, crypt [256]byte
for i := 0; i < len(plain); i++ {
plain[i] = byte(255 - i)
}
b := new(bytes.Buffer)
for block := 1; block <= 64 && block <= maxio; block *= 2 {
// compute encrypted version
n := byte(0)
for i := 0; i < len(crypt); i++ {
if i%block == 0 {
n++
}
crypt[i] = plain[i] ^ n
n++
}
for mode := 0; mode < len(readers); mode++ {
for frag := 0; frag < 2; frag++ {
test := fmt.Sprintf("block=%d mode=%d frag=%d maxio=%d", block, mode, frag, maxio)
s := newIncStream(block)
b.Reset()
r := newXorReader(s, readers[mode](bytes.NewBuffer(crypt[0:maxio])))
// read from crypt in increasingly large chunks: 1, 1, 2, 4, 8, ...
// if frag == 1, move the 1 to the end to cause fragmentation.
if frag == 0 {
_, err := io.Copyn(b, r, 1)
if err != nil {
t.Errorf("%s: first Copyn: %s", test, err)
continue
}
}
for n := 1; n <= maxio/2; n *= 2 {
_, err := io.Copyn(b, r, int64(n))
if err != nil {
t.Errorf("%s: Copyn %d: %s", test, n, err)
}
}
// check output
data := b.Bytes()
crypt := crypt[0 : maxio-frag]
plain := plain[0 : maxio-frag]
if len(data) != len(plain) {
t.Errorf("%s: want %d bytes, got %d", test, len(plain), len(data))
continue
}
if string(data) != string(plain) {
t.Errorf("%s: input=%x want %x got %x", test, crypt, plain, data)
}
}
}
}
}
func TestXorReader(t *testing.T) {
// Do shorter I/O sizes first; they're easier to debug.
for n := 1; n <= 256 && !t.Failed(); n *= 2 {
testXorReader(t, n)
}
}
// TODO(rsc): Test handling of writes after write errors.
// Copyright 2011 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 des
import (
"encoding/binary"
)
func cryptBlock(subkeys []uint64, dst, src []byte, decrypt bool) {
b := binary.BigEndian.Uint64(src)
b = permuteBlock(b, initialPermutation[:])
left, right := uint32(b>>32), uint32(b)
var subkey uint64
for i := 0; i < 16; i++ {
if decrypt {
subkey = subkeys[15-i]
} else {
subkey = subkeys[i]
}
left, right = right, left^feistel(right, subkey)
}
// switch left & right and perform final permutation
preOutput := (uint64(right) << 32) | uint64(left)
binary.BigEndian.PutUint64(dst, permuteBlock(preOutput, finalPermutation[:]))
}
// Encrypt one block from src into dst, using the subkeys.
func encryptBlock(subkeys []uint64, dst, src []byte) {
cryptBlock(subkeys, dst, src, false)
}
// Decrypt one block from src into dst, using the subkeys.
func decryptBlock(subkeys []uint64, dst, src []byte) {
cryptBlock(subkeys, dst, src, true)
}
// DES Feistel function
func feistel(right uint32, key uint64) (result uint32) {
sBoxLocations := key ^ permuteBlock(uint64(right), expansionFunction[:])
var sBoxResult uint32
for i := uint8(0); i < 8; i++ {
sBoxLocation := uint8(sBoxLocations>>42) & 0x3f
sBoxLocations <<= 6
// row determined by 1st and 6th bit
row := (sBoxLocation & 0x1) | ((sBoxLocation & 0x20) >> 4)
// column is middle four bits
column := (sBoxLocation >> 1) & 0xf
sBoxResult |= uint32(sBoxes[i][row][column]) << (4 * (7 - i))
}
return uint32(permuteBlock(uint64(sBoxResult), permutationFunction[:]))
}
// general purpose function to perform DES block permutations
func permuteBlock(src uint64, permutation []uint8) (block uint64) {
for position, n := range permutation {
bit := (src >> n) & 1
block |= bit << uint((len(permutation)-1)-position)
}
return
}
// creates 16 28-bit blocks rotated according
// to the rotation schedule
func ksRotate(in uint32) (out []uint32) {
out = make([]uint32, 16)
last := in
for i := 0; i < 16; i++ {
// 28-bit circular left shift
left := (last << (4 + ksRotations[i])) >> 4
right := (last << 4) >> (32 - ksRotations[i])
out[i] = left | right
last = out[i]
}
return
}
// creates 16 56-bit subkeys from the original key
func (c *Cipher) generateSubkeys(keyBytes []byte) {
// apply PC1 permutation to key
key := binary.BigEndian.Uint64(keyBytes)
permutedKey := permuteBlock(key, permutedChoice1[:])
// rotate halves of permuted key according to the rotation schedule
leftRotations := ksRotate(uint32(permutedKey >> 28))
rightRotations := ksRotate(uint32(permutedKey<<4) >> 4)
// generate subkeys
for i := 0; i < 16; i++ {
// combine halves to form 56-bit input to PC2
pc2Input := uint64(leftRotations[i])<<28 | uint64(rightRotations[i])
// apply PC2 permutation to 7 byte input
c.subkeys[i] = permuteBlock(pc2Input, permutedChoice2[:])
}
}
// Copyright 2011 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 des
import (
"os"
"strconv"
)
// The DES block size in bytes.
const BlockSize = 8
type KeySizeError int
func (k KeySizeError) String() string {
return "crypto/des: invalid key size " + strconv.Itoa(int(k))
}
// Cipher is an instance of DES encryption.
type Cipher struct {
subkeys [16]uint64
}
// NewCipher creates and returns a new Cipher.
func NewCipher(key []byte) (*Cipher, os.Error) {
if len(key) != 8 {
return nil, KeySizeError(len(key))
}
c := new(Cipher)
c.generateSubkeys(key)
return c, nil
}
// BlockSize returns the DES block size, 8 bytes.
func (c *Cipher) BlockSize() int { return BlockSize }
// Encrypts the 8-byte buffer src and stores the result in dst.
// Note that for amounts of data larger than a block,
// it is not safe to just call Encrypt on successive blocks;
// instead, use an encryption mode like CBC (see crypto/cipher/cbc.go).
func (c *Cipher) Encrypt(dst, src []byte) { encryptBlock(c.subkeys[:], dst, src) }
// Decrypts the 8-byte buffer src and stores the result in dst.
func (c *Cipher) Decrypt(dst, src []byte) { decryptBlock(c.subkeys[:], dst, src) }
// Reset zeros the key data, so that it will no longer
// appear in the process's memory.
func (c *Cipher) Reset() {
for i := 0; i < len(c.subkeys); i++ {
c.subkeys[i] = 0
}
}
// A TripleDESCipher is an instance of TripleDES encryption.
type TripleDESCipher struct {
cipher1, cipher2, cipher3 Cipher
}
// NewCipher creates and returns a new Cipher.
func NewTripleDESCipher(key []byte) (*TripleDESCipher, os.Error) {
if len(key) != 24 {
return nil, KeySizeError(len(key))
}
c := new(TripleDESCipher)
c.cipher1.generateSubkeys(key[:8])
c.cipher2.generateSubkeys(key[8:16])
c.cipher3.generateSubkeys(key[16:])
return c, nil
}
// BlockSize returns the TripleDES block size, 8 bytes.
// It is necessary to satisfy the Block interface in the
// package "crypto/cipher".
func (c *TripleDESCipher) BlockSize() int { return BlockSize }
// Encrypts the 8-byte buffer src and stores the result in dst.
// Note that for amounts of data larger than a block,
// it is not safe to just call Encrypt on successive blocks;
// instead, use an encryption mode like CBC (see crypto/cipher/cbc.go).
func (c *TripleDESCipher) Encrypt(dst, src []byte) {
c.cipher1.Encrypt(dst, src)
c.cipher2.Decrypt(dst, dst)
c.cipher3.Encrypt(dst, dst)
}
// Decrypts the 8-byte buffer src and stores the result in dst.
func (c *TripleDESCipher) Decrypt(dst, src []byte) {
c.cipher3.Decrypt(dst, src)
c.cipher2.Encrypt(dst, dst)
c.cipher1.Decrypt(dst, dst)
}
// Reset zeros the key data, so that it will no longer
// appear in the process's memory.
func (c *TripleDESCipher) Reset() {
c.cipher1.Reset()
c.cipher2.Reset()
c.cipher3.Reset()
}
// 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 des implements the Data Encryption Standard (DES) and the
// Triple Data Encryption Algorithm (TDEA) as defined
// in U.S. Federal Information Processing Standards Publication 46-3.
package des
// Used to perform an initial permutation of a 64-bit input block.
var initialPermutation = [64]byte{
6, 14, 22, 30, 38, 46, 54, 62,
4, 12, 20, 28, 36, 44, 52, 60,
2, 10, 18, 26, 34, 42, 50, 58,
0, 8, 16, 24, 32, 40, 48, 56,
7, 15, 23, 31, 39, 47, 55, 63,
5, 13, 21, 29, 37, 45, 53, 61,
3, 11, 19, 27, 35, 43, 51, 59,
1, 9, 17, 25, 33, 41, 49, 57,
}
// Used to perform a final permutation of a 4-bit preoutput block. This is the
// inverse of initialPermutation
var finalPermutation = [64]byte{
24, 56, 16, 48, 8, 40, 0, 32,
25, 57, 17, 49, 9, 41, 1, 33,
26, 58, 18, 50, 10, 42, 2, 34,
27, 59, 19, 51, 11, 43, 3, 35,
28, 60, 20, 52, 12, 44, 4, 36,
29, 61, 21, 53, 13, 45, 5, 37,
30, 62, 22, 54, 14, 46, 6, 38,
31, 63, 23, 55, 15, 47, 7, 39,
}
// Used to expand an input block of 32 bits, producing an output block of 48
// bits.
var expansionFunction = [48]byte{
0, 31, 30, 29, 28, 27, 28, 27,
26, 25, 24, 23, 24, 23, 22, 21,
20, 19, 20, 19, 18, 17, 16, 15,
16, 15, 14, 13, 12, 11, 12, 11,
10, 9, 8, 7, 8, 7, 6, 5,
4, 3, 4, 3, 2, 1, 0, 31,
}
// Yields a 32-bit output from a 32-bit input
var permutationFunction = [32]byte{
16, 25, 12, 11, 3, 20, 4, 15,
31, 17, 9, 6, 27, 14, 1, 22,
30, 24, 8, 18, 0, 5, 29, 23,
13, 19, 2, 26, 10, 21, 28, 7,
}
// Used in the key schedule to select 56 bits
// from a 64-bit input.
var permutedChoice1 = [56]byte{
7, 15, 23, 31, 39, 47, 55, 63,
6, 14, 22, 30, 38, 46, 54, 62,
5, 13, 21, 29, 37, 45, 53, 61,
4, 12, 20, 28, 1, 9, 17, 25,
33, 41, 49, 57, 2, 10, 18, 26,
34, 42, 50, 58, 3, 11, 19, 27,
35, 43, 51, 59, 36, 44, 52, 60,
}
// Used in the key schedule to produce each subkey by selecting 48 bits from
// the 56-bit input
var permutedChoice2 = [48]byte{
42, 39, 45, 32, 55, 51, 53, 28,
41, 50, 35, 46, 33, 37, 44, 52,
30, 48, 40, 49, 29, 36, 43, 54,
15, 4, 25, 19, 9, 1, 26, 16,
5, 11, 23, 8, 12, 7, 17, 0,
22, 3, 10, 14, 6, 20, 27, 24,
}
// 8 S-boxes composed of 4 rows and 16 columns
// Used in the DES cipher function
var sBoxes = [8][4][16]uint8{
// S-box 1
{
{14, 4, 13, 1, 2, 15, 11, 8, 3, 10, 6, 12, 5, 9, 0, 7},
{0, 15, 7, 4, 14, 2, 13, 1, 10, 6, 12, 11, 9, 5, 3, 8},
{4, 1, 14, 8, 13, 6, 2, 11, 15, 12, 9, 7, 3, 10, 5, 0},
{15, 12, 8, 2, 4, 9, 1, 7, 5, 11, 3, 14, 10, 0, 6, 13},
},
// S-box 2
{
{15, 1, 8, 14, 6, 11, 3, 4, 9, 7, 2, 13, 12, 0, 5, 10},
{3, 13, 4, 7, 15, 2, 8, 14, 12, 0, 1, 10, 6, 9, 11, 5},
{0, 14, 7, 11, 10, 4, 13, 1, 5, 8, 12, 6, 9, 3, 2, 15},
{13, 8, 10, 1, 3, 15, 4, 2, 11, 6, 7, 12, 0, 5, 14, 9},
},
// S-box 3
{
{10, 0, 9, 14, 6, 3, 15, 5, 1, 13, 12, 7, 11, 4, 2, 8},
{13, 7, 0, 9, 3, 4, 6, 10, 2, 8, 5, 14, 12, 11, 15, 1},
{13, 6, 4, 9, 8, 15, 3, 0, 11, 1, 2, 12, 5, 10, 14, 7},
{1, 10, 13, 0, 6, 9, 8, 7, 4, 15, 14, 3, 11, 5, 2, 12},
},
// S-box 4
{
{7, 13, 14, 3, 0, 6, 9, 10, 1, 2, 8, 5, 11, 12, 4, 15},
{13, 8, 11, 5, 6, 15, 0, 3, 4, 7, 2, 12, 1, 10, 14, 9},
{10, 6, 9, 0, 12, 11, 7, 13, 15, 1, 3, 14, 5, 2, 8, 4},
{3, 15, 0, 6, 10, 1, 13, 8, 9, 4, 5, 11, 12, 7, 2, 14},
},
// S-box 5
{
{2, 12, 4, 1, 7, 10, 11, 6, 8, 5, 3, 15, 13, 0, 14, 9},
{14, 11, 2, 12, 4, 7, 13, 1, 5, 0, 15, 10, 3, 9, 8, 6},
{4, 2, 1, 11, 10, 13, 7, 8, 15, 9, 12, 5, 6, 3, 0, 14},
{11, 8, 12, 7, 1, 14, 2, 13, 6, 15, 0, 9, 10, 4, 5, 3},
},
// S-box 6
{
{12, 1, 10, 15, 9, 2, 6, 8, 0, 13, 3, 4, 14, 7, 5, 11},
{10, 15, 4, 2, 7, 12, 9, 5, 6, 1, 13, 14, 0, 11, 3, 8},
{9, 14, 15, 5, 2, 8, 12, 3, 7, 0, 4, 10, 1, 13, 11, 6},
{4, 3, 2, 12, 9, 5, 15, 10, 11, 14, 1, 7, 6, 0, 8, 13},
},
// S-box 7
{
{4, 11, 2, 14, 15, 0, 8, 13, 3, 12, 9, 7, 5, 10, 6, 1},
{13, 0, 11, 7, 4, 9, 1, 10, 14, 3, 5, 12, 2, 15, 8, 6},
{1, 4, 11, 13, 12, 3, 7, 14, 10, 15, 6, 8, 0, 5, 9, 2},
{6, 11, 13, 8, 1, 4, 10, 7, 9, 5, 0, 15, 14, 2, 3, 12},
},
// S-box 8
{
{13, 2, 8, 4, 6, 15, 11, 1, 10, 9, 3, 14, 5, 0, 12, 7},
{1, 15, 13, 8, 10, 3, 7, 4, 12, 5, 6, 11, 0, 14, 9, 2},
{7, 11, 4, 1, 9, 12, 14, 2, 0, 6, 10, 13, 15, 3, 5, 8},
{2, 1, 14, 7, 4, 10, 8, 13, 15, 12, 9, 0, 3, 5, 6, 11},
},
}
// Size of left rotation per round in each half of the key schedule
var ksRotations = [16]uint8{1, 1, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 1}
// Copyright 2011 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 des
import (
"bytes"
"testing"
)
type CryptTest struct {
key []byte
in []byte
out []byte
}
// some custom tests for DES
var encryptDESTests = []CryptTest{
{
[]byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
[]byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
[]byte{0x8c, 0xa6, 0x4d, 0xe9, 0xc1, 0xb1, 0x23, 0xa7}},
{
[]byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
[]byte{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff},
[]byte{0x35, 0x55, 0x50, 0xb2, 0x15, 0x0e, 0x24, 0x51}},
{
[]byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
[]byte{0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef},
[]byte{0x61, 0x7b, 0x3a, 0x0c, 0xe8, 0xf0, 0x71, 0x00}},
{
[]byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
[]byte{0xfe, 0xdc, 0xba, 0x98, 0x76, 0x54, 0x32, 0x10},
[]byte{0x92, 0x31, 0xf2, 0x36, 0xff, 0x9a, 0xa9, 0x5c}},
{
[]byte{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff},
[]byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
[]byte{0xca, 0xaa, 0xaf, 0x4d, 0xea, 0xf1, 0xdb, 0xae}},
{
[]byte{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff},
[]byte{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff},
[]byte{0x73, 0x59, 0xb2, 0x16, 0x3e, 0x4e, 0xdc, 0x58}},
{
[]byte{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff},
[]byte{0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef},
[]byte{0x6d, 0xce, 0x0d, 0xc9, 0x00, 0x65, 0x56, 0xa3}},
{
[]byte{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff},
[]byte{0xfe, 0xdc, 0xba, 0x98, 0x76, 0x54, 0x32, 0x10},
[]byte{0x9e, 0x84, 0xc5, 0xf3, 0x17, 0x0f, 0x8e, 0xff}},
{
[]byte{0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef},
[]byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
[]byte{0xd5, 0xd4, 0x4f, 0xf7, 0x20, 0x68, 0x3d, 0x0d}},
{
[]byte{0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef},
[]byte{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff},
[]byte{0x59, 0x73, 0x23, 0x56, 0xf3, 0x6f, 0xde, 0x06}},
{
[]byte{0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef},
[]byte{0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef},
[]byte{0x56, 0xcc, 0x09, 0xe7, 0xcf, 0xdc, 0x4c, 0xef}},
{
[]byte{0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef},
[]byte{0xfe, 0xdc, 0xba, 0x98, 0x76, 0x54, 0x32, 0x10},
[]byte{0x12, 0xc6, 0x26, 0xaf, 0x05, 0x8b, 0x43, 0x3b}},
{
[]byte{0xfe, 0xdc, 0xba, 0x98, 0x76, 0x54, 0x32, 0x10},
[]byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
[]byte{0xa6, 0x8c, 0xdc, 0xa9, 0x0c, 0x90, 0x21, 0xf9}},
{
[]byte{0xfe, 0xdc, 0xba, 0x98, 0x76, 0x54, 0x32, 0x10},
[]byte{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff},
[]byte{0x2a, 0x2b, 0xb0, 0x08, 0xdf, 0x97, 0xc2, 0xf2}},
{
[]byte{0xfe, 0xdc, 0xba, 0x98, 0x76, 0x54, 0x32, 0x10},
[]byte{0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef},
[]byte{0xed, 0x39, 0xd9, 0x50, 0xfa, 0x74, 0xbc, 0xc4}},
{
[]byte{0xfe, 0xdc, 0xba, 0x98, 0x76, 0x54, 0x32, 0x10},
[]byte{0xfe, 0xdc, 0xba, 0x98, 0x76, 0x54, 0x32, 0x10},
[]byte{0xa9, 0x33, 0xf6, 0x18, 0x30, 0x23, 0xb3, 0x10}},
{
[]byte{0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef},
[]byte{0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11},
[]byte{0x17, 0x66, 0x8d, 0xfc, 0x72, 0x92, 0x53, 0x2d}},
{
[]byte{0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef},
[]byte{0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01},
[]byte{0xb4, 0xfd, 0x23, 0x16, 0x47, 0xa5, 0xbe, 0xc0}},
{
[]byte{0x0e, 0x32, 0x92, 0x32, 0xea, 0x6d, 0x0d, 0x73},
[]byte{0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87},
[]byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}},
{
[]byte{0x73, 0x65, 0x63, 0x52, 0x33, 0x74, 0x24, 0x3b}, // "secR3t$;"
[]byte{0x61, 0x20, 0x74, 0x65, 0x73, 0x74, 0x31, 0x32}, // "a test12"
[]byte{0x37, 0x0d, 0xee, 0x2c, 0x1f, 0xb4, 0xf7, 0xa5}},
{
[]byte{0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68}, // "abcdefgh"
[]byte{0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68}, // "abcdefgh"
[]byte{0x2a, 0x8d, 0x69, 0xde, 0x9d, 0x5f, 0xdf, 0xf9}},
{
[]byte{0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68}, // "abcdefgh"
[]byte{0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38}, // "12345678"
[]byte{0x21, 0xc6, 0x0d, 0xa5, 0x34, 0x24, 0x8b, 0xce}},
{
[]byte{0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38}, // "12345678"
[]byte{0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68}, // "abcdefgh"
[]byte{0x94, 0xd4, 0x43, 0x6b, 0xc3, 0xb5, 0xb6, 0x93}},
{
[]byte{0x1f, 0x79, 0x90, 0x5f, 0x88, 0x01, 0xc8, 0x88}, // random
[]byte{0xc7, 0x46, 0x18, 0x73, 0xaf, 0x48, 0x5f, 0xb3}, // random
[]byte{0xb0, 0x93, 0x50, 0x88, 0xf9, 0x92, 0x44, 0x6a}},
{
[]byte{0xe6, 0xf4, 0xf2, 0xdb, 0x31, 0x42, 0x53, 0x01}, // random
[]byte{0xff, 0x3d, 0x25, 0x50, 0x12, 0xe3, 0x4a, 0xc5}, // random
[]byte{0x86, 0x08, 0xd3, 0xd1, 0x6c, 0x2f, 0xd2, 0x55}},
{
[]byte{0x69, 0xc1, 0x9d, 0xc1, 0x15, 0xc5, 0xfb, 0x2b}, // random
[]byte{0x1a, 0x22, 0x5c, 0xaf, 0x1f, 0x1d, 0xa3, 0xf9}, // random
[]byte{0x64, 0xba, 0x31, 0x67, 0x56, 0x91, 0x1e, 0xa7}},
{
[]byte{0x6e, 0x5e, 0xe2, 0x47, 0xc4, 0xbf, 0xf6, 0x51}, // random
[]byte{0x11, 0xc9, 0x57, 0xff, 0x66, 0x89, 0x0e, 0xf0}, // random
[]byte{0x94, 0xc5, 0x35, 0xb2, 0xc5, 0x8b, 0x39, 0x72}},
}
var weakKeyTests = []CryptTest{
{
[]byte{0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01},
[]byte{0x55, 0x74, 0xc0, 0xbd, 0x7c, 0xdf, 0xf7, 0x39}, // random
nil},
{
[]byte{0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe},
[]byte{0xe8, 0xe1, 0xa7, 0xc1, 0xde, 0x11, 0x89, 0xaa}, // random
nil},
{
[]byte{0xe0, 0xe0, 0xe0, 0xe0, 0xf1, 0xf1, 0xf1, 0xf1},
[]byte{0x50, 0x6a, 0x4b, 0x94, 0x3b, 0xed, 0x7d, 0xdc}, // random
nil},
{
[]byte{0x1f, 0x1f, 0x1f, 0x1f, 0x0e, 0x0e, 0x0e, 0x0e},
[]byte{0x88, 0x81, 0x56, 0x38, 0xec, 0x3b, 0x1c, 0x97}, // random
nil},
{
[]byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
[]byte{0x17, 0xa0, 0x83, 0x62, 0x32, 0xfe, 0x9a, 0x0b}, // random
nil},
{
[]byte{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff},
[]byte{0xca, 0x8f, 0xca, 0x1f, 0x50, 0xc5, 0x7b, 0x49}, // random
nil},
{
[]byte{0xe1, 0xe1, 0xe1, 0xe1, 0xf0, 0xf0, 0xf0, 0xf0},
[]byte{0xb1, 0xea, 0xad, 0x7d, 0xe7, 0xc3, 0x7a, 0x43}, // random
nil},
{
[]byte{0x1e, 0x1e, 0x1e, 0x1e, 0x0f, 0x0f, 0x0f, 0x0f},
[]byte{0xae, 0x74, 0x7d, 0x6f, 0xef, 0x16, 0xbb, 0x81}, // random
nil},
}
var semiWeakKeyTests = []CryptTest{
// key and out contain the semi-weak key pair
{
[]byte{0x01, 0x1f, 0x01, 0x1f, 0x01, 0x0e, 0x01, 0x0e},
[]byte{0x12, 0xfa, 0x31, 0x16, 0xf9, 0xc5, 0x0a, 0xe4}, // random
[]byte{0x1f, 0x01, 0x1f, 0x01, 0x0e, 0x01, 0x0e, 0x01}},
{
[]byte{0x01, 0xe0, 0x01, 0xe0, 0x01, 0xf1, 0x01, 0xf1},
[]byte{0xb0, 0x4c, 0x7a, 0xee, 0xd2, 0xe5, 0x4d, 0xb7}, // random
[]byte{0xe0, 0x01, 0xe0, 0x01, 0xf1, 0x01, 0xf1, 0x01}},
{
[]byte{0x01, 0xfe, 0x01, 0xfe, 0x01, 0xfe, 0x01, 0xfe},
[]byte{0xa4, 0x81, 0xcd, 0xb1, 0x64, 0x6f, 0xd3, 0xbc}, // random
[]byte{0xfe, 0x01, 0xfe, 0x01, 0xfe, 0x01, 0xfe, 0x01}},
{
[]byte{0x1f, 0xe0, 0x1f, 0xe0, 0x0e, 0xf1, 0x0e, 0xf1},
[]byte{0xee, 0x27, 0xdd, 0x88, 0x4c, 0x22, 0xcd, 0xce}, // random
[]byte{0xe0, 0x1f, 0xe0, 0x1f, 0xf1, 0x0e, 0xf1, 0x0e}},
{
[]byte{0x1f, 0xfe, 0x1f, 0xfe, 0x0e, 0xfe, 0x0e, 0xfe},
[]byte{0x19, 0x3d, 0xcf, 0x97, 0x70, 0xfb, 0xab, 0xe1}, // random
[]byte{0xfe, 0x1f, 0xfe, 0x1f, 0xfe, 0x0e, 0xfe, 0x0e}},
{
[]byte{0xe0, 0xfe, 0xe0, 0xfe, 0xf1, 0xfe, 0xf1, 0xfe},
[]byte{0x7c, 0x82, 0x69, 0xe4, 0x1e, 0x86, 0x99, 0xd7}, // random
[]byte{0xfe, 0xe0, 0xfe, 0xe0, 0xfe, 0xf1, 0xfe, 0xf1}},
}
// some custom tests for TripleDES
var encryptTripleDESTests = []CryptTest{
{
[]byte{
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
[]byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
[]byte{0x92, 0x95, 0xb5, 0x9b, 0xb3, 0x84, 0x73, 0x6e}},
{
[]byte{
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
[]byte{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff},
[]byte{0xc1, 0x97, 0xf5, 0x58, 0x74, 0x8a, 0x20, 0xe7}},
{
[]byte{
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff},
[]byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
[]byte{0x3e, 0x68, 0x0a, 0xa7, 0x8b, 0x75, 0xdf, 0x18}},
{
[]byte{
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff},
[]byte{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff},
[]byte{0x6d, 0x6a, 0x4a, 0x64, 0x4c, 0x7b, 0x8c, 0x91}},
{
[]byte{ // "abcdefgh12345678ABCDEFGH"
0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68,
0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38,
0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48},
[]byte{0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30}, // "00000000"
[]byte{0xe4, 0x61, 0xb7, 0x59, 0x68, 0x8b, 0xff, 0x66}},
{
[]byte{ // "abcdefgh12345678ABCDEFGH"
0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68,
0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38,
0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48},
[]byte{0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38}, // "12345678"
[]byte{0xdb, 0xd0, 0x92, 0xde, 0xf8, 0x34, 0xff, 0x58}},
{
[]byte{ // "abcdefgh12345678ABCDEFGH"
0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68,
0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38,
0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48},
[]byte{0xf0, 0xc5, 0x82, 0x22, 0xd3, 0xe6, 0x12, 0xd2}, // random
[]byte{0xba, 0xe4, 0x41, 0xb1, 0x3c, 0x37, 0x4d, 0xf4}},
{
[]byte{ // random
0xd3, 0x7d, 0x45, 0xee, 0x22, 0xe9, 0xcf, 0x52,
0xf4, 0x65, 0xa2, 0x4f, 0x70, 0xd1, 0x81, 0x8a,
0x3d, 0xbe, 0x2f, 0x39, 0xc7, 0x71, 0xd2, 0xe9},
[]byte{0x49, 0x53, 0xc3, 0xe9, 0x78, 0xdf, 0x9f, 0xaf}, // random
[]byte{0x53, 0x40, 0x51, 0x24, 0xd8, 0x3c, 0xf9, 0x88}},
{
[]byte{ // random
0xcb, 0x10, 0x7d, 0xda, 0x7e, 0x96, 0x57, 0x0a,
0xe8, 0xeb, 0xe8, 0x07, 0x8e, 0x87, 0xd3, 0x57,
0xb2, 0x61, 0x12, 0xb8, 0x2a, 0x90, 0xb7, 0x2f},
[]byte{0xa3, 0xc2, 0x60, 0xb1, 0x0b, 0xb7, 0x28, 0x6e}, // random
[]byte{0x56, 0x73, 0x7d, 0xfb, 0xb5, 0xa1, 0xc3, 0xde}},
}
// NIST Special Publication 800-20, Appendix A
// Key for use with Table A.1 tests
var tableA1Key = []byte{
0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
}
// Table A.1 Resulting Ciphertext from the Variable Plaintext Known Answer Test
var tableA1Tests = []CryptTest{
{nil, // 0
[]byte{0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
[]byte{0x95, 0xf8, 0xa5, 0xe5, 0xdd, 0x31, 0xd9, 0x00}},
{nil, // 1
[]byte{0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
[]byte{0xdd, 0x7f, 0x12, 0x1c, 0xa5, 0x01, 0x56, 0x19}},
{nil, // 2
[]byte{0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
[]byte{0x2e, 0x86, 0x53, 0x10, 0x4f, 0x38, 0x34, 0xea}},
{nil, // 3
[]byte{0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
[]byte{0x4b, 0xd3, 0x88, 0xff, 0x6c, 0xd8, 0x1d, 0x4f}},
{nil, // 4
[]byte{0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
[]byte{0x20, 0xb9, 0xe7, 0x67, 0xb2, 0xfb, 0x14, 0x56}},
{nil, // 5
[]byte{0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
[]byte{0x55, 0x57, 0x93, 0x80, 0xd7, 0x71, 0x38, 0xef}},
{nil, // 6
[]byte{0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
[]byte{0x6c, 0xc5, 0xde, 0xfa, 0xaf, 0x04, 0x51, 0x2f}},
{nil, // 7
[]byte{0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
[]byte{0x0d, 0x9f, 0x27, 0x9b, 0xa5, 0xd8, 0x72, 0x60}},
{nil, // 8
[]byte{0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
[]byte{0xd9, 0x03, 0x1b, 0x02, 0x71, 0xbd, 0x5a, 0x0a}},
{nil, // 9
[]byte{0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
[]byte{0x42, 0x42, 0x50, 0xb3, 0x7c, 0x3d, 0xd9, 0x51}},
{nil, // 10
[]byte{0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
[]byte{0xb8, 0x06, 0x1b, 0x7e, 0xcd, 0x9a, 0x21, 0xe5}},
{nil, // 11
[]byte{0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
[]byte{0xf1, 0x5d, 0x0f, 0x28, 0x6b, 0x65, 0xbd, 0x28}},
{nil, // 12
[]byte{0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
[]byte{0xad, 0xd0, 0xcc, 0x8d, 0x6e, 0x5d, 0xeb, 0xa1}},
{nil, // 13
[]byte{0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
[]byte{0xe6, 0xd5, 0xf8, 0x27, 0x52, 0xad, 0x63, 0xd1}},
{nil, // 14
[]byte{0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
[]byte{0xec, 0xbf, 0xe3, 0xbd, 0x3f, 0x59, 0x1a, 0x5e}},
{nil, // 15
[]byte{0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
[]byte{0xf3, 0x56, 0x83, 0x43, 0x79, 0xd1, 0x65, 0xcd}},
{nil, // 16
[]byte{0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00},
[]byte{0x2b, 0x9f, 0x98, 0x2f, 0x20, 0x03, 0x7f, 0xa9}},
{nil, // 17
[]byte{0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00},
[]byte{0x88, 0x9d, 0xe0, 0x68, 0xa1, 0x6f, 0x0b, 0xe6}},
{nil, // 18
[]byte{0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00},
[]byte{0xe1, 0x9e, 0x27, 0x5d, 0x84, 0x6a, 0x12, 0x98}},
{nil, // 19
[]byte{0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00},
[]byte{0x32, 0x9a, 0x8e, 0xd5, 0x23, 0xd7, 0x1a, 0xec}},
{nil, // 20
[]byte{0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00},
[]byte{0xe7, 0xfc, 0xe2, 0x25, 0x57, 0xd2, 0x3c, 0x97}},
{nil, // 21
[]byte{0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00},
[]byte{0x12, 0xa9, 0xf5, 0x81, 0x7f, 0xf2, 0xd6, 0x5d}},
{nil, // 22
[]byte{0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00},
[]byte{0xa4, 0x84, 0xc3, 0xad, 0x38, 0xdc, 0x9c, 0x19}},
{nil, // 23
[]byte{0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00},
[]byte{0xfb, 0xe0, 0x0a, 0x8a, 0x1e, 0xf8, 0xad, 0x72}},
{nil, // 24
[]byte{0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00},
[]byte{0x75, 0x0d, 0x07, 0x94, 0x07, 0x52, 0x13, 0x63}},
{nil, // 25
[]byte{0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00},
[]byte{0x64, 0xfe, 0xed, 0x9c, 0x72, 0x4c, 0x2f, 0xaf}},
{nil, // 26
[]byte{0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00},
[]byte{0xf0, 0x2b, 0x26, 0x3b, 0x32, 0x8e, 0x2b, 0x60}},
{nil, // 27
[]byte{0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00},
[]byte{0x9d, 0x64, 0x55, 0x5a, 0x9a, 0x10, 0xb8, 0x52}},
{nil, // 28
[]byte{0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00},
[]byte{0xd1, 0x06, 0xff, 0x0b, 0xed, 0x52, 0x55, 0xd7}},
{nil, // 29
[]byte{0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00},
[]byte{0xe1, 0x65, 0x2c, 0x6b, 0x13, 0x8c, 0x64, 0xa5}},
{nil, // 30
[]byte{0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00},
[]byte{0xe4, 0x28, 0x58, 0x11, 0x86, 0xec, 0x8f, 0x46}},
{nil, // 31
[]byte{0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00},
[]byte{0xae, 0xb5, 0xf5, 0xed, 0xe2, 0x2d, 0x1a, 0x36}},
{nil, // 32
[]byte{0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00},
[]byte{0xe9, 0x43, 0xd7, 0x56, 0x8a, 0xec, 0x0c, 0x5c}},
{nil, // 33
[]byte{0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00},
[]byte{0xdf, 0x98, 0xc8, 0x27, 0x6f, 0x54, 0xb0, 0x4b}},
{nil, // 34
[]byte{0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00},
[]byte{0xb1, 0x60, 0xe4, 0x68, 0x0f, 0x6c, 0x69, 0x6f}},
{nil, // 35
[]byte{0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00},
[]byte{0xfa, 0x07, 0x52, 0xb0, 0x7d, 0x9c, 0x4a, 0xb8}},
{nil, // 36
[]byte{0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00},
[]byte{0xca, 0x3a, 0x2b, 0x03, 0x6d, 0xbc, 0x85, 0x02}},
{nil, // 37
[]byte{0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00},
[]byte{0x5e, 0x09, 0x05, 0x51, 0x7b, 0xb5, 0x9b, 0xcf}},
{nil, // 38
[]byte{0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00},
[]byte{0x81, 0x4e, 0xeb, 0x3b, 0x91, 0xd9, 0x07, 0x26}},
{nil, // 39
[]byte{0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00},
[]byte{0x4d, 0x49, 0xdb, 0x15, 0x32, 0x91, 0x9c, 0x9f}},
{nil, // 40
[]byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00},
[]byte{0x25, 0xeb, 0x5f, 0xc3, 0xf8, 0xcf, 0x06, 0x21}},
{nil, // 41
[]byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00},
[]byte{0xab, 0x6a, 0x20, 0xc0, 0x62, 0x0d, 0x1c, 0x6f}},
{nil, // 42
[]byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00},
[]byte{0x79, 0xe9, 0x0d, 0xbc, 0x98, 0xf9, 0x2c, 0xca}},
{nil, // 43
[]byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00},
[]byte{0x86, 0x6e, 0xce, 0xdd, 0x80, 0x72, 0xbb, 0x0e}},
{nil, // 44
[]byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00},
[]byte{0x8b, 0x54, 0x53, 0x6f, 0x2f, 0x3e, 0x64, 0xa8}},
{nil, // 45
[]byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00},
[]byte{0xea, 0x51, 0xd3, 0x97, 0x55, 0x95, 0xb8, 0x6b}},
{nil, // 46
[]byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00},
[]byte{0xca, 0xff, 0xc6, 0xac, 0x45, 0x42, 0xde, 0x31}},
{nil, // 47
[]byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00},
[]byte{0x8d, 0xd4, 0x5a, 0x2d, 0xdf, 0x90, 0x79, 0x6c}},
{nil, // 48
[]byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00},
[]byte{0x10, 0x29, 0xd5, 0x5e, 0x88, 0x0e, 0xc2, 0xd0}},
{nil, // 49
[]byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00},
[]byte{0x5d, 0x86, 0xcb, 0x23, 0x63, 0x9d, 0xbe, 0xa9}},
{nil, // 50
[]byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00},
[]byte{0x1d, 0x1c, 0xa8, 0x53, 0xae, 0x7c, 0x0c, 0x5f}},
{nil, // 51
[]byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00},
[]byte{0xce, 0x33, 0x23, 0x29, 0x24, 0x8f, 0x32, 0x28}},
{nil, // 52
[]byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00},
[]byte{0x84, 0x05, 0xd1, 0xab, 0xe2, 0x4f, 0xb9, 0x42}},
{nil, // 53
[]byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00},
[]byte{0xe6, 0x43, 0xd7, 0x80, 0x90, 0xca, 0x42, 0x07}},
{nil, // 54
[]byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00},
[]byte{0x48, 0x22, 0x1b, 0x99, 0x37, 0x74, 0x8a, 0x23}},
{nil, // 55
[]byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00},
[]byte{0xdd, 0x7c, 0x0b, 0xbd, 0x61, 0xfa, 0xfd, 0x54}},
{nil, // 56
[]byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80},
[]byte{0x2f, 0xbc, 0x29, 0x1a, 0x57, 0x0d, 0xb5, 0xc4}},
{nil, // 57
[]byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40},
[]byte{0xe0, 0x7c, 0x30, 0xd7, 0xe4, 0xe2, 0x6e, 0x12}},
{nil, // 58
[]byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20},
[]byte{0x09, 0x53, 0xe2, 0x25, 0x8e, 0x8e, 0x90, 0xa1}},
{nil, // 59
[]byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10},
[]byte{0x5b, 0x71, 0x1b, 0xc4, 0xce, 0xeb, 0xf2, 0xee}},
{nil, // 60
[]byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08},
[]byte{0xcc, 0x08, 0x3f, 0x1e, 0x6d, 0x9e, 0x85, 0xf6}},
{nil, // 61
[]byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04},
[]byte{0xd2, 0xfd, 0x88, 0x67, 0xd5, 0x0d, 0x2d, 0xfe}},
{nil, // 62
[]byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02},
[]byte{0x06, 0xe7, 0xea, 0x22, 0xce, 0x92, 0x70, 0x8f}},
{nil, // 63
[]byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01},
[]byte{0x16, 0x6b, 0x40, 0xb4, 0x4a, 0xba, 0x4b, 0xd6}},
}
// Plaintext for use with Table A.2 tests
var tableA2Plaintext = []byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}
// Table A.2 Resulting Ciphertext from the Variable Key Known Answer Test
var tableA2Tests = []CryptTest{
{ // 0
[]byte{
0x80, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
0x80, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
0x80, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01},
nil,
[]byte{0x95, 0xa8, 0xd7, 0x28, 0x13, 0xda, 0xa9, 0x4d}},
{ // 1
[]byte{
0x40, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
0x40, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
0x40, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01},
nil,
[]byte{0x0e, 0xec, 0x14, 0x87, 0xdd, 0x8c, 0x26, 0xd5}},
{ // 2
[]byte{
0x20, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
0x20, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
0x20, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01},
nil,
[]byte{0x7a, 0xd1, 0x6f, 0xfb, 0x79, 0xc4, 0x59, 0x26}},
{ // 3
[]byte{
0x10, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
0x10, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
0x10, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01},
nil,
[]byte{0xd3, 0x74, 0x62, 0x94, 0xca, 0x6a, 0x6c, 0xf3}},
{ // 4
[]byte{
0x08, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
0x08, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
0x08, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01},
nil,
[]byte{0x80, 0x9f, 0x5f, 0x87, 0x3c, 0x1f, 0xd7, 0x61}},
{ // 5
[]byte{
0x04, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
0x04, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
0x04, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01},
nil,
[]byte{0xc0, 0x2f, 0xaf, 0xfe, 0xc9, 0x89, 0xd1, 0xfc}},
{ // 6
[]byte{
0x02, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
0x02, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
0x02, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01},
nil,
[]byte{0x46, 0x15, 0xaa, 0x1d, 0x33, 0xe7, 0x2f, 0x10}},
{ // 7
[]byte{
0x01, 0x80, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
0x01, 0x80, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
0x01, 0x80, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01},
nil,
[]byte{0x20, 0x55, 0x12, 0x33, 0x50, 0xc0, 0x08, 0x58}},
{ // 8
[]byte{
0x01, 0x40, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
0x01, 0x40, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
0x01, 0x40, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01},
nil,
[]byte{0xdf, 0x3b, 0x99, 0xd6, 0x57, 0x73, 0x97, 0xc8}},
{ // 9
[]byte{
0x01, 0x20, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
0x01, 0x20, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
0x01, 0x20, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01},
nil,
[]byte{0x31, 0xfe, 0x17, 0x36, 0x9b, 0x52, 0x88, 0xc9}},
{ // 10
[]byte{
0x01, 0x10, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
0x01, 0x10, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
0x01, 0x10, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01},
nil,
[]byte{0xdf, 0xdd, 0x3c, 0xc6, 0x4d, 0xae, 0x16, 0x42}},
{ // 11
[]byte{
0x01, 0x08, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
0x01, 0x08, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
0x01, 0x08, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01},
nil,
[]byte{0x17, 0x8c, 0x83, 0xce, 0x2b, 0x39, 0x9d, 0x94}},
{ // 12
[]byte{
0x01, 0x04, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
0x01, 0x04, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
0x01, 0x04, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01},
nil,
[]byte{0x50, 0xf6, 0x36, 0x32, 0x4a, 0x9b, 0x7f, 0x80}},
{ // 13
[]byte{
0x01, 0x02, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
0x01, 0x02, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
0x01, 0x02, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01},
nil,
[]byte{0xa8, 0x46, 0x8e, 0xe3, 0xbc, 0x18, 0xf0, 0x6d}},
{ // 14
[]byte{
0x01, 0x01, 0x80, 0x01, 0x01, 0x01, 0x01, 0x01,
0x01, 0x01, 0x80, 0x01, 0x01, 0x01, 0x01, 0x01,
0x01, 0x01, 0x80, 0x01, 0x01, 0x01, 0x01, 0x01},
nil,
[]byte{0xa2, 0xdc, 0x9e, 0x92, 0xfd, 0x3c, 0xde, 0x92}},
{ // 15
[]byte{
0x01, 0x01, 0x40, 0x01, 0x01, 0x01, 0x01, 0x01,
0x01, 0x01, 0x40, 0x01, 0x01, 0x01, 0x01, 0x01,
0x01, 0x01, 0x40, 0x01, 0x01, 0x01, 0x01, 0x01},
nil,
[]byte{0xca, 0xc0, 0x9f, 0x79, 0x7d, 0x03, 0x12, 0x87}},
{ // 16
[]byte{
0x01, 0x01, 0x20, 0x01, 0x01, 0x01, 0x01, 0x01,
0x01, 0x01, 0x20, 0x01, 0x01, 0x01, 0x01, 0x01,
0x01, 0x01, 0x20, 0x01, 0x01, 0x01, 0x01, 0x01},
nil,
[]byte{0x90, 0xba, 0x68, 0x0b, 0x22, 0xae, 0xb5, 0x25}},
{ // 17
[]byte{
0x01, 0x01, 0x10, 0x01, 0x01, 0x01, 0x01, 0x01,
0x01, 0x01, 0x10, 0x01, 0x01, 0x01, 0x01, 0x01,
0x01, 0x01, 0x10, 0x01, 0x01, 0x01, 0x01, 0x01},
nil,
[]byte{0xce, 0x7a, 0x24, 0xf3, 0x50, 0xe2, 0x80, 0xb6}},
{ // 18
[]byte{
0x01, 0x01, 0x08, 0x01, 0x01, 0x01, 0x01, 0x01,
0x01, 0x01, 0x08, 0x01, 0x01, 0x01, 0x01, 0x01,
0x01, 0x01, 0x08, 0x01, 0x01, 0x01, 0x01, 0x01},
nil,
[]byte{0x88, 0x2b, 0xff, 0x0a, 0xa0, 0x1a, 0x0b, 0x87}},
{ // 19
[]byte{
0x01, 0x01, 0x04, 0x01, 0x01, 0x01, 0x01, 0x01,
0x01, 0x01, 0x04, 0x01, 0x01, 0x01, 0x01, 0x01,
0x01, 0x01, 0x04, 0x01, 0x01, 0x01, 0x01, 0x01},
nil,
[]byte{0x25, 0x61, 0x02, 0x88, 0x92, 0x45, 0x11, 0xc2}},
{ // 20
[]byte{
0x01, 0x01, 0x02, 0x01, 0x01, 0x01, 0x01, 0x01,
0x01, 0x01, 0x02, 0x01, 0x01, 0x01, 0x01, 0x01,
0x01, 0x01, 0x02, 0x01, 0x01, 0x01, 0x01, 0x01},
nil,
[]byte{0xc7, 0x15, 0x16, 0xc2, 0x9c, 0x75, 0xd1, 0x70}},
{ // 21
[]byte{
0x01, 0x01, 0x01, 0x80, 0x01, 0x01, 0x01, 0x01,
0x01, 0x01, 0x01, 0x80, 0x01, 0x01, 0x01, 0x01,
0x01, 0x01, 0x01, 0x80, 0x01, 0x01, 0x01, 0x01},
nil,
[]byte{0x51, 0x99, 0xc2, 0x9a, 0x52, 0xc9, 0xf0, 0x59}},
{ // 22
[]byte{
0x01, 0x01, 0x01, 0x40, 0x01, 0x01, 0x01, 0x01,
0x01, 0x01, 0x01, 0x40, 0x01, 0x01, 0x01, 0x01,
0x01, 0x01, 0x01, 0x40, 0x01, 0x01, 0x01, 0x01},
nil,
[]byte{0xc2, 0x2f, 0x0a, 0x29, 0x4a, 0x71, 0xf2, 0x9f}},
{ // 23
[]byte{
0x01, 0x01, 0x01, 0x20, 0x01, 0x01, 0x01, 0x01,
0x01, 0x01, 0x01, 0x20, 0x01, 0x01, 0x01, 0x01,
0x01, 0x01, 0x01, 0x20, 0x01, 0x01, 0x01, 0x01},
nil,
[]byte{0xee, 0x37, 0x14, 0x83, 0x71, 0x4c, 0x02, 0xea}},
{ // 24
[]byte{
0x01, 0x01, 0x01, 0x10, 0x01, 0x01, 0x01, 0x01,
0x01, 0x01, 0x01, 0x10, 0x01, 0x01, 0x01, 0x01,
0x01, 0x01, 0x01, 0x10, 0x01, 0x01, 0x01, 0x01},
nil,
[]byte{0xa8, 0x1f, 0xbd, 0x44, 0x8f, 0x9e, 0x52, 0x2f}},
{ // 25
[]byte{
0x01, 0x01, 0x01, 0x08, 0x01, 0x01, 0x01, 0x01,
0x01, 0x01, 0x01, 0x08, 0x01, 0x01, 0x01, 0x01,
0x01, 0x01, 0x01, 0x08, 0x01, 0x01, 0x01, 0x01},
nil,
[]byte{0x4f, 0x64, 0x4c, 0x92, 0xe1, 0x92, 0xdf, 0xed}},
{ // 26
[]byte{
0x01, 0x01, 0x01, 0x04, 0x01, 0x01, 0x01, 0x01,
0x01, 0x01, 0x01, 0x04, 0x01, 0x01, 0x01, 0x01,
0x01, 0x01, 0x01, 0x04, 0x01, 0x01, 0x01, 0x01},
nil,
[]byte{0x1a, 0xfa, 0x9a, 0x66, 0xa6, 0xdf, 0x92, 0xae}},
{ // 27
[]byte{
0x01, 0x01, 0x01, 0x02, 0x01, 0x01, 0x01, 0x01,
0x01, 0x01, 0x01, 0x02, 0x01, 0x01, 0x01, 0x01,
0x01, 0x01, 0x01, 0x02, 0x01, 0x01, 0x01, 0x01},
nil,
[]byte{0xb3, 0xc1, 0xcc, 0x71, 0x5c, 0xb8, 0x79, 0xd8}},
{ // 28
[]byte{
0x01, 0x01, 0x01, 0x01, 0x80, 0x01, 0x01, 0x01,
0x01, 0x01, 0x01, 0x01, 0x80, 0x01, 0x01, 0x01,
0x01, 0x01, 0x01, 0x01, 0x80, 0x01, 0x01, 0x01},
nil,
[]byte{0x19, 0xd0, 0x32, 0xe6, 0x4a, 0xb0, 0xbd, 0x8b}},
{ // 29
[]byte{
0x01, 0x01, 0x01, 0x01, 0x40, 0x01, 0x01, 0x01,
0x01, 0x01, 0x01, 0x01, 0x40, 0x01, 0x01, 0x01,
0x01, 0x01, 0x01, 0x01, 0x40, 0x01, 0x01, 0x01},
nil,
[]byte{0x3c, 0xfa, 0xa7, 0xa7, 0xdc, 0x87, 0x20, 0xdc}},
{ // 30
[]byte{
0x01, 0x01, 0x01, 0x01, 0x20, 0x01, 0x01, 0x01,
0x01, 0x01, 0x01, 0x01, 0x20, 0x01, 0x01, 0x01,
0x01, 0x01, 0x01, 0x01, 0x20, 0x01, 0x01, 0x01},
nil,
[]byte{0xb7, 0x26, 0x5f, 0x7f, 0x44, 0x7a, 0xc6, 0xf3}},
{ // 31
[]byte{
0x01, 0x01, 0x01, 0x01, 0x10, 0x01, 0x01, 0x01,
0x01, 0x01, 0x01, 0x01, 0x10, 0x01, 0x01, 0x01,
0x01, 0x01, 0x01, 0x01, 0x10, 0x01, 0x01, 0x01},
nil,
[]byte{0x9d, 0xb7, 0x3b, 0x3c, 0x0d, 0x16, 0x3f, 0x54}},
{ // 32
[]byte{
0x01, 0x01, 0x01, 0x01, 0x08, 0x01, 0x01, 0x01,
0x01, 0x01, 0x01, 0x01, 0x08, 0x01, 0x01, 0x01,
0x01, 0x01, 0x01, 0x01, 0x08, 0x01, 0x01, 0x01},
nil,
[]byte{0x81, 0x81, 0xb6, 0x5b, 0xab, 0xf4, 0xa9, 0x75}},
{ // 33
[]byte{
0x01, 0x01, 0x01, 0x01, 0x04, 0x01, 0x01, 0x01,
0x01, 0x01, 0x01, 0x01, 0x04, 0x01, 0x01, 0x01,
0x01, 0x01, 0x01, 0x01, 0x04, 0x01, 0x01, 0x01},
nil,
[]byte{0x93, 0xc9, 0xb6, 0x40, 0x42, 0xea, 0xa2, 0x40}},
{ // 34
[]byte{
0x01, 0x01, 0x01, 0x01, 0x02, 0x01, 0x01, 0x01,
0x01, 0x01, 0x01, 0x01, 0x02, 0x01, 0x01, 0x01,
0x01, 0x01, 0x01, 0x01, 0x02, 0x01, 0x01, 0x01},
nil,
[]byte{0x55, 0x70, 0x53, 0x08, 0x29, 0x70, 0x55, 0x92}},
{ // 35
[]byte{
0x01, 0x01, 0x01, 0x01, 0x01, 0x80, 0x01, 0x01,
0x01, 0x01, 0x01, 0x01, 0x01, 0x80, 0x01, 0x01,
0x01, 0x01, 0x01, 0x01, 0x01, 0x80, 0x01, 0x01},
nil,
[]byte{0x86, 0x38, 0x80, 0x9e, 0x87, 0x87, 0x87, 0xa0}},
{ // 36
[]byte{
0x01, 0x01, 0x01, 0x01, 0x01, 0x40, 0x01, 0x01,
0x01, 0x01, 0x01, 0x01, 0x01, 0x40, 0x01, 0x01,
0x01, 0x01, 0x01, 0x01, 0x01, 0x40, 0x01, 0x01},
nil,
[]byte{0x41, 0xb9, 0xa7, 0x9a, 0xf7, 0x9a, 0xc2, 0x08}},
{ // 37
[]byte{
0x01, 0x01, 0x01, 0x01, 0x01, 0x20, 0x01, 0x01,
0x01, 0x01, 0x01, 0x01, 0x01, 0x20, 0x01, 0x01,
0x01, 0x01, 0x01, 0x01, 0x01, 0x20, 0x01, 0x01},
nil,
[]byte{0x7a, 0x9b, 0xe4, 0x2f, 0x20, 0x09, 0xa8, 0x92}},
{ // 38
[]byte{
0x01, 0x01, 0x01, 0x01, 0x01, 0x10, 0x01, 0x01,
0x01, 0x01, 0x01, 0x01, 0x01, 0x10, 0x01, 0x01,
0x01, 0x01, 0x01, 0x01, 0x01, 0x10, 0x01, 0x01},
nil,
[]byte{0x29, 0x03, 0x8d, 0x56, 0xba, 0x6d, 0x27, 0x45}},
{ // 39
[]byte{
0x01, 0x01, 0x01, 0x01, 0x01, 0x08, 0x01, 0x01,
0x01, 0x01, 0x01, 0x01, 0x01, 0x08, 0x01, 0x01,
0x01, 0x01, 0x01, 0x01, 0x01, 0x08, 0x01, 0x01},
nil,
[]byte{0x54, 0x95, 0xc6, 0xab, 0xf1, 0xe5, 0xdf, 0x51}},
{ // 40
[]byte{
0x01, 0x01, 0x01, 0x01, 0x01, 0x04, 0x01, 0x01,
0x01, 0x01, 0x01, 0x01, 0x01, 0x04, 0x01, 0x01,
0x01, 0x01, 0x01, 0x01, 0x01, 0x04, 0x01, 0x01},
nil,
[]byte{0xae, 0x13, 0xdb, 0xd5, 0x61, 0x48, 0x89, 0x33}},
{ // 41
[]byte{
0x01, 0x01, 0x01, 0x01, 0x01, 0x02, 0x01, 0x01,
0x01, 0x01, 0x01, 0x01, 0x01, 0x02, 0x01, 0x01,
0x01, 0x01, 0x01, 0x01, 0x01, 0x02, 0x01, 0x01},
nil,
[]byte{0x02, 0x4d, 0x1f, 0xfa, 0x89, 0x04, 0xe3, 0x89}},
{ // 42
[]byte{
0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x80, 0x01,
0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x80, 0x01,
0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x80, 0x01},
nil,
[]byte{0xd1, 0x39, 0x97, 0x12, 0xf9, 0x9b, 0xf0, 0x2e}},
{ // 43
[]byte{
0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x40, 0x01,
0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x40, 0x01,
0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x40, 0x01},
nil,
[]byte{0x14, 0xc1, 0xd7, 0xc1, 0xcf, 0xfe, 0xc7, 0x9e}},
{ // 44
[]byte{
0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x20, 0x01,
0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x20, 0x01,
0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x20, 0x01},
nil,
[]byte{0x1d, 0xe5, 0x27, 0x9d, 0xae, 0x3b, 0xed, 0x6f}},
{ // 45
[]byte{
0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x10, 0x01,
0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x10, 0x01,
0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x10, 0x01},
nil,
[]byte{0xe9, 0x41, 0xa3, 0x3f, 0x85, 0x50, 0x13, 0x03}},
{ // 46
[]byte{
0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x08, 0x01,
0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x08, 0x01,
0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x08, 0x01},
nil,
[]byte{0xda, 0x99, 0xdb, 0xbc, 0x9a, 0x03, 0xf3, 0x79}},
{ // 47
[]byte{
0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x04, 0x01,
0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x04, 0x01,
0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x04, 0x01},
nil,
[]byte{0xb7, 0xfc, 0x92, 0xf9, 0x1d, 0x8e, 0x92, 0xe9}},
{ // 48
[]byte{
0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x02, 0x01,
0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x02, 0x01,
0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x02, 0x01},
nil,
[]byte{0xae, 0x8e, 0x5c, 0xaa, 0x3c, 0xa0, 0x4e, 0x85}},
{ // 49
[]byte{
0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x80,
0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x80,
0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x80},
nil,
[]byte{0x9c, 0xc6, 0x2d, 0xf4, 0x3b, 0x6e, 0xed, 0x74}},
{ // 50
[]byte{
0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x40,
0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x40,
0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x40},
nil,
[]byte{0xd8, 0x63, 0xdb, 0xb5, 0xc5, 0x9a, 0x91, 0xa0}},
{ // 50
[]byte{
0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x20,
0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x20,
0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x20},
nil,
[]byte{0xa1, 0xab, 0x21, 0x90, 0x54, 0x5b, 0x91, 0xd7}},
{ // 52
[]byte{
0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x10,
0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x10,
0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x10},
nil,
[]byte{0x08, 0x75, 0x04, 0x1e, 0x64, 0xc5, 0x70, 0xf7}},
{ // 53
[]byte{
0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x08,
0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x08,
0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x08},
nil,
[]byte{0x5a, 0x59, 0x45, 0x28, 0xbe, 0xbe, 0xf1, 0xcc}},
{ // 54
[]byte{
0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x04,
0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x04,
0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x04},
nil,
[]byte{0xfc, 0xdb, 0x32, 0x91, 0xde, 0x21, 0xf0, 0xc0}},
{ // 55
[]byte{
0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x02,
0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x02,
0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x02},
nil,
[]byte{0x86, 0x9e, 0xfd, 0x7f, 0x9f, 0x26, 0x5a, 0x09}},
}
// Plaintext for use with Table A.3 tests
var tableA3Plaintext = []byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}
// Table A.3 Values To Be Used for the Permutation Operation Known Answer Test
var tableA3Tests = []CryptTest{
{ // 0
[]byte{
0x10, 0x46, 0x91, 0x34, 0x89, 0x98, 0x01, 0x31,
0x10, 0x46, 0x91, 0x34, 0x89, 0x98, 0x01, 0x31,
0x10, 0x46, 0x91, 0x34, 0x89, 0x98, 0x01, 0x31,
},
nil,
[]byte{0x88, 0xd5, 0x5e, 0x54, 0xf5, 0x4c, 0x97, 0xb4}},
{ // 1
[]byte{
0x10, 0x07, 0x10, 0x34, 0x89, 0x98, 0x80, 0x20,
0x10, 0x07, 0x10, 0x34, 0x89, 0x98, 0x80, 0x20,
0x10, 0x07, 0x10, 0x34, 0x89, 0x98, 0x80, 0x20,
},
nil,
[]byte{0x0c, 0x0c, 0xc0, 0x0c, 0x83, 0xea, 0x48, 0xfd}},
{ // 2
[]byte{
0x10, 0x07, 0x10, 0x34, 0xc8, 0x98, 0x01, 0x20,
0x10, 0x07, 0x10, 0x34, 0xc8, 0x98, 0x01, 0x20,
0x10, 0x07, 0x10, 0x34, 0xc8, 0x98, 0x01, 0x20,
},
nil,
[]byte{0x83, 0xbc, 0x8e, 0xf3, 0xa6, 0x57, 0x01, 0x83}},
{ // 3
[]byte{
0x10, 0x46, 0x10, 0x34, 0x89, 0x98, 0x80, 0x20,
0x10, 0x46, 0x10, 0x34, 0x89, 0x98, 0x80, 0x20,
0x10, 0x46, 0x10, 0x34, 0x89, 0x98, 0x80, 0x20,
},
nil,
[]byte{0xdf, 0x72, 0x5d, 0xca, 0xd9, 0x4e, 0xa2, 0xe9}},
{ // 4
[]byte{
0x10, 0x86, 0x91, 0x15, 0x19, 0x19, 0x01, 0x01,
0x10, 0x86, 0x91, 0x15, 0x19, 0x19, 0x01, 0x01,
0x10, 0x86, 0x91, 0x15, 0x19, 0x19, 0x01, 0x01,
},
nil,
[]byte{0xe6, 0x52, 0xb5, 0x3b, 0x55, 0x0b, 0xe8, 0xb0}},
{ // 5
[]byte{
0x10, 0x86, 0x91, 0x15, 0x19, 0x58, 0x01, 0x01,
0x10, 0x86, 0x91, 0x15, 0x19, 0x58, 0x01, 0x01,
0x10, 0x86, 0x91, 0x15, 0x19, 0x58, 0x01, 0x01,
},
nil,
[]byte{0xaf, 0x52, 0x71, 0x20, 0xc4, 0x85, 0xcb, 0xb0}},
{ // 6
[]byte{
0x51, 0x07, 0xb0, 0x15, 0x19, 0x58, 0x01, 0x01,
0x51, 0x07, 0xb0, 0x15, 0x19, 0x58, 0x01, 0x01,
0x51, 0x07, 0xb0, 0x15, 0x19, 0x58, 0x01, 0x01,
},
nil,
[]byte{0x0f, 0x04, 0xce, 0x39, 0x3d, 0xb9, 0x26, 0xd5}},
{ // 7
[]byte{
0x10, 0x07, 0xb0, 0x15, 0x19, 0x19, 0x01, 0x01,
0x10, 0x07, 0xb0, 0x15, 0x19, 0x19, 0x01, 0x01,
0x10, 0x07, 0xb0, 0x15, 0x19, 0x19, 0x01, 0x01,
},
nil,
[]byte{0xc9, 0xf0, 0x0f, 0xfc, 0x74, 0x07, 0x90, 0x67}},
{ // 8
[]byte{
0x31, 0x07, 0x91, 0x54, 0x98, 0x08, 0x01, 0x01,
0x31, 0x07, 0x91, 0x54, 0x98, 0x08, 0x01, 0x01,
0x31, 0x07, 0x91, 0x54, 0x98, 0x08, 0x01, 0x01,
},
nil,
[]byte{0x7c, 0xfd, 0x82, 0xa5, 0x93, 0x25, 0x2b, 0x4e}},
{ // 9
[]byte{
0x31, 0x07, 0x91, 0x94, 0x98, 0x08, 0x01, 0x01,
0x31, 0x07, 0x91, 0x94, 0x98, 0x08, 0x01, 0x01,
0x31, 0x07, 0x91, 0x94, 0x98, 0x08, 0x01, 0x01,
},
nil,
[]byte{0xcb, 0x49, 0xa2, 0xf9, 0xe9, 0x13, 0x63, 0xe3}},
{ // 10
[]byte{
0x10, 0x07, 0x91, 0x15, 0xb9, 0x08, 0x01, 0x40,
0x10, 0x07, 0x91, 0x15, 0xb9, 0x08, 0x01, 0x40,
0x10, 0x07, 0x91, 0x15, 0xb9, 0x08, 0x01, 0x40,
},
nil,
[]byte{0x00, 0xb5, 0x88, 0xbe, 0x70, 0xd2, 0x3f, 0x56}},
{ // 11
[]byte{
0x31, 0x07, 0x91, 0x15, 0x98, 0x08, 0x01, 0x40,
0x31, 0x07, 0x91, 0x15, 0x98, 0x08, 0x01, 0x40,
0x31, 0x07, 0x91, 0x15, 0x98, 0x08, 0x01, 0x40,
},
nil,
[]byte{0x40, 0x6a, 0x9a, 0x6a, 0xb4, 0x33, 0x99, 0xae}},
{ // 12
[]byte{
0x10, 0x07, 0xd0, 0x15, 0x89, 0x98, 0x01, 0x01,
0x10, 0x07, 0xd0, 0x15, 0x89, 0x98, 0x01, 0x01,
0x10, 0x07, 0xd0, 0x15, 0x89, 0x98, 0x01, 0x01,
},
nil,
[]byte{0x6c, 0xb7, 0x73, 0x61, 0x1d, 0xca, 0x9a, 0xda}},
{ // 13
[]byte{
0x91, 0x07, 0x91, 0x15, 0x89, 0x98, 0x01, 0x01,
0x91, 0x07, 0x91, 0x15, 0x89, 0x98, 0x01, 0x01,
0x91, 0x07, 0x91, 0x15, 0x89, 0x98, 0x01, 0x01,
},
nil,
[]byte{0x67, 0xfd, 0x21, 0xc1, 0x7d, 0xbb, 0x5d, 0x70}},
{ // 14
[]byte{
0x91, 0x07, 0xd0, 0x15, 0x89, 0x19, 0x01, 0x01,
0x91, 0x07, 0xd0, 0x15, 0x89, 0x19, 0x01, 0x01,
0x91, 0x07, 0xd0, 0x15, 0x89, 0x19, 0x01, 0x01,
},
nil,
[]byte{0x95, 0x92, 0xcb, 0x41, 0x10, 0x43, 0x07, 0x87}},
{ // 15
[]byte{
0x10, 0x07, 0xd0, 0x15, 0x98, 0x98, 0x01, 0x20,
0x10, 0x07, 0xd0, 0x15, 0x98, 0x98, 0x01, 0x20,
0x10, 0x07, 0xd0, 0x15, 0x98, 0x98, 0x01, 0x20,
},
nil,
[]byte{0xa6, 0xb7, 0xff, 0x68, 0xa3, 0x18, 0xdd, 0xd3}},
{ // 16
[]byte{
0x10, 0x07, 0x94, 0x04, 0x98, 0x19, 0x01, 0x01,
0x10, 0x07, 0x94, 0x04, 0x98, 0x19, 0x01, 0x01,
0x10, 0x07, 0x94, 0x04, 0x98, 0x19, 0x01, 0x01,
},
nil,
[]byte{0x4d, 0x10, 0x21, 0x96, 0xc9, 0x14, 0xca, 0x16}},
{ // 17
[]byte{
0x01, 0x07, 0x91, 0x04, 0x91, 0x19, 0x04, 0x01,
0x01, 0x07, 0x91, 0x04, 0x91, 0x19, 0x04, 0x01,
0x01, 0x07, 0x91, 0x04, 0x91, 0x19, 0x04, 0x01,
},
nil,
[]byte{0x2d, 0xfa, 0x9f, 0x45, 0x73, 0x59, 0x49, 0x65}},
{ // 18
[]byte{
0x01, 0x07, 0x91, 0x04, 0x91, 0x19, 0x01, 0x01,
0x01, 0x07, 0x91, 0x04, 0x91, 0x19, 0x01, 0x01,
0x01, 0x07, 0x91, 0x04, 0x91, 0x19, 0x01, 0x01,
},
nil,
[]byte{0xb4, 0x66, 0x04, 0x81, 0x6c, 0x0e, 0x07, 0x74}},
{ // 19
[]byte{
0x01, 0x07, 0x94, 0x04, 0x91, 0x19, 0x04, 0x01,
0x01, 0x07, 0x94, 0x04, 0x91, 0x19, 0x04, 0x01,
0x01, 0x07, 0x94, 0x04, 0x91, 0x19, 0x04, 0x01,
},
nil,
[]byte{0x6e, 0x7e, 0x62, 0x21, 0xa4, 0xf3, 0x4e, 0x87}},
{ // 20
[]byte{
0x19, 0x07, 0x92, 0x10, 0x98, 0x1a, 0x01, 0x01,
0x19, 0x07, 0x92, 0x10, 0x98, 0x1a, 0x01, 0x01,
0x19, 0x07, 0x92, 0x10, 0x98, 0x1a, 0x01, 0x01,
},
nil,
[]byte{0xaa, 0x85, 0xe7, 0x46, 0x43, 0x23, 0x31, 0x99}},
{ // 21
[]byte{
0x10, 0x07, 0x91, 0x19, 0x98, 0x19, 0x08, 0x01,
0x10, 0x07, 0x91, 0x19, 0x98, 0x19, 0x08, 0x01,
0x10, 0x07, 0x91, 0x19, 0x98, 0x19, 0x08, 0x01,
},
nil,
[]byte{0x2e, 0x5a, 0x19, 0xdb, 0x4d, 0x19, 0x62, 0xd6}},
{ // 22
[]byte{
0x10, 0x07, 0x91, 0x19, 0x98, 0x1a, 0x08, 0x01,
0x10, 0x07, 0x91, 0x19, 0x98, 0x1a, 0x08, 0x01,
0x10, 0x07, 0x91, 0x19, 0x98, 0x1a, 0x08, 0x01,
},
nil,
[]byte{0x23, 0xa8, 0x66, 0xa8, 0x09, 0xd3, 0x08, 0x94}},
{ // 23
[]byte{
0x10, 0x07, 0x92, 0x10, 0x98, 0x19, 0x01, 0x01,
0x10, 0x07, 0x92, 0x10, 0x98, 0x19, 0x01, 0x01,
0x10, 0x07, 0x92, 0x10, 0x98, 0x19, 0x01, 0x01,
},
nil,
[]byte{0xd8, 0x12, 0xd9, 0x61, 0xf0, 0x17, 0xd3, 0x20}},
{ // 24
[]byte{
0x10, 0x07, 0x91, 0x15, 0x98, 0x19, 0x01, 0x0b,
0x10, 0x07, 0x91, 0x15, 0x98, 0x19, 0x01, 0x0b,
0x10, 0x07, 0x91, 0x15, 0x98, 0x19, 0x01, 0x0b,
},
nil,
[]byte{0x05, 0x56, 0x05, 0x81, 0x6e, 0x58, 0x60, 0x8f}},
{ // 25
[]byte{
0x10, 0x04, 0x80, 0x15, 0x98, 0x19, 0x01, 0x01,
0x10, 0x04, 0x80, 0x15, 0x98, 0x19, 0x01, 0x01,
0x10, 0x04, 0x80, 0x15, 0x98, 0x19, 0x01, 0x01,
},
nil,
[]byte{0xab, 0xd8, 0x8e, 0x8b, 0x1b, 0x77, 0x16, 0xf1}},
{ // 26
[]byte{
0x10, 0x04, 0x80, 0x15, 0x98, 0x19, 0x01, 0x02,
0x10, 0x04, 0x80, 0x15, 0x98, 0x19, 0x01, 0x02,
0x10, 0x04, 0x80, 0x15, 0x98, 0x19, 0x01, 0x02,
},
nil,
[]byte{0x53, 0x7a, 0xc9, 0x5b, 0xe6, 0x9d, 0xa1, 0xe1}},
{ // 27
[]byte{
0x10, 0x04, 0x80, 0x15, 0x98, 0x19, 0x01, 0x08,
0x10, 0x04, 0x80, 0x15, 0x98, 0x19, 0x01, 0x08,
0x10, 0x04, 0x80, 0x15, 0x98, 0x19, 0x01, 0x08,
},
nil,
[]byte{0xae, 0xd0, 0xf6, 0xae, 0x3c, 0x25, 0xcd, 0xd8}},
{ // 28
[]byte{
0x10, 0x02, 0x91, 0x15, 0x98, 0x10, 0x01, 0x04,
0x10, 0x02, 0x91, 0x15, 0x98, 0x10, 0x01, 0x04,
0x10, 0x02, 0x91, 0x15, 0x98, 0x10, 0x01, 0x04,
},
nil,
[]byte{0xb3, 0xe3, 0x5a, 0x5e, 0xe5, 0x3e, 0x7b, 0x8d}},
{ // 29
[]byte{
0x10, 0x02, 0x91, 0x15, 0x98, 0x19, 0x01, 0x04,
0x10, 0x02, 0x91, 0x15, 0x98, 0x19, 0x01, 0x04,
0x10, 0x02, 0x91, 0x15, 0x98, 0x19, 0x01, 0x04,
},
nil,
[]byte{0x61, 0xc7, 0x9c, 0x71, 0x92, 0x1a, 0x2e, 0xf8}},
{ // 30
[]byte{
0x10, 0x02, 0x91, 0x15, 0x98, 0x10, 0x02, 0x01,
0x10, 0x02, 0x91, 0x15, 0x98, 0x10, 0x02, 0x01,
0x10, 0x02, 0x91, 0x15, 0x98, 0x10, 0x02, 0x01,
},
nil,
[]byte{0xe2, 0xf5, 0x72, 0x8f, 0x09, 0x95, 0x01, 0x3c}},
{ // 31
[]byte{
0x10, 0x02, 0x91, 0x16, 0x98, 0x10, 0x01, 0x01,
0x10, 0x02, 0x91, 0x16, 0x98, 0x10, 0x01, 0x01,
0x10, 0x02, 0x91, 0x16, 0x98, 0x10, 0x01, 0x01,
},
nil,
[]byte{0x1a, 0xea, 0xc3, 0x9a, 0x61, 0xf0, 0xa4, 0x64}},
}
// Table A.4 Values To Be Used for the Substitution Table Known Answer Test
var tableA4Tests = []CryptTest{
{ // 0
[]byte{
0x7c, 0xa1, 0x10, 0x45, 0x4a, 0x1a, 0x6e, 0x57,
0x7c, 0xa1, 0x10, 0x45, 0x4a, 0x1a, 0x6e, 0x57,
0x7c, 0xa1, 0x10, 0x45, 0x4a, 0x1a, 0x6e, 0x57},
[]byte{0x01, 0xa1, 0xd6, 0xd0, 0x39, 0x77, 0x67, 0x42},
[]byte{0x69, 0x0f, 0x5b, 0x0d, 0x9a, 0x26, 0x93, 0x9b}},
{ // 1
[]byte{
0x01, 0x31, 0xd9, 0x61, 0x9d, 0xc1, 0x37, 0x6e,
0x01, 0x31, 0xd9, 0x61, 0x9d, 0xc1, 0x37, 0x6e,
0x01, 0x31, 0xd9, 0x61, 0x9d, 0xc1, 0x37, 0x6e},
[]byte{0x5c, 0xd5, 0x4c, 0xa8, 0x3d, 0xef, 0x57, 0xda},
[]byte{0x7a, 0x38, 0x9d, 0x10, 0x35, 0x4b, 0xd2, 0x71}},
{ // 2
[]byte{
0x07, 0xa1, 0x13, 0x3e, 0x4a, 0x0b, 0x26, 0x86,
0x07, 0xa1, 0x13, 0x3e, 0x4a, 0x0b, 0x26, 0x86,
0x07, 0xa1, 0x13, 0x3e, 0x4a, 0x0b, 0x26, 0x86},
[]byte{0x02, 0x48, 0xd4, 0x38, 0x06, 0xf6, 0x71, 0x72},
[]byte{0x86, 0x8e, 0xbb, 0x51, 0xca, 0xb4, 0x59, 0x9a}},
{ // 3
[]byte{
0x38, 0x49, 0x67, 0x4c, 0x26, 0x02, 0x31, 0x9e,
0x38, 0x49, 0x67, 0x4c, 0x26, 0x02, 0x31, 0x9e,
0x38, 0x49, 0x67, 0x4c, 0x26, 0x02, 0x31, 0x9e},
[]byte{0x51, 0x45, 0x4b, 0x58, 0x2d, 0xdf, 0x44, 0x0a},
[]byte{0x71, 0x78, 0x87, 0x6e, 0x01, 0xf1, 0x9b, 0x2a}},
{ // 4
[]byte{
0x04, 0xb9, 0x15, 0xba, 0x43, 0xfe, 0xb5, 0xb6,
0x04, 0xb9, 0x15, 0xba, 0x43, 0xfe, 0xb5, 0xb6,
0x04, 0xb9, 0x15, 0xba, 0x43, 0xfe, 0xb5, 0xb6},
[]byte{0x42, 0xfd, 0x44, 0x30, 0x59, 0x57, 0x7f, 0xa2},
[]byte{0xaf, 0x37, 0xfb, 0x42, 0x1f, 0x8c, 0x40, 0x95}},
{ // 5
[]byte{
0x01, 0x13, 0xb9, 0x70, 0xfd, 0x34, 0xf2, 0xce,
0x01, 0x13, 0xb9, 0x70, 0xfd, 0x34, 0xf2, 0xce,
0x01, 0x13, 0xb9, 0x70, 0xfd, 0x34, 0xf2, 0xce},
[]byte{0x05, 0x9b, 0x5e, 0x08, 0x51, 0xcf, 0x14, 0x3a},
[]byte{0x86, 0xa5, 0x60, 0xf1, 0x0e, 0xc6, 0xd8, 0x5b}},
{ // 6
[]byte{
0x01, 0x70, 0xf1, 0x75, 0x46, 0x8f, 0xb5, 0xe6,
0x01, 0x70, 0xf1, 0x75, 0x46, 0x8f, 0xb5, 0xe6,
0x01, 0x70, 0xf1, 0x75, 0x46, 0x8f, 0xb5, 0xe6},
[]byte{0x07, 0x56, 0xd8, 0xe0, 0x77, 0x47, 0x61, 0xd2},
[]byte{0x0c, 0xd3, 0xda, 0x02, 0x00, 0x21, 0xdc, 0x09}},
{ // 7
[]byte{
0x43, 0x29, 0x7f, 0xad, 0x38, 0xe3, 0x73, 0xfe,
0x43, 0x29, 0x7f, 0xad, 0x38, 0xe3, 0x73, 0xfe,
0x43, 0x29, 0x7f, 0xad, 0x38, 0xe3, 0x73, 0xfe},
[]byte{0x76, 0x25, 0x14, 0xb8, 0x29, 0xbf, 0x48, 0x6a},
[]byte{0xea, 0x67, 0x6b, 0x2c, 0xb7, 0xdb, 0x2b, 0x7a}},
{ // 8
[]byte{
0x07, 0xa7, 0x13, 0x70, 0x45, 0xda, 0x2a, 0x16,
0x07, 0xa7, 0x13, 0x70, 0x45, 0xda, 0x2a, 0x16,
0x07, 0xa7, 0x13, 0x70, 0x45, 0xda, 0x2a, 0x16},
[]byte{0x3b, 0xdd, 0x11, 0x90, 0x49, 0x37, 0x28, 0x02},
[]byte{0xdf, 0xd6, 0x4a, 0x81, 0x5c, 0xaf, 0x1a, 0x0f}},
{ // 9
[]byte{
0x04, 0x68, 0x91, 0x04, 0xc2, 0xfd, 0x3b, 0x2f,
0x04, 0x68, 0x91, 0x04, 0xc2, 0xfd, 0x3b, 0x2f,
0x04, 0x68, 0x91, 0x04, 0xc2, 0xfd, 0x3b, 0x2f},
[]byte{0x26, 0x95, 0x5f, 0x68, 0x35, 0xaf, 0x60, 0x9a},
[]byte{0x5c, 0x51, 0x3c, 0x9c, 0x48, 0x86, 0xc0, 0x88}},
{ // 10
[]byte{
0x37, 0xd0, 0x6b, 0xb5, 0x16, 0xcb, 0x75, 0x46,
0x37, 0xd0, 0x6b, 0xb5, 0x16, 0xcb, 0x75, 0x46,
0x37, 0xd0, 0x6b, 0xb5, 0x16, 0xcb, 0x75, 0x46},
[]byte{0x16, 0x4d, 0x5e, 0x40, 0x4f, 0x27, 0x52, 0x32},
[]byte{0x0a, 0x2a, 0xee, 0xae, 0x3f, 0xf4, 0xab, 0x77}},
{ // 11
[]byte{
0x1f, 0x08, 0x26, 0x0d, 0x1a, 0xc2, 0x46, 0x5e,
0x1f, 0x08, 0x26, 0x0d, 0x1a, 0xc2, 0x46, 0x5e,
0x1f, 0x08, 0x26, 0x0d, 0x1a, 0xc2, 0x46, 0x5e},
[]byte{0x6b, 0x05, 0x6e, 0x18, 0x75, 0x9f, 0x5c, 0xca},
[]byte{0xef, 0x1b, 0xf0, 0x3e, 0x5d, 0xfa, 0x57, 0x5a}},
{ // 12
[]byte{
0x58, 0x40, 0x23, 0x64, 0x1a, 0xba, 0x61, 0x76,
0x58, 0x40, 0x23, 0x64, 0x1a, 0xba, 0x61, 0x76,
0x58, 0x40, 0x23, 0x64, 0x1a, 0xba, 0x61, 0x76},
[]byte{0x00, 0x4b, 0xd6, 0xef, 0x09, 0x17, 0x60, 0x62},
[]byte{0x88, 0xbf, 0x0d, 0xb6, 0xd7, 0x0d, 0xee, 0x56}},
{ // 13
[]byte{
0x02, 0x58, 0x16, 0x16, 0x46, 0x29, 0xb0, 0x07,
0x02, 0x58, 0x16, 0x16, 0x46, 0x29, 0xb0, 0x07,
0x02, 0x58, 0x16, 0x16, 0x46, 0x29, 0xb0, 0x07},
[]byte{0x48, 0x0d, 0x39, 0x00, 0x6e, 0xe7, 0x62, 0xf2},
[]byte{0xa1, 0xf9, 0x91, 0x55, 0x41, 0x02, 0x0b, 0x56}},
{ // 14
[]byte{
0x49, 0x79, 0x3e, 0xbc, 0x79, 0xb3, 0x25, 0x8f,
0x49, 0x79, 0x3e, 0xbc, 0x79, 0xb3, 0x25, 0x8f,
0x49, 0x79, 0x3e, 0xbc, 0x79, 0xb3, 0x25, 0x8f},
[]byte{0x43, 0x75, 0x40, 0xc8, 0x69, 0x8f, 0x3c, 0xfa},
[]byte{0x6f, 0xbf, 0x1c, 0xaf, 0xcf, 0xfd, 0x05, 0x56}},
{ // 15
[]byte{
0x4f, 0xb0, 0x5e, 0x15, 0x15, 0xab, 0x73, 0xa7,
0x4f, 0xb0, 0x5e, 0x15, 0x15, 0xab, 0x73, 0xa7,
0x4f, 0xb0, 0x5e, 0x15, 0x15, 0xab, 0x73, 0xa7},
[]byte{0x07, 0x2d, 0x43, 0xa0, 0x77, 0x07, 0x52, 0x92},
[]byte{0x2f, 0x22, 0xe4, 0x9b, 0xab, 0x7c, 0xa1, 0xac}},
{ // 16
[]byte{
0x49, 0xe9, 0x5d, 0x6d, 0x4c, 0xa2, 0x29, 0xbf,
0x49, 0xe9, 0x5d, 0x6d, 0x4c, 0xa2, 0x29, 0xbf,
0x49, 0xe9, 0x5d, 0x6d, 0x4c, 0xa2, 0x29, 0xbf},
[]byte{0x02, 0xfe, 0x55, 0x77, 0x81, 0x17, 0xf1, 0x2a},
[]byte{0x5a, 0x6b, 0x61, 0x2c, 0xc2, 0x6c, 0xce, 0x4a}},
{ // 17
[]byte{
0x01, 0x83, 0x10, 0xdc, 0x40, 0x9b, 0x26, 0xd6,
0x01, 0x83, 0x10, 0xdc, 0x40, 0x9b, 0x26, 0xd6,
0x01, 0x83, 0x10, 0xdc, 0x40, 0x9b, 0x26, 0xd6},
[]byte{0x1d, 0x9d, 0x5c, 0x50, 0x18, 0xf7, 0x28, 0xc2},
[]byte{0x5f, 0x4c, 0x03, 0x8e, 0xd1, 0x2b, 0x2e, 0x41}},
{ // 18
[]byte{
0x1c, 0x58, 0x7f, 0x1c, 0x13, 0x92, 0x4f, 0xef,
0x1c, 0x58, 0x7f, 0x1c, 0x13, 0x92, 0x4f, 0xef,
0x1c, 0x58, 0x7f, 0x1c, 0x13, 0x92, 0x4f, 0xef},
[]byte{0x30, 0x55, 0x32, 0x28, 0x6d, 0x6f, 0x29, 0x5a},
[]byte{0x63, 0xfa, 0xc0, 0xd0, 0x34, 0xd9, 0xf7, 0x93}},
}
// Use the known weak keys to test DES implementation
func TestWeakKeys(t *testing.T) {
for i, tt := range weakKeyTests {
var encrypt = func(in []byte) (out []byte) {
c, _ := NewCipher(tt.key)
out = make([]byte, len(in))
encryptBlock(c.subkeys[:], out, in)
return
}
// Encrypting twice with a DES weak
// key should reproduce the original input
result := encrypt(tt.in)
result = encrypt(result)
if !bytes.Equal(result, tt.in) {
t.Errorf("#%d: result: %x want: %x", i, result, tt.in)
}
}
}
// Use the known semi-weak key pairs to test DES implementation
func TestSemiWeakKeyPairs(t *testing.T) {
for i, tt := range semiWeakKeyTests {
var encrypt = func(key, in []byte) (out []byte) {
c, _ := NewCipher(key)
out = make([]byte, len(in))
encryptBlock(c.subkeys[:], out, in)
return
}
// Encrypting with one member of the semi-weak pair
// and then encrypting the result with the other member
// should reproduce the original input.
result := encrypt(tt.key, tt.in)
result = encrypt(tt.out, result)
if !bytes.Equal(result, tt.in) {
t.Errorf("#%d: result: %x want: %x", i, result, tt.in)
}
}
}
func TestDESEncryptBlock(t *testing.T) {
for i, tt := range encryptDESTests {
c, _ := NewCipher(tt.key)
out := make([]byte, len(tt.in))
encryptBlock(c.subkeys[:], out, tt.in)
if !bytes.Equal(out, tt.out) {
t.Errorf("#%d: result: %x want: %x", i, out, tt.out)
}
}
}
func TestDESDecryptBlock(t *testing.T) {
for i, tt := range encryptDESTests {
c, _ := NewCipher(tt.key)
plain := make([]byte, len(tt.in))
decryptBlock(c.subkeys[:], plain, tt.out)
if !bytes.Equal(plain, tt.in) {
t.Errorf("#%d: result: %x want: %x", i, plain, tt.in)
}
}
}
func TestEncryptTripleDES(t *testing.T) {
for i, tt := range encryptTripleDESTests {
c, _ := NewTripleDESCipher(tt.key)
out := make([]byte, len(tt.in))
c.Encrypt(out, tt.in)
if !bytes.Equal(out, tt.out) {
t.Errorf("#%d: result: %x want: %x", i, out, tt.out)
}
}
}
func TestDecryptTripleDES(t *testing.T) {
for i, tt := range encryptTripleDESTests {
c, _ := NewTripleDESCipher(tt.key)
plain := make([]byte, len(tt.in))
c.Decrypt(plain, tt.out)
if !bytes.Equal(plain, tt.in) {
t.Errorf("#%d: result: %x want: %x", i, plain, tt.in)
}
}
}
// Defined in Pub 800-20
func TestVariablePlaintextKnownAnswer(t *testing.T) {
for i, tt := range tableA1Tests {
c, _ := NewTripleDESCipher(tableA1Key)
out := make([]byte, len(tt.in))
c.Encrypt(out, tt.in)
if !bytes.Equal(out, tt.out) {
t.Errorf("#%d: result: %x want: %x", i, out, tt.out)
}
}
}
// Defined in Pub 800-20
func TestVariableCiphertextKnownAnswer(t *testing.T) {
for i, tt := range tableA1Tests {
c, _ := NewTripleDESCipher(tableA1Key)
plain := make([]byte, len(tt.out))
c.Decrypt(plain, tt.out)
if !bytes.Equal(plain, tt.in) {
t.Errorf("#%d: result: %x want: %x", i, plain, tt.in)
}
}
}
// Defined in Pub 800-20
// Encrypting the Table A.1 ciphertext with the
// 0x01... key produces the original plaintext
func TestInversePermutationKnownAnswer(t *testing.T) {
for i, tt := range tableA1Tests {
c, _ := NewTripleDESCipher(tableA1Key)
plain := make([]byte, len(tt.in))
c.Encrypt(plain, tt.out)
if !bytes.Equal(plain, tt.in) {
t.Errorf("#%d: result: %x want: %x", i, plain, tt.in)
}
}
}
// Defined in Pub 800-20
// Decrypting the Table A.1 plaintext with the
// 0x01... key produces the corresponding ciphertext
func TestInitialPermutationKnownAnswer(t *testing.T) {
for i, tt := range tableA1Tests {
c, _ := NewTripleDESCipher(tableA1Key)
out := make([]byte, len(tt.in))
c.Decrypt(out, tt.in)
if !bytes.Equal(out, tt.out) {
t.Errorf("#%d: result: %x want: %x", i, out, tt.out)
}
}
}
// Defined in Pub 800-20
func TestVariableKeyKnownAnswerEncrypt(t *testing.T) {
for i, tt := range tableA2Tests {
c, _ := NewTripleDESCipher(tt.key)
out := make([]byte, len(tableA2Plaintext))
c.Encrypt(out, tableA2Plaintext)
if !bytes.Equal(out, tt.out) {
t.Errorf("#%d: result: %x want: %x", i, out, tt.out)
}
}
}
// Defined in Pub 800-20
func TestVariableKeyKnownAnswerDecrypt(t *testing.T) {
for i, tt := range tableA2Tests {
c, _ := NewTripleDESCipher(tt.key)
out := make([]byte, len(tt.out))
c.Decrypt(out, tt.out)
if !bytes.Equal(out, tableA2Plaintext) {
t.Errorf("#%d: result: %x want: %x", i, out, tableA2Plaintext)
}
}
}
// Defined in Pub 800-20
func TestPermutationOperationKnownAnswerEncrypt(t *testing.T) {
for i, tt := range tableA3Tests {
c, _ := NewTripleDESCipher(tt.key)
out := make([]byte, len(tableA3Plaintext))
c.Encrypt(out, tableA3Plaintext)
if !bytes.Equal(out, tt.out) {
t.Errorf("#%d: result: %x want: %x", i, out, tt.out)
}
}
}
// Defined in Pub 800-20
func TestPermutationOperationKnownAnswerDecrypt(t *testing.T) {
for i, tt := range tableA3Tests {
c, _ := NewTripleDESCipher(tt.key)
out := make([]byte, len(tt.out))
c.Decrypt(out, tt.out)
if !bytes.Equal(out, tableA3Plaintext) {
t.Errorf("#%d: result: %x want: %x", i, out, tableA3Plaintext)
}
}
}
// Defined in Pub 800-20
func TestSubstitutionTableKnownAnswerEncrypt(t *testing.T) {
for i, tt := range tableA4Tests {
c, _ := NewTripleDESCipher(tt.key)
out := make([]byte, len(tt.in))
c.Encrypt(out, tt.in)
if !bytes.Equal(out, tt.out) {
t.Errorf("#%d: result: %x want: %x", i, out, tt.out)
}
}
}
// Defined in Pub 800-20
func TestSubstitutionTableKnownAnswerDecrypt(t *testing.T) {
for i, tt := range tableA4Tests {
c, _ := NewTripleDESCipher(tt.key)
out := make([]byte, len(tt.out))
c.Decrypt(out, tt.out)
if !bytes.Equal(out, tt.in) {
t.Errorf("#%d: result: %x want: %x", i, out, tt.in)
}
}
}
...@@ -37,7 +37,7 @@ var one = new(big.Int).SetInt64(1) ...@@ -37,7 +37,7 @@ var one = new(big.Int).SetInt64(1)
// curve using the procedure given in [NSA] A.2.1. // curve using the procedure given in [NSA] A.2.1.
func randFieldElement(c *elliptic.Curve, rand io.Reader) (k *big.Int, err os.Error) { func randFieldElement(c *elliptic.Curve, rand io.Reader) (k *big.Int, err os.Error) {
b := make([]byte, c.BitSize/8+8) b := make([]byte, c.BitSize/8+8)
_, err = rand.Read(b) _, err = io.ReadFull(rand, b)
if err != nil { if err != nil {
return return
} }
......
...@@ -32,7 +32,7 @@ func (r *devReader) Read(b []byte) (n int, err os.Error) { ...@@ -32,7 +32,7 @@ func (r *devReader) Read(b []byte) (n int, err os.Error) {
r.mu.Lock() r.mu.Lock()
defer r.mu.Unlock() defer r.mu.Unlock()
if r.f == nil { if r.f == nil {
f, err := os.Open(r.name, os.O_RDONLY, 0) f, err := os.Open(r.name)
if f == nil { if f == nil {
return 0, err return 0, err
} }
......
...@@ -127,7 +127,7 @@ func nonZeroRandomBytes(s []byte, rand io.Reader) (err os.Error) { ...@@ -127,7 +127,7 @@ func nonZeroRandomBytes(s []byte, rand io.Reader) (err os.Error) {
for i := 0; i < len(s); i++ { for i := 0; i < len(s); i++ {
for s[i] == 0 { for s[i] == 0 {
_, err = rand.Read(s[i : i+1]) _, err = io.ReadFull(rand, s[i:i+1])
if err != nil { if err != nil {
return return
} }
......
...@@ -13,6 +13,7 @@ import ( ...@@ -13,6 +13,7 @@ import (
"hash" "hash"
"io" "io"
"os" "os"
"sync"
) )
var bigZero = big.NewInt(0) var bigZero = big.NewInt(0)
...@@ -91,15 +92,21 @@ type PublicKey struct { ...@@ -91,15 +92,21 @@ type PublicKey struct {
type PrivateKey struct { type PrivateKey struct {
PublicKey // public part. PublicKey // public part.
D *big.Int // private exponent D *big.Int // private exponent
P, Q *big.Int // prime factors of N P, Q, R *big.Int // prime factors of N (R may be nil)
rwMutex sync.RWMutex // protects the following
dP, dQ, dR *big.Int // D mod (P-1) (or mod Q-1 etc)
qInv *big.Int // q^-1 mod p
pq *big.Int // P*Q
tr *big.Int // pq·tr ≡ 1 mod r
} }
// Validate performs basic sanity checks on the key. // Validate performs basic sanity checks on the key.
// It returns nil if the key is valid, or else an os.Error describing a problem. // It returns nil if the key is valid, or else an os.Error describing a problem.
func (priv PrivateKey) Validate() os.Error { func (priv *PrivateKey) Validate() os.Error {
// Check that p and q are prime. Note that this is just a sanity // Check that p, q and, maybe, r are prime. Note that this is just a
// check. Since the random witnesses chosen by ProbablyPrime are // sanity check. Since the random witnesses chosen by ProbablyPrime are
// deterministic, given the candidate number, it's easy for an attack // deterministic, given the candidate number, it's easy for an attack
// to generate composites that pass this test. // to generate composites that pass this test.
if !big.ProbablyPrime(priv.P, 20) { if !big.ProbablyPrime(priv.P, 20) {
...@@ -108,16 +115,26 @@ func (priv PrivateKey) Validate() os.Error { ...@@ -108,16 +115,26 @@ func (priv PrivateKey) Validate() os.Error {
if !big.ProbablyPrime(priv.Q, 20) { if !big.ProbablyPrime(priv.Q, 20) {
return os.ErrorString("Q is composite") return os.ErrorString("Q is composite")
} }
if priv.R != nil && !big.ProbablyPrime(priv.R, 20) {
return os.ErrorString("R is composite")
}
// Check that p*q == n. // Check that p*q*r == n.
modulus := new(big.Int).Mul(priv.P, priv.Q) modulus := new(big.Int).Mul(priv.P, priv.Q)
if priv.R != nil {
modulus.Mul(modulus, priv.R)
}
if modulus.Cmp(priv.N) != 0 { if modulus.Cmp(priv.N) != 0 {
return os.ErrorString("invalid modulus") return os.ErrorString("invalid modulus")
} }
// Check that e and totient(p, q) are coprime. // Check that e and totient(p, q, r) are coprime.
pminus1 := new(big.Int).Sub(priv.P, bigOne) pminus1 := new(big.Int).Sub(priv.P, bigOne)
qminus1 := new(big.Int).Sub(priv.Q, bigOne) qminus1 := new(big.Int).Sub(priv.Q, bigOne)
totient := new(big.Int).Mul(pminus1, qminus1) totient := new(big.Int).Mul(pminus1, qminus1)
if priv.R != nil {
rminus1 := new(big.Int).Sub(priv.R, bigOne)
totient.Mul(totient, rminus1)
}
e := big.NewInt(int64(priv.E)) e := big.NewInt(int64(priv.E))
gcd := new(big.Int) gcd := new(big.Int)
x := new(big.Int) x := new(big.Int)
...@@ -126,7 +143,7 @@ func (priv PrivateKey) Validate() os.Error { ...@@ -126,7 +143,7 @@ func (priv PrivateKey) Validate() os.Error {
if gcd.Cmp(bigOne) != 0 { if gcd.Cmp(bigOne) != 0 {
return os.ErrorString("invalid public exponent E") return os.ErrorString("invalid public exponent E")
} }
// Check that de ≡ 1 (mod totient(p, q)) // Check that de ≡ 1 (mod totient(p, q, r))
de := new(big.Int).Mul(priv.D, e) de := new(big.Int).Mul(priv.D, e)
de.Mod(de, totient) de.Mod(de, totient)
if de.Cmp(bigOne) != 0 { if de.Cmp(bigOne) != 0 {
...@@ -135,7 +152,7 @@ func (priv PrivateKey) Validate() os.Error { ...@@ -135,7 +152,7 @@ func (priv PrivateKey) Validate() os.Error {
return nil return nil
} }
// GenerateKeyPair generates an RSA keypair of the given bit size. // GenerateKey generates an RSA keypair of the given bit size.
func GenerateKey(rand io.Reader, bits int) (priv *PrivateKey, err os.Error) { func GenerateKey(rand io.Reader, bits int) (priv *PrivateKey, err os.Error) {
priv = new(PrivateKey) priv = new(PrivateKey)
// Smaller public exponents lead to faster public key // Smaller public exponents lead to faster public key
...@@ -191,6 +208,77 @@ func GenerateKey(rand io.Reader, bits int) (priv *PrivateKey, err os.Error) { ...@@ -191,6 +208,77 @@ func GenerateKey(rand io.Reader, bits int) (priv *PrivateKey, err os.Error) {
return return
} }
// Generate3PrimeKey generates a 3-prime RSA keypair of the given bit size, as
// suggested in [1]. Although the public keys are compatible (actually,
// indistinguishable) from the 2-prime case, the private keys are not. Thus it
// may not be possible to export 3-prime private keys in certain formats or to
// subsequently import them into other code.
//
// Table 1 in [2] suggests that size should be >= 1024 when using 3 primes.
//
// [1] US patent 4405829 (1972, expired)
// [2] http://www.cacr.math.uwaterloo.ca/techreports/2006/cacr2006-16.pdf
func Generate3PrimeKey(rand io.Reader, bits int) (priv *PrivateKey, err os.Error) {
priv = new(PrivateKey)
priv.E = 3
pminus1 := new(big.Int)
qminus1 := new(big.Int)
rminus1 := new(big.Int)
totient := new(big.Int)
for {
p, err := randomPrime(rand, bits/3)
if err != nil {
return nil, err
}
todo := bits - p.BitLen()
q, err := randomPrime(rand, todo/2)
if err != nil {
return nil, err
}
todo -= q.BitLen()
r, err := randomPrime(rand, todo)
if err != nil {
return nil, err
}
if p.Cmp(q) == 0 ||
q.Cmp(r) == 0 ||
r.Cmp(p) == 0 {
continue
}
n := new(big.Int).Mul(p, q)
n.Mul(n, r)
pminus1.Sub(p, bigOne)
qminus1.Sub(q, bigOne)
rminus1.Sub(r, bigOne)
totient.Mul(pminus1, qminus1)
totient.Mul(totient, rminus1)
g := new(big.Int)
priv.D = new(big.Int)
y := new(big.Int)
e := big.NewInt(int64(priv.E))
big.GcdInt(g, priv.D, y, e, totient)
if g.Cmp(bigOne) == 0 {
priv.D.Add(priv.D, totient)
priv.P = p
priv.Q = q
priv.R = r
priv.N = n
break
}
}
return
}
// incCounter increments a four byte, big-endian counter. // incCounter increments a four byte, big-endian counter.
func incCounter(c *[4]byte) { func incCounter(c *[4]byte) {
if c[3]++; c[3] != 0 { if c[3]++; c[3] != 0 {
...@@ -321,6 +409,26 @@ func modInverse(a, n *big.Int) (ia *big.Int, ok bool) { ...@@ -321,6 +409,26 @@ func modInverse(a, n *big.Int) (ia *big.Int, ok bool) {
return x, true return x, true
} }
// precompute performs some calculations that speed up private key operations
// in the future.
func (priv *PrivateKey) precompute() {
priv.dP = new(big.Int).Sub(priv.P, bigOne)
priv.dP.Mod(priv.D, priv.dP)
priv.dQ = new(big.Int).Sub(priv.Q, bigOne)
priv.dQ.Mod(priv.D, priv.dQ)
priv.qInv = new(big.Int).ModInverse(priv.Q, priv.P)
if priv.R != nil {
priv.dR = new(big.Int).Sub(priv.R, bigOne)
priv.dR.Mod(priv.D, priv.dR)
priv.pq = new(big.Int).Mul(priv.P, priv.Q)
priv.tr = new(big.Int).ModInverse(priv.pq, priv.R)
}
}
// decrypt performs an RSA decryption, resulting in a plaintext integer. If a // decrypt performs an RSA decryption, resulting in a plaintext integer. If a
// random source is given, RSA blinding is used. // random source is given, RSA blinding is used.
func decrypt(rand io.Reader, priv *PrivateKey, c *big.Int) (m *big.Int, err os.Error) { func decrypt(rand io.Reader, priv *PrivateKey, c *big.Int) (m *big.Int, err os.Error) {
...@@ -359,7 +467,48 @@ func decrypt(rand io.Reader, priv *PrivateKey, c *big.Int) (m *big.Int, err os.E ...@@ -359,7 +467,48 @@ func decrypt(rand io.Reader, priv *PrivateKey, c *big.Int) (m *big.Int, err os.E
c.Mod(c, priv.N) c.Mod(c, priv.N)
} }
priv.rwMutex.RLock()
if priv.dP == nil && priv.P != nil {
priv.rwMutex.RUnlock()
priv.rwMutex.Lock()
if priv.dP == nil && priv.P != nil {
priv.precompute()
}
priv.rwMutex.Unlock()
priv.rwMutex.RLock()
}
if priv.dP == nil {
m = new(big.Int).Exp(c, priv.D, priv.N) m = new(big.Int).Exp(c, priv.D, priv.N)
} else {
// We have the precalculated values needed for the CRT.
m = new(big.Int).Exp(c, priv.dP, priv.P)
m2 := new(big.Int).Exp(c, priv.dQ, priv.Q)
m.Sub(m, m2)
if m.Sign() < 0 {
m.Add(m, priv.P)
}
m.Mul(m, priv.qInv)
m.Mod(m, priv.P)
m.Mul(m, priv.Q)
m.Add(m, m2)
if priv.dR != nil {
// 3-prime CRT.
m2.Exp(c, priv.dR, priv.R)
m2.Sub(m2, m)
m2.Mul(m2, priv.tr)
m2.Mod(m2, priv.R)
if m2.Sign() < 0 {
m2.Add(m2, priv.R)
}
m2.Mul(m2, priv.pq)
m.Add(m, m2)
}
}
priv.rwMutex.RUnlock()
if ir != nil { if ir != nil {
// Unblind. // Unblind.
......
...@@ -13,28 +13,48 @@ import ( ...@@ -13,28 +13,48 @@ import (
) )
func TestKeyGeneration(t *testing.T) { func TestKeyGeneration(t *testing.T) {
random := rand.Reader
size := 1024 size := 1024
if testing.Short() { if testing.Short() {
size = 128 size = 128
} }
priv, err := GenerateKey(random, size) priv, err := GenerateKey(rand.Reader, size)
if err != nil {
t.Errorf("failed to generate key")
}
testKeyBasics(t, priv)
}
func Test3PrimeKeyGeneration(t *testing.T) {
if testing.Short() {
return
}
size := 768
priv, err := Generate3PrimeKey(rand.Reader, size)
if err != nil { if err != nil {
t.Errorf("failed to generate key") t.Errorf("failed to generate key")
} }
testKeyBasics(t, priv)
}
func testKeyBasics(t *testing.T, priv *PrivateKey) {
if err := priv.Validate(); err != nil {
t.Errorf("Validate() failed: %s", err)
}
pub := &priv.PublicKey pub := &priv.PublicKey
m := big.NewInt(42) m := big.NewInt(42)
c := encrypt(new(big.Int), pub, m) c := encrypt(new(big.Int), pub, m)
m2, err := decrypt(nil, priv, c) m2, err := decrypt(nil, priv, c)
if err != nil { if err != nil {
t.Errorf("error while decrypting: %s", err) t.Errorf("error while decrypting: %s", err)
return
} }
if m.Cmp(m2) != 0 { if m.Cmp(m2) != 0 {
t.Errorf("got:%v, want:%v (%s)", m2, m, priv) t.Errorf("got:%v, want:%v (%+v)", m2, m, priv)
} }
m3, err := decrypt(random, priv, c) m3, err := decrypt(rand.Reader, priv, c)
if err != nil { if err != nil {
t.Errorf("error while decrypting (blind): %s", err) t.Errorf("error while decrypting (blind): %s", err)
} }
...@@ -43,6 +63,57 @@ func TestKeyGeneration(t *testing.T) { ...@@ -43,6 +63,57 @@ func TestKeyGeneration(t *testing.T) {
} }
} }
func fromBase10(base10 string) *big.Int {
i := new(big.Int)
i.SetString(base10, 10)
return i
}
func BenchmarkRSA2048Decrypt(b *testing.B) {
b.StopTimer()
priv := &PrivateKey{
PublicKey: PublicKey{
N: fromBase10("14314132931241006650998084889274020608918049032671858325988396851334124245188214251956198731333464217832226406088020736932173064754214329009979944037640912127943488972644697423190955557435910767690712778463524983667852819010259499695177313115447116110358524558307947613422897787329221478860907963827160223559690523660574329011927531289655711860504630573766609239332569210831325633840174683944553667352219670930408593321661375473885147973879086994006440025257225431977751512374815915392249179976902953721486040787792801849818254465486633791826766873076617116727073077821584676715609985777563958286637185868165868520557"),
E: 3,
},
D: fromBase10("9542755287494004433998723259516013739278699355114572217325597900889416163458809501304132487555642811888150937392013824621448709836142886006653296025093941418628992648429798282127303704957273845127141852309016655778568546006839666463451542076964744073572349705538631742281931858219480985907271975884773482372966847639853897890615456605598071088189838676728836833012254065983259638538107719766738032720239892094196108713378822882383694456030043492571063441943847195939549773271694647657549658603365629458610273821292232646334717612674519997533901052790334279661754176490593041941863932308687197618671528035670452762731"),
P: fromBase10("130903255182996722426771613606077755295583329135067340152947172868415809027537376306193179624298874215608270802054347609836776473930072411958753044562214537013874103802006369634761074377213995983876788718033850153719421695468704276694983032644416930879093914927146648402139231293035971427838068945045019075433"),
Q: fromBase10("109348945610485453577574767652527472924289229538286649661240938988020367005475727988253438647560958573506159449538793540472829815903949343191091817779240101054552748665267574271163617694640513549693841337820602726596756351006149518830932261246698766355347898158548465400674856021497190430791824869615170301029"),
}
priv.precompute()
c := fromBase10("1000")
b.StartTimer()
for i := 0; i < b.N; i++ {
decrypt(nil, priv, c)
}
}
func Benchmark3PrimeRSA2048Decrypt(b *testing.B) {
b.StopTimer()
priv := &PrivateKey{
PublicKey: PublicKey{
N: fromBase10("16346378922382193400538269749936049106320265317511766357599732575277382844051791096569333808598921852351577762718529818072849191122419410612033592401403764925096136759934497687765453905884149505175426053037420486697072448609022753683683718057795566811401938833367954642951433473337066311978821180526439641496973296037000052546108507805269279414789035461158073156772151892452251106173507240488993608650881929629163465099476849643165682709047462010581308719577053905787496296934240246311806555924593059995202856826239801816771116902778517096212527979497399966526283516447337775509777558018145573127308919204297111496233"),
E: 3,
},
D: fromBase10("10897585948254795600358846499957366070880176878341177571733155050184921896034527397712889205732614568234385175145686545381899460748279607074689061600935843283397424506622998458510302603922766336783617368686090042765718290914099334449154829375179958369993407724946186243249568928237086215759259909861748642124071874879861299389874230489928271621259294894142840428407196932444474088857746123104978617098858619445675532587787023228852383149557470077802718705420275739737958953794088728369933811184572620857678792001136676902250566845618813972833750098806496641114644760255910789397593428910198080271317419213080834885003"),
P: fromBase10("1025363189502892836833747188838978207017355117492483312747347695538428729137306368764177201532277413433182799108299960196606011786562992097313508180436744488171474690412562218914213688661311117337381958560443"),
Q: fromBase10("3467903426626310123395340254094941045497208049900750380025518552334536945536837294961497712862519984786362199788654739924501424784631315081391467293694361474867825728031147665777546570788493758372218019373"),
R: fromBase10("4597024781409332673052708605078359346966325141767460991205742124888960305710298765592730135879076084498363772408626791576005136245060321874472727132746643162385746062759369754202494417496879741537284589047"),
}
priv.precompute()
c := fromBase10("1000")
b.StartTimer()
for i := 0; i < b.N; i++ {
decrypt(nil, priv, c)
}
}
type testEncryptOAEPMessage struct { type testEncryptOAEPMessage struct {
in []byte in []byte
seed []byte seed []byte
...@@ -85,10 +156,12 @@ func TestDecryptOAEP(t *testing.T) { ...@@ -85,10 +156,12 @@ func TestDecryptOAEP(t *testing.T) {
for i, test := range testEncryptOAEPData { for i, test := range testEncryptOAEPData {
n.SetString(test.modulus, 16) n.SetString(test.modulus, 16)
d.SetString(test.d, 16) d.SetString(test.d, 16)
private := PrivateKey{PublicKey{n, test.e}, d, nil, nil} private := new(PrivateKey)
private.PublicKey = PublicKey{n, test.e}
private.D = d
for j, message := range test.msgs { for j, message := range test.msgs {
out, err := DecryptOAEP(sha1, nil, &private, message.out, nil) out, err := DecryptOAEP(sha1, nil, private, message.out, nil)
if err != nil { if err != nil {
t.Errorf("#%d,%d error: %s", i, j, err) t.Errorf("#%d,%d error: %s", i, j, err)
} else if bytes.Compare(out, message.in) != 0 { } else if bytes.Compare(out, message.in) != 0 {
...@@ -96,7 +169,7 @@ func TestDecryptOAEP(t *testing.T) { ...@@ -96,7 +169,7 @@ func TestDecryptOAEP(t *testing.T) {
} }
// Decrypt with blinding. // Decrypt with blinding.
out, err = DecryptOAEP(sha1, random, &private, message.out, nil) out, err = DecryptOAEP(sha1, random, private, message.out, nil)
if err != nil { if err != nil {
t.Errorf("#%d,%d (blind) error: %s", i, j, err) t.Errorf("#%d,%d (blind) error: %s", i, j, err)
} else if bytes.Compare(out, message.in) != 0 { } else if bytes.Compare(out, message.in) != 0 {
......
...@@ -50,7 +50,7 @@ func main() { ...@@ -50,7 +50,7 @@ func main() {
return return
} }
certOut, err := os.Open("cert.pem", os.O_WRONLY|os.O_CREAT, 0644) certOut, err := os.Create("cert.pem")
if err != nil { if err != nil {
log.Fatalf("failed to open cert.pem for writing: %s", err) log.Fatalf("failed to open cert.pem for writing: %s", err)
return return
...@@ -59,7 +59,7 @@ func main() { ...@@ -59,7 +59,7 @@ func main() {
certOut.Close() certOut.Close()
log.Print("written cert.pem\n") log.Print("written cert.pem\n")
keyOut, err := os.Open("key.pem", os.O_WRONLY|os.O_CREAT, 0600) keyOut, err := os.OpenFile("key.pem", os.O_WRONLY|os.O_CREAT|os.O_TRUNC, 0600)
if err != nil { if err != nil {
log.Print("failed to open key.pem for writing:", err) log.Print("failed to open key.pem for writing:", err)
return return
......
...@@ -124,7 +124,16 @@ func LoadX509KeyPair(certFile string, keyFile string) (cert Certificate, err os. ...@@ -124,7 +124,16 @@ func LoadX509KeyPair(certFile string, keyFile string) (cert Certificate, err os.
if err != nil { if err != nil {
return return
} }
keyPEMBlock, err := ioutil.ReadFile(keyFile)
if err != nil {
return
}
return X509KeyPair(certPEMBlock, keyPEMBlock)
}
// X509KeyPair parses a public/private key pair from a pair of
// PEM encoded data.
func X509KeyPair(certPEMBlock, keyPEMBlock []byte) (cert Certificate, err os.Error) {
var certDERBlock *pem.Block var certDERBlock *pem.Block
for { for {
certDERBlock, certPEMBlock = pem.Decode(certPEMBlock) certDERBlock, certPEMBlock = pem.Decode(certPEMBlock)
...@@ -141,11 +150,6 @@ func LoadX509KeyPair(certFile string, keyFile string) (cert Certificate, err os. ...@@ -141,11 +150,6 @@ func LoadX509KeyPair(certFile string, keyFile string) (cert Certificate, err os.
return return
} }
keyPEMBlock, err := ioutil.ReadFile(keyFile)
if err != nil {
return
}
keyDERBlock, _ := pem.Decode(keyPEMBlock) keyDERBlock, _ := pem.Decode(keyPEMBlock)
if keyDERBlock == nil { if keyDERBlock == nil {
err = os.ErrorString("crypto/tls: failed to parse key PEM data") err = os.ErrorString("crypto/tls: failed to parse key PEM data")
......
...@@ -54,20 +54,21 @@ func ParsePKCS1PrivateKey(der []byte) (key *rsa.PrivateKey, err os.Error) { ...@@ -54,20 +54,21 @@ func ParsePKCS1PrivateKey(der []byte) (key *rsa.PrivateKey, err os.Error) {
return return
} }
key = &rsa.PrivateKey{ key = new(rsa.PrivateKey)
PublicKey: rsa.PublicKey{ key.PublicKey = rsa.PublicKey{
E: priv.E, E: priv.E,
N: new(big.Int).SetBytes(priv.N.Bytes), N: new(big.Int).SetBytes(priv.N.Bytes),
},
D: new(big.Int).SetBytes(priv.D.Bytes),
P: new(big.Int).SetBytes(priv.P.Bytes),
Q: new(big.Int).SetBytes(priv.Q.Bytes),
} }
key.D = new(big.Int).SetBytes(priv.D.Bytes)
key.P = new(big.Int).SetBytes(priv.P.Bytes)
key.Q = new(big.Int).SetBytes(priv.Q.Bytes)
err = key.Validate() err = key.Validate()
if err != nil { if err != nil {
return nil, err return nil, err
} }
return return
} }
......
...@@ -11,7 +11,6 @@ import ( ...@@ -11,7 +11,6 @@ import (
"crypto/rsa" "crypto/rsa"
"encoding/hex" "encoding/hex"
"encoding/pem" "encoding/pem"
"reflect"
"testing" "testing"
"time" "time"
) )
...@@ -22,7 +21,11 @@ func TestParsePKCS1PrivateKey(t *testing.T) { ...@@ -22,7 +21,11 @@ func TestParsePKCS1PrivateKey(t *testing.T) {
if err != nil { if err != nil {
t.Errorf("Failed to parse private key: %s", err) t.Errorf("Failed to parse private key: %s", err)
} }
if !reflect.DeepEqual(priv, rsaPrivateKey) { if priv.PublicKey.N.Cmp(rsaPrivateKey.PublicKey.N) != 0 ||
priv.PublicKey.E != rsaPrivateKey.PublicKey.E ||
priv.D.Cmp(rsaPrivateKey.D) != 0 ||
priv.P.Cmp(rsaPrivateKey.P) != 0 ||
priv.Q.Cmp(rsaPrivateKey.Q) != 0 {
t.Errorf("got:%+v want:%+v", priv, rsaPrivateKey) t.Errorf("got:%+v want:%+v", priv, rsaPrivateKey)
} }
} }
......
...@@ -144,7 +144,7 @@ func (e *FormatError) String() string { ...@@ -144,7 +144,7 @@ func (e *FormatError) String() string {
// Open opens the named file using os.Open and prepares it for use as an ELF binary. // Open opens the named file using os.Open and prepares it for use as an ELF binary.
func Open(name string) (*File, os.Error) { func Open(name string) (*File, os.Error) {
f, err := os.Open(name, os.O_RDONLY, 0) f, err := os.Open(name)
if err != nil { if err != nil {
return nil, err return nil, err
} }
...@@ -228,7 +228,7 @@ func NewFile(r io.ReaderAt) (*File, os.Error) { ...@@ -228,7 +228,7 @@ func NewFile(r io.ReaderAt) (*File, os.Error) {
switch f.Class { switch f.Class {
case ELFCLASS32: case ELFCLASS32:
hdr := new(Header32) hdr := new(Header32)
sr.Seek(0, 0) sr.Seek(0, os.SEEK_SET)
if err := binary.Read(sr, f.ByteOrder, hdr); err != nil { if err := binary.Read(sr, f.ByteOrder, hdr); err != nil {
return nil, err return nil, err
} }
...@@ -243,7 +243,7 @@ func NewFile(r io.ReaderAt) (*File, os.Error) { ...@@ -243,7 +243,7 @@ func NewFile(r io.ReaderAt) (*File, os.Error) {
shstrndx = int(hdr.Shstrndx) shstrndx = int(hdr.Shstrndx)
case ELFCLASS64: case ELFCLASS64:
hdr := new(Header64) hdr := new(Header64)
sr.Seek(0, 0) sr.Seek(0, os.SEEK_SET)
if err := binary.Read(sr, f.ByteOrder, hdr); err != nil { if err := binary.Read(sr, f.ByteOrder, hdr); err != nil {
return nil, err return nil, err
} }
...@@ -269,7 +269,7 @@ func NewFile(r io.ReaderAt) (*File, os.Error) { ...@@ -269,7 +269,7 @@ func NewFile(r io.ReaderAt) (*File, os.Error) {
names := make([]uint32, shnum) names := make([]uint32, shnum)
for i := 0; i < shnum; i++ { for i := 0; i < shnum; i++ {
off := shoff + int64(i)*int64(shentsize) off := shoff + int64(i)*int64(shentsize)
sr.Seek(off, 0) sr.Seek(off, os.SEEK_SET)
s := new(Section) s := new(Section)
switch f.Class { switch f.Class {
case ELFCLASS32: case ELFCLASS32:
......
...@@ -159,7 +159,7 @@ func (e *FormatError) String() string { ...@@ -159,7 +159,7 @@ func (e *FormatError) String() string {
// Open opens the named file using os.Open and prepares it for use as a Mach-O binary. // Open opens the named file using os.Open and prepares it for use as a Mach-O binary.
func Open(name string) (*File, os.Error) { func Open(name string) (*File, os.Error) {
f, err := os.Open(name, os.O_RDONLY, 0) f, err := os.Open(name)
if err != nil { if err != nil {
return nil, err return nil, err
} }
......
...@@ -87,7 +87,7 @@ func (e *FormatError) String() string { ...@@ -87,7 +87,7 @@ func (e *FormatError) String() string {
// Open opens the named file using os.Open and prepares it for use as a PE binary. // Open opens the named file using os.Open and prepares it for use as a PE binary.
func Open(name string) (*File, os.Error) { func Open(name string) (*File, os.Error) {
f, err := os.Open(name, os.O_RDONLY, 0) f, err := os.Open(name)
if err != nil { if err != nil {
return nil, err return nil, err
} }
...@@ -132,7 +132,7 @@ func NewFile(r io.ReaderAt) (*File, os.Error) { ...@@ -132,7 +132,7 @@ func NewFile(r io.ReaderAt) (*File, os.Error) {
} else { } else {
base = int64(0) base = int64(0)
} }
sr.Seek(base, 0) sr.Seek(base, os.SEEK_SET)
if err := binary.Read(sr, binary.LittleEndian, &f.FileHeader); err != nil { if err := binary.Read(sr, binary.LittleEndian, &f.FileHeader); err != nil {
return nil, err return nil, err
} }
...@@ -140,7 +140,7 @@ func NewFile(r io.ReaderAt) (*File, os.Error) { ...@@ -140,7 +140,7 @@ func NewFile(r io.ReaderAt) (*File, os.Error) {
return nil, os.NewError("Invalid PE File Format.") return nil, os.NewError("Invalid PE File Format.")
} }
// get symbol string table // get symbol string table
sr.Seek(int64(f.FileHeader.PointerToSymbolTable+18*f.FileHeader.NumberOfSymbols), 0) sr.Seek(int64(f.FileHeader.PointerToSymbolTable+18*f.FileHeader.NumberOfSymbols), os.SEEK_SET)
var l uint32 var l uint32
if err := binary.Read(sr, binary.LittleEndian, &l); err != nil { if err := binary.Read(sr, binary.LittleEndian, &l); err != nil {
return nil, err return nil, err
...@@ -149,9 +149,9 @@ func NewFile(r io.ReaderAt) (*File, os.Error) { ...@@ -149,9 +149,9 @@ func NewFile(r io.ReaderAt) (*File, os.Error) {
if _, err := r.ReadAt(ss, int64(f.FileHeader.PointerToSymbolTable+18*f.FileHeader.NumberOfSymbols)); err != nil { if _, err := r.ReadAt(ss, int64(f.FileHeader.PointerToSymbolTable+18*f.FileHeader.NumberOfSymbols)); err != nil {
return nil, err return nil, err
} }
sr.Seek(base, 0) sr.Seek(base, os.SEEK_SET)
binary.Read(sr, binary.LittleEndian, &f.FileHeader) binary.Read(sr, binary.LittleEndian, &f.FileHeader)
sr.Seek(int64(f.FileHeader.SizeOfOptionalHeader), 1) //Skip OptionalHeader sr.Seek(int64(f.FileHeader.SizeOfOptionalHeader), os.SEEK_CUR) //Skip OptionalHeader
f.Sections = make([]*Section, f.FileHeader.NumberOfSections) f.Sections = make([]*Section, f.FileHeader.NumberOfSections)
for i := 0; i < int(f.FileHeader.NumberOfSections); i++ { for i := 0; i < int(f.FileHeader.NumberOfSections); i++ {
sh := new(SectionHeader32) sh := new(SectionHeader32)
......
...@@ -1184,7 +1184,7 @@ func (p *process) attachThread(tid int) (*thread, os.Error) { ...@@ -1184,7 +1184,7 @@ func (p *process) attachThread(tid int) (*thread, os.Error) {
// attachAllThreads attaches to all threads in a process. // attachAllThreads attaches to all threads in a process.
func (p *process) attachAllThreads() os.Error { func (p *process) attachAllThreads() os.Error {
taskPath := "/proc/" + strconv.Itoa(p.pid) + "/task" taskPath := "/proc/" + strconv.Itoa(p.pid) + "/task"
taskDir, err := os.Open(taskPath, os.O_RDONLY, 0) taskDir, err := os.Open(taskPath)
if err != nil { if err != nil {
return err return err
} }
......
...@@ -2,9 +2,13 @@ ...@@ -2,9 +2,13 @@
// Use of this source code is governed by a BSD-style // Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.
// The exec package runs external commands. // The exec package runs external commands. It wraps os.StartProcess
// to make it easier to remap stdin and stdout, connect I/O with pipes,
// and do other adjustments.
package exec package exec
// BUG(r): This package should be made even easier to use or merged into os.
import ( import (
"os" "os"
"strconv" "strconv"
...@@ -49,7 +53,7 @@ func modeToFiles(mode, fd int) (*os.File, *os.File, os.Error) { ...@@ -49,7 +53,7 @@ func modeToFiles(mode, fd int) (*os.File, *os.File, os.Error) {
if fd == 0 { if fd == 0 {
rw = os.O_RDONLY rw = os.O_RDONLY
} }
f, err := os.Open(os.DevNull, rw, 0) f, err := os.OpenFile(os.DevNull, rw, 0)
return f, nil, err return f, nil, err
case PassThrough: case PassThrough:
switch fd { switch fd {
......
...@@ -53,7 +53,7 @@ func readAuth(displayStr string) (name, data string, err os.Error) { ...@@ -53,7 +53,7 @@ func readAuth(displayStr string) (name, data string, err os.Error) {
} }
fn = home + "/.Xauthority" fn = home + "/.Xauthority"
} }
r, err := os.Open(fn, os.O_RDONLY, 0444) r, err := os.Open(fn)
if err != nil { if err != nil {
return return
} }
......
...@@ -170,7 +170,7 @@ func cmdLoad(args []byte) os.Error { ...@@ -170,7 +170,7 @@ func cmdLoad(args []byte) os.Error {
} }
// Get symbols // Get symbols
f, err := os.Open(fname, os.O_RDONLY, 0) f, err := os.Open(fname)
if err != nil { if err != nil {
tproc.Detach() tproc.Detach()
return err return err
......
...@@ -139,7 +139,17 @@ var fmttests = []struct { ...@@ -139,7 +139,17 @@ var fmttests = []struct {
{"%5s", "abc", " abc"}, {"%5s", "abc", " abc"},
{"%2s", "\u263a", " \u263a"}, {"%2s", "\u263a", " \u263a"},
{"%-5s", "abc", "abc "}, {"%-5s", "abc", "abc "},
{"%-8q", "abc", `"abc" `},
{"%05s", "abc", "00abc"}, {"%05s", "abc", "00abc"},
{"%08q", "abc", `000"abc"`},
{"%5s", "abcdefghijklmnopqrstuvwxyz", "abcdefghijklmnopqrstuvwxyz"},
{"%.5s", "abcdefghijklmnopqrstuvwxyz", "abcde"},
{"%.5s", "日本語日本語", "日本語日本"},
{"%.5s", []byte("日本語日本語"), "日本語日本"},
{"%.5q", "abcdefghijklmnopqrstuvwxyz", `"abcde"`},
{"%.3q", "日本語日本語", `"\u65e5\u672c\u8a9e"`},
{"%.3q", []byte("日本語日本語"), `"\u65e5\u672c\u8a9e"`},
{"%10.1q", "日本語日本語", ` "\u65e5"`},
// integers // integers
{"%d", 12345, "12345"}, {"%d", 12345, "12345"},
......
...@@ -235,13 +235,24 @@ func (f *fmt) integer(a int64, base uint64, signedness bool, digits string) { ...@@ -235,13 +235,24 @@ func (f *fmt) integer(a int64, base uint64, signedness bool, digits string) {
f.pad(buf[i:]) f.pad(buf[i:])
} }
// fmt_s formats a string. // truncate truncates the string to the specified precision, if present.
func (f *fmt) fmt_s(s string) { func (f *fmt) truncate(s string) string {
if f.precPresent { if f.precPresent && f.prec < utf8.RuneCountInString(s) {
if f.prec < len(s) { n := f.prec
s = s[0:f.prec] for i := range s {
if n == 0 {
s = s[:i]
break
}
n--
} }
} }
return s
}
// fmt_s formats a string.
func (f *fmt) fmt_s(s string) {
s = f.truncate(s)
f.padString(s) f.padString(s)
} }
...@@ -275,6 +286,7 @@ func (f *fmt) fmt_sX(s string) { ...@@ -275,6 +286,7 @@ func (f *fmt) fmt_sX(s string) {
// fmt_q formats a string as a double-quoted, escaped Go string constant. // fmt_q formats a string as a double-quoted, escaped Go string constant.
func (f *fmt) fmt_q(s string) { func (f *fmt) fmt_q(s string) {
s = f.truncate(s)
var quoted string var quoted string
if f.sharp && strconv.CanBackquote(s) { if f.sharp && strconv.CanBackquote(s) {
quoted = "`" + s + "`" quoted = "`" + s + "`"
......
...@@ -520,12 +520,14 @@ func (p *pp) fmtBytes(v []byte, verb int, goSyntax bool, depth int, value interf ...@@ -520,12 +520,14 @@ func (p *pp) fmtBytes(v []byte, verb int, goSyntax bool, depth int, value interf
} }
func (p *pp) fmtPointer(field interface{}, value reflect.Value, verb int, goSyntax bool) { func (p *pp) fmtPointer(field interface{}, value reflect.Value, verb int, goSyntax bool) {
v, ok := value.(uintptrGetter) var u uintptr
if !ok { // reflect.PtrValue is a uintptrGetter, so failure means it's not a pointer at all. switch value.(type) {
case *reflect.ChanValue, *reflect.FuncValue, *reflect.MapValue, *reflect.PtrValue, *reflect.SliceValue, *reflect.UnsafePointerValue:
u = value.(uintptrGetter).Get()
default:
p.badVerb(verb, field) p.badVerb(verb, field)
return return
} }
u := v.Get()
if goSyntax { if goSyntax {
p.add('(') p.add('(')
p.buf.WriteString(reflect.Typeof(field).String()) p.buf.WriteString(reflect.Typeof(field).String())
...@@ -534,7 +536,7 @@ func (p *pp) fmtPointer(field interface{}, value reflect.Value, verb int, goSynt ...@@ -534,7 +536,7 @@ func (p *pp) fmtPointer(field interface{}, value reflect.Value, verb int, goSynt
if u == 0 { if u == 0 {
p.buf.Write(nilBytes) p.buf.Write(nilBytes)
} else { } else {
p.fmt0x64(uint64(v.Get()), true) p.fmt0x64(uint64(u), true)
} }
p.add(')') p.add(')')
} else { } else {
...@@ -811,7 +813,7 @@ BigSwitch: ...@@ -811,7 +813,7 @@ BigSwitch:
break break
} }
p.fmt0x64(uint64(v), true) p.fmt0x64(uint64(v), true)
case uintptrGetter: case *reflect.ChanValue, *reflect.FuncValue, *reflect.UnsafePointerValue:
p.fmtPointer(field, value, verb, goSyntax) p.fmtPointer(field, value, verb, goSyntax)
default: default:
p.unknownType(f) p.unknownType(f)
......
...@@ -183,7 +183,7 @@ func ParseFiles(fset *token.FileSet, filenames []string, mode uint) (pkgs map[st ...@@ -183,7 +183,7 @@ func ParseFiles(fset *token.FileSet, filenames []string, mode uint) (pkgs map[st
// error are returned. // error are returned.
// //
func ParseDir(fset *token.FileSet, path string, filter func(*os.FileInfo) bool, mode uint) (map[string]*ast.Package, os.Error) { func ParseDir(fset *token.FileSet, path string, filter func(*os.FileInfo) bool, mode uint) (map[string]*ast.Package, os.Error) {
fd, err := os.Open(path, os.O_RDONLY, 0) fd, err := os.Open(path)
if err != nil { if err != nil {
return nil, err return nil, err
} }
......
...@@ -332,7 +332,7 @@ func (p *parser) next() { ...@@ -332,7 +332,7 @@ func (p *parser) next() {
var endline int var endline int
if p.file.Line(p.pos) == line { if p.file.Line(p.pos) == line {
// The comment is on same line as previous token; it // The comment is on same line as the previous token; it
// cannot be a lead comment but may be a line comment. // cannot be a lead comment but may be a line comment.
comment, endline = p.consumeCommentGroup() comment, endline = p.consumeCommentGroup()
if p.file.Line(p.pos) != endline { if p.file.Line(p.pos) != endline {
...@@ -2016,16 +2016,18 @@ func parseTypeSpec(p *parser, doc *ast.CommentGroup, _ int) ast.Spec { ...@@ -2016,16 +2016,18 @@ func parseTypeSpec(p *parser, doc *ast.CommentGroup, _ int) ast.Spec {
} }
ident := p.parseIdent() ident := p.parseIdent()
typ := p.parseType()
p.expectSemi() // call before accessing p.linecomment
// Go spec: The scope of a type identifier declared inside a function begins // Go spec: The scope of a type identifier declared inside a function begins
// at the identifier in the TypeSpec and ends at the end of the innermost // at the identifier in the TypeSpec and ends at the end of the innermost
// containing block. // containing block.
// (Global identifiers are resolved in a separate phase after parsing.) // (Global identifiers are resolved in a separate phase after parsing.)
spec := &ast.TypeSpec{doc, ident, typ, p.lineComment} spec := &ast.TypeSpec{doc, ident, nil, nil}
p.declare(spec, p.topScope, ast.Typ, ident) p.declare(spec, p.topScope, ast.Typ, ident)
spec.Type = p.parseType()
p.expectSemi() // call before accessing p.linecomment
spec.Comment = p.lineComment
return spec return spec
} }
...@@ -2207,6 +2209,9 @@ func (p *parser) parseFile() *ast.File { ...@@ -2207,6 +2209,9 @@ func (p *parser) parseFile() *ast.File {
// Go spec: The package clause is not a declaration; // Go spec: The package clause is not a declaration;
// the package name does not appear in any scope. // the package name does not appear in any scope.
ident := p.parseIdent() ident := p.parseIdent()
if ident.Name == "_" {
p.error(p.pos, "invalid package name _")
}
p.expectSemi() p.expectSemi()
var decls []ast.Decl var decls []ast.Decl
......
...@@ -28,7 +28,7 @@ func pipeErr(err os.Error) io.Reader { ...@@ -28,7 +28,7 @@ func pipeErr(err os.Error) io.Reader {
} }
func readDat(filename string, c chan io.Reader) { func readDat(filename string, c chan io.Reader) {
f, err := os.Open("testdata/webkit/"+filename, os.O_RDONLY, 0600) f, err := os.Open("testdata/webkit/" + filename)
if err != nil { if err != nil {
c <- pipeErr(err) c <- pipeErr(err)
return return
......
...@@ -72,7 +72,7 @@ func serveFile(w ResponseWriter, r *Request, name string, redirect bool) { ...@@ -72,7 +72,7 @@ func serveFile(w ResponseWriter, r *Request, name string, redirect bool) {
return return
} }
f, err := os.Open(name, os.O_RDONLY, 0) f, err := os.Open(name)
if err != nil { if err != nil {
// TODO expose actual error? // TODO expose actual error?
NotFound(w, r) NotFound(w, r)
...@@ -113,7 +113,7 @@ func serveFile(w ResponseWriter, r *Request, name string, redirect bool) { ...@@ -113,7 +113,7 @@ func serveFile(w ResponseWriter, r *Request, name string, redirect bool) {
// use contents of index.html for directory, if present // use contents of index.html for directory, if present
if d.IsDirectory() { if d.IsDirectory() {
index := name + filepath.FromSlash(indexPage) index := name + filepath.FromSlash(indexPage)
ff, err := os.Open(index, os.O_RDONLY, 0) ff, err := os.Open(index)
if err == nil { if err == nil {
defer ff.Close() defer ff.Close()
dd, err := ff.Stat() dd, err := ff.Stat()
...@@ -134,21 +134,23 @@ func serveFile(w ResponseWriter, r *Request, name string, redirect bool) { ...@@ -134,21 +134,23 @@ func serveFile(w ResponseWriter, r *Request, name string, redirect bool) {
size := d.Size size := d.Size
code := StatusOK code := StatusOK
// use extension to find content type. // If Content-Type isn't set, use the file's extension to find it.
ext := filepath.Ext(name) if w.Header().Get("Content-Type") == "" {
if ctype := mime.TypeByExtension(ext); ctype != "" { ctype := mime.TypeByExtension(filepath.Ext(name))
w.Header().Set("Content-Type", ctype) if ctype == "" {
} else { // read a chunk to decide between utf-8 text and binary
// read first chunk to decide between utf-8 text and binary
var buf [1024]byte var buf [1024]byte
n, _ := io.ReadFull(f, buf[:]) n, _ := io.ReadFull(f, buf[:])
b := buf[:n] b := buf[:n]
if isText(b) { if isText(b) {
w.Header().Set("Content-Type", "text-plain; charset=utf-8") ctype = "text-plain; charset=utf-8"
} else { } else {
w.Header().Set("Content-Type", "application/octet-stream") // generic binary // generic binary
ctype = "application/octet-stream"
} }
f.Seek(0, 0) // rewind to output whole file f.Seek(0, os.SEEK_SET) // rewind to output whole file
}
w.Header().Set("Content-Type", ctype)
} }
// handle Content-Range header. // handle Content-Range header.
...@@ -163,7 +165,7 @@ func serveFile(w ResponseWriter, r *Request, name string, redirect bool) { ...@@ -163,7 +165,7 @@ func serveFile(w ResponseWriter, r *Request, name string, redirect bool) {
} }
if len(ranges) == 1 { if len(ranges) == 1 {
ra := ranges[0] ra := ranges[0]
if _, err := f.Seek(ra.start, 0); err != nil { if _, err := f.Seek(ra.start, os.SEEK_SET); err != nil {
Error(w, err.String(), StatusRequestedRangeNotSatisfiable) Error(w, err.String(), StatusRequestedRangeNotSatisfiable)
return return
} }
......
...@@ -85,6 +85,30 @@ func TestServeFile(t *testing.T) { ...@@ -85,6 +85,30 @@ func TestServeFile(t *testing.T) {
} }
} }
func TestServeFileContentType(t *testing.T) {
const ctype = "icecream/chocolate"
override := false
ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) {
if override {
w.Header().Set("Content-Type", ctype)
}
ServeFile(w, r, "testdata/file")
}))
defer ts.Close()
get := func(want string) {
resp, _, err := Get(ts.URL)
if err != nil {
t.Fatal(err)
}
if h := resp.Header.Get("Content-Type"); h != want {
t.Errorf("Content-Type mismatch: got %q, want %q", h, want)
}
}
get("text-plain; charset=utf-8")
override = true
get(ctype)
}
func getBody(t *testing.T, req Request) (*Response, []byte) { func getBody(t *testing.T, req Request) (*Response, []byte) {
r, err := DefaultClient.Do(&req) r, err := DefaultClient.Do(&req)
if err != nil { if err != nil {
......
...@@ -7,10 +7,13 @@ ...@@ -7,10 +7,13 @@
package httptest package httptest
import ( import (
"crypto/rand"
"crypto/tls"
"fmt" "fmt"
"http" "http"
"os"
"net" "net"
"os"
"time"
) )
// A Server is an HTTP server listening on a system-chosen port on the // A Server is an HTTP server listening on a system-chosen port on the
...@@ -18,6 +21,7 @@ import ( ...@@ -18,6 +21,7 @@ import (
type Server struct { type Server struct {
URL string // base URL of form http://ipaddr:port with no trailing slash URL string // base URL of form http://ipaddr:port with no trailing slash
Listener net.Listener Listener net.Listener
TLS *tls.Config // nil if not using using TLS
} }
// historyListener keeps track of all connections that it's ever // historyListener keeps track of all connections that it's ever
...@@ -35,16 +39,21 @@ func (hs *historyListener) Accept() (c net.Conn, err os.Error) { ...@@ -35,16 +39,21 @@ func (hs *historyListener) Accept() (c net.Conn, err os.Error) {
return return
} }
// NewServer starts and returns a new Server. func newLocalListener() net.Listener {
// The caller should call Close when finished, to shut it down.
func NewServer(handler http.Handler) *Server {
ts := new(Server)
l, err := net.Listen("tcp", "127.0.0.1:0") l, err := net.Listen("tcp", "127.0.0.1:0")
if err != nil { if err != nil {
if l, err = net.Listen("tcp6", "[::1]:0"); err != nil { if l, err = net.Listen("tcp6", "[::1]:0"); err != nil {
panic(fmt.Sprintf("httptest: failed to listen on a port: %v", err)) panic(fmt.Sprintf("httptest: failed to listen on a port: %v", err))
} }
} }
return l
}
// NewServer starts and returns a new Server.
// The caller should call Close when finished, to shut it down.
func NewServer(handler http.Handler) *Server {
ts := new(Server)
l := newLocalListener()
ts.Listener = &historyListener{l, make([]net.Conn, 0)} ts.Listener = &historyListener{l, make([]net.Conn, 0)}
ts.URL = "http://" + l.Addr().String() ts.URL = "http://" + l.Addr().String()
server := &http.Server{Handler: handler} server := &http.Server{Handler: handler}
...@@ -52,6 +61,32 @@ func NewServer(handler http.Handler) *Server { ...@@ -52,6 +61,32 @@ func NewServer(handler http.Handler) *Server {
return ts return ts
} }
// NewTLSServer starts and returns a new Server using TLS.
// The caller should call Close when finished, to shut it down.
func NewTLSServer(handler http.Handler) *Server {
l := newLocalListener()
ts := new(Server)
cert, err := tls.X509KeyPair(localhostCert, localhostKey)
if err != nil {
panic(fmt.Sprintf("httptest: NewTLSServer: %v", err))
}
ts.TLS = &tls.Config{
Rand: rand.Reader,
Time: time.Seconds,
NextProtos: []string{"http/1.1"},
Certificates: []tls.Certificate{cert},
}
tlsListener := tls.NewListener(l, ts.TLS)
ts.Listener = &historyListener{tlsListener, make([]net.Conn, 0)}
ts.URL = "https://" + l.Addr().String()
server := &http.Server{Handler: handler}
go server.Serve(ts.Listener)
return ts
}
// Close shuts down the server. // Close shuts down the server.
func (s *Server) Close() { func (s *Server) Close() {
s.Listener.Close() s.Listener.Close()
...@@ -68,3 +103,34 @@ func (s *Server) CloseClientConnections() { ...@@ -68,3 +103,34 @@ func (s *Server) CloseClientConnections() {
conn.Close() conn.Close()
} }
} }
// localhostCert is a PEM-encoded TLS cert with SAN DNS names
// "127.0.0.1" and "[::1]", expiring at the last second of 2049 (the end
// of ASN.1 time).
var localhostCert = []byte(`-----BEGIN CERTIFICATE-----
MIIBwTCCASugAwIBAgIBADALBgkqhkiG9w0BAQUwADAeFw0xMTAzMzEyMDI1MDda
Fw00OTEyMzEyMzU5NTlaMAAwggCdMAsGCSqGSIb3DQEBAQOCAIwAMIIAhwKCAIB6
oy4iT42G6qk+GGn5VL5JlnJT6ZG5cqaMNFaNGlIxNb6CPUZLKq2sM3gRaimsktIw
nNAcNwQGHpe1tZo+J/Pl04JTt71Y/TTAxy7OX27aZf1Rpt0SjdZ7vTPnFDPNsHGe
KBKvPt55l2+YKjkZmV7eRevsVbpkNvNGB+T5d4Ge/wIBA6NPME0wDgYDVR0PAQH/
BAQDAgCgMA0GA1UdDgQGBAQBAgMEMA8GA1UdIwQIMAaABAECAwQwGwYDVR0RBBQw
EoIJMTI3LjAuMC4xggVbOjoxXTALBgkqhkiG9w0BAQUDggCBAHC3gbdvc44vs+wD
g2kONiENnx8WKc0UTGg/TOXS3gaRb+CUIQtHWja65l8rAfclEovjHgZ7gx8brO0W
JuC6p3MUAKsgOssIrrRIx2rpnfcmFVMzguCmrMNVmKUAalw18Yp0F72xYAIitVQl
kJrLdIhBajcJRYu/YGltHQRaXuVt
-----END CERTIFICATE-----
`)
// localhostKey is the private key for localhostCert.
var localhostKey = []byte(`-----BEGIN RSA PRIVATE KEY-----
MIIBkgIBAQKCAIB6oy4iT42G6qk+GGn5VL5JlnJT6ZG5cqaMNFaNGlIxNb6CPUZL
Kq2sM3gRaimsktIwnNAcNwQGHpe1tZo+J/Pl04JTt71Y/TTAxy7OX27aZf1Rpt0S
jdZ7vTPnFDPNsHGeKBKvPt55l2+YKjkZmV7eRevsVbpkNvNGB+T5d4Ge/wIBAwKC
AIBRwh7Bil5Z8cYpZZv7jdQxDvbim7Z7ocRdeDmzZuF2I9RW04QyHHPIIlALnBvI
YeF1veASz1gEFGUjzmbUGqKYSbCoTzXoev+F4bmbRxcX9sOmtslqvhMSHRSzA5NH
aDVI3Hn4wvBVD8gePu8ACWqvPGbCiql11OKCMfjlPn2uuwJAx/24/F5DjXZ6hQQ7
HxScOxKrpx5WnA9r1wZTltOTZkhRRzuLc21WJeE3M15QUdWi3zZxCKRFoth65HEs
jy9YHQJAnPueRI44tz79b5QqVbeaOMUr7ZCb1Kp0uo6G+ANPLdlfliAupwij2eIz
mHRJOWk0jBtXfRft1McH2H51CpXAyw==
-----END RSA PRIVATE KEY-----
`)
...@@ -164,6 +164,28 @@ var respTests = []respTest{ ...@@ -164,6 +164,28 @@ var respTests = []respTest{
"Body here\n", "Body here\n",
}, },
// Chunked response in response to a HEAD request (the "chunked" should
// be ignored, as HEAD responses never have bodies)
{
"HTTP/1.0 200 OK\r\n" +
"Transfer-Encoding: chunked\r\n" +
"\r\n",
Response{
Status: "200 OK",
StatusCode: 200,
Proto: "HTTP/1.0",
ProtoMajor: 1,
ProtoMinor: 0,
RequestMethod: "HEAD",
Header: Header{},
Close: true,
ContentLength: 0,
},
"",
},
// Status line without a Reason-Phrase, but trailing space. // Status line without a Reason-Phrase, but trailing space.
// (permitted by RFC 2616) // (permitted by RFC 2616)
{ {
......
...@@ -507,3 +507,30 @@ func TestHeadResponses(t *testing.T) { ...@@ -507,3 +507,30 @@ func TestHeadResponses(t *testing.T) {
t.Errorf("got unexpected body %q", string(body)) t.Errorf("got unexpected body %q", string(body))
} }
} }
func TestTLSServer(t *testing.T) {
ts := httptest.NewTLSServer(HandlerFunc(func(w ResponseWriter, r *Request) {
fmt.Fprintf(w, "tls=%v", r.TLS != nil)
}))
defer ts.Close()
if !strings.HasPrefix(ts.URL, "https://") {
t.Fatalf("expected test TLS server to start with https://, got %q", ts.URL)
}
res, _, err := Get(ts.URL)
if err != nil {
t.Error(err)
}
if res == nil {
t.Fatalf("got nil Response")
}
if res.Body == nil {
t.Fatalf("got nil Response.Body")
}
body, err := ioutil.ReadAll(res.Body)
if err != nil {
t.Error(err)
}
if e, g := "tls=true", string(body); e != g {
t.Errorf("expected body %q; got %q", e, g)
}
}
...@@ -215,7 +215,7 @@ func readTransfer(msg interface{}, r *bufio.Reader) (err os.Error) { ...@@ -215,7 +215,7 @@ func readTransfer(msg interface{}, r *bufio.Reader) (err os.Error) {
} }
// Transfer encoding, content length // Transfer encoding, content length
t.TransferEncoding, err = fixTransferEncoding(t.Header) t.TransferEncoding, err = fixTransferEncoding(t.RequestMethod, t.Header)
if err != nil { if err != nil {
return err return err
} }
...@@ -289,13 +289,20 @@ func readTransfer(msg interface{}, r *bufio.Reader) (err os.Error) { ...@@ -289,13 +289,20 @@ func readTransfer(msg interface{}, r *bufio.Reader) (err os.Error) {
func chunked(te []string) bool { return len(te) > 0 && te[0] == "chunked" } func chunked(te []string) bool { return len(te) > 0 && te[0] == "chunked" }
// Sanitize transfer encoding // Sanitize transfer encoding
func fixTransferEncoding(header Header) ([]string, os.Error) { func fixTransferEncoding(requestMethod string, header Header) ([]string, os.Error) {
raw, present := header["Transfer-Encoding"] raw, present := header["Transfer-Encoding"]
if !present { if !present {
return nil, nil return nil, nil
} }
header["Transfer-Encoding"] = nil, false header["Transfer-Encoding"] = nil, false
// Head responses have no bodies, so the transfer encoding
// should be ignored.
if requestMethod == "HEAD" {
return nil, nil
}
encodings := strings.Split(raw[0], ",", -1) encodings := strings.Split(raw[0], ",", -1)
te := make([]string, 0, len(encodings)) te := make([]string, 0, len(encodings))
// TODO: Even though we only support "identity" and "chunked" // TODO: Even though we only support "identity" and "chunked"
......
...@@ -24,6 +24,10 @@ import ( ...@@ -24,6 +24,10 @@ import (
// environment variables. // environment variables.
var DefaultTransport RoundTripper = &Transport{} var DefaultTransport RoundTripper = &Transport{}
// DefaultMaxIdleConnsPerHost is the default value of Transport's
// MaxIdleConnsPerHost.
const DefaultMaxIdleConnsPerHost = 2
// Transport is an implementation of RoundTripper that supports http, // Transport is an implementation of RoundTripper that supports http,
// https, and http proxies (for either http or https with CONNECT). // https, and http proxies (for either http or https with CONNECT).
// Transport can also cache connections for future re-use. // Transport can also cache connections for future re-use.
...@@ -31,11 +35,17 @@ type Transport struct { ...@@ -31,11 +35,17 @@ type Transport struct {
lk sync.Mutex lk sync.Mutex
idleConn map[string][]*persistConn idleConn map[string][]*persistConn
// TODO: tunables on max cached connections (total, per-server), duration // TODO: tunable on global max cached connections
// TODO: tunable on timeout on cached connections
// TODO: optional pipelining // TODO: optional pipelining
IgnoreEnvironment bool // don't look at environment variables for proxy configuration IgnoreEnvironment bool // don't look at environment variables for proxy configuration
DisableKeepAlives bool DisableKeepAlives bool
// MaxIdleConnsPerHost, if non-zero, controls the maximum idle
// (keep-alive) to keep to keep per-host. If zero,
// DefaultMaxIdleConnsPerHost is used.
MaxIdleConnsPerHost int
} }
// RoundTrip implements the RoundTripper interface. // RoundTrip implements the RoundTripper interface.
...@@ -147,7 +157,7 @@ func (cm *connectMethod) proxyAuth() string { ...@@ -147,7 +157,7 @@ func (cm *connectMethod) proxyAuth() string {
func (t *Transport) putIdleConn(pconn *persistConn) { func (t *Transport) putIdleConn(pconn *persistConn) {
t.lk.Lock() t.lk.Lock()
defer t.lk.Unlock() defer t.lk.Unlock()
if t.DisableKeepAlives { if t.DisableKeepAlives || t.MaxIdleConnsPerHost < 0 {
pconn.close() pconn.close()
return return
} }
...@@ -155,6 +165,14 @@ func (t *Transport) putIdleConn(pconn *persistConn) { ...@@ -155,6 +165,14 @@ func (t *Transport) putIdleConn(pconn *persistConn) {
return return
} }
key := pconn.cacheKey key := pconn.cacheKey
max := t.MaxIdleConnsPerHost
if max == 0 {
max = DefaultMaxIdleConnsPerHost
}
if len(t.idleConn[key]) >= max {
pconn.close()
return
}
t.idleConn[key] = append(t.idleConn[key], pconn) t.idleConn[key] = append(t.idleConn[key], pconn)
} }
...@@ -406,24 +424,37 @@ func (pc *persistConn) readLoop() { ...@@ -406,24 +424,37 @@ func (pc *persistConn) readLoop() {
rc := <-pc.reqch rc := <-pc.reqch
resp, err := pc.cc.Read(rc.req) resp, err := pc.cc.Read(rc.req)
if err == nil && !rc.req.Close {
pc.t.putIdleConn(pc)
}
if err == ErrPersistEOF { if err == ErrPersistEOF {
// Succeeded, but we can't send any more // Succeeded, but we can't send any more
// persistent connections on this again. We // persistent connections on this again. We
// hide this error to upstream callers. // hide this error to upstream callers.
alive = false alive = false
err = nil err = nil
} else if err != nil { } else if err != nil || rc.req.Close {
alive = false alive = false
} }
hasBody := resp != nil && resp.ContentLength != 0
var waitForBodyRead chan bool
if alive {
if hasBody {
waitForBodyRead = make(chan bool)
resp.Body.(*bodyEOFSignal).fn = func() {
pc.t.putIdleConn(pc)
waitForBodyRead <- true
}
} else {
pc.t.putIdleConn(pc)
}
}
rc.ch <- responseAndError{resp, err} rc.ch <- responseAndError{resp, err}
// Wait for the just-returned response body to be fully consumed // Wait for the just-returned response body to be fully consumed
// before we race and peek on the underlying bufio reader. // before we race and peek on the underlying bufio reader.
if alive { if waitForBodyRead != nil {
<-resp.Body.(*bodyEOFSignal).ch <-waitForBodyRead
} }
} }
} }
...@@ -494,34 +525,34 @@ func responseIsKeepAlive(res *Response) bool { ...@@ -494,34 +525,34 @@ func responseIsKeepAlive(res *Response) bool {
// the response body with a bodyEOFSignal-wrapped version. // the response body with a bodyEOFSignal-wrapped version.
func readResponseWithEOFSignal(r *bufio.Reader, requestMethod string) (resp *Response, err os.Error) { func readResponseWithEOFSignal(r *bufio.Reader, requestMethod string) (resp *Response, err os.Error) {
resp, err = ReadResponse(r, requestMethod) resp, err = ReadResponse(r, requestMethod)
if err == nil { if err == nil && resp.ContentLength != 0 {
resp.Body = &bodyEOFSignal{resp.Body, make(chan bool, 1), false} resp.Body = &bodyEOFSignal{resp.Body, nil}
} }
return return
} }
// bodyEOFSignal wraps a ReadCloser but sends on ch once once // bodyEOFSignal wraps a ReadCloser but runs fn (if non-nil) at most
// the wrapped ReadCloser is fully consumed (including on Close) // once, right before the final Read() or Close() call returns, but after
// EOF has been seen.
type bodyEOFSignal struct { type bodyEOFSignal struct {
body io.ReadCloser body io.ReadCloser
ch chan bool fn func()
done bool
} }
func (es *bodyEOFSignal) Read(p []byte) (n int, err os.Error) { func (es *bodyEOFSignal) Read(p []byte) (n int, err os.Error) {
n, err = es.body.Read(p) n, err = es.body.Read(p)
if err == os.EOF && !es.done { if err == os.EOF && es.fn != nil {
es.ch <- true es.fn()
es.done = true es.fn = nil
} }
return return
} }
func (es *bodyEOFSignal) Close() (err os.Error) { func (es *bodyEOFSignal) Close() (err os.Error) {
err = es.body.Close() err = es.body.Close()
if err == nil && !es.done { if err == nil && es.fn != nil {
es.ch <- true es.fn()
es.done = true es.fn = nil
} }
return return
} }
...@@ -85,6 +85,7 @@ func TestTransportConnectionCloseOnResponse(t *testing.T) { ...@@ -85,6 +85,7 @@ func TestTransportConnectionCloseOnResponse(t *testing.T) {
t.Fatalf("error in connectionClose=%v, req #%d, Do: %v", connectionClose, n, err) t.Fatalf("error in connectionClose=%v, req #%d, Do: %v", connectionClose, n, err)
} }
body, err := ioutil.ReadAll(res.Body) body, err := ioutil.ReadAll(res.Body)
defer res.Body.Close()
if err != nil { if err != nil {
t.Fatalf("error in connectionClose=%v, req #%d, ReadAll: %v", connectionClose, n, err) t.Fatalf("error in connectionClose=%v, req #%d, ReadAll: %v", connectionClose, n, err)
} }
...@@ -154,9 +155,11 @@ func TestTransportIdleCacheKeys(t *testing.T) { ...@@ -154,9 +155,11 @@ func TestTransportIdleCacheKeys(t *testing.T) {
t.Errorf("After CloseIdleConnections expected %d idle conn cache keys; got %d", e, g) t.Errorf("After CloseIdleConnections expected %d idle conn cache keys; got %d", e, g)
} }
if _, _, err := c.Get(ts.URL); err != nil { resp, _, err := c.Get(ts.URL)
if err != nil {
t.Error(err) t.Error(err)
} }
ioutil.ReadAll(resp.Body)
keys := tr.IdleConnKeysForTesting() keys := tr.IdleConnKeysForTesting()
if e, g := 1, len(keys); e != g { if e, g := 1, len(keys); e != g {
...@@ -164,7 +167,7 @@ func TestTransportIdleCacheKeys(t *testing.T) { ...@@ -164,7 +167,7 @@ func TestTransportIdleCacheKeys(t *testing.T) {
} }
if e := "|http|" + ts.Listener.Addr().String(); keys[0] != e { if e := "|http|" + ts.Listener.Addr().String(); keys[0] != e {
t.Logf("Expected idle cache key %q; got %q", e, keys[0]) t.Errorf("Expected idle cache key %q; got %q", e, keys[0])
} }
tr.CloseIdleConnections() tr.CloseIdleConnections()
...@@ -173,6 +176,62 @@ func TestTransportIdleCacheKeys(t *testing.T) { ...@@ -173,6 +176,62 @@ func TestTransportIdleCacheKeys(t *testing.T) {
} }
} }
func TestTransportMaxPerHostIdleConns(t *testing.T) {
ch := make(chan string)
ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) {
fmt.Fprintf(w, "%s", <-ch)
}))
defer ts.Close()
maxIdleConns := 2
tr := &Transport{DisableKeepAlives: false, MaxIdleConnsPerHost: maxIdleConns}
c := &Client{Transport: tr}
// Start 3 outstanding requests (will hang until we write to
// ch)
donech := make(chan bool)
doReq := func() {
resp, _, err := c.Get(ts.URL)
if err != nil {
t.Error(err)
}
ioutil.ReadAll(resp.Body)
donech <- true
}
go doReq()
go doReq()
go doReq()
if e, g := 0, len(tr.IdleConnKeysForTesting()); e != g {
t.Fatalf("Before writes, expected %d idle conn cache keys; got %d", e, g)
}
ch <- "res1"
<-donech
keys := tr.IdleConnKeysForTesting()
if e, g := 1, len(keys); e != g {
t.Fatalf("after first response, expected %d idle conn cache keys; got %d", e, g)
}
cacheKey := "|http|" + ts.Listener.Addr().String()
if keys[0] != cacheKey {
t.Fatalf("Expected idle cache key %q; got %q", cacheKey, keys[0])
}
if e, g := 1, tr.IdleConnCountForTesting(cacheKey); e != g {
t.Errorf("after first response, expected %d idle conns; got %d", e, g)
}
ch <- "res2"
<-donech
if e, g := 2, tr.IdleConnCountForTesting(cacheKey); e != g {
t.Errorf("after second response, expected %d idle conns; got %d", e, g)
}
ch <- "res3"
<-donech
if e, g := maxIdleConns, tr.IdleConnCountForTesting(cacheKey); e != g {
t.Errorf("after third response, still expected %d idle conns; got %d", e, g)
}
}
func TestTransportServerClosingUnexpectedly(t *testing.T) { func TestTransportServerClosingUnexpectedly(t *testing.T) {
ts := httptest.NewServer(hostPortHandler) ts := httptest.NewServer(hostPortHandler)
defer ts.Close() defer ts.Close()
...@@ -209,6 +268,63 @@ func TestTransportServerClosingUnexpectedly(t *testing.T) { ...@@ -209,6 +268,63 @@ func TestTransportServerClosingUnexpectedly(t *testing.T) {
} }
} }
// TestTransportHeadResponses verifies that we deal with Content-Lengths
// with no bodies properly
func TestTransportHeadResponses(t *testing.T) {
ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) {
if r.Method != "HEAD" {
panic("expected HEAD; got " + r.Method)
}
w.Header().Set("Content-Length", "123")
w.WriteHeader(200)
}))
defer ts.Close()
tr := &Transport{DisableKeepAlives: false}
c := &Client{Transport: tr}
for i := 0; i < 2; i++ {
res, err := c.Head(ts.URL)
if err != nil {
t.Errorf("error on loop %d: %v", i, err)
}
if e, g := "123", res.Header.Get("Content-Length"); e != g {
t.Errorf("loop %d: expected Content-Length header of %q, got %q", e, g)
}
if e, g := int64(0), res.ContentLength; e != g {
t.Errorf("loop %d: expected res.ContentLength of %v, got %v", e, g)
}
}
}
// TestTransportHeadChunkedResponse verifies that we ignore chunked transfer-encoding
// on responses to HEAD requests.
func TestTransportHeadChunkedResponse(t *testing.T) {
ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) {
if r.Method != "HEAD" {
panic("expected HEAD; got " + r.Method)
}
w.Header().Set("Transfer-Encoding", "chunked") // client should ignore
w.Header().Set("x-client-ipport", r.RemoteAddr)
w.WriteHeader(200)
}))
defer ts.Close()
tr := &Transport{DisableKeepAlives: false}
c := &Client{Transport: tr}
res1, err := c.Head(ts.URL)
if err != nil {
t.Fatalf("request 1 error: %v", err)
}
res2, err := c.Head(ts.URL)
if err != nil {
t.Fatalf("request 2 error: %v", err)
}
if v1, v2 := res1.Header.Get("x-client-ipport"), res2.Header.Get("x-client-ipport"); v1 != v2 {
t.Errorf("ip/ports differed between head requests: %q vs %q", v1, v2)
}
}
func TestTransportNilURL(t *testing.T) { func TestTransportNilURL(t *testing.T) {
ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) { ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) {
fmt.Fprintf(w, "Hi") fmt.Fprintf(w, "Hi")
......
...@@ -213,8 +213,8 @@ func urlEscape(s string, mode encoding) string { ...@@ -213,8 +213,8 @@ func urlEscape(s string, mode encoding) string {
j++ j++
case shouldEscape(c, mode): case shouldEscape(c, mode):
t[j] = '%' t[j] = '%'
t[j+1] = "0123456789abcdef"[c>>4] t[j+1] = "0123456789ABCDEF"[c>>4]
t[j+2] = "0123456789abcdef"[c&15] t[j+2] = "0123456789ABCDEF"[c&15]
j += 3 j += 3
default: default:
t[j] = s[i] t[j] = s[i]
......
...@@ -490,7 +490,7 @@ var escapeTests = []URLEscapeTest{ ...@@ -490,7 +490,7 @@ var escapeTests = []URLEscapeTest{
}, },
{ {
" ?&=#+%!<>#\"{}|\\^[]`☺\t", " ?&=#+%!<>#\"{}|\\^[]`☺\t",
"+%3f%26%3d%23%2b%25!%3c%3e%23%22%7b%7d%7c%5c%5e%5b%5d%60%e2%98%ba%09", "+%3F%26%3D%23%2B%25!%3C%3E%23%22%7B%7D%7C%5C%5E%5B%5D%60%E2%98%BA%09",
nil, nil,
}, },
} }
...@@ -519,7 +519,7 @@ type UserinfoTest struct { ...@@ -519,7 +519,7 @@ type UserinfoTest struct {
var userinfoTests = []UserinfoTest{ var userinfoTests = []UserinfoTest{
{"user", "password", "user:password"}, {"user", "password", "user:password"},
{"foo:bar", "~!@#$%^&*()_+{}|[]\\-=`:;'\"<>?,./", {"foo:bar", "~!@#$%^&*()_+{}|[]\\-=`:;'\"<>?,./",
"foo%3abar:~!%40%23$%25%5e&*()_+%7b%7d%7c%5b%5d%5c-=%60%3a;'%22%3c%3e?,.%2f"}, "foo%3Abar:~!%40%23$%25%5E&*()_+%7B%7D%7C%5B%5D%5C-=%60%3A;'%22%3C%3E?,.%2F"},
} }
func TestEscapeUserinfo(t *testing.T) { func TestEscapeUserinfo(t *testing.T) {
......
...@@ -34,7 +34,7 @@ var imageTests = []imageTest{ ...@@ -34,7 +34,7 @@ var imageTests = []imageTest{
} }
func decode(filename string) (image.Image, string, os.Error) { func decode(filename string) (image.Image, string, os.Error) {
f, err := os.Open(filename, os.O_RDONLY, 0400) f, err := os.Open(filename)
if err != nil { if err != nil {
return nil, "", err return nil, "", err
} }
......
...@@ -41,7 +41,7 @@ var filenamesShort = []string{ ...@@ -41,7 +41,7 @@ var filenamesShort = []string{
} }
func readPng(filename string) (image.Image, os.Error) { func readPng(filename string) (image.Image, os.Error) {
f, err := os.Open(filename, os.O_RDONLY, 0444) f, err := os.Open(filename)
if err != nil { if err != nil {
return nil, err return nil, err
} }
...@@ -191,7 +191,7 @@ func TestReader(t *testing.T) { ...@@ -191,7 +191,7 @@ func TestReader(t *testing.T) {
defer piper.Close() defer piper.Close()
// Read the .sng file. // Read the .sng file.
sf, err := os.Open("testdata/pngsuite/"+fn+".sng", os.O_RDONLY, 0444) sf, err := os.Open("testdata/pngsuite/" + fn + ".sng")
if err != nil { if err != nil {
t.Error(fn, err) t.Error(fn, err)
continue continue
......
...@@ -28,7 +28,7 @@ func ReadAll(r io.Reader) ([]byte, os.Error) { ...@@ -28,7 +28,7 @@ func ReadAll(r io.Reader) ([]byte, os.Error) {
// ReadFile reads the file named by filename and returns the contents. // ReadFile reads the file named by filename and returns the contents.
func ReadFile(filename string) ([]byte, os.Error) { func ReadFile(filename string) ([]byte, os.Error) {
f, err := os.Open(filename, os.O_RDONLY, 0) f, err := os.Open(filename)
if err != nil { if err != nil {
return nil, err return nil, err
} }
...@@ -52,7 +52,7 @@ func ReadFile(filename string) ([]byte, os.Error) { ...@@ -52,7 +52,7 @@ func ReadFile(filename string) ([]byte, os.Error) {
// If the file does not exist, WriteFile creates it with permissions perm; // If the file does not exist, WriteFile creates it with permissions perm;
// otherwise WriteFile truncates it before writing. // otherwise WriteFile truncates it before writing.
func WriteFile(filename string, data []byte, perm uint32) os.Error { func WriteFile(filename string, data []byte, perm uint32) os.Error {
f, err := os.Open(filename, os.O_WRONLY|os.O_CREAT|os.O_TRUNC, perm) f, err := os.OpenFile(filename, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, perm)
if err != nil { if err != nil {
return err return err
} }
...@@ -74,7 +74,7 @@ func (f fileInfoList) Swap(i, j int) { f[i], f[j] = f[j], f[i] } ...@@ -74,7 +74,7 @@ func (f fileInfoList) Swap(i, j int) { f[i], f[j] = f[j], f[i] }
// ReadDir reads the directory named by dirname and returns // ReadDir reads the directory named by dirname and returns
// a list of sorted directory entries. // a list of sorted directory entries.
func ReadDir(dirname string) ([]*os.FileInfo, os.Error) { func ReadDir(dirname string) ([]*os.FileInfo, os.Error) {
f, err := os.Open(dirname, os.O_RDONLY, 0) f, err := os.Open(dirname)
if err != nil { if err != nil {
return nil, err return nil, err
} }
......
...@@ -48,7 +48,7 @@ func TempFile(dir, prefix string) (f *os.File, err os.Error) { ...@@ -48,7 +48,7 @@ func TempFile(dir, prefix string) (f *os.File, err os.Error) {
nconflict := 0 nconflict := 0
for i := 0; i < 10000; i++ { for i := 0; i < 10000; i++ {
name := filepath.Join(dir, prefix+nextSuffix()) name := filepath.Join(dir, prefix+nextSuffix())
f, err = os.Open(name, os.O_RDWR|os.O_CREATE|os.O_EXCL, 0600) f, err = os.OpenFile(name, os.O_RDWR|os.O_CREATE|os.O_EXCL, 0600)
if pe, ok := err.(*os.PathError); ok && pe.Error == os.EEXIST { if pe, ok := err.(*os.PathError); ok && pe.Error == os.EEXIST {
if nconflict++; nconflict > 10 { if nconflict++; nconflict > 10 {
rand = reseed() rand = reseed()
......
...@@ -33,6 +33,7 @@ const ( ...@@ -33,6 +33,7 @@ const (
Lmicroseconds // microsecond resolution: 01:23:23.123123. assumes Ltime. Lmicroseconds // microsecond resolution: 01:23:23.123123. assumes Ltime.
Llongfile // full file name and line number: /a/b/c/d.go:23 Llongfile // full file name and line number: /a/b/c/d.go:23
Lshortfile // final file name element and line number: d.go:23. overrides Llongfile Lshortfile // final file name element and line number: d.go:23. overrides Llongfile
LstdFlags = Ldate | Ltime // initial values for the standard logger
) )
// A Logger represents an active logging object that generates lines of // A Logger represents an active logging object that generates lines of
...@@ -40,10 +41,11 @@ const ( ...@@ -40,10 +41,11 @@ const (
// the Writer's Write method. A Logger can be used simultaneously from // the Writer's Write method. A Logger can be used simultaneously from
// multiple goroutines; it guarantees to serialize access to the Writer. // multiple goroutines; it guarantees to serialize access to the Writer.
type Logger struct { type Logger struct {
mu sync.Mutex // ensures atomic writes
out io.Writer // destination for output
prefix string // prefix to write at beginning of each line prefix string // prefix to write at beginning of each line
flag int // properties flag int // properties
mu sync.Mutex // ensures atomic writes; protects the following fields
out io.Writer // destination for output
buf bytes.Buffer // for accumulating text to write
} }
// New creates a new Logger. The out variable sets the // New creates a new Logger. The out variable sets the
...@@ -54,7 +56,7 @@ func New(out io.Writer, prefix string, flag int) *Logger { ...@@ -54,7 +56,7 @@ func New(out io.Writer, prefix string, flag int) *Logger {
return &Logger{out: out, prefix: prefix, flag: flag} return &Logger{out: out, prefix: prefix, flag: flag}
} }
var std = New(os.Stderr, "", Ldate|Ltime) var std = New(os.Stderr, "", LstdFlags)
// Cheap integer to fixed-width decimal ASCII. Give a negative width to avoid zero-padding. // Cheap integer to fixed-width decimal ASCII. Give a negative width to avoid zero-padding.
// Knows the buffer has capacity. // Knows the buffer has capacity.
...@@ -81,7 +83,7 @@ func itoa(buf *bytes.Buffer, i int, wid int) { ...@@ -81,7 +83,7 @@ func itoa(buf *bytes.Buffer, i int, wid int) {
} }
} }
func (l *Logger) formatHeader(buf *bytes.Buffer, ns int64, calldepth int) { func (l *Logger) formatHeader(buf *bytes.Buffer, ns int64, file string, line int) {
buf.WriteString(l.prefix) buf.WriteString(l.prefix)
if l.flag&(Ldate|Ltime|Lmicroseconds) != 0 { if l.flag&(Ldate|Ltime|Lmicroseconds) != 0 {
t := time.SecondsToLocalTime(ns / 1e9) t := time.SecondsToLocalTime(ns / 1e9)
...@@ -107,8 +109,6 @@ func (l *Logger) formatHeader(buf *bytes.Buffer, ns int64, calldepth int) { ...@@ -107,8 +109,6 @@ func (l *Logger) formatHeader(buf *bytes.Buffer, ns int64, calldepth int) {
} }
} }
if l.flag&(Lshortfile|Llongfile) != 0 { if l.flag&(Lshortfile|Llongfile) != 0 {
_, file, line, ok := runtime.Caller(calldepth)
if ok {
if l.flag&Lshortfile != 0 { if l.flag&Lshortfile != 0 {
short := file short := file
for i := len(file) - 1; i > 0; i-- { for i := len(file) - 1; i > 0; i-- {
...@@ -119,10 +119,6 @@ func (l *Logger) formatHeader(buf *bytes.Buffer, ns int64, calldepth int) { ...@@ -119,10 +119,6 @@ func (l *Logger) formatHeader(buf *bytes.Buffer, ns int64, calldepth int) {
} }
file = short file = short
} }
} else {
file = "???"
line = 0
}
buf.WriteString(file) buf.WriteString(file)
buf.WriteByte(':') buf.WriteByte(':')
itoa(buf, line, -1) itoa(buf, line, -1)
...@@ -138,15 +134,26 @@ func (l *Logger) formatHeader(buf *bytes.Buffer, ns int64, calldepth int) { ...@@ -138,15 +134,26 @@ func (l *Logger) formatHeader(buf *bytes.Buffer, ns int64, calldepth int) {
// paths it will be 2. // paths it will be 2.
func (l *Logger) Output(calldepth int, s string) os.Error { func (l *Logger) Output(calldepth int, s string) os.Error {
now := time.Nanoseconds() // get this early. now := time.Nanoseconds() // get this early.
buf := new(bytes.Buffer) // get caller info (if required) before locking - it's expensive.
l.formatHeader(buf, now, calldepth+1) var file string
buf.WriteString(s) var line int
if len(s) > 0 && s[len(s)-1] != '\n' { if l.flag&(Lshortfile|Llongfile) != 0 {
buf.WriteByte('\n') var ok bool
_, file, line, ok = runtime.Caller(calldepth)
if !ok {
file = "???"
line = 0
}
} }
l.mu.Lock() l.mu.Lock()
defer l.mu.Unlock() defer l.mu.Unlock()
_, err := l.out.Write(buf.Bytes()) l.buf.Reset()
l.formatHeader(&l.buf, now, file, line)
l.buf.WriteString(s)
if len(s) > 0 && s[len(s)-1] != '\n' {
l.buf.WriteByte('\n')
}
_, err := l.out.Write(l.buf.Bytes())
return err return err
} }
...@@ -203,19 +210,49 @@ func (l *Logger) Panicln(v ...interface{}) { ...@@ -203,19 +210,49 @@ func (l *Logger) Panicln(v ...interface{}) {
panic(s) panic(s)
} }
// Flags returns the output flags for the logger.
func (l *Logger) Flags() int {
return l.flag
}
// SetFlags sets the output flags for the logger.
func (l *Logger) SetFlags(flag int) {
l.flag = flag
}
// Prefix returns the output prefix for the logger.
func (l *Logger) Prefix() string {
return l.prefix
}
// SetPrefix sets the output prefix for the logger.
func (l *Logger) SetPrefix(prefix string) {
l.prefix = prefix
}
// SetOutput sets the output destination for the standard logger. // SetOutput sets the output destination for the standard logger.
func SetOutput(w io.Writer) { func SetOutput(w io.Writer) {
std.out = w std.out = w
} }
// Flags returns the output flags for the standard logger.
func Flags() int {
return std.Flags()
}
// SetFlags sets the output flags for the standard logger. // SetFlags sets the output flags for the standard logger.
func SetFlags(flag int) { func SetFlags(flag int) {
std.flag = flag std.SetFlags(flag)
}
// Prefix returns the output prefix for the standard logger.
func Prefix() string {
return std.Prefix()
} }
// SetPrefix sets the output prefix for the standard logger. // SetPrefix sets the output prefix for the standard logger.
func SetPrefix(prefix string) { func SetPrefix(prefix string) {
std.prefix = prefix std.SetPrefix(prefix)
} }
// These functions write to the standard logger. // These functions write to the standard logger.
......
...@@ -84,3 +84,36 @@ func TestOutput(t *testing.T) { ...@@ -84,3 +84,36 @@ func TestOutput(t *testing.T) {
t.Errorf("log output should match %q is %q", expect, b.String()) t.Errorf("log output should match %q is %q", expect, b.String())
} }
} }
func TestFlagAndPrefixSetting(t *testing.T) {
var b bytes.Buffer
l := New(&b, "Test:", LstdFlags)
f := l.Flags()
if f != LstdFlags {
t.Errorf("Flags 1: expected %x got %x", LstdFlags, f)
}
l.SetFlags(f | Lmicroseconds)
f = l.Flags()
if f != LstdFlags|Lmicroseconds {
t.Errorf("Flags 2: expected %x got %x", LstdFlags|Lmicroseconds, f)
}
p := l.Prefix()
if p != "Test:" {
t.Errorf(`Prefix: expected "Test:" got %q`, p)
}
l.SetPrefix("Reality:")
p = l.Prefix()
if p != "Reality:" {
t.Errorf(`Prefix: expected "Reality:" got %q`, p)
}
// Verify a log message looks right, with our prefix and microseconds present.
l.Print("hello")
pattern := "^Reality:" + Rdate + " " + Rtime + Rmicroseconds + " hello\n"
matched, err := regexp.Match(pattern, b.Bytes())
if err != nil {
t.Fatalf("pattern %q did not compile: %s", pattern, err)
}
if !matched {
t.Error("message did not match pattern")
}
}
...@@ -33,7 +33,7 @@ var mimeTypes = map[string]string{ ...@@ -33,7 +33,7 @@ var mimeTypes = map[string]string{
var mimeLock sync.RWMutex var mimeLock sync.RWMutex
func loadMimeFile(filename string) { func loadMimeFile(filename string) {
f, err := os.Open(filename, os.O_RDONLY, 0666) f, err := os.Open(filename)
if err != nil { if err != nil {
return return
} }
......
...@@ -59,7 +59,7 @@ func readHosts() { ...@@ -59,7 +59,7 @@ func readHosts() {
} }
} }
// lookupStaticHosts looks up the addresses for the given host from /etc/hosts. // lookupStaticHost looks up the addresses for the given host from /etc/hosts.
func lookupStaticHost(host string) []string { func lookupStaticHost(host string) []string {
hosts.Lock() hosts.Lock()
defer hosts.Unlock() defer hosts.Unlock()
...@@ -72,7 +72,7 @@ func lookupStaticHost(host string) []string { ...@@ -72,7 +72,7 @@ func lookupStaticHost(host string) []string {
return nil return nil
} }
// rlookupStaticHosts looks up the hosts for the given address from /etc/hosts. // lookupStaticAddr looks up the hosts for the given address from /etc/hosts.
func lookupStaticAddr(addr string) []string { func lookupStaticAddr(addr string) []string {
hosts.Lock() hosts.Lock()
defer hosts.Unlock() defer hosts.Unlock()
......
...@@ -63,7 +63,7 @@ func (f *file) readLine() (s string, ok bool) { ...@@ -63,7 +63,7 @@ func (f *file) readLine() (s string, ok bool) {
} }
func open(name string) (*file, os.Error) { func open(name string) (*file, os.Error) {
fd, err := os.Open(name, os.O_RDONLY, 0) fd, err := os.Open(name)
if err != nil { if err != nil {
return nil, err return nil, err
} }
......
...@@ -18,7 +18,7 @@ func TestReadLine(t *testing.T) { ...@@ -18,7 +18,7 @@ func TestReadLine(t *testing.T) {
} }
filename := "/etc/services" // a nice big file filename := "/etc/services" // a nice big file
fd, err := os.Open(filename, os.O_RDONLY, 0) fd, err := os.Open(filename)
if err != nil { if err != nil {
t.Fatalf("open %s: %v", filename, err) t.Fatalf("open %s: %v", filename, err)
} }
......
...@@ -14,26 +14,51 @@ import ( ...@@ -14,26 +14,51 @@ import (
var hostentLock sync.Mutex var hostentLock sync.Mutex
var serventLock sync.Mutex var serventLock sync.Mutex
func LookupHost(name string) (cname string, addrs []string, err os.Error) { func goLookupHost(name string) (addrs []string, err os.Error) {
ips, err := goLookupIP(name)
if err != nil {
return
}
addrs = make([]string, 0, len(ips))
for _, ip := range ips {
addrs = append(addrs, ip.String())
}
return
}
func goLookupIP(name string) (addrs []IP, err os.Error) {
hostentLock.Lock() hostentLock.Lock()
defer hostentLock.Unlock() defer hostentLock.Unlock()
h, e := syscall.GetHostByName(name) h, e := syscall.GetHostByName(name)
if e != 0 { if e != 0 {
return "", nil, os.NewSyscallError("GetHostByName", e) return nil, os.NewSyscallError("GetHostByName", e)
} }
cname = name
switch h.AddrType { switch h.AddrType {
case syscall.AF_INET: case syscall.AF_INET:
i := 0 i := 0
addrs = make([]string, 100) // plenty of room to grow addrs = make([]IP, 100) // plenty of room to grow
for p := (*[100](*[4]byte))(unsafe.Pointer(h.AddrList)); i < cap(addrs) && p[i] != nil; i++ { for p := (*[100](*[4]byte))(unsafe.Pointer(h.AddrList)); i < cap(addrs) && p[i] != nil; i++ {
addrs[i] = IPv4(p[i][0], p[i][1], p[i][2], p[i][3]).String() addrs[i] = IPv4(p[i][0], p[i][1], p[i][2], p[i][3])
} }
addrs = addrs[0:i] addrs = addrs[0:i]
default: // TODO(vcc): Implement non IPv4 address lookups. default: // TODO(vcc): Implement non IPv4 address lookups.
return "", nil, os.NewSyscallError("LookupHost", syscall.EWINDOWS) return nil, os.NewSyscallError("LookupHost", syscall.EWINDOWS)
}
return addrs, nil
}
func LookupCNAME(name string) (cname string, err os.Error) {
var r *syscall.DNSRecord
e := syscall.DnsQuery(name, syscall.DNS_TYPE_CNAME, 0, nil, &r, nil)
if int(e) != 0 {
return "", os.NewSyscallError("LookupCNAME", int(e))
}
defer syscall.DnsRecordListFree(r, 1)
if r != nil && r.Type == syscall.DNS_TYPE_CNAME {
v := (*syscall.DNSPTRData)(unsafe.Pointer(&r.Data[0]))
cname = syscall.UTF16ToString((*[256]uint16)(unsafe.Pointer(v.Host))[:]) + "."
} }
return cname, addrs, nil return
} }
type SRV struct { type SRV struct {
...@@ -62,7 +87,7 @@ func LookupSRV(service, proto, name string) (cname string, addrs []*SRV, err os. ...@@ -62,7 +87,7 @@ func LookupSRV(service, proto, name string) (cname string, addrs []*SRV, err os.
return name, addrs, nil return name, addrs, nil
} }
func LookupPort(network, service string) (port int, err os.Error) { func goLookupPort(network, service string) (port int, err os.Error) {
switch network { switch network {
case "tcp4", "tcp6": case "tcp4", "tcp6":
network = "tcp" network = "tcp"
......
// 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 os
import (
"syscall"
)
type dirInfo int
var markDirectory dirInfo = ^0
// Readdir reads the contents of the directory associated with file and
// returns an array of up to count FileInfo structures, as would be returned
// by Lstat, in directory order. Subsequent calls on the same file will yield
// further FileInfos. A negative count means to read the entire directory.
// Readdir returns the array and an Error, if any.
func (file *File) Readdir(count int) (fi []FileInfo, err Error) {
// If this file has no dirinfo, create one.
if file.dirinfo == nil {
file.dirinfo = &markDirectory
}
size := count
if size < 0 {
size = 100
}
result := make([]FileInfo, 0, size)
var buf [syscall.STATMAX]byte
for {
n, e := file.Read(buf[:])
if e != nil {
if e == EOF {
break
}
return []FileInfo{}, &PathError{"readdir", file.name, e}
}
if n < syscall.STATFIXLEN {
return []FileInfo{}, &PathError{"readdir", file.name, Eshortstat}
}
for i := 0; i < n; {
m, _ := gbit16(buf[i:])
m += 2
if m < syscall.STATFIXLEN {
return []FileInfo{}, &PathError{"readdir", file.name, Eshortstat}
}
d, e := UnmarshalDir(buf[i : i+int(m)])
if e != nil {
return []FileInfo{}, &PathError{"readdir", file.name, e}
}
var f FileInfo
fileInfoFromStat(&f, d)
result = append(result, f)
// a negative count means to read until EOF.
if count > 0 && len(result) >= count {
break
}
i += int(m)
}
}
return result, nil
}
// Readdirnames returns an array of up to count file names residing in the
// directory associated with file. A negative count will return all of them.
// Readdir returns the array and an Error, if any.
func (file *File) Readdirnames(count int) (names []string, err Error) {
fi, e := file.Readdir(count)
if e != nil {
return []string{}, e
}
names = make([]string, len(fi))
err = nil
for i, _ := range fi {
names[i] = fi[i].Name
}
return
}
type Dir struct {
// system-modified data
Type uint16 // server type
Dev uint32 // server subtype
// file data
Qid Qid // unique id from server
Mode uint32 // permissions
Atime uint32 // last read time
Mtime uint32 // last write time
Length uint64 // file length
Name string // last element of path
Uid string // owner name
Gid string // group name
Muid string // last modifier name
}
type Qid struct {
Path uint64 // the file server's unique identification for the file
Vers uint32 // version number for given Path
Type uint8 // the type of the file (syscall.QTDIR for example)
}
var nullDir = Dir{
^uint16(0),
^uint32(0),
Qid{^uint64(0), ^uint32(0), ^uint8(0)},
^uint32(0),
^uint32(0),
^uint32(0),
^uint64(0),
"",
"",
"",
"",
}
// Null assigns members of d with special "don't care" values indicating
// they should not be written by syscall.Wstat.
func (d *Dir) Null() {
*d = nullDir
}
// pdir appends a 9P Stat message based on the contents of Dir d to a byte slice b.
func pdir(b []byte, d *Dir) []byte {
n := len(b)
b = pbit16(b, 0) // length, filled in later
b = pbit16(b, d.Type)
b = pbit32(b, d.Dev)
b = pqid(b, d.Qid)
b = pbit32(b, d.Mode)
b = pbit32(b, d.Atime)
b = pbit32(b, d.Mtime)
b = pbit64(b, d.Length)
b = pstring(b, d.Name)
b = pstring(b, d.Uid)
b = pstring(b, d.Gid)
b = pstring(b, d.Muid)
pbit16(b[0:n], uint16(len(b)-(n+2)))
return b
}
// UnmarshalDir reads a 9P Stat message from a 9P protocol message strored in b,
// returning the corresponding Dir struct.
func UnmarshalDir(b []byte) (d *Dir, err Error) {
n := uint16(0)
n, b = gbit16(b)
if int(n) != len(b) {
return nil, Ebadstat
}
d = new(Dir)
d.Type, b = gbit16(b)
d.Dev, b = gbit32(b)
d.Qid, b = gqid(b)
d.Mode, b = gbit32(b)
d.Atime, b = gbit32(b)
d.Mtime, b = gbit32(b)
d.Length, b = gbit64(b)
d.Name, b = gstring(b)
d.Uid, b = gstring(b)
d.Gid, b = gstring(b)
d.Muid, b = gstring(b)
if len(b) != 0 {
return nil, Ebadstat
}
return d, nil
}
// gqid reads the qid part of a 9P Stat message from a 9P protocol message strored in b,
// returning the corresponding Qid struct and the remaining slice of b.
func gqid(b []byte) (Qid, []byte) {
var q Qid
q.Path, b = gbit64(b)
q.Vers, b = gbit32(b)
q.Type, b = gbit8(b)
return q, b
}
// pqid appends a Qid struct q to a 9P message b.
func pqid(b []byte, q Qid) []byte {
b = pbit64(b, q.Path)
b = pbit32(b, q.Vers)
b = pbit8(b, q.Type)
return b
}
// gbit8 reads a byte-sized numeric value from a 9P protocol message strored in b,
// returning the value and the remaining slice of b.
func gbit8(b []byte) (uint8, []byte) {
return uint8(b[0]), b[1:]
}
// gbit16 reads a 16-bit numeric value from a 9P protocol message strored in b,
// returning the value and the remaining slice of b.
func gbit16(b []byte) (uint16, []byte) {
return uint16(b[0]) | uint16(b[1])<<8, b[2:]
}
// gbit32 reads a 32-bit numeric value from a 9P protocol message strored in b,
// returning the value and the remaining slice of b.
func gbit32(b []byte) (uint32, []byte) {
return uint32(b[0]) | uint32(b[1])<<8 | uint32(b[2])<<16 | uint32(b[3])<<24, b[4:]
}
// gbit64 reads a 64-bit numeric value from a 9P protocol message strored in b,
// returning the value and the remaining slice of b.
func gbit64(b []byte) (uint64, []byte) {
lo, b := gbit32(b)
hi, b := gbit32(b)
return uint64(hi)<<32 | uint64(lo), b
}
// gstring reads a string from a 9P protocol message strored in b,
// returning the value as a Go string and the remaining slice of b.
func gstring(b []byte) (string, []byte) {
n, b := gbit16(b)
return string(b[0:n]), b[n:]
}
// pbit8 appends a byte-sized numeric value x to a 9P message b.
func pbit8(b []byte, x uint8) []byte {
n := len(b)
if n+1 > cap(b) {
nb := make([]byte, n, 100+2*cap(b))
copy(nb, b)
b = nb
}
b = b[0 : n+1]
b[n] = x
return b
}
// pbit16 appends a 16-bit numeric value x to a 9P message b.
func pbit16(b []byte, x uint16) []byte {
n := len(b)
if n+2 > cap(b) {
nb := make([]byte, n, 100+2*cap(b))
copy(nb, b)
b = nb
}
b = b[0 : n+2]
b[n] = byte(x)
b[n+1] = byte(x >> 8)
return b
}
// pbit32 appends a 32-bit numeric value x to a 9P message b.
func pbit32(b []byte, x uint32) []byte {
n := len(b)
if n+4 > cap(b) {
nb := make([]byte, n, 100+2*cap(b))
copy(nb, b)
b = nb
}
b = b[0 : n+4]
b[n] = byte(x)
b[n+1] = byte(x >> 8)
b[n+2] = byte(x >> 16)
b[n+3] = byte(x >> 24)
return b
}
// pbit64 appends a 64-bit numeric value x to a 9P message b.
func pbit64(b []byte, x uint64) []byte {
b = pbit32(b, uint32(x))
b = pbit32(b, uint32(x>>32))
return b
}
// pstring appends a Go string s to a 9P message b.
func pstring(b []byte, s string) []byte {
if len(s) >= 1<<16 {
panic(NewError("string too long"))
}
b = pbit16(b, uint16(len(s)))
b = append(b, []byte(s)...)
return b
}
// 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 os
import (
"syscall"
)
const (
blockSize = 4096
)
// Readdirnames reads the contents of the directory associated with file and
// returns an array of up to count names, in directory order. Subsequent
// calls on the same file will yield further names.
// A negative count means to read until EOF.
// Readdirnames returns the array and an Error, if any.
func (file *File) Readdirnames(count int) (names []string, err Error) {
// If this file has no dirinfo, create one.
if file.dirinfo == nil {
file.dirinfo = new(dirInfo)
// The buffer must be at least a block long.
file.dirinfo.buf = make([]byte, blockSize)
}
d := file.dirinfo
size := count
if size < 0 {
size = 100
}
names = make([]string, 0, size) // Empty with room to grow.
for count != 0 {
// Refill the buffer if necessary
if d.bufp >= d.nbuf {
d.bufp = 0
var errno int
d.nbuf, errno = syscall.ReadDirent(file.fd, d.buf)
if errno != 0 {
return names, NewSyscallError("readdirent", errno)
}
if d.nbuf <= 0 {
break // EOF
}
}
// Drain the buffer
var nb, nc int
nb, nc, names = syscall.ParseDirent(d.buf[d.bufp:d.nbuf], count, names)
d.bufp += nb
count -= nc
}
return names, nil
}
// Copyright 2011 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.
// Plan 9 environment variables.
package os
import "syscall"
// ENOENV is the Error indicating that an environment variable does not exist.
var ENOENV = NewError("no such environment variable")
// Getenverror retrieves the value of the environment variable named by the key.
// It returns the value and an error, if any.
func Getenverror(key string) (value string, err Error) {
if len(key) == 0 {
return "", EINVAL
}
f, e := Open("/env/" + key)
if iserror(e) {
return "", ENOENV
}
defer f.Close()
var buf [4096]byte
n, e := f.Read(buf[:len(buf)-1])
if iserror(e) {
return "", ENOENV
}
buf[n] = 0
return string(buf[0:n]), nil
}
// Getenv retrieves the value of the environment variable named by the key.
// It returns the value, which will be empty if the variable is not present.
func Getenv(key string) string {
v, _ := Getenverror(key)
return v
}
// Setenv sets the value of the environment variable named by the key.
// It returns an Error, if any.
func Setenv(key, value string) Error {
if len(key) == 0 {
return EINVAL
}
f, e := Create("/env/" + key)
if iserror(e) {
return e
}
defer f.Close()
_, e = f.Write(syscall.StringByteSlice(value))
return nil
}
// Clearenv deletes all environment variables.
func Clearenv() {
syscall.RawSyscall(syscall.SYS_RFORK, syscall.RFCENVG, 0, 0)
}
// Environ returns an array of strings representing the environment,
// in the form "key=value".
func Environ() []string {
env := make([]string, 0, 100)
f, e := Open("/env")
if iserror(e) {
panic(e)
}
defer f.Close()
names, e := f.Readdirnames(-1)
if iserror(e) {
panic(e)
}
for _, k := range names {
if v, e := Getenverror(k); !iserror(e) {
env = append(env, k+"="+v)
}
}
return env[0:len(env)]
}
// TempDir returns the default directory to use for temporary files.
func TempDir() string {
return "/tmp"
}
...@@ -4,8 +4,6 @@ ...@@ -4,8 +4,6 @@
package os package os
import syscall "syscall"
// An Error can represent any printable error condition. // An Error can represent any printable error condition.
type Error interface { type Error interface {
String() string String() string
...@@ -26,63 +24,6 @@ func (e ErrorString) Timeout() bool { return false } ...@@ -26,63 +24,6 @@ func (e ErrorString) Timeout() bool { return false }
// NewError converts s to an ErrorString, which satisfies the Error interface. // NewError converts s to an ErrorString, which satisfies the Error interface.
func NewError(s string) Error { return ErrorString(s) } func NewError(s string) Error { return ErrorString(s) }
// Errno is the Unix error number. Names such as EINVAL are simple
// wrappers to convert the error number into an Error.
type Errno int64
func (e Errno) String() string { return syscall.Errstr(int(e)) }
func (e Errno) Temporary() bool {
return e == Errno(syscall.EINTR) || e.Timeout()
}
func (e Errno) Timeout() bool {
return e == Errno(syscall.EAGAIN) || e == Errno(syscall.EWOULDBLOCK) || e == Errno(syscall.ETIMEDOUT)
}
// Commonly known Unix errors.
var (
EPERM Error = Errno(syscall.EPERM)
ENOENT Error = Errno(syscall.ENOENT)
ESRCH Error = Errno(syscall.ESRCH)
EINTR Error = Errno(syscall.EINTR)
EIO Error = Errno(syscall.EIO)
ENXIO Error = Errno(syscall.ENXIO)
E2BIG Error = Errno(syscall.E2BIG)
ENOEXEC Error = Errno(syscall.ENOEXEC)
EBADF Error = Errno(syscall.EBADF)
ECHILD Error = Errno(syscall.ECHILD)
EDEADLK Error = Errno(syscall.EDEADLK)
ENOMEM Error = Errno(syscall.ENOMEM)
EACCES Error = Errno(syscall.EACCES)
EFAULT Error = Errno(syscall.EFAULT)
EBUSY Error = Errno(syscall.EBUSY)
EEXIST Error = Errno(syscall.EEXIST)
EXDEV Error = Errno(syscall.EXDEV)
ENODEV Error = Errno(syscall.ENODEV)
ENOTDIR Error = Errno(syscall.ENOTDIR)
EISDIR Error = Errno(syscall.EISDIR)
EINVAL Error = Errno(syscall.EINVAL)
ENFILE Error = Errno(syscall.ENFILE)
EMFILE Error = Errno(syscall.EMFILE)
ENOTTY Error = Errno(syscall.ENOTTY)
EFBIG Error = Errno(syscall.EFBIG)
ENOSPC Error = Errno(syscall.ENOSPC)
ESPIPE Error = Errno(syscall.ESPIPE)
EROFS Error = Errno(syscall.EROFS)
EMLINK Error = Errno(syscall.EMLINK)
EPIPE Error = Errno(syscall.EPIPE)
EAGAIN Error = Errno(syscall.EAGAIN)
EDOM Error = Errno(syscall.EDOM)
ERANGE Error = Errno(syscall.ERANGE)
EADDRINUSE Error = Errno(syscall.EADDRINUSE)
ECONNREFUSED Error = Errno(syscall.ECONNREFUSED)
ENAMETOOLONG Error = Errno(syscall.ENAMETOOLONG)
EAFNOSUPPORT Error = Errno(syscall.EAFNOSUPPORT)
ETIMEDOUT Error = Errno(syscall.ETIMEDOUT)
ENOTCONN Error = Errno(syscall.ENOTCONN)
)
// PathError records an error and the operation and file path that caused it. // PathError records an error and the operation and file path that caused it.
type PathError struct { type PathError struct {
Op string Op string
...@@ -91,25 +32,3 @@ type PathError struct { ...@@ -91,25 +32,3 @@ type PathError struct {
} }
func (e *PathError) String() string { return e.Op + " " + e.Path + ": " + e.Error.String() } func (e *PathError) String() string { return e.Op + " " + e.Path + ": " + e.Error.String() }
// SyscallError records an error from a specific system call.
type SyscallError struct {
Syscall string
Errno Errno
}
func (e *SyscallError) String() string { return e.Syscall + ": " + e.Errno.String() }
// Note: If the name of the function NewSyscallError changes,
// pkg/go/doc/doc.go should be adjusted since it hardwires
// this name in a heuristic.
// NewSyscallError returns, as an Error, a new SyscallError
// with the given system call name and error number.
// As a convenience, if errno is 0, NewSyscallError returns nil.
func NewSyscallError(syscall string, errno int) Error {
if errno == 0 {
return nil
}
return &SyscallError{syscall, Errno(errno)}
}
// Copyright 2011 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 os
import syscall "syscall"
// SyscallError records an error from a specific system call.
type SyscallError struct {
Syscall string
Err string
}
func (e *SyscallError) String() string { return e.Syscall + ": " + e.Err }
// Note: If the name of the function NewSyscallError changes,
// pkg/go/doc/doc.go should be adjusted since it hardwires
// this name in a heuristic.
// NewSyscallError returns, as an Error, a new SyscallError
// with the given system call name and error details.
// As a convenience, if err is nil, NewSyscallError returns nil.
func NewSyscallError(syscall string, err syscall.Error) Error {
if err == nil {
return nil
}
return &SyscallError{syscall, err.String()}
}
var (
Eshortstat = NewError("stat buffer too small")
Ebadstat = NewError("malformed stat buffer")
Ebadfd = NewError("fd out of range or not open")
Ebadarg = NewError("bad arg in system call")
Enotdir = NewError("not a directory")
Enonexist = NewError("file does not exist")
Eexist = NewError("file already exists")
Eio = NewError("i/o error")
EINVAL = Ebadarg
ENOTDIR = Enotdir
ENOENT = Enonexist
EEXIST = Eexist
EIO = Eio
ENAMETOOLONG = NewError("file name too long")
ERANGE = NewError("math result not representable")
EPIPE = NewError("Broken Pipe")
EPLAN9 = NewError("not supported by plan 9")
)
func iserror(err syscall.Error) bool {
return err != nil
}
func Errno(e syscall.Error) syscall.Error { return e }
// 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 os
import syscall "syscall"
// Errno is the Unix error number. Names such as EINVAL are simple
// wrappers to convert the error number into an Error.
type Errno int64
func (e Errno) String() string { return syscall.Errstr(int(e)) }
func (e Errno) Temporary() bool {
return e == Errno(syscall.EINTR) || e.Timeout()
}
func (e Errno) Timeout() bool {
return e == Errno(syscall.EAGAIN) || e == Errno(syscall.EWOULDBLOCK) || e == Errno(syscall.ETIMEDOUT)
}
// Commonly known Unix errors.
var (
EPERM Error = Errno(syscall.EPERM)
ENOENT Error = Errno(syscall.ENOENT)
ESRCH Error = Errno(syscall.ESRCH)
EINTR Error = Errno(syscall.EINTR)
EIO Error = Errno(syscall.EIO)
ENXIO Error = Errno(syscall.ENXIO)
E2BIG Error = Errno(syscall.E2BIG)
ENOEXEC Error = Errno(syscall.ENOEXEC)
EBADF Error = Errno(syscall.EBADF)
ECHILD Error = Errno(syscall.ECHILD)
EDEADLK Error = Errno(syscall.EDEADLK)
ENOMEM Error = Errno(syscall.ENOMEM)
EACCES Error = Errno(syscall.EACCES)
EFAULT Error = Errno(syscall.EFAULT)
EBUSY Error = Errno(syscall.EBUSY)
EEXIST Error = Errno(syscall.EEXIST)
EXDEV Error = Errno(syscall.EXDEV)
ENODEV Error = Errno(syscall.ENODEV)
ENOTDIR Error = Errno(syscall.ENOTDIR)
EISDIR Error = Errno(syscall.EISDIR)
EINVAL Error = Errno(syscall.EINVAL)
ENFILE Error = Errno(syscall.ENFILE)
EMFILE Error = Errno(syscall.EMFILE)
ENOTTY Error = Errno(syscall.ENOTTY)
EFBIG Error = Errno(syscall.EFBIG)
ENOSPC Error = Errno(syscall.ENOSPC)
ESPIPE Error = Errno(syscall.ESPIPE)
EROFS Error = Errno(syscall.EROFS)
EMLINK Error = Errno(syscall.EMLINK)
EPIPE Error = Errno(syscall.EPIPE)
EAGAIN Error = Errno(syscall.EAGAIN)
EDOM Error = Errno(syscall.EDOM)
ERANGE Error = Errno(syscall.ERANGE)
EADDRINUSE Error = Errno(syscall.EADDRINUSE)
ECONNREFUSED Error = Errno(syscall.ECONNREFUSED)
ENAMETOOLONG Error = Errno(syscall.ENAMETOOLONG)
EAFNOSUPPORT Error = Errno(syscall.EAFNOSUPPORT)
ETIMEDOUT Error = Errno(syscall.ETIMEDOUT)
ENOTCONN Error = Errno(syscall.ENOTCONN)
)
// SyscallError records an error from a specific system call.
type SyscallError struct {
Syscall string
Errno Errno
}
func (e *SyscallError) String() string { return e.Syscall + ": " + e.Errno.String() }
// Note: If the name of the function NewSyscallError changes,
// pkg/go/doc/doc.go should be adjusted since it hardwires
// this name in a heuristic.
// NewSyscallError returns, as an Error, a new SyscallError
// with the given system call name and error details.
// As a convenience, if errno is 0, NewSyscallError returns nil.
func NewSyscallError(syscall string, errno int) Error {
if errno == 0 {
return nil
}
return &SyscallError{syscall, Errno(errno)}
}
func iserror(errno int) bool {
return errno != 0
}
...@@ -39,126 +39,6 @@ type ProcAttr struct { ...@@ -39,126 +39,6 @@ type ProcAttr struct {
Files []*File Files []*File
} }
// StartProcess starts a new process with the program, arguments and attributes
// specified by name, argv and attr.
func StartProcess(name string, argv []string, attr *ProcAttr) (p *Process, err Error) {
sysattr := &syscall.ProcAttr{
Dir: attr.Dir,
Env: attr.Env,
}
if sysattr.Env == nil {
sysattr.Env = Environ()
}
// Create array of integer (system) fds.
intfd := make([]int, len(attr.Files))
for i, f := range attr.Files {
if f == nil {
intfd[i] = -1
} else {
intfd[i] = f.Fd()
}
}
sysattr.Files = intfd
pid, h, e := syscall.StartProcess(name, argv, sysattr)
if e != 0 {
return nil, &PathError{"fork/exec", name, Errno(e)}
}
return newProcess(pid, h), nil
}
// Exec replaces the current process with an execution of the
// named binary, with arguments argv and environment envv.
// If successful, Exec never returns. If it fails, it returns an Error.
// StartProcess is almost always a better way to execute a program.
func Exec(name string, argv []string, envv []string) Error {
if envv == nil {
envv = Environ()
}
e := syscall.Exec(name, argv, envv)
if e != 0 {
return &PathError{"exec", name, Errno(e)}
}
return nil
}
// TODO(rsc): Should os implement its own syscall.WaitStatus
// wrapper with the methods, or is exposing the underlying one enough?
//
// TODO(rsc): Certainly need to have Rusage struct,
// since syscall one might have different field types across
// different OS.
// Waitmsg stores the information about an exited process as reported by Wait.
type Waitmsg struct {
Pid int // The process's id.
syscall.WaitStatus // System-dependent status info.
Rusage *syscall.Rusage // System-dependent resource usage info.
}
// Wait waits for process pid to exit or stop, and then returns a
// Waitmsg describing its status and an Error, if any. The options
// (WNOHANG etc.) affect the behavior of the Wait call.
// Wait is equivalent to calling FindProcess and then Wait
// and Release on the result.
func Wait(pid int, options int) (w *Waitmsg, err Error) {
p, e := FindProcess(pid)
if e != nil {
return nil, e
}
defer p.Release()
return p.Wait(options)
}
// Convert i to decimal string.
func itod(i int) string {
if i == 0 {
return "0"
}
u := uint64(i)
if i < 0 {
u = -u
}
// Assemble decimal in reverse order.
var b [32]byte
bp := len(b)
for ; u > 0; u /= 10 {
bp--
b[bp] = byte(u%10) + '0'
}
if i < 0 {
bp--
b[bp] = '-'
}
return string(b[bp:])
}
func (w Waitmsg) String() string {
// TODO(austin) Use signal names when possible?
res := ""
switch {
case w.Exited():
res = "exit status " + itod(w.ExitStatus())
case w.Signaled():
res = "signal " + itod(w.Signal())
case w.Stopped():
res = "stop signal " + itod(w.StopSignal())
if w.StopSignal() == syscall.SIGTRAP && w.TrapCause() != 0 {
res += " (trap " + itod(w.TrapCause()) + ")"
}
case w.Continued():
res = "continued"
}
if w.CoreDump() {
res += " (core dumped)"
}
return res
}
// Getpid returns the process id of the caller. // Getpid returns the process id of the caller.
func Getpid() int { return syscall.Getpid() } func Getpid() int { return syscall.Getpid() }
......
// 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 os
import (
"runtime"
"syscall"
)
// StartProcess starts a new process with the program, arguments and attributes
// specified by name, argv and attr.
func StartProcess(name string, argv []string, attr *ProcAttr) (p *Process, err Error) {
sysattr := &syscall.ProcAttr{
Dir: attr.Dir,
Env: attr.Env,
}
// Create array of integer (system) fds.
intfd := make([]int, len(attr.Files))
for i, f := range attr.Files {
if f == nil {
intfd[i] = -1
} else {
intfd[i] = f.Fd()
}
}
sysattr.Files = intfd
pid, h, e := syscall.StartProcess(name, argv, sysattr)
if iserror(e) {
return nil, &PathError{"fork/exec", name, e}
}
return newProcess(pid, h), nil
}
// Exec replaces the current process with an execution of the
// named binary, with arguments argv and environment envv.
// If successful, Exec never returns. If it fails, it returns an Error.
// ForkExec is almost always a better way to execute a program.
func Exec(name string, argv []string, envv []string) Error {
e := syscall.Exec(name, argv, envv)
if iserror(e) {
return &PathError{"exec", name, e}
}
return nil
}
// Waitmsg stores the information about an exited process as reported by Wait.
type Waitmsg syscall.Waitmsg
// Wait waits for the Process to exit or stop, and then returns a
// Waitmsg describing its status and an Error, if any. The options
// (WNOHANG etc.) affect the behavior of the Wait call.
func (p *Process) Wait(options int) (w *Waitmsg, err Error) {
var waitmsg syscall.Waitmsg
if p.Pid == -1 {
return nil, EINVAL
}
for true {
err = syscall.Await(&waitmsg)
if iserror(err) {
return nil, NewSyscallError("wait", err)
}
if waitmsg.Pid == p.Pid {
break
}
}
return (*Waitmsg)(&waitmsg), nil
}
// Wait waits for process pid to exit or stop, and then returns a
// Waitmsg describing its status and an Error, if any. The options
// (WNOHANG etc.) affect the behavior of the Wait call.
// Wait is equivalent to calling FindProcess and then Wait
// and Release on the result.
func Wait(pid int, options int) (w *Waitmsg, err Error) {
p, e := FindProcess(pid)
if e != nil {
return nil, e
}
defer p.Release()
return p.Wait(options)
}
// Release releases any resources associated with the Process.
func (p *Process) Release() Error {
// NOOP for Plan 9.
p.Pid = -1
// no need for a finalizer anymore
runtime.SetFinalizer(p, nil)
return nil
}
// FindProcess looks for a running process by its pid.
// The Process it returns can be used to obtain information
// about the underlying operating system process.
func FindProcess(pid int) (p *Process, err Error) {
// NOOP for Plan 9.
return newProcess(pid, 0), nil
}
func (w Waitmsg) String() string {
return "exit status: " + w.Msg
}
// 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 os
import "syscall"
// StartProcess starts a new process with the program, arguments and attributes
// specified by name, argv and attr.
func StartProcess(name string, argv []string, attr *ProcAttr) (p *Process, err Error) {
sysattr := &syscall.ProcAttr{
Dir: attr.Dir,
Env: attr.Env,
}
if sysattr.Env == nil {
sysattr.Env = Environ()
}
// Create array of integer (system) fds.
intfd := make([]int, len(attr.Files))
for i, f := range attr.Files {
if f == nil {
intfd[i] = -1
} else {
intfd[i] = f.Fd()
}
}
sysattr.Files = intfd
pid, h, e := syscall.StartProcess(name, argv, sysattr)
if iserror(e) {
return nil, &PathError{"fork/exec", name, Errno(e)}
}
return newProcess(pid, h), nil
}
// Exec replaces the current process with an execution of the
// named binary, with arguments argv and environment envv.
// If successful, Exec never returns. If it fails, it returns an Error.
// StartProcess is almost always a better way to execute a program.
func Exec(name string, argv []string, envv []string) Error {
if envv == nil {
envv = Environ()
}
e := syscall.Exec(name, argv, envv)
if iserror(e) {
return &PathError{"exec", name, Errno(e)}
}
return nil
}
// TODO(rsc): Should os implement its own syscall.WaitStatus
// wrapper with the methods, or is exposing the underlying one enough?
//
// TODO(rsc): Certainly need to have Rusage struct,
// since syscall one might have different field types across
// different OS.
// Waitmsg stores the information about an exited process as reported by Wait.
type Waitmsg struct {
Pid int // The process's id.
syscall.WaitStatus // System-dependent status info.
Rusage *syscall.Rusage // System-dependent resource usage info.
}
// Wait waits for process pid to exit or stop, and then returns a
// Waitmsg describing its status and an Error, if any. The options
// (WNOHANG etc.) affect the behavior of the Wait call.
// Wait is equivalent to calling FindProcess and then Wait
// and Release on the result.
func Wait(pid int, options int) (w *Waitmsg, err Error) {
p, e := FindProcess(pid)
if e != nil {
return nil, e
}
defer p.Release()
return p.Wait(options)
}
// Convert i to decimal string.
func itod(i int) string {
if i == 0 {
return "0"
}
u := uint64(i)
if i < 0 {
u = -u
}
// Assemble decimal in reverse order.
var b [32]byte
bp := len(b)
for ; u > 0; u /= 10 {
bp--
b[bp] = byte(u%10) + '0'
}
if i < 0 {
bp--
b[bp] = '-'
}
return string(b[bp:])
}
func (w Waitmsg) String() string {
// TODO(austin) Use signal names when possible?
res := ""
switch {
case w.Exited():
res = "exit status " + itod(w.ExitStatus())
case w.Signaled():
res = "signal " + itod(w.Signal())
case w.Stopped():
res = "stop signal " + itod(w.StopSignal())
if w.StopSignal() == syscall.SIGTRAP && w.TrapCause() != 0 {
res += " (trap " + itod(w.TrapCause()) + ")"
}
case w.Continued():
res = "continued"
}
if w.CoreDump() {
res += " (core dumped)"
}
return res
}
...@@ -51,14 +51,20 @@ const ( ...@@ -51,14 +51,20 @@ const (
O_RDWR int = syscall.O_RDWR // open the file read-write. O_RDWR int = syscall.O_RDWR // open the file read-write.
O_APPEND int = syscall.O_APPEND // append data to the file when writing. O_APPEND int = syscall.O_APPEND // append data to the file when writing.
O_ASYNC int = syscall.O_ASYNC // generate a signal when I/O is available. O_ASYNC int = syscall.O_ASYNC // generate a signal when I/O is available.
O_CREAT int = syscall.O_CREAT // create a new file if none exists. O_CREATE int = syscall.O_CREAT // create a new file if none exists.
O_EXCL int = syscall.O_EXCL // used with O_CREAT, file must not exist O_EXCL int = syscall.O_EXCL // used with O_CREATE, file must not exist
O_NOCTTY int = syscall.O_NOCTTY // do not make file the controlling tty. O_NOCTTY int = syscall.O_NOCTTY // do not make file the controlling tty.
O_NONBLOCK int = syscall.O_NONBLOCK // open in non-blocking mode. O_NONBLOCK int = syscall.O_NONBLOCK // open in non-blocking mode.
O_NDELAY int = O_NONBLOCK // synonym for O_NONBLOCK O_NDELAY int = O_NONBLOCK // synonym for O_NONBLOCK
O_SYNC int = syscall.O_SYNC // open for synchronous I/O. O_SYNC int = syscall.O_SYNC // open for synchronous I/O.
O_TRUNC int = syscall.O_TRUNC // if possible, truncate file when opened. O_TRUNC int = syscall.O_TRUNC // if possible, truncate file when opened.
O_CREATE int = O_CREAT // create a new file if none exists. )
// Seek whence values.
const (
SEEK_SET int = 0 // seek relative to the origin of the file
SEEK_CUR int = 1 // seek relative to the current offset
SEEK_END int = 2 // seek relative to the end
) )
type eofError int type eofError int
...@@ -83,10 +89,10 @@ func (file *File) Read(b []byte) (n int, err Error) { ...@@ -83,10 +89,10 @@ func (file *File) Read(b []byte) (n int, err Error) {
if n < 0 { if n < 0 {
n = 0 n = 0
} }
if n == 0 && e == 0 { if n == 0 && !iserror(e) {
return 0, EOF return 0, EOF
} }
if e != 0 { if iserror(e) {
err = &PathError{"read", file.name, Errno(e)} err = &PathError{"read", file.name, Errno(e)}
} }
return n, err return n, err
...@@ -102,10 +108,10 @@ func (file *File) ReadAt(b []byte, off int64) (n int, err Error) { ...@@ -102,10 +108,10 @@ func (file *File) ReadAt(b []byte, off int64) (n int, err Error) {
} }
for len(b) > 0 { for len(b) > 0 {
m, e := syscall.Pread(file.fd, b, off) m, e := syscall.Pread(file.fd, b, off)
if m == 0 && e == 0 { if m == 0 && !iserror(e) {
return n, EOF return n, EOF
} }
if e != 0 { if iserror(e) {
err = &PathError{"read", file.name, Errno(e)} err = &PathError{"read", file.name, Errno(e)}
break break
} }
...@@ -127,15 +133,10 @@ func (file *File) Write(b []byte) (n int, err Error) { ...@@ -127,15 +133,10 @@ func (file *File) Write(b []byte) (n int, err Error) {
if n < 0 { if n < 0 {
n = 0 n = 0
} }
if e == syscall.EPIPE {
file.nepipe++ epipecheck(file, e)
if file.nepipe >= 10 {
Exit(syscall.EPIPE) if iserror(e) {
}
} else {
file.nepipe = 0
}
if e != 0 {
err = &PathError{"write", file.name, Errno(e)} err = &PathError{"write", file.name, Errno(e)}
} }
return n, err return n, err
...@@ -150,7 +151,7 @@ func (file *File) WriteAt(b []byte, off int64) (n int, err Error) { ...@@ -150,7 +151,7 @@ func (file *File) WriteAt(b []byte, off int64) (n int, err Error) {
} }
for len(b) > 0 { for len(b) > 0 {
m, e := syscall.Pwrite(file.fd, b, off) m, e := syscall.Pwrite(file.fd, b, off)
if e != 0 { if iserror(e) {
err = &PathError{"write", file.name, Errno(e)} err = &PathError{"write", file.name, Errno(e)}
break break
} }
...@@ -167,10 +168,10 @@ func (file *File) WriteAt(b []byte, off int64) (n int, err Error) { ...@@ -167,10 +168,10 @@ func (file *File) WriteAt(b []byte, off int64) (n int, err Error) {
// It returns the new offset and an Error, if any. // It returns the new offset and an Error, if any.
func (file *File) Seek(offset int64, whence int) (ret int64, err Error) { func (file *File) Seek(offset int64, whence int) (ret int64, err Error) {
r, e := syscall.Seek(file.fd, offset, whence) r, e := syscall.Seek(file.fd, offset, whence)
if e == 0 && file.dirinfo != nil && r != 0 { if !iserror(e) && file.dirinfo != nil && r != 0 {
e = syscall.EISDIR e = syscall.EISDIR
} }
if e != 0 { if iserror(e) {
return 0, &PathError{"seek", file.name, Errno(e)} return 0, &PathError{"seek", file.name, Errno(e)}
} }
return r, nil return r, nil
...@@ -187,71 +188,19 @@ func (file *File) WriteString(s string) (ret int, err Error) { ...@@ -187,71 +188,19 @@ func (file *File) WriteString(s string) (ret int, err Error) {
return file.Write(b) return file.Write(b)
} }
// Pipe returns a connected pair of Files; reads from r return bytes written to w.
// It returns the files and an Error, if any.
func Pipe() (r *File, w *File, err Error) {
var p [2]int
// See ../syscall/exec.go for description of lock.
syscall.ForkLock.RLock()
e := syscall.Pipe(p[0:])
if e != 0 {
syscall.ForkLock.RUnlock()
return nil, nil, NewSyscallError("pipe", e)
}
syscall.CloseOnExec(p[0])
syscall.CloseOnExec(p[1])
syscall.ForkLock.RUnlock()
return NewFile(p[0], "|0"), NewFile(p[1], "|1"), nil
}
// Mkdir creates a new directory with the specified name and permission bits. // Mkdir creates a new directory with the specified name and permission bits.
// It returns an error, if any. // It returns an error, if any.
func Mkdir(name string, perm uint32) Error { func Mkdir(name string, perm uint32) Error {
e := syscall.Mkdir(name, perm) e := syscall.Mkdir(name, perm)
if e != 0 { if iserror(e) {
return &PathError{"mkdir", name, Errno(e)} return &PathError{"mkdir", name, Errno(e)}
} }
return nil return nil
} }
// Stat returns a FileInfo structure describing the named file and an error, if any.
// If name names a valid symbolic link, the returned FileInfo describes
// the file pointed at by the link and has fi.FollowedSymlink set to true.
// If name names an invalid symbolic link, the returned FileInfo describes
// the link itself and has fi.FollowedSymlink set to false.
func Stat(name string) (fi *FileInfo, err Error) {
var lstat, stat syscall.Stat_t
e := syscall.Lstat(name, &lstat)
if e != 0 {
return nil, &PathError{"stat", name, Errno(e)}
}
statp := &lstat
if lstat.Mode&syscall.S_IFMT == syscall.S_IFLNK {
e := syscall.Stat(name, &stat)
if e == 0 {
statp = &stat
}
}
return fileInfoFromStat(name, new(FileInfo), &lstat, statp), nil
}
// Lstat returns the FileInfo structure describing the named file and an
// error, if any. If the file is a symbolic link, the returned FileInfo
// describes the symbolic link. Lstat makes no attempt to follow the link.
func Lstat(name string) (fi *FileInfo, err Error) {
var stat syscall.Stat_t
e := syscall.Lstat(name, &stat)
if e != 0 {
return nil, &PathError{"lstat", name, Errno(e)}
}
return fileInfoFromStat(name, new(FileInfo), &stat, &stat), nil
}
// Chdir changes the current working directory to the named directory. // Chdir changes the current working directory to the named directory.
func Chdir(dir string) Error { func Chdir(dir string) Error {
if e := syscall.Chdir(dir); e != 0 { if e := syscall.Chdir(dir); iserror(e) {
return &PathError{"chdir", dir, Errno(e)} return &PathError{"chdir", dir, Errno(e)}
} }
return nil return nil
...@@ -260,179 +209,25 @@ func Chdir(dir string) Error { ...@@ -260,179 +209,25 @@ func Chdir(dir string) Error {
// Chdir changes the current working directory to the file, // Chdir changes the current working directory to the file,
// which must be a directory. // which must be a directory.
func (f *File) Chdir() Error { func (f *File) Chdir() Error {
if e := syscall.Fchdir(f.fd); e != 0 { if e := syscall.Fchdir(f.fd); iserror(e) {
return &PathError{"chdir", f.name, Errno(e)} return &PathError{"chdir", f.name, Errno(e)}
} }
return nil return nil
} }
// Remove removes the named file or directory. // Open opens the named file for reading. If successful, methods on
func Remove(name string) Error { // the returned file can be used for reading; the associated file
// System call interface forces us to know // descriptor has mode O_RDONLY.
// whether name is a file or directory. // It returns the File and an Error, if any.
// Try both: it is cheaper on average than func Open(name string) (file *File, err Error) {
// doing a Stat plus the right one. return OpenFile(name, O_RDONLY, 0)
e := syscall.Unlink(name)
if e == 0 {
return nil
}
e1 := syscall.Rmdir(name)
if e1 == 0 {
return nil
}
// Both failed: figure out which error to return.
// OS X and Linux differ on whether unlink(dir)
// returns EISDIR, so can't use that. However,
// both agree that rmdir(file) returns ENOTDIR,
// so we can use that to decide which error is real.
// Rmdir might also return ENOTDIR if given a bad
// file path, like /etc/passwd/foo, but in that case,
// both errors will be ENOTDIR, so it's okay to
// use the error from unlink.
// For windows syscall.ENOTDIR is set
// to syscall.ERROR_DIRECTORY, hopefully it should
// do the trick.
if e1 != syscall.ENOTDIR {
e = e1
}
return &PathError{"remove", name, Errno(e)}
}
// LinkError records an error during a link or symlink or rename
// system call and the paths that caused it.
type LinkError struct {
Op string
Old string
New string
Error Error
}
func (e *LinkError) String() string {
return e.Op + " " + e.Old + " " + e.New + ": " + e.Error.String()
} }
// Link creates a hard link. // Create creates the named file mode 0666 (before umask), truncating
func Link(oldname, newname string) Error { // it if it already exists. If successful, methods on the returned
e := syscall.Link(oldname, newname) // File can be used for I/O; the associated file descriptor has mode
if e != 0 { // O_RDWR.
return &LinkError{"link", oldname, newname, Errno(e)} // It returns the File and an Error, if any.
} func Create(name string) (file *File, err Error) {
return nil return OpenFile(name, O_RDWR|O_CREATE|O_TRUNC, 0666)
}
// Symlink creates a symbolic link.
func Symlink(oldname, newname string) Error {
e := syscall.Symlink(oldname, newname)
if e != 0 {
return &LinkError{"symlink", oldname, newname, Errno(e)}
}
return nil
}
// Readlink reads the contents of a symbolic link: the destination of
// the link. It returns the contents and an Error, if any.
func Readlink(name string) (string, Error) {
for len := 128; ; len *= 2 {
b := make([]byte, len)
n, e := syscall.Readlink(name, b)
if e != 0 {
return "", &PathError{"readlink", name, Errno(e)}
}
if n < len {
return string(b[0:n]), nil
}
}
// Silence 6g.
return "", nil
}
// Rename renames a file.
func Rename(oldname, newname string) Error {
e := syscall.Rename(oldname, newname)
if e != 0 {
return &LinkError{"rename", oldname, newname, Errno(e)}
}
return nil
}
// Chmod changes the mode of the named file to mode.
// If the file is a symbolic link, it changes the mode of the link's target.
func Chmod(name string, mode uint32) Error {
if e := syscall.Chmod(name, mode); e != 0 {
return &PathError{"chmod", name, Errno(e)}
}
return nil
}
// Chmod changes the mode of the file to mode.
func (f *File) Chmod(mode uint32) Error {
if e := syscall.Fchmod(f.fd, mode); e != 0 {
return &PathError{"chmod", f.name, Errno(e)}
}
return nil
}
// Chown changes the numeric uid and gid of the named file.
// If the file is a symbolic link, it changes the uid and gid of the link's target.
func Chown(name string, uid, gid int) Error {
if e := syscall.Chown(name, uid, gid); e != 0 {
return &PathError{"chown", name, Errno(e)}
}
return nil
}
// Lchown changes the numeric uid and gid of the named file.
// If the file is a symbolic link, it changes the uid and gid of the link itself.
func Lchown(name string, uid, gid int) Error {
if e := syscall.Lchown(name, uid, gid); e != 0 {
return &PathError{"lchown", name, Errno(e)}
}
return nil
}
// Chown changes the numeric uid and gid of the named file.
func (f *File) Chown(uid, gid int) Error {
if e := syscall.Fchown(f.fd, uid, gid); e != 0 {
return &PathError{"chown", f.name, Errno(e)}
}
return nil
}
// Truncate changes the size of the file.
// It does not change the I/O offset.
func (f *File) Truncate(size int64) Error {
if e := syscall.Ftruncate(f.fd, size); e != 0 {
return &PathError{"truncate", f.name, Errno(e)}
}
return nil
}
// Sync commits the current contents of the file to stable storage.
// Typically, this means flushing the file system's in-memory copy
// of recently written data to disk.
func (file *File) Sync() (err Error) {
if file == nil {
return EINVAL
}
if e := syscall.Fsync(file.fd); e != 0 {
return NewSyscallError("fsync", e)
}
return nil
}
// Chtimes changes the access and modification times of the named
// file, similar to the Unix utime() or utimes() functions.
//
// The argument times are in nanoseconds, although the underlying
// filesystem may truncate or round the values to a more
// coarse time unit.
func Chtimes(name string, atime_ns int64, mtime_ns int64) Error {
var utimes [2]syscall.Timeval
utimes[0] = syscall.NsecToTimeval(atime_ns)
utimes[1] = syscall.NsecToTimeval(mtime_ns)
if e := syscall.Utimes(name, utimes[0:]); e != 0 {
return &PathError{"chtimes", name, Errno(e)}
}
return nil
} }
// Copyright 2011 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 os
import (
"runtime"
"syscall"
)
func epipecheck(file *File, e syscall.Error) {
}
// DevNull is the name of the operating system's ``null device.''
// On Unix-like systems, it is "/dev/null"; on Windows, "NUL".
const DevNull = "/dev/null"
// OpenFile is the generalized open call; most users will use Open
// or Create instead. It opens the named file with specified flag
// (O_RDONLY etc.) and perm, (0666 etc.) if applicable. If successful,
// methods on the returned File can be used for I/O.
// It returns the File and an Error, if any.
func OpenFile(name string, flag int, perm uint32) (file *File, err Error) {
var fd int
var e syscall.Error
syscall.ForkLock.RLock()
if flag&O_CREATE == O_CREATE {
fd, e = syscall.Create(name, flag & ^O_CREATE, perm)
} else {
fd, e = syscall.Open(name, flag)
}
syscall.ForkLock.RUnlock()
if e != nil {
return nil, &PathError{"open", name, e}
}
return NewFile(fd, name), nil
}
// Close closes the File, rendering it unusable for I/O.
// It returns an Error, if any.
func (file *File) Close() Error {
if file == nil || file.fd < 0 {
return Ebadfd
}
var err Error
syscall.ForkLock.RLock()
if e := syscall.Close(file.fd); e != nil {
err = &PathError{"close", file.name, e}
}
syscall.ForkLock.RUnlock()
file.fd = -1 // so it can't be closed again
// no need for a finalizer anymore
runtime.SetFinalizer(file, nil)
return err
}
// Stat returns the FileInfo structure describing file.
// It returns the FileInfo and an error, if any.
func (file *File) Stat() (fi *FileInfo, err Error) {
return dirstat(file)
}
// Truncate changes the size of the file.
// It does not change the I/O offset.
func (f *File) Truncate(size int64) Error {
var d Dir
d.Null()
d.Length = uint64(size)
if e := syscall.Fwstat(f.fd, pdir(nil, &d)); iserror(e) {
return &PathError{"truncate", f.name, e}
}
return nil
}
// Chmod changes the mode of the file to mode.
func (f *File) Chmod(mode uint32) Error {
var d Dir
d.Null()
d.Mode = mode & 0777
if e := syscall.Fwstat(f.fd, pdir(nil, &d)); iserror(e) {
return &PathError{"chmod", f.name, e}
}
return nil
}
// Sync commits the current contents of the file to stable storage.
// Typically, this means flushing the file system's in-memory copy
// of recently written data to disk.
func (f *File) Sync() (err Error) {
if f == nil {
return EINVAL
}
var d Dir
d.Null()
if e := syscall.Fwstat(f.fd, pdir(nil, &d)); iserror(e) {
return NewSyscallError("fsync", e)
}
return nil
}
// Truncate changes the size of the named file.
// If the file is a symbolic link, it changes the size of the link's target.
func Truncate(name string, size int64) Error {
var d Dir
d.Null()
d.Length = uint64(size)
if e := syscall.Wstat(name, pdir(nil, &d)); iserror(e) {
return &PathError{"truncate", name, e}
}
return nil
}
// Remove removes the named file or directory.
func Remove(name string) Error {
if e := syscall.Remove(name); iserror(e) {
return &PathError{"remove", name, e}
}
return nil
}
// Rename renames a file.
func Rename(oldname, newname string) Error {
var d Dir
d.Null()
d.Name = newname
if e := syscall.Wstat(oldname, pdir(nil, &d)); iserror(e) {
return &PathError{"rename", oldname, e}
}
return nil
}
// Chmod changes the mode of the named file to mode.
func Chmod(name string, mode uint32) Error {
var d Dir
d.Null()
d.Mode = mode & 0777
if e := syscall.Wstat(name, pdir(nil, &d)); iserror(e) {
return &PathError{"chmod", name, e}
}
return nil
}
// ChownPlan9 changes the uid and gid strings of the named file.
func ChownPlan9(name, uid, gid string) Error {
var d Dir
d.Null()
d.Uid = uid
d.Gid = gid
if e := syscall.Wstat(name, pdir(nil, &d)); iserror(e) {
return &PathError{"chown_plan9", name, e}
}
return nil
}
// Chtimes changes the access and modification times of the named
// file, similar to the Unix utime() or utimes() functions.
//
// The argument times are in nanoseconds, although the underlying
// filesystem may truncate or round the values to a more
// coarse time unit.
func Chtimes(name string, atimeNs int64, mtimeNs int64) Error {
var d Dir
d.Null()
d.Atime = uint32(atimeNs / 1e9)
d.Mtime = uint32(mtimeNs / 1e9)
if e := syscall.Wstat(name, pdir(nil, &d)); iserror(e) {
return &PathError{"chtimes", name, e}
}
return nil
}
func Pipe() (r *File, w *File, err Error) {
var p [2]int
syscall.ForkLock.RLock()
if e := syscall.Pipe(p[0:]); iserror(e) {
syscall.ForkLock.RUnlock()
return nil, nil, NewSyscallError("pipe", e)
}
syscall.ForkLock.RUnlock()
return NewFile(p[0], "|0"), NewFile(p[1], "|1"), nil
}
// not supported on Plan 9
// Link creates a hard link.
func Link(oldname, newname string) Error {
return EPLAN9
}
func Symlink(oldname, newname string) Error {
return EPLAN9
}
func Readlink(name string) (string, Error) {
return "", EPLAN9
}
func Chown(name string, uid, gid int) Error {
return EPLAN9
}
func Lchown(name string, uid, gid int) Error {
return EPLAN9
}
func (f *File) Chown(uid, gid int) Error {
return EPLAN9
}
// 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.
// The os package provides a platform-independent interface to operating
// system functionality. The design is Unix-like.
package os
import (
"syscall"
)
func epipecheck(file *File, e int) {
if e == syscall.EPIPE {
file.nepipe++
if file.nepipe >= 10 {
Exit(syscall.EPIPE)
}
} else {
file.nepipe = 0
}
}
// Pipe returns a connected pair of Files; reads from r return bytes written to w.
// It returns the files and an Error, if any.
func Pipe() (r *File, w *File, err Error) {
var p [2]int
// See ../syscall/exec.go for description of lock.
syscall.ForkLock.RLock()
e := syscall.Pipe(p[0:])
if iserror(e) {
syscall.ForkLock.RUnlock()
return nil, nil, NewSyscallError("pipe", e)
}
syscall.CloseOnExec(p[0])
syscall.CloseOnExec(p[1])
syscall.ForkLock.RUnlock()
return NewFile(p[0], "|0"), NewFile(p[1], "|1"), nil
}
// Stat returns a FileInfo structure describing the named file and an error, if any.
// If name names a valid symbolic link, the returned FileInfo describes
// the file pointed at by the link and has fi.FollowedSymlink set to true.
// If name names an invalid symbolic link, the returned FileInfo describes
// the link itself and has fi.FollowedSymlink set to false.
func Stat(name string) (fi *FileInfo, err Error) {
var lstat, stat syscall.Stat_t
e := syscall.Lstat(name, &lstat)
if iserror(e) {
return nil, &PathError{"stat", name, Errno(e)}
}
statp := &lstat
if lstat.Mode&syscall.S_IFMT == syscall.S_IFLNK {
e := syscall.Stat(name, &stat)
if !iserror(e) {
statp = &stat
}
}
return fileInfoFromStat(name, new(FileInfo), &lstat, statp), nil
}
// Lstat returns the FileInfo structure describing the named file and an
// error, if any. If the file is a symbolic link, the returned FileInfo
// describes the symbolic link. Lstat makes no attempt to follow the link.
func Lstat(name string) (fi *FileInfo, err Error) {
var stat syscall.Stat_t
e := syscall.Lstat(name, &stat)
if iserror(e) {
return nil, &PathError{"lstat", name, Errno(e)}
}
return fileInfoFromStat(name, new(FileInfo), &stat, &stat), nil
}
// Remove removes the named file or directory.
func Remove(name string) Error {
// System call interface forces us to know
// whether name is a file or directory.
// Try both: it is cheaper on average than
// doing a Stat plus the right one.
e := syscall.Unlink(name)
if !iserror(e) {
return nil
}
e1 := syscall.Rmdir(name)
if !iserror(e1) {
return nil
}
// Both failed: figure out which error to return.
// OS X and Linux differ on whether unlink(dir)
// returns EISDIR, so can't use that. However,
// both agree that rmdir(file) returns ENOTDIR,
// so we can use that to decide which error is real.
// Rmdir might also return ENOTDIR if given a bad
// file path, like /etc/passwd/foo, but in that case,
// both errors will be ENOTDIR, so it's okay to
// use the error from unlink.
// For windows syscall.ENOTDIR is set
// to syscall.ERROR_DIRECTORY, hopefully it should
// do the trick.
if e1 != syscall.ENOTDIR {
e = e1
}
return &PathError{"remove", name, Errno(e)}
}
// LinkError records an error during a link or symlink or rename
// system call and the paths that caused it.
type LinkError struct {
Op string
Old string
New string
Error Error
}
func (e *LinkError) String() string {
return e.Op + " " + e.Old + " " + e.New + ": " + e.Error.String()
}
// Link creates a hard link.
func Link(oldname, newname string) Error {
e := syscall.Link(oldname, newname)
if iserror(e) {
return &LinkError{"link", oldname, newname, Errno(e)}
}
return nil
}
// Symlink creates a symbolic link.
func Symlink(oldname, newname string) Error {
e := syscall.Symlink(oldname, newname)
if iserror(e) {
return &LinkError{"symlink", oldname, newname, Errno(e)}
}
return nil
}
// Readlink reads the contents of a symbolic link: the destination of
// the link. It returns the contents and an Error, if any.
func Readlink(name string) (string, Error) {
for len := 128; ; len *= 2 {
b := make([]byte, len)
n, e := syscall.Readlink(name, b)
if iserror(e) {
return "", &PathError{"readlink", name, Errno(e)}
}
if n < len {
return string(b[0:n]), nil
}
}
// Silence 6g.
return "", nil
}
// Rename renames a file.
func Rename(oldname, newname string) Error {
e := syscall.Rename(oldname, newname)
if iserror(e) {
return &LinkError{"rename", oldname, newname, Errno(e)}
}
return nil
}
// Chmod changes the mode of the named file to mode.
// If the file is a symbolic link, it changes the mode of the link's target.
func Chmod(name string, mode uint32) Error {
if e := syscall.Chmod(name, mode); iserror(e) {
return &PathError{"chmod", name, Errno(e)}
}
return nil
}
// Chmod changes the mode of the file to mode.
func (f *File) Chmod(mode uint32) Error {
if e := syscall.Fchmod(f.fd, mode); iserror(e) {
return &PathError{"chmod", f.name, Errno(e)}
}
return nil
}
// Chown changes the numeric uid and gid of the named file.
// If the file is a symbolic link, it changes the uid and gid of the link's target.
func Chown(name string, uid, gid int) Error {
if e := syscall.Chown(name, uid, gid); iserror(e) {
return &PathError{"chown", name, Errno(e)}
}
return nil
}
// Lchown changes the numeric uid and gid of the named file.
// If the file is a symbolic link, it changes the uid and gid of the link itself.
func Lchown(name string, uid, gid int) Error {
if e := syscall.Lchown(name, uid, gid); iserror(e) {
return &PathError{"lchown", name, Errno(e)}
}
return nil
}
// Chown changes the numeric uid and gid of the named file.
func (f *File) Chown(uid, gid int) Error {
if e := syscall.Fchown(f.fd, uid, gid); iserror(e) {
return &PathError{"chown", f.name, Errno(e)}
}
return nil
}
// Truncate changes the size of the file.
// It does not change the I/O offset.
func (f *File) Truncate(size int64) Error {
if e := syscall.Ftruncate(f.fd, size); iserror(e) {
return &PathError{"truncate", f.name, Errno(e)}
}
return nil
}
// Sync commits the current contents of the file to stable storage.
// Typically, this means flushing the file system's in-memory copy
// of recently written data to disk.
func (file *File) Sync() (err Error) {
if file == nil {
return EINVAL
}
if e := syscall.Fsync(file.fd); iserror(e) {
return NewSyscallError("fsync", e)
}
return nil
}
// Chtimes changes the access and modification times of the named
// file, similar to the Unix utime() or utimes() functions.
//
// The argument times are in nanoseconds, although the underlying
// filesystem may truncate or round the values to a more
// coarse time unit.
func Chtimes(name string, atime_ns int64, mtime_ns int64) Error {
var utimes [2]syscall.Timeval
utimes[0] = syscall.NsecToTimeval(atime_ns)
utimes[1] = syscall.NsecToTimeval(mtime_ns)
if e := syscall.Utimes(name, utimes[0:]); iserror(e) {
return &PathError{"chtimes", name, Errno(e)}
}
return nil
}
...@@ -19,10 +19,12 @@ type dirInfo struct { ...@@ -19,10 +19,12 @@ type dirInfo struct {
// On Unix-like systems, it is "/dev/null"; on Windows, "NUL". // On Unix-like systems, it is "/dev/null"; on Windows, "NUL".
const DevNull = "/dev/null" const DevNull = "/dev/null"
// Open opens the named file with specified flag (O_RDONLY etc.) and perm, (0666 etc.) // OpenFile is the generalized open call; most users will use Open
// if applicable. If successful, methods on the returned File can be used for I/O. // or Create instead. It opens the named file with specified flag
// (O_RDONLY etc.) and perm, (0666 etc.) if applicable. If successful,
// methods on the returned File can be used for I/O.
// It returns the File and an Error, if any. // It returns the File and an Error, if any.
func Open(name string, flag int, perm uint32) (file *File, err Error) { func OpenFile(name string, flag int, perm uint32) (file *File, err Error) {
r, e := syscall.Open(name, flag|syscall.O_CLOEXEC, perm) r, e := syscall.Open(name, flag|syscall.O_CLOEXEC, perm)
if e != 0 { if e != 0 {
return nil, &PathError{"open", name, Errno(e)} return nil, &PathError{"open", name, Errno(e)}
......
...@@ -54,7 +54,7 @@ func Getwd() (string, Error) { ...@@ -54,7 +54,7 @@ func Getwd() (string, Error) {
if len(parent) >= 1024 { // Sanity check if len(parent) >= 1024 { // Sanity check
return "", ENAMETOOLONG return "", ENAMETOOLONG
} }
fd, err := Open(parent, O_RDONLY, 0) fd, err := Open(parent)
if err != nil { if err != nil {
return "", err return "", err
} }
......
...@@ -51,7 +51,7 @@ func TestInotifyEvents(t *testing.T) { ...@@ -51,7 +51,7 @@ func TestInotifyEvents(t *testing.T) {
// Create a file // Create a file
// This should add at least one event to the inotify event queue // This should add at least one event to the inotify event queue
_, err = os.Open(testFile, os.O_WRONLY|os.O_CREAT, 0666) _, err = os.OpenFile(testFile, os.O_WRONLY|os.O_CREATE, 0666)
if err != nil { if err != nil {
t.Fatalf("creating test file failed: %s", err) t.Fatalf("creating test file failed: %s", err)
} }
......
...@@ -17,6 +17,7 @@ import ( ...@@ -17,6 +17,7 @@ import (
) )
var dot = []string{ var dot = []string{
"dir_unix.go",
"env_unix.go", "env_unix.go",
"error.go", "error.go",
"file.go", "file.go",
...@@ -56,7 +57,7 @@ var sysdir = func() (sd *sysDir) { ...@@ -56,7 +57,7 @@ var sysdir = func() (sd *sysDir) {
}() }()
func size(name string, t *testing.T) int64 { func size(name string, t *testing.T) int64 {
file, err := Open(name, O_RDONLY, 0) file, err := Open(name)
defer file.Close() defer file.Close()
if err != nil { if err != nil {
t.Fatal("open failed:", err) t.Fatal("open failed:", err)
...@@ -121,7 +122,7 @@ func TestStat(t *testing.T) { ...@@ -121,7 +122,7 @@ func TestStat(t *testing.T) {
func TestFstat(t *testing.T) { func TestFstat(t *testing.T) {
path := sfdir + "/" + sfname path := sfdir + "/" + sfname
file, err1 := Open(path, O_RDONLY, 0) file, err1 := Open(path)
defer file.Close() defer file.Close()
if err1 != nil { if err1 != nil {
t.Fatal("open failed:", err1) t.Fatal("open failed:", err1)
...@@ -155,7 +156,7 @@ func TestLstat(t *testing.T) { ...@@ -155,7 +156,7 @@ func TestLstat(t *testing.T) {
} }
func testReaddirnames(dir string, contents []string, t *testing.T) { func testReaddirnames(dir string, contents []string, t *testing.T) {
file, err := Open(dir, O_RDONLY, 0) file, err := Open(dir)
defer file.Close() defer file.Close()
if err != nil { if err != nil {
t.Fatalf("open %q failed: %v", dir, err) t.Fatalf("open %q failed: %v", dir, err)
...@@ -184,7 +185,7 @@ func testReaddirnames(dir string, contents []string, t *testing.T) { ...@@ -184,7 +185,7 @@ func testReaddirnames(dir string, contents []string, t *testing.T) {
} }
func testReaddir(dir string, contents []string, t *testing.T) { func testReaddir(dir string, contents []string, t *testing.T) {
file, err := Open(dir, O_RDONLY, 0) file, err := Open(dir)
defer file.Close() defer file.Close()
if err != nil { if err != nil {
t.Fatalf("open %q failed: %v", dir, err) t.Fatalf("open %q failed: %v", dir, err)
...@@ -245,7 +246,7 @@ func TestReaddirnamesOneAtATime(t *testing.T) { ...@@ -245,7 +246,7 @@ func TestReaddirnamesOneAtATime(t *testing.T) {
if syscall.OS == "windows" { if syscall.OS == "windows" {
dir = Getenv("SystemRoot") + "\\system32" dir = Getenv("SystemRoot") + "\\system32"
} }
file, err := Open(dir, O_RDONLY, 0) file, err := Open(dir)
defer file.Close() defer file.Close()
if err != nil { if err != nil {
t.Fatalf("open %q failed: %v", dir, err) t.Fatalf("open %q failed: %v", dir, err)
...@@ -254,7 +255,7 @@ func TestReaddirnamesOneAtATime(t *testing.T) { ...@@ -254,7 +255,7 @@ func TestReaddirnamesOneAtATime(t *testing.T) {
if err1 != nil { if err1 != nil {
t.Fatalf("readdirnames %q failed: %v", dir, err1) t.Fatalf("readdirnames %q failed: %v", dir, err1)
} }
file1, err2 := Open(dir, O_RDONLY, 0) file1, err2 := Open(dir)
if err2 != nil { if err2 != nil {
t.Fatalf("open %q failed: %v", dir, err2) t.Fatalf("open %q failed: %v", dir, err2)
} }
...@@ -273,7 +274,7 @@ func TestHardLink(t *testing.T) { ...@@ -273,7 +274,7 @@ func TestHardLink(t *testing.T) {
} }
from, to := "hardlinktestfrom", "hardlinktestto" from, to := "hardlinktestfrom", "hardlinktestto"
Remove(from) // Just in case. Remove(from) // Just in case.
file, err := Open(to, O_CREAT|O_WRONLY, 0666) file, err := Create(to)
if err != nil { if err != nil {
t.Fatalf("open %q failed: %v", to, err) t.Fatalf("open %q failed: %v", to, err)
} }
...@@ -306,7 +307,7 @@ func TestSymLink(t *testing.T) { ...@@ -306,7 +307,7 @@ func TestSymLink(t *testing.T) {
} }
from, to := "symlinktestfrom", "symlinktestto" from, to := "symlinktestfrom", "symlinktestto"
Remove(from) // Just in case. Remove(from) // Just in case.
file, err := Open(to, O_CREAT|O_WRONLY, 0666) file, err := Create(to)
if err != nil { if err != nil {
t.Fatalf("open %q failed: %v", to, err) t.Fatalf("open %q failed: %v", to, err)
} }
...@@ -354,7 +355,7 @@ func TestSymLink(t *testing.T) { ...@@ -354,7 +355,7 @@ func TestSymLink(t *testing.T) {
if s != to { if s != to {
t.Fatalf("after symlink %q != %q", s, to) t.Fatalf("after symlink %q != %q", s, to)
} }
file, err = Open(from, O_RDONLY, 0) file, err = Open(from)
if err != nil { if err != nil {
t.Fatalf("open %q failed: %v", from, err) t.Fatalf("open %q failed: %v", from, err)
} }
...@@ -388,7 +389,7 @@ func TestLongSymlink(t *testing.T) { ...@@ -388,7 +389,7 @@ func TestLongSymlink(t *testing.T) {
func TestRename(t *testing.T) { func TestRename(t *testing.T) {
from, to := "renamefrom", "renameto" from, to := "renamefrom", "renameto"
Remove(to) // Just in case. Remove(to) // Just in case.
file, err := Open(from, O_CREAT|O_WRONLY, 0666) file, err := Create(from)
if err != nil { if err != nil {
t.Fatalf("open %q failed: %v", to, err) t.Fatalf("open %q failed: %v", to, err)
} }
...@@ -615,7 +616,7 @@ func TestChdirAndGetwd(t *testing.T) { ...@@ -615,7 +616,7 @@ func TestChdirAndGetwd(t *testing.T) {
if syscall.OS == "windows" { if syscall.OS == "windows" {
return return
} }
fd, err := Open(".", O_RDONLY, 0) fd, err := Open(".")
if err != nil { if err != nil {
t.Fatalf("Open .: %s", err) t.Fatalf("Open .: %s", err)
} }
...@@ -627,7 +628,7 @@ func TestChdirAndGetwd(t *testing.T) { ...@@ -627,7 +628,7 @@ func TestChdirAndGetwd(t *testing.T) {
if mode == 0 { if mode == 0 {
err = Chdir(d) err = Chdir(d)
} else { } else {
fd1, err := Open(d, O_RDONLY, 0) fd1, err := Open(d)
if err != nil { if err != nil {
t.Errorf("Open %s: %s", d, err) t.Errorf("Open %s: %s", d, err)
continue continue
...@@ -736,7 +737,7 @@ var openErrorTests = []openErrorTest{ ...@@ -736,7 +737,7 @@ var openErrorTests = []openErrorTest{
func TestOpenError(t *testing.T) { func TestOpenError(t *testing.T) {
for _, tt := range openErrorTests { for _, tt := range openErrorTests {
f, err := Open(tt.path, tt.mode, 0) f, err := OpenFile(tt.path, tt.mode, 0)
if err == nil { if err == nil {
t.Errorf("Open(%q, %d) succeeded", tt.path, tt.mode) t.Errorf("Open(%q, %d) succeeded", tt.path, tt.mode)
f.Close() f.Close()
...@@ -842,7 +843,7 @@ func TestWriteAt(t *testing.T) { ...@@ -842,7 +843,7 @@ func TestWriteAt(t *testing.T) {
} }
func writeFile(t *testing.T, fname string, flag int, text string) string { func writeFile(t *testing.T, fname string, flag int, text string) string {
f, err := Open(fname, flag, 0666) f, err := OpenFile(fname, flag, 0666)
if err != nil { if err != nil {
t.Fatalf("Open: %v", err) t.Fatalf("Open: %v", err)
} }
...@@ -861,7 +862,7 @@ func writeFile(t *testing.T, fname string, flag int, text string) string { ...@@ -861,7 +862,7 @@ func writeFile(t *testing.T, fname string, flag int, text string) string {
func TestAppend(t *testing.T) { func TestAppend(t *testing.T) {
const f = "append.txt" const f = "append.txt"
defer Remove(f) defer Remove(f)
s := writeFile(t, f, O_CREAT|O_TRUNC|O_RDWR, "new") s := writeFile(t, f, O_CREATE|O_TRUNC|O_RDWR, "new")
if s != "new" { if s != "new" {
t.Fatalf("writeFile: have %q want %q", s, "new") t.Fatalf("writeFile: have %q want %q", s, "new")
} }
......
...@@ -33,7 +33,7 @@ func MkdirAll(path string, perm uint32) Error { ...@@ -33,7 +33,7 @@ func MkdirAll(path string, perm uint32) Error {
j-- j--
} }
if j > 0 { if j > 1 {
// Create parent // Create parent
err = MkdirAll(path[0:j-1], perm) err = MkdirAll(path[0:j-1], perm)
if err != nil { if err != nil {
...@@ -80,7 +80,7 @@ func RemoveAll(path string) Error { ...@@ -80,7 +80,7 @@ func RemoveAll(path string) Error {
} }
// Directory. // Directory.
fd, err := Open(path, O_RDONLY, 0) fd, err := Open(path)
if err != nil { if err != nil {
return err return err
} }
......
...@@ -29,7 +29,7 @@ func TestMkdirAll(t *testing.T) { ...@@ -29,7 +29,7 @@ func TestMkdirAll(t *testing.T) {
// Make file. // Make file.
fpath := path + "/file" fpath := path + "/file"
_, err = Open(fpath, O_WRONLY|O_CREAT, 0666) _, err = Create(fpath)
if err != nil { if err != nil {
t.Fatalf("create %q: %s", fpath, err) t.Fatalf("create %q: %s", fpath, err)
} }
...@@ -72,7 +72,7 @@ func TestRemoveAll(t *testing.T) { ...@@ -72,7 +72,7 @@ func TestRemoveAll(t *testing.T) {
if err := MkdirAll(path, 0777); err != nil { if err := MkdirAll(path, 0777); err != nil {
t.Fatalf("MkdirAll %q: %s", path, err) t.Fatalf("MkdirAll %q: %s", path, err)
} }
fd, err := Open(fpath, O_WRONLY|O_CREAT, 0666) fd, err := Create(fpath)
if err != nil { if err != nil {
t.Fatalf("create %q: %s", fpath, err) t.Fatalf("create %q: %s", fpath, err)
} }
...@@ -88,12 +88,12 @@ func TestRemoveAll(t *testing.T) { ...@@ -88,12 +88,12 @@ func TestRemoveAll(t *testing.T) {
if err = MkdirAll(dpath, 0777); err != nil { if err = MkdirAll(dpath, 0777); err != nil {
t.Fatalf("MkdirAll %q: %s", dpath, err) t.Fatalf("MkdirAll %q: %s", dpath, err)
} }
fd, err = Open(fpath, O_WRONLY|O_CREAT, 0666) fd, err = Create(fpath)
if err != nil { if err != nil {
t.Fatalf("create %q: %s", fpath, err) t.Fatalf("create %q: %s", fpath, err)
} }
fd.Close() fd.Close()
fd, err = Open(dpath+"/file", O_WRONLY|O_CREAT, 0666) fd, err = Create(dpath + "/file")
if err != nil { if err != nil {
t.Fatalf("create %q: %s", fpath, err) t.Fatalf("create %q: %s", fpath, err)
} }
...@@ -121,7 +121,7 @@ func TestRemoveAll(t *testing.T) { ...@@ -121,7 +121,7 @@ func TestRemoveAll(t *testing.T) {
} }
for _, s := range []string{fpath, dpath + "/file1", path + "/zzz"} { for _, s := range []string{fpath, dpath + "/file1", path + "/zzz"} {
fd, err = Open(s, O_WRONLY|O_CREAT, 0666) fd, err = Create(s)
if err != nil { if err != nil {
t.Fatalf("create %q: %s", s, err) t.Fatalf("create %q: %s", s, err)
} }
...@@ -179,3 +179,20 @@ func TestMkdirAllWithSymlink(t *testing.T) { ...@@ -179,3 +179,20 @@ func TestMkdirAllWithSymlink(t *testing.T) {
t.Errorf("MkdirAll %q: %s", path, err) t.Errorf("MkdirAll %q: %s", path, err)
} }
} }
func TestMkdirAllAtSlash(t *testing.T) {
if runtime.GOOS == "windows" {
return
}
RemoveAll("/_go_os_test")
err := MkdirAll("/_go_os_test/dir", 0777)
if err != nil {
pathErr, ok := err.(*PathError)
// common for users not to be able to write to /
if ok && pathErr.Error == EACCES {
return
}
t.Fatalf(`MkdirAll "/_go_os_test/dir": %v`, err)
}
RemoveAll("/_go_os_test")
}
...@@ -26,8 +26,8 @@ func Getegid() int { return syscall.Getegid() } ...@@ -26,8 +26,8 @@ func Getegid() int { return syscall.Getegid() }
// Getgroups returns a list of the numeric ids of groups that the caller belongs to. // Getgroups returns a list of the numeric ids of groups that the caller belongs to.
func Getgroups() ([]int, Error) { func Getgroups() ([]int, Error) {
gids, errno := syscall.Getgroups() gids, e := syscall.Getgroups()
return gids, NewSyscallError("getgroups", errno) return gids, NewSyscallError("getgroups", e)
} }
// Exit causes the current program to exit with the given status code. // Exit causes the current program to exit with the given status code.
......
// Copyright 2011 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 os
import "syscall"
func fileInfoFromStat(fi *FileInfo, d *Dir) *FileInfo {
fi.Dev = uint64(d.Qid.Vers) | uint64(d.Qid.Type<<32)
fi.Ino = d.Qid.Path
fi.Mode = uint32(d.Mode) & 0777
if (d.Mode & syscall.DMDIR) == syscall.DMDIR {
fi.Mode |= syscall.S_IFDIR
} else {
fi.Mode |= syscall.S_IFREG
}
fi.Size = int64(d.Length)
fi.Atime_ns = 1e9 * int64(d.Atime)
fi.Mtime_ns = 1e9 * int64(d.Mtime)
fi.Name = d.Name
fi.FollowedSymlink = false
return fi
}
// arg is an open *File or a path string.
func dirstat(arg interface{}) (fi *FileInfo, err Error) {
var name string
nd := syscall.STATFIXLEN + 16*4
for i := 0; i < 2; i++ { /* should work by the second try */
buf := make([]byte, nd)
var n int
var e syscall.Error
switch syscallArg := arg.(type) {
case *File:
name = syscallArg.name
n, e = syscall.Fstat(syscallArg.fd, buf)
case string:
name = syscallArg
n, e = syscall.Stat(name, buf)
}
if e != nil {
return nil, &PathError{"stat", name, e}
}
if n < syscall.STATFIXLEN {
return nil, &PathError{"stat", name, Eshortstat}
}
ntmp, _ := gbit16(buf)
nd = int(ntmp)
if nd <= n {
d, e := UnmarshalDir(buf[:n])
if e != nil {
return nil, &PathError{"stat", name, e}
}
return fileInfoFromStat(new(FileInfo), d), nil
}
}
return nil, &PathError{"stat", name, Ebadstat}
}
// Stat returns a FileInfo structure describing the named file and an error, if any.
func Stat(name string) (fi *FileInfo, err Error) {
return dirstat(name)
}
// Lstat returns the FileInfo structure describing the named file and an
// error, if any. If the file is a symbolic link (though Plan 9 does not have symbolic links),
// the returned FileInfo describes the symbolic link. Lstat makes no attempt to follow the link.
func Lstat(name string) (fi *FileInfo, err Error) {
return dirstat(name)
}
...@@ -9,7 +9,7 @@ package os ...@@ -9,7 +9,7 @@ package os
// Hostname returns the host name reported by the kernel. // Hostname returns the host name reported by the kernel.
func Hostname() (name string, err Error) { func Hostname() (name string, err Error) {
f, err := Open("/proc/sys/kernel/hostname", O_RDONLY, 0) f, err := Open("/proc/sys/kernel/hostname")
if err != nil { if err != nil {
return "", err return "", err
} }
......
// Copyright 2011 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.
// Plan 9-specific
package os
func Hostname() (name string, err Error) {
f, err := Open("#c/sysname")
if err != nil {
return "", err
}
defer f.Close()
var buf [128]byte
n, err := f.Read(buf[:len(buf)-1])
if err != nil {
return "", err
}
if n > 0 {
buf[n] = 0
}
return string(buf[0:n]), nil
}
...@@ -13,8 +13,8 @@ import "syscall" ...@@ -13,8 +13,8 @@ import "syscall"
// time is the Unix epoch. // time is the Unix epoch.
func Time() (sec int64, nsec int64, err Error) { func Time() (sec int64, nsec int64, err Error) {
var tv syscall.Timeval var tv syscall.Timeval
if errno := syscall.Gettimeofday(&tv); errno != 0 { if e := syscall.Gettimeofday(&tv); iserror(e) {
return 0, 0, NewSyscallError("gettimeofday", errno) return 0, 0, NewSyscallError("gettimeofday", e)
} }
return int64(tv.Sec), int64(tv.Usec) * 1000, err return int64(tv.Sec), int64(tv.Usec) * 1000, err
} }
...@@ -32,7 +32,7 @@ var ErrBadPattern = os.NewError("syntax error in pattern") ...@@ -32,7 +32,7 @@ var ErrBadPattern = os.NewError("syntax error in pattern")
// lo '-' hi matches character c for lo <= c <= hi // lo '-' hi matches character c for lo <= c <= hi
// //
// Match requires pattern to match all of name, not just a substring. // Match requires pattern to match all of name, not just a substring.
// The only possible error return is when pattern is malformed. // The only possible error return occurs when the pattern is malformed.
// //
func Match(pattern, name string) (matched bool, err os.Error) { func Match(pattern, name string) (matched bool, err os.Error) {
Pattern: Pattern:
...@@ -211,13 +211,14 @@ func getEsc(chunk string) (r int, nchunk string, err os.Error) { ...@@ -211,13 +211,14 @@ func getEsc(chunk string) (r int, nchunk string, err os.Error) {
// if there is no matching file. The syntax of patterns is the same // if there is no matching file. The syntax of patterns is the same
// as in Match. The pattern may describe hierarchical names such as // as in Match. The pattern may describe hierarchical names such as
// /usr/*/bin/ed (assuming the Separator is '/'). // /usr/*/bin/ed (assuming the Separator is '/').
// The only possible error return occurs when the pattern is malformed.
// //
func Glob(pattern string) (matches []string) { func Glob(pattern string) (matches []string, err os.Error) {
if !hasMeta(pattern) { if !hasMeta(pattern) {
if _, err := os.Stat(pattern); err == nil { if _, err = os.Stat(pattern); err != nil {
return []string{pattern} return
} }
return nil return []string{pattern}, nil
} }
dir, file := Split(pattern) dir, file := Split(pattern)
...@@ -230,48 +231,60 @@ func Glob(pattern string) (matches []string) { ...@@ -230,48 +231,60 @@ func Glob(pattern string) (matches []string) {
dir = dir[0 : len(dir)-1] // chop off trailing separator dir = dir[0 : len(dir)-1] // chop off trailing separator
} }
if hasMeta(dir) { if !hasMeta(dir) {
for _, d := range Glob(dir) {
matches = glob(d, file, matches)
}
} else {
return glob(dir, file, nil) return glob(dir, file, nil)
} }
return matches
var m []string
m, err = Glob(dir)
if err != nil {
return
}
for _, d := range m {
matches, err = glob(d, file, matches)
if err != nil {
return
}
}
return
} }
// glob searches for files matching pattern in the directory dir // glob searches for files matching pattern in the directory dir
// and appends them to matches. // and appends them to matches. If the directory cannot be
func glob(dir, pattern string, matches []string) []string { // opened, it returns the existing matches. New matches are
// added in lexicographical order.
// The only possible error return occurs when the pattern is malformed.
func glob(dir, pattern string, matches []string) (m []string, e os.Error) {
m = matches
fi, err := os.Stat(dir) fi, err := os.Stat(dir)
if err != nil { if err != nil {
return nil return
} }
if !fi.IsDirectory() { if !fi.IsDirectory() {
return matches return
} }
d, err := os.Open(dir, os.O_RDONLY, 0666) d, err := os.Open(dir)
if err != nil { if err != nil {
return nil return
} }
defer d.Close() defer d.Close()
names, err := d.Readdirnames(-1) names, err := d.Readdirnames(-1)
if err != nil { if err != nil {
return nil return
} }
sort.SortStrings(names) sort.SortStrings(names)
for _, n := range names { for _, n := range names {
matched, err := Match(pattern, n) matched, err := Match(pattern, n)
if err != nil { if err != nil {
return matches return m, err
} }
if matched { if matched {
matches = append(matches, Join(dir, n)) m = append(m, Join(dir, n))
} }
} }
return matches return
} }
// hasMeta returns true if path contains any of the magic characters // hasMeta returns true if path contains any of the magic characters
......
...@@ -6,7 +6,7 @@ package filepath_test ...@@ -6,7 +6,7 @@ package filepath_test
import ( import (
"os" "os"
"path/filepath" . "path/filepath"
"testing" "testing"
"runtime" "runtime"
) )
...@@ -56,16 +56,16 @@ var matchTests = []MatchTest{ ...@@ -56,16 +56,16 @@ var matchTests = []MatchTest{
{"[\\-x]", "x", true, nil}, {"[\\-x]", "x", true, nil},
{"[\\-x]", "-", true, nil}, {"[\\-x]", "-", true, nil},
{"[\\-x]", "a", false, nil}, {"[\\-x]", "a", false, nil},
{"[]a]", "]", false, filepath.ErrBadPattern}, {"[]a]", "]", false, ErrBadPattern},
{"[-]", "-", false, filepath.ErrBadPattern}, {"[-]", "-", false, ErrBadPattern},
{"[x-]", "x", false, filepath.ErrBadPattern}, {"[x-]", "x", false, ErrBadPattern},
{"[x-]", "-", false, filepath.ErrBadPattern}, {"[x-]", "-", false, ErrBadPattern},
{"[x-]", "z", false, filepath.ErrBadPattern}, {"[x-]", "z", false, ErrBadPattern},
{"[-x]", "x", false, filepath.ErrBadPattern}, {"[-x]", "x", false, ErrBadPattern},
{"[-x]", "-", false, filepath.ErrBadPattern}, {"[-x]", "-", false, ErrBadPattern},
{"[-x]", "a", false, filepath.ErrBadPattern}, {"[-x]", "a", false, ErrBadPattern},
{"\\", "a", false, filepath.ErrBadPattern}, {"\\", "a", false, ErrBadPattern},
{"[a-b-c]", "a", false, filepath.ErrBadPattern}, {"[a-b-c]", "a", false, ErrBadPattern},
{"*x", "xxx", true, nil}, {"*x", "xxx", true, nil},
} }
...@@ -75,7 +75,7 @@ func TestMatch(t *testing.T) { ...@@ -75,7 +75,7 @@ func TestMatch(t *testing.T) {
return return
} }
for _, tt := range matchTests { for _, tt := range matchTests {
ok, err := filepath.Match(tt.pattern, tt.s) ok, err := Match(tt.pattern, tt.s)
if ok != tt.match || err != tt.err { if ok != tt.match || err != tt.err {
t.Errorf("Match(%#q, %#q) = %v, %v want %v, nil", tt.pattern, tt.s, ok, err, tt.match) t.Errorf("Match(%#q, %#q) = %v, %v want %v, nil", tt.pattern, tt.s, ok, err, tt.match)
} }
...@@ -84,7 +84,7 @@ func TestMatch(t *testing.T) { ...@@ -84,7 +84,7 @@ func TestMatch(t *testing.T) {
// contains returns true if vector contains the string s. // contains returns true if vector contains the string s.
func contains(vector []string, s string) bool { func contains(vector []string, s string) bool {
s = filepath.ToSlash(s) s = ToSlash(s)
for _, elem := range vector { for _, elem := range vector {
if elem == s { if elem == s {
return true return true
...@@ -109,9 +109,20 @@ func TestGlob(t *testing.T) { ...@@ -109,9 +109,20 @@ func TestGlob(t *testing.T) {
return return
} }
for _, tt := range globTests { for _, tt := range globTests {
matches := filepath.Glob(tt.pattern) matches, err := Glob(tt.pattern)
if err != nil {
t.Errorf("Glob error for %q: %s", tt.pattern, err)
continue
}
if !contains(matches, tt.result) { if !contains(matches, tt.result) {
t.Errorf("Glob(%#q) = %#v want %v", tt.pattern, matches, tt.result) t.Errorf("Glob(%#q) = %#v want %v", tt.pattern, matches, tt.result)
} }
} }
} }
func TestGlobError(t *testing.T) {
_, err := Glob("[7]")
if err != nil {
t.Error("expected error for bad pattern; got none")
}
}
...@@ -231,6 +231,21 @@ func EvalSymlinks(path string) (string, os.Error) { ...@@ -231,6 +231,21 @@ func EvalSymlinks(path string) (string, os.Error) {
return Clean(b.String()), nil return Clean(b.String()), nil
} }
// Abs returns an absolute representation of path.
// If the path is not absolute it will be joined with the current
// working directory to turn it into an absolute path. The absolute
// path name for a given file is not guaranteed to be unique.
func Abs(path string) (string, os.Error) {
if IsAbs(path) {
return path, nil
}
wd, err := os.Getwd()
if err != nil {
return "", err
}
return Join(wd, path), nil
}
// Visitor methods are invoked for corresponding file tree entries // Visitor methods are invoked for corresponding file tree entries
// visited by Walk. The parameter path is the full path of f relative // visited by Walk. The parameter path is the full path of f relative
// to root. // to root.
...@@ -265,7 +280,7 @@ func walk(path string, f *os.FileInfo, v Visitor, errors chan<- os.Error) { ...@@ -265,7 +280,7 @@ func walk(path string, f *os.FileInfo, v Visitor, errors chan<- os.Error) {
// a list of sorted directory entries. // a list of sorted directory entries.
// Copied from io/ioutil to avoid the circular import. // Copied from io/ioutil to avoid the circular import.
func readDir(dirname string) ([]*os.FileInfo, os.Error) { func readDir(dirname string) ([]*os.FileInfo, os.Error) {
f, err := os.Open(dirname, os.O_RDONLY, 0) f, err := os.Open(dirname)
if err != nil { if err != nil {
return nil, err return nil, err
} }
......
// 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 filepath
import "strings"
const (
Separator = '/' // OS-specific path separator
ListSeparator = 0 // OS-specific path list separator
)
// isSeparator returns true if c is a directory separator character.
func isSeparator(c uint8) bool {
return Separator == c
}
// IsAbs returns true if the path is absolute.
func IsAbs(path string) bool {
return strings.HasPrefix(path, "/") || strings.HasPrefix(path, "#")
}
// volumeName returns the leading volume name on Windows.
// It returns "" elsewhere
func volumeName(path string) string {
return ""
}
...@@ -248,7 +248,7 @@ func walkTree(n *Node, path string, f func(path string, n *Node)) { ...@@ -248,7 +248,7 @@ func walkTree(n *Node, path string, f func(path string, n *Node)) {
func makeTree(t *testing.T) { func makeTree(t *testing.T) {
walkTree(tree, tree.name, func(path string, n *Node) { walkTree(tree, tree.name, func(path string, n *Node) {
if n.entries == nil { if n.entries == nil {
fd, err := os.Open(path, os.O_CREAT, 0660) fd, err := os.Create(path)
if err != nil { if err != nil {
t.Errorf("makeTree: %v", err) t.Errorf("makeTree: %v", err)
} }
...@@ -459,9 +459,9 @@ func TestEvalSymlinks(t *testing.T) { ...@@ -459,9 +459,9 @@ func TestEvalSymlinks(t *testing.T) {
// relative // relative
for _, d := range EvalSymlinksTests { for _, d := range EvalSymlinksTests {
if p, err := filepath.EvalSymlinks(d.path); err != nil { if p, err := filepath.EvalSymlinks(d.path); err != nil {
t.Errorf("EvalSymlinks(%v) error: %v", d.path, err) t.Errorf("EvalSymlinks(%q) error: %v", d.path, err)
} else if p != d.dest { } else if p != d.dest {
t.Errorf("EvalSymlinks(%v)=%v, want %v", d.path, p, d.dest) t.Errorf("EvalSymlinks(%q)=%q, want %q", d.path, p, d.dest)
} }
} }
// absolute // absolute
...@@ -477,10 +477,54 @@ func TestEvalSymlinks(t *testing.T) { ...@@ -477,10 +477,54 @@ func TestEvalSymlinks(t *testing.T) {
filepath.Join(testroot, d.dest), filepath.Join(testroot, d.dest),
} }
if p, err := filepath.EvalSymlinks(a.path); err != nil { if p, err := filepath.EvalSymlinks(a.path); err != nil {
t.Errorf("EvalSymlinks(%v) error: %v", a.path, err) t.Errorf("EvalSymlinks(%q) error: %v", a.path, err)
} else if p != a.dest { } else if p != a.dest {
t.Errorf("EvalSymlinks(%v)=%v, want %v", a.path, p, a.dest) t.Errorf("EvalSymlinks(%q)=%q, want %q", a.path, p, a.dest)
} }
} }
*/ */
} }
/* These tests do not work in the gccgo test environment.
// Test paths relative to $GOROOT/src
var abstests = []string{
"../AUTHORS",
"pkg/../../AUTHORS",
"Make.pkg",
"pkg/Makefile",
// Already absolute
"$GOROOT/src/Make.pkg",
}
func TestAbs(t *testing.T) {
oldwd, err := os.Getwd()
if err != nil {
t.Fatal("Getwd failed: " + err.String())
}
defer os.Chdir(oldwd)
goroot := os.Getenv("GOROOT")
cwd := filepath.Join(goroot, "src")
os.Chdir(cwd)
for _, path := range abstests {
path = strings.Replace(path, "$GOROOT", goroot, -1)
abspath, err := filepath.Abs(path)
if err != nil {
t.Errorf("Abs(%q) error: %v", path, err)
}
info, err := os.Stat(path)
if err != nil {
t.Errorf("%s: %s", path, err)
}
absinfo, err := os.Stat(abspath)
if err != nil || absinfo.Ino != info.Ino {
t.Errorf("Abs(%q)=%q, not the same file", path, abspath)
}
if !filepath.IsAbs(abspath) {
t.Errorf("Abs(%q)=%q, not an absolute path", path, abspath)
}
}
}
*/
...@@ -22,7 +22,7 @@ func IsAbs(path string) bool { ...@@ -22,7 +22,7 @@ func IsAbs(path string) bool {
} }
// volumeName returns the leading volume name on Windows. // volumeName returns the leading volume name on Windows.
// It returns "" on Unix. // It returns "" elsewhere.
func volumeName(path string) string { func volumeName(path string) string {
return "" return ""
} }
...@@ -331,7 +331,7 @@ func (s *Scanner) error(msg string) { ...@@ -331,7 +331,7 @@ func (s *Scanner) error(msg string) {
s.Error(s, msg) s.Error(s, msg)
return return
} }
fmt.Fprintf(os.Stderr, "%s: %s", s.Position, msg) fmt.Fprintf(os.Stderr, "%s: %s\n", s.Position, msg)
} }
...@@ -503,41 +503,32 @@ func (s *Scanner) scanChar() { ...@@ -503,41 +503,32 @@ func (s *Scanner) scanChar() {
} }
func (s *Scanner) scanLineComment() { func (s *Scanner) scanComment(ch int) int {
ch := s.next() // read character after "//" // ch == '/' || ch == '*'
for ch != '\n' { if ch == '/' {
if ch < 0 { // line comment
s.error("comment not terminated") ch = s.next() // read character after "//"
return for ch != '\n' && ch >= 0 {
}
ch = s.next() ch = s.next()
} }
} return ch
}
func (s *Scanner) scanGeneralComment() { // general comment
ch := s.next() // read character after "/*" ch = s.next() // read character after "/*"
for { for {
if ch < 0 { if ch < 0 {
s.error("comment not terminated") s.error("comment not terminated")
return break
} }
ch0 := ch ch0 := ch
ch = s.next() ch = s.next()
if ch0 == '*' && ch == '/' { if ch0 == '*' && ch == '/' {
ch = s.next()
break break
} }
} }
} return ch
func (s *Scanner) scanComment(ch int) {
// ch == '/' || ch == '*'
if ch == '/' {
s.scanLineComment()
return
}
s.scanGeneralComment()
} }
...@@ -619,13 +610,11 @@ redo: ...@@ -619,13 +610,11 @@ redo:
if (ch == '/' || ch == '*') && s.Mode&ScanComments != 0 { if (ch == '/' || ch == '*') && s.Mode&ScanComments != 0 {
if s.Mode&SkipComments != 0 { if s.Mode&SkipComments != 0 {
s.tokPos = -1 // don't collect token text s.tokPos = -1 // don't collect token text
s.scanComment(ch) ch = s.scanComment(ch)
ch = s.next()
goto redo goto redo
} }
s.scanComment(ch) ch = s.scanComment(ch)
tok = Comment tok = Comment
ch = s.next()
} }
case '`': case '`':
if s.Mode&ScanRawStrings != 0 { if s.Mode&ScanRawStrings != 0 {
......
...@@ -77,15 +77,15 @@ type token struct { ...@@ -77,15 +77,15 @@ type token struct {
var f100 = "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff" var f100 = "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"
var tokenList = []token{ var tokenList = []token{
{Comment, "// line comments\n"}, {Comment, "// line comments"},
{Comment, "//\n"}, {Comment, "//"},
{Comment, "////\n"}, {Comment, "////"},
{Comment, "// comment\n"}, {Comment, "// comment"},
{Comment, "// /* comment */\n"}, {Comment, "// /* comment */"},
{Comment, "// // comment //\n"}, {Comment, "// // comment //"},
{Comment, "//" + f100 + "\n"}, {Comment, "//" + f100},
{Comment, "// general comments\n"}, {Comment, "// general comments"},
{Comment, "/**/"}, {Comment, "/**/"},
{Comment, "/***/"}, {Comment, "/***/"},
{Comment, "/* comment */"}, {Comment, "/* comment */"},
...@@ -94,7 +94,7 @@ var tokenList = []token{ ...@@ -94,7 +94,7 @@ var tokenList = []token{
{Comment, "/*\n comment\n*/"}, {Comment, "/*\n comment\n*/"},
{Comment, "/*" + f100 + "*/"}, {Comment, "/*" + f100 + "*/"},
{Comment, "// identifiers\n"}, {Comment, "// identifiers"},
{Ident, "a"}, {Ident, "a"},
{Ident, "a0"}, {Ident, "a0"},
{Ident, "foobar"}, {Ident, "foobar"},
...@@ -116,21 +116,21 @@ var tokenList = []token{ ...@@ -116,21 +116,21 @@ var tokenList = []token{
{Ident, "bar9876"}, {Ident, "bar9876"},
{Ident, f100}, {Ident, f100},
{Comment, "// decimal ints\n"}, {Comment, "// decimal ints"},
{Int, "0"}, {Int, "0"},
{Int, "1"}, {Int, "1"},
{Int, "9"}, {Int, "9"},
{Int, "42"}, {Int, "42"},
{Int, "1234567890"}, {Int, "1234567890"},
{Comment, "// octal ints\n"}, {Comment, "// octal ints"},
{Int, "00"}, {Int, "00"},
{Int, "01"}, {Int, "01"},
{Int, "07"}, {Int, "07"},
{Int, "042"}, {Int, "042"},
{Int, "01234567"}, {Int, "01234567"},
{Comment, "// hexadecimal ints\n"}, {Comment, "// hexadecimal ints"},
{Int, "0x0"}, {Int, "0x0"},
{Int, "0x1"}, {Int, "0x1"},
{Int, "0xf"}, {Int, "0xf"},
...@@ -144,7 +144,7 @@ var tokenList = []token{ ...@@ -144,7 +144,7 @@ var tokenList = []token{
{Int, "0X123456789abcDEF"}, {Int, "0X123456789abcDEF"},
{Int, "0X" + f100}, {Int, "0X" + f100},
{Comment, "// floats\n"}, {Comment, "// floats"},
{Float, "0."}, {Float, "0."},
{Float, "1."}, {Float, "1."},
{Float, "42."}, {Float, "42."},
...@@ -174,7 +174,7 @@ var tokenList = []token{ ...@@ -174,7 +174,7 @@ var tokenList = []token{
{Float, "42E+10"}, {Float, "42E+10"},
{Float, "01234567890E-10"}, {Float, "01234567890E-10"},
{Comment, "// chars\n"}, {Comment, "// chars"},
{Char, `' '`}, {Char, `' '`},
{Char, `'a'`}, {Char, `'a'`},
{Char, `'本'`}, {Char, `'本'`},
...@@ -195,7 +195,7 @@ var tokenList = []token{ ...@@ -195,7 +195,7 @@ var tokenList = []token{
{Char, `'\U00000000'`}, {Char, `'\U00000000'`},
{Char, `'\U0000ffAB'`}, {Char, `'\U0000ffAB'`},
{Comment, "// strings\n"}, {Comment, "// strings"},
{String, `" "`}, {String, `" "`},
{String, `"a"`}, {String, `"a"`},
{String, `"本"`}, {String, `"本"`},
...@@ -217,13 +217,13 @@ var tokenList = []token{ ...@@ -217,13 +217,13 @@ var tokenList = []token{
{String, `"\U0000ffAB"`}, {String, `"\U0000ffAB"`},
{String, `"` + f100 + `"`}, {String, `"` + f100 + `"`},
{Comment, "// raw strings\n"}, {Comment, "// raw strings"},
{String, "``"}, {String, "``"},
{String, "`\\`"}, {String, "`\\`"},
{String, "`" + "\n\n/* foobar */\n\n" + "`"}, {String, "`" + "\n\n/* foobar */\n\n" + "`"},
{String, "`" + f100 + "`"}, {String, "`" + f100 + "`"},
{Comment, "// individual characters\n"}, {Comment, "// individual characters"},
// NUL character is not allowed // NUL character is not allowed
{'\x01', "\x01"}, {'\x01', "\x01"},
{' ' - 1, string(' ' - 1)}, {' ' - 1, string(' ' - 1)},
...@@ -276,7 +276,7 @@ func countNewlines(s string) int { ...@@ -276,7 +276,7 @@ func countNewlines(s string) int {
func testScan(t *testing.T, mode uint) { func testScan(t *testing.T, mode uint) {
s := new(Scanner).Init(makeSource(" \t%s\t\n\r")) s := new(Scanner).Init(makeSource(" \t%s\n"))
s.Mode = mode s.Mode = mode
tok := s.Scan() tok := s.Scan()
line := 1 line := 1
...@@ -287,7 +287,7 @@ func testScan(t *testing.T, mode uint) { ...@@ -287,7 +287,7 @@ func testScan(t *testing.T, mode uint) {
} }
line += countNewlines(k.text) + 1 // each token is on a new line line += countNewlines(k.text) + 1 // each token is on a new line
} }
checkTok(t, s, line, tok, -1, "") checkTok(t, s, line, tok, EOF, "")
} }
...@@ -317,6 +317,10 @@ func TestPosition(t *testing.T) { ...@@ -317,6 +317,10 @@ func TestPosition(t *testing.T) {
pos.Line += countNewlines(k.text) + 1 // each token is on a new line pos.Line += countNewlines(k.text) + 1 // each token is on a new line
s.Scan() s.Scan()
} }
// make sure there were no token-internal errors reported by scanner
if s.ErrorCount != 0 {
t.Errorf("%d errors", s.ErrorCount)
}
} }
...@@ -336,6 +340,9 @@ func TestScanZeroMode(t *testing.T) { ...@@ -336,6 +340,9 @@ func TestScanZeroMode(t *testing.T) {
if tok != EOF { if tok != EOF {
t.Fatalf("tok = %s, want EOF", TokenString(tok)) t.Fatalf("tok = %s, want EOF", TokenString(tok))
} }
if s.ErrorCount != 0 {
t.Errorf("%d errors", s.ErrorCount)
}
} }
...@@ -350,6 +357,9 @@ func testScanSelectedMode(t *testing.T, mode uint, class int) { ...@@ -350,6 +357,9 @@ func testScanSelectedMode(t *testing.T, mode uint, class int) {
} }
tok = s.Scan() tok = s.Scan()
} }
if s.ErrorCount != 0 {
t.Errorf("%d errors", s.ErrorCount)
}
} }
...@@ -367,7 +377,7 @@ func TestScanSelectedMask(t *testing.T) { ...@@ -367,7 +377,7 @@ func TestScanSelectedMask(t *testing.T) {
func TestScanNext(t *testing.T) { func TestScanNext(t *testing.T) {
s := new(Scanner).Init(bytes.NewBufferString("if a == bcd /* comment */ {\n\ta += c\n}")) s := new(Scanner).Init(bytes.NewBufferString("if a == bcd /* comment */ {\n\ta += c\n} // line comment ending in eof"))
checkTok(t, s, 1, s.Scan(), Ident, "if") checkTok(t, s, 1, s.Scan(), Ident, "if")
checkTok(t, s, 1, s.Scan(), Ident, "a") checkTok(t, s, 1, s.Scan(), Ident, "a")
checkTok(t, s, 1, s.Scan(), '=', "=") checkTok(t, s, 1, s.Scan(), '=', "=")
...@@ -382,6 +392,9 @@ func TestScanNext(t *testing.T) { ...@@ -382,6 +392,9 @@ func TestScanNext(t *testing.T) {
checkTok(t, s, 2, s.Scan(), Ident, "c") checkTok(t, s, 2, s.Scan(), Ident, "c")
checkTok(t, s, 3, s.Scan(), '}', "}") checkTok(t, s, 3, s.Scan(), '}', "}")
checkTok(t, s, 3, s.Scan(), -1, "") checkTok(t, s, 3, s.Scan(), -1, "")
if s.ErrorCount != 0 {
t.Errorf("%d errors", s.ErrorCount)
}
} }
...@@ -441,7 +454,6 @@ func TestError(t *testing.T) { ...@@ -441,7 +454,6 @@ func TestError(t *testing.T) {
testError(t, `"\'"`, "illegal char escape", String) testError(t, `"\'"`, "illegal char escape", String)
testError(t, `"abc`, "literal not terminated", String) testError(t, `"abc`, "literal not terminated", String)
testError(t, "`abc", "literal not terminated", String) testError(t, "`abc", "literal not terminated", String)
testError(t, `//`, "comment not terminated", EOF)
testError(t, `/*/`, "comment not terminated", EOF) testError(t, `/*/`, "comment not terminated", EOF)
testError(t, `"abc`+"\x00"+`def"`, "illegal character NUL", String) testError(t, `"abc`+"\x00"+`def"`, "illegal character NUL", String)
testError(t, `"abc`+"\xff"+`def"`, "illegal UTF-8 encoding", String) testError(t, `"abc`+"\xff"+`def"`, "illegal UTF-8 encoding", String)
...@@ -493,6 +505,9 @@ func TestPos(t *testing.T) { ...@@ -493,6 +505,9 @@ func TestPos(t *testing.T) {
for i := 10; i > 0; i-- { for i := 10; i > 0; i-- {
checkScanPos(t, s, 1, 2, 1, EOF) checkScanPos(t, s, 1, 2, 1, EOF)
} }
if s.ErrorCount != 0 {
t.Errorf("%d errors", s.ErrorCount)
}
// corner case: source with only a single character // corner case: source with only a single character
s = new(Scanner).Init(bytes.NewBufferString("本")) s = new(Scanner).Init(bytes.NewBufferString("本"))
...@@ -502,6 +517,9 @@ func TestPos(t *testing.T) { ...@@ -502,6 +517,9 @@ func TestPos(t *testing.T) {
for i := 10; i > 0; i-- { for i := 10; i > 0; i-- {
checkScanPos(t, s, 3, 1, 2, EOF) checkScanPos(t, s, 3, 1, 2, EOF)
} }
if s.ErrorCount != 0 {
t.Errorf("%d errors", s.ErrorCount)
}
// positions after calling Next // positions after calling Next
s = new(Scanner).Init(bytes.NewBufferString(" foo६४ \n\n本語\n")) s = new(Scanner).Init(bytes.NewBufferString(" foo६४ \n\n本語\n"))
...@@ -524,6 +542,9 @@ func TestPos(t *testing.T) { ...@@ -524,6 +542,9 @@ func TestPos(t *testing.T) {
for i := 10; i > 0; i-- { for i := 10; i > 0; i-- {
checkScanPos(t, s, 22, 4, 1, EOF) checkScanPos(t, s, 22, 4, 1, EOF)
} }
if s.ErrorCount != 0 {
t.Errorf("%d errors", s.ErrorCount)
}
// positions after calling Scan // positions after calling Scan
s = new(Scanner).Init(bytes.NewBufferString("abc\n本語\n\nx")) s = new(Scanner).Init(bytes.NewBufferString("abc\n本語\n\nx"))
...@@ -543,4 +564,7 @@ func TestPos(t *testing.T) { ...@@ -543,4 +564,7 @@ func TestPos(t *testing.T) {
for i := 10; i > 0; i-- { for i := 10; i > 0; i-- {
checkScanPos(t, s, 13, 4, 2, EOF) checkScanPos(t, s, 13, 4, 2, EOF)
} }
if s.ErrorCount != 0 {
t.Errorf("%d errors", s.ErrorCount)
}
} }
...@@ -94,7 +94,7 @@ func myatof32(s string) (f float32, ok bool) { ...@@ -94,7 +94,7 @@ func myatof32(s string) (f float32, ok bool) {
} }
func TestFp(t *testing.T) { func TestFp(t *testing.T) {
f, err := os.Open("testfp.txt", os.O_RDONLY, 0) f, err := os.Open("testfp.txt")
if err != nil { if err != nil {
t.Fatal("testfp: open testfp.txt:", err.String()) t.Fatal("testfp: open testfp.txt:", err.String())
} }
......
...@@ -212,7 +212,7 @@ func before() { ...@@ -212,7 +212,7 @@ func before() {
runtime.MemProfileRate = *memProfileRate runtime.MemProfileRate = *memProfileRate
} }
if *cpuProfile != "" { if *cpuProfile != "" {
f, err := os.Open(*cpuProfile, os.O_WRONLY|os.O_CREAT|os.O_TRUNC, 0666) f, err := os.Create(*cpuProfile)
if err != nil { if err != nil {
fmt.Fprintf(os.Stderr, "testing: %s", err) fmt.Fprintf(os.Stderr, "testing: %s", err)
return return
...@@ -233,7 +233,7 @@ func after() { ...@@ -233,7 +233,7 @@ func after() {
pprof.StopCPUProfile() // flushes profile to disk pprof.StopCPUProfile() // flushes profile to disk
} }
if *memProfile != "" { if *memProfile != "" {
f, err := os.Open(*memProfile, os.O_WRONLY|os.O_CREAT|os.O_TRUNC, 0666) f, err := os.Create(*memProfile)
if err != nil { if err != nil {
fmt.Fprintf(os.Stderr, "testing: %s", err) fmt.Fprintf(os.Stderr, "testing: %s", err)
return return
......
...@@ -57,6 +57,9 @@ cat > sysinfo.c <<EOF ...@@ -57,6 +57,9 @@ cat > sysinfo.c <<EOF
#if defined(HAVE_SYS_EPOLL_H) #if defined(HAVE_SYS_EPOLL_H)
#include <sys/epoll.h> #include <sys/epoll.h>
#endif #endif
#if defined(HAVE_SYS_MMAN_H)
#include <sys/mman.h>
#endif
#if defined(HAVE_SYS_PTRACE_H) #if defined(HAVE_SYS_PTRACE_H)
#include <sys/ptrace.h> #include <sys/ptrace.h>
#endif #endif
...@@ -131,6 +134,12 @@ grep '^const _SYS_' gen-sysinfo.go | \ ...@@ -131,6 +134,12 @@ grep '^const _SYS_' gen-sysinfo.go | \
grep '^const _S_' gen-sysinfo.go | \ grep '^const _S_' gen-sysinfo.go | \
sed -e 's/^\(const \)_\(S_[^= ]*\)\(.*\)$/\1\2 = _\2/' >> ${OUT} sed -e 's/^\(const \)_\(S_[^= ]*\)\(.*\)$/\1\2 = _\2/' >> ${OUT}
# Mmap constants.
grep '^const _PROT_' gen-sysinfo.go | \
sed -e 's/^\(const \)_\(PROT_[^= ]*\)\(.*\)$/\1\2 = _\2/' >> ${OUT}
grep '^const _MAP_' gen-sysinfo.go | \
sed -e 's/^\(const \)_\(MAP_[^= ]*\)\(.*\)$/\1\2 = _\2/' >> ${OUT}
# Process status constants. # Process status constants.
grep '^const _W' gen-sysinfo.go | grep '^const _W' gen-sysinfo.go |
sed -e 's/^\(const \)_\(W[^= ]*\)\(.*\)$/\1\2 = _\2/' >> ${OUT} sed -e 's/^\(const \)_\(W[^= ]*\)\(.*\)$/\1\2 = _\2/' >> ${OUT}
......
...@@ -13,7 +13,10 @@ ...@@ -13,7 +13,10 @@
// the manuals for the appropriate operating system. // the manuals for the appropriate operating system.
package syscall package syscall
import "unsafe" import (
"sync"
"unsafe"
)
func libc_syscall32(trap int32, a1, a2, a3, a4, a5, a6 int32) int32 __asm__ ("syscall"); func libc_syscall32(trap int32, a1, a2, a3, a4, a5, a6 int32) int32 __asm__ ("syscall");
func libc_syscall64(trap int64, a1, a2, a3, a4, a5, a6 int64) int64 __asm__ ("syscall"); func libc_syscall64(trap int64, a1, a2, a3, a4, a5, a6 int64) int64 __asm__ ("syscall");
...@@ -46,3 +49,63 @@ func Syscall6(trap, a1, a2, a3, a4, a5, a6 uintptr) (r1, r2, err uintptr) { ...@@ -46,3 +49,63 @@ func Syscall6(trap, a1, a2, a3, a4, a5, a6 uintptr) (r1, r2, err uintptr) {
} }
return r, 0, uintptr(GetErrno()); return r, 0, uintptr(GetErrno());
} }
// Mmap manager, for use by operating system-specific implementations.
type mmapper struct {
sync.Mutex
active map[*byte][]byte // active mappings; key is last byte in mapping
mmap func(addr, length uintptr, prot, flags, fd int, offset int64) (uintptr, int)
munmap func(addr uintptr, length uintptr) int
}
func (m *mmapper) Mmap(fd int, offset int64, length int, prot int, flags int) (data []byte, errno int) {
if length <= 0 {
return nil, EINVAL
}
// Map the requested memory.
addr, errno := m.mmap(0, uintptr(length), prot, flags, fd, offset)
if errno != 0 {
return nil, errno
}
// Slice memory layout
var sl = struct {
addr uintptr
len int
cap int
}{addr, length, length}
// Use unsafe to turn sl into a []byte.
b := *(*[]byte)(unsafe.Pointer(&sl))
// Register mapping in m and return it.
p := &b[cap(b)-1]
m.Lock()
defer m.Unlock()
m.active[p] = b
return b, 0
}
func (m *mmapper) Munmap(data []byte) (errno int) {
if len(data) == 0 || len(data) != cap(data) {
return EINVAL
}
// Find the base of the mapping.
p := &data[cap(data)-1]
m.Lock()
defer m.Unlock()
b := m.active[p]
if b == nil || &b[0] != &data[0] {
return EINVAL
}
// Unmap the memory and update m.
if errno := m.munmap(uintptr(unsafe.Pointer(&b[0])), uintptr(len(b))); errno != 0 {
return errno
}
m.active[p] = nil, false
return 0
}
...@@ -4,6 +4,8 @@ ...@@ -4,6 +4,8 @@
package syscall package syscall
import "unsafe"
var ( var (
Stdin = 0 Stdin = 0
Stdout = 1 Stdout = 1
...@@ -22,3 +24,35 @@ func Uname(buf *Utsname) (errno int) { ...@@ -22,3 +24,35 @@ func Uname(buf *Utsname) (errno int) {
} }
return return
} }
var mapper = &mmapper{
active: make(map[*byte][]byte),
mmap: mmap,
munmap: munmap,
}
func Mmap(fd int, offset int64, length int, prot int, flags int) (data []byte, errno int) {
return mapper.Mmap(fd, offset, length, prot, flags)
}
func Munmap(b []byte) (errno int) {
return mapper.Munmap(b)
}
func libc_munmap(*byte, Size_t) int __asm__ ("munmap")
func mmap(addr uintptr, length uintptr, prot int, flag int, fd int, pos int64) (ret uintptr, errno int) {
r0 := libc_mmap((*byte)(unsafe.Pointer(addr)), Size_t(length), prot, flag, fd, Offset_t(pos))
ret = uintptr(unsafe.Pointer(r0))
if ret + 1 == 0 {
errno = GetErrno()
}
return
}
func munmap(addr uintptr, length uintptr) (errno int) {
if libc_munmap((*byte)(unsafe.Pointer(addr)), Size_t(length)) < 0 {
errno = GetErrno()
}
return
}
...@@ -11,3 +11,4 @@ func libc_pwrite(fd int, buf *byte, count Size_t, offset Offset_t) Ssize_t __asm ...@@ -11,3 +11,4 @@ func libc_pwrite(fd int, buf *byte, count Size_t, offset Offset_t) Ssize_t __asm
func libc_lseek(int, Offset_t, int) Offset_t __asm__ ("lseek64") func libc_lseek(int, Offset_t, int) Offset_t __asm__ ("lseek64")
func libc_truncate(path *byte, length Offset_t) int __asm__ ("truncate64") func libc_truncate(path *byte, length Offset_t) int __asm__ ("truncate64")
func libc_ftruncate(fd int, length Offset_t) int __asm__ ("ftruncate64") func libc_ftruncate(fd int, length Offset_t) int __asm__ ("ftruncate64")
func libc_mmap(*byte, Size_t, int, int, int, Offset_t) *byte __asm__ ("mmap64")
...@@ -11,3 +11,4 @@ func libc_pwrite(fd int, buf *byte, count Size_t, offset Offset_t) Ssize_t __asm ...@@ -11,3 +11,4 @@ func libc_pwrite(fd int, buf *byte, count Size_t, offset Offset_t) Ssize_t __asm
func libc_lseek(int, Offset_t, int) Offset_t __asm__ ("lseek") func libc_lseek(int, Offset_t, int) Offset_t __asm__ ("lseek")
func libc_truncate(path *byte, length Offset_t) int __asm__ ("truncate") func libc_truncate(path *byte, length Offset_t) int __asm__ ("truncate")
func libc_ftruncate(fd int, length Offset_t) int __asm__ ("ftruncate") func libc_ftruncate(fd int, length Offset_t) int __asm__ ("ftruncate")
func libc_mmap(*byte, Size_t, int, int, int, Offset_t) *byte __asm__ ("mmap")
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment