libgo: Update to weekly.2012-01-27.

From-SVN: r183810
This commit is contained in:
Ian Lance Taylor 2012-02-01 19:26:59 +00:00
parent 6b6cd722f3
commit 9af4cb9545
277 changed files with 15512 additions and 24913 deletions

View File

@ -1,4 +1,4 @@
9f2be4fbbf69 1107a7d3cb07
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.

View File

@ -116,7 +116,6 @@ toolexeclibgo_DATA = \
mime.gox \ mime.gox \
net.gox \ net.gox \
os.gox \ os.gox \
patch.gox \
path.gox \ path.gox \
reflect.gox \ reflect.gox \
regexp.gox \ regexp.gox \
@ -128,8 +127,7 @@ toolexeclibgo_DATA = \
syscall.gox \ syscall.gox \
testing.gox \ testing.gox \
time.gox \ time.gox \
unicode.gox \ unicode.gox
websocket.gox
toolexeclibgoarchivedir = $(toolexeclibgodir)/archive toolexeclibgoarchivedir = $(toolexeclibgodir)/archive
@ -157,40 +155,22 @@ toolexeclibgocryptodir = $(toolexeclibgodir)/crypto
toolexeclibgocrypto_DATA = \ toolexeclibgocrypto_DATA = \
crypto/aes.gox \ crypto/aes.gox \
crypto/bcrypt.gox \
crypto/blowfish.gox \
crypto/cast5.gox \
crypto/cipher.gox \ crypto/cipher.gox \
crypto/des.gox \ crypto/des.gox \
crypto/dsa.gox \ crypto/dsa.gox \
crypto/ecdsa.gox \ crypto/ecdsa.gox \
crypto/elliptic.gox \ crypto/elliptic.gox \
crypto/hmac.gox \ crypto/hmac.gox \
crypto/md4.gox \
crypto/md5.gox \ crypto/md5.gox \
crypto/ocsp.gox \
crypto/openpgp.gox \
crypto/rand.gox \ crypto/rand.gox \
crypto/rc4.gox \ crypto/rc4.gox \
crypto/ripemd160.gox \
crypto/rsa.gox \ crypto/rsa.gox \
crypto/sha1.gox \ crypto/sha1.gox \
crypto/sha256.gox \ crypto/sha256.gox \
crypto/sha512.gox \ crypto/sha512.gox \
crypto/subtle.gox \ crypto/subtle.gox \
crypto/tls.gox \ crypto/tls.gox \
crypto/twofish.gox \ crypto/x509.gox
crypto/x509.gox \
crypto/xtea.gox
toolexeclibgocryptoopenpgpdir = $(toolexeclibgocryptodir)/openpgp
toolexeclibgocryptoopenpgp_DATA = \
crypto/openpgp/armor.gox \
crypto/openpgp/elgamal.gox \
crypto/openpgp/errors.gox \
crypto/openpgp/packet.gox \
crypto/openpgp/s2k.gox
toolexeclibgocryptox509dir = $(toolexeclibgocryptodir)/x509 toolexeclibgocryptox509dir = $(toolexeclibgocryptodir)/x509
@ -225,7 +205,6 @@ toolexeclibgoencoding_DATA = \
encoding/base64.gox \ encoding/base64.gox \
encoding/binary.gox \ encoding/binary.gox \
encoding/csv.gox \ encoding/csv.gox \
encoding/git85.gox \
encoding/gob.gox \ encoding/gob.gox \
encoding/hex.gox \ encoding/hex.gox \
encoding/json.gox \ encoding/json.gox \
@ -243,11 +222,10 @@ toolexeclibgoexpdir = $(toolexeclibgodir)/exp
toolexeclibgoexp_DATA = \ toolexeclibgoexp_DATA = \
exp/ebnf.gox \ exp/ebnf.gox \
exp/html.gox \
$(exp_inotify_gox) \ $(exp_inotify_gox) \
exp/norm.gox \ exp/norm.gox \
exp/proxy.gox \ exp/proxy.gox \
exp/spdy.gox \
exp/ssh.gox \
exp/terminal.gox \ exp/terminal.gox \
exp/types.gox \ exp/types.gox \
exp/utf8string.gox exp/utf8string.gox
@ -317,7 +295,6 @@ toolexeclibgomime_DATA = \
toolexeclibgonetdir = $(toolexeclibgodir)/net toolexeclibgonetdir = $(toolexeclibgodir)/net
toolexeclibgonet_DATA = \ toolexeclibgonet_DATA = \
net/dict.gox \
net/http.gox \ net/http.gox \
net/mail.gox \ net/mail.gox \
net/rpc.gox \ net/rpc.gox \
@ -577,16 +554,8 @@ go_hash_files = \
go/hash/hash.go go/hash/hash.go
go_html_files = \ go_html_files = \
go/html/const.go \
go/html/doc.go \
go/html/doctype.go \
go/html/entity.go \ go/html/entity.go \
go/html/escape.go \ go/html/escape.go
go/html/foreign.go \
go/html/node.go \
go/html/parse.go \
go/html/render.go \
go/html/token.go
go_image_files = \ go_image_files = \
go/image/format.go \ go/image/format.go \
@ -821,12 +790,6 @@ go_os_files = \
go/os/types.go \ go/os/types.go \
signal_unix.go signal_unix.go
go_patch_files = \
go/patch/apply.go \
go/patch/git.go \
go/patch/patch.go \
go/patch/textdiff.go
go_path_files = \ go_path_files = \
go/path/match.go \ go/path/match.go \
go/path/path.go go/path/path.go
@ -929,13 +892,6 @@ go_unicode_files = \
go/unicode/letter.go \ go/unicode/letter.go \
go/unicode/tables.go go/unicode/tables.go
go_websocket_files = \
go/websocket/client.go \
go/websocket/hixie.go \
go/websocket/hybi.go \
go/websocket/server.go \
go/websocket/websocket.go
go_archive_tar_files = \ go_archive_tar_files = \
go/archive/tar/common.go \ go/archive/tar/common.go \
@ -959,8 +915,7 @@ go_compress_flate_files = \
go/compress/flate/huffman_code.go \ go/compress/flate/huffman_code.go \
go/compress/flate/inflate.go \ go/compress/flate/inflate.go \
go/compress/flate/reverse_bits.go \ go/compress/flate/reverse_bits.go \
go/compress/flate/token.go \ go/compress/flate/token.go
go/compress/flate/util.go
go_compress_gzip_files = \ go_compress_gzip_files = \
go/compress/gzip/gzip.go \ go/compress/gzip/gzip.go \
@ -987,15 +942,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_bcrypt_files = \
go/crypto/bcrypt/base64.go \
go/crypto/bcrypt/bcrypt.go
go_crypto_blowfish_files = \
go/crypto/blowfish/block.go \
go/crypto/blowfish/const.go \
go/crypto/blowfish/cipher.go
go_crypto_cast5_files = \
go/crypto/cast5/cast5.go
go_crypto_cipher_files = \ go_crypto_cipher_files = \
go/crypto/cipher/cbc.go \ go/crypto/cipher/cbc.go \
go/crypto/cipher/cfb.go \ go/crypto/cipher/cfb.go \
@ -1017,28 +963,15 @@ go_crypto_elliptic_files = \
go/crypto/elliptic/p224.go go/crypto/elliptic/p224.go
go_crypto_hmac_files = \ go_crypto_hmac_files = \
go/crypto/hmac/hmac.go go/crypto/hmac/hmac.go
go_crypto_md4_files = \
go/crypto/md4/md4.go \
go/crypto/md4/md4block.go
go_crypto_md5_files = \ go_crypto_md5_files = \
go/crypto/md5/md5.go \ go/crypto/md5/md5.go \
go/crypto/md5/md5block.go go/crypto/md5/md5block.go
go_crypto_ocsp_files = \
go/crypto/ocsp/ocsp.go
go_crypto_openpgp_files = \
go/crypto/openpgp/canonical_text.go \
go/crypto/openpgp/keys.go \
go/crypto/openpgp/read.go \
go/crypto/openpgp/write.go
go_crypto_rand_files = \ go_crypto_rand_files = \
go/crypto/rand/rand.go \ go/crypto/rand/rand.go \
go/crypto/rand/rand_unix.go \ go/crypto/rand/rand_unix.go \
go/crypto/rand/util.go go/crypto/rand/util.go
go_crypto_rc4_files = \ go_crypto_rc4_files = \
go/crypto/rc4/rc4.go go/crypto/rc4/rc4.go
go_crypto_ripemd160_files = \
go/crypto/ripemd160/ripemd160.go \
go/crypto/ripemd160/ripemd160block.go
go_crypto_rsa_files = \ go_crypto_rsa_files = \
go/crypto/rsa/pkcs1v15.go \ go/crypto/rsa/pkcs1v15.go \
go/crypto/rsa/rsa.go go/crypto/rsa/rsa.go
@ -1065,40 +998,12 @@ go_crypto_tls_files = \
go/crypto/tls/prf.go \ go/crypto/tls/prf.go \
go/crypto/tls/root_unix.go \ go/crypto/tls/root_unix.go \
go/crypto/tls/tls.go go/crypto/tls/tls.go
go_crypto_twofish_files = \
go/crypto/twofish/twofish.go
go_crypto_x509_files = \ go_crypto_x509_files = \
go/crypto/x509/cert_pool.go \ go/crypto/x509/cert_pool.go \
go/crypto/x509/pkcs1.go \ go/crypto/x509/pkcs1.go \
go/crypto/x509/pkcs8.go \ go/crypto/x509/pkcs8.go \
go/crypto/x509/verify.go \ go/crypto/x509/verify.go \
go/crypto/x509/x509.go go/crypto/x509/x509.go
go_crypto_xtea_files = \
go/crypto/xtea/block.go \
go/crypto/xtea/cipher.go
go_crypto_openpgp_armor_files = \
go/crypto/openpgp/armor/armor.go \
go/crypto/openpgp/armor/encode.go
go_crypto_openpgp_elgamal_files = \
go/crypto/openpgp/elgamal/elgamal.go
go_crypto_openpgp_errors_files = \
go/crypto/openpgp/errors/errors.go
go_crypto_openpgp_packet_files = \
go/crypto/openpgp/packet/compressed.go \
go/crypto/openpgp/packet/encrypted_key.go \
go/crypto/openpgp/packet/literal.go \
go/crypto/openpgp/packet/one_pass_signature.go \
go/crypto/openpgp/packet/packet.go \
go/crypto/openpgp/packet/private_key.go \
go/crypto/openpgp/packet/public_key.go \
go/crypto/openpgp/packet/reader.go \
go/crypto/openpgp/packet/signature.go \
go/crypto/openpgp/packet/symmetric_key_encrypted.go \
go/crypto/openpgp/packet/symmetrically_encrypted.go \
go/crypto/openpgp/packet/userid.go
go_crypto_openpgp_s2k_files = \
go/crypto/openpgp/s2k/s2k.go
go_crypto_x509_pkix_files = \ go_crypto_x509_pkix_files = \
go/crypto/x509/pkix/pkix.go go/crypto/x509/pkix/pkix.go
@ -1147,8 +1052,6 @@ go_encoding_binary_files = \
go_encoding_csv_files = \ go_encoding_csv_files = \
go/encoding/csv/reader.go \ go/encoding/csv/reader.go \
go/encoding/csv/writer.go go/encoding/csv/writer.go
go_encoding_git85_files = \
go/encoding/git85/git.go
go_encoding_gob_files = \ go_encoding_gob_files = \
go/encoding/gob/decode.go \ go/encoding/gob/decode.go \
go/encoding/gob/decoder.go \ go/encoding/gob/decoder.go \
@ -1177,6 +1080,17 @@ go_encoding_xml_files = \
go_exp_ebnf_files = \ go_exp_ebnf_files = \
go/exp/ebnf/ebnf.go \ go/exp/ebnf/ebnf.go \
go/exp/ebnf/parser.go go/exp/ebnf/parser.go
go_exp_html_files = \
go/exp/html/const.go \
go/exp/html/doc.go \
go/exp/html/doctype.go \
go/exp/html/entity.go \
go/exp/html/escape.go \
go/exp/html/foreign.go \
go/exp/html/node.go \
go/exp/html/parse.go \
go/exp/html/render.go \
go/exp/html/token.go
go_exp_inotify_files = \ go_exp_inotify_files = \
go/exp/inotify/inotify_linux.go go/exp/inotify/inotify_linux.go
go_exp_norm_files = \ go_exp_norm_files = \
@ -1192,23 +1106,6 @@ go_exp_proxy_files = \
go/exp/proxy/per_host.go \ go/exp/proxy/per_host.go \
go/exp/proxy/proxy.go \ go/exp/proxy/proxy.go \
go/exp/proxy/socks5.go go/exp/proxy/socks5.go
go_exp_spdy_files = \
go/exp/spdy/read.go \
go/exp/spdy/types.go \
go/exp/spdy/write.go
go_exp_ssh_files = \
go/exp/ssh/channel.go \
go/exp/ssh/cipher.go \
go/exp/ssh/client.go \
go/exp/ssh/client_auth.go \
go/exp/ssh/common.go \
go/exp/ssh/doc.go \
go/exp/ssh/messages.go \
go/exp/ssh/server.go \
go/exp/ssh/server_terminal.go \
go/exp/ssh/session.go \
go/exp/ssh/tcpip.go \
go/exp/ssh/transport.go
go_exp_terminal_files = \ go_exp_terminal_files = \
go/exp/terminal/terminal.go \ go/exp/terminal/terminal.go \
go/exp/terminal/util.go go/exp/terminal/util.go
@ -1351,8 +1248,6 @@ go_mime_multipart_files = \
go/mime/multipart/multipart.go \ go/mime/multipart/multipart.go \
go/mime/multipart/writer.go go/mime/multipart/writer.go
go_net_dict_files = \
go/net/dict/dict.go
go_net_http_files = \ go_net_http_files = \
go/net/http/chunked.go \ go/net/http/chunked.go \
go/net/http/client.go \ go/net/http/client.go \
@ -1717,7 +1612,6 @@ libgo_go_objs = \
net/net.lo \ net/net.lo \
os/exec.lo \ os/exec.lo \
os/os.lo \ os/os.lo \
patch/patch.lo \
path/path.lo \ path/path.lo \
reflect/reflect.lo \ reflect/reflect.lo \
regexp/regexp.lo \ regexp/regexp.lo \
@ -1728,7 +1622,6 @@ libgo_go_objs = \
sync/sync.lo \ sync/sync.lo \
time/time.lo \ time/time.lo \
unicode/unicode.lo \ unicode/unicode.lo \
websocket/websocket.lo \
archive/tar.lo \ archive/tar.lo \
archive/zip.lo \ archive/zip.lo \
compress/bzip2.lo \ compress/bzip2.lo \
@ -1740,36 +1633,22 @@ libgo_go_objs = \
container/list.lo \ container/list.lo \
container/ring.lo \ container/ring.lo \
crypto/aes.lo \ crypto/aes.lo \
crypto/bcrypt.lo \
crypto/blowfish.lo \
crypto/cast5.lo \
crypto/cipher.lo \ crypto/cipher.lo \
crypto/des.lo \ crypto/des.lo \
crypto/dsa.lo \ crypto/dsa.lo \
crypto/ecdsa.lo \ crypto/ecdsa.lo \
crypto/elliptic.lo \ crypto/elliptic.lo \
crypto/hmac.lo \ crypto/hmac.lo \
crypto/md4.lo \
crypto/md5.lo \ crypto/md5.lo \
crypto/ocsp.lo \
crypto/openpgp.lo \
crypto/rand.lo \ crypto/rand.lo \
crypto/rc4.lo \ crypto/rc4.lo \
crypto/ripemd160.lo \
crypto/rsa.lo \ crypto/rsa.lo \
crypto/sha1.lo \ crypto/sha1.lo \
crypto/sha256.lo \ crypto/sha256.lo \
crypto/sha512.lo \ crypto/sha512.lo \
crypto/subtle.lo \ crypto/subtle.lo \
crypto/tls.lo \ crypto/tls.lo \
crypto/twofish.lo \
crypto/x509.lo \ crypto/x509.lo \
crypto/xtea.lo \
crypto/openpgp/armor.lo \
crypto/openpgp/elgamal.lo \
crypto/openpgp/errors.lo \
crypto/openpgp/packet.lo \
crypto/openpgp/s2k.lo \
crypto/x509/pkix.lo \ crypto/x509/pkix.lo \
database/sql.lo \ database/sql.lo \
database/sql/driver.lo \ database/sql/driver.lo \
@ -1784,17 +1663,15 @@ libgo_go_objs = \
encoding/base64.lo \ encoding/base64.lo \
encoding/binary.lo \ encoding/binary.lo \
encoding/csv.lo \ encoding/csv.lo \
encoding/git85.lo \
encoding/gob.lo \ encoding/gob.lo \
encoding/hex.lo \ encoding/hex.lo \
encoding/json.lo \ encoding/json.lo \
encoding/pem.lo \ encoding/pem.lo \
encoding/xml.lo \ encoding/xml.lo \
exp/ebnf.lo \ exp/ebnf.lo \
exp/html.lo \
exp/norm.lo \ exp/norm.lo \
exp/proxy.lo \ exp/proxy.lo \
exp/spdy.lo \
exp/ssh.lo \
exp/terminal.lo \ exp/terminal.lo \
exp/types.lo \ exp/types.lo \
exp/utf8string.lo \ exp/utf8string.lo \
@ -1831,7 +1708,6 @@ libgo_go_objs = \
math/rand.lo \ math/rand.lo \
mime/mime.lo \ mime/mime.lo \
mime/multipart.lo \ mime/multipart.lo \
net/dict.lo \
net/http.lo \ net/http.lo \
net/mail.lo \ net/mail.lo \
net/rpc.lo \ net/rpc.lo \
@ -1946,7 +1822,6 @@ CHECK_DEPS = libgo.la libgobegin.a \
$(toolexeclibgocompress_DATA) \ $(toolexeclibgocompress_DATA) \
$(toolexeclibgocontainer_DATA) \ $(toolexeclibgocontainer_DATA) \
$(toolexeclibgocrypto_DATA) \ $(toolexeclibgocrypto_DATA) \
$(toolexeclibgocryptoopenpgp_DATA) \
$(toolexeclibgodebug_DATA) \ $(toolexeclibgodebug_DATA) \
$(toolexeclibgoencoding_DATA) \ $(toolexeclibgoencoding_DATA) \
$(toolexeclibgoexp_DATA) \ $(toolexeclibgoexp_DATA) \
@ -2120,15 +1995,6 @@ signal_unix.go: $(srcdir)/go/os/mkunixsignals.sh sysinfo.go
$(SHELL) $(srcdir)/go/os/mkunixsignals.sh sysinfo.go > $@.tmp $(SHELL) $(srcdir)/go/os/mkunixsignals.sh sysinfo.go > $@.tmp
mv -f $@.tmp $@ mv -f $@.tmp $@
@go_include@ patch/patch.lo.dep
patch/patch.lo.dep: $(go_patch_files)
$(BUILDDEPS)
patch/patch.lo: $(go_patch_files)
$(BUILDPACKAGE)
patch/check: $(CHECK_DEPS)
@$(CHECK)
.PHONY: patch/check
@go_include@ path/path.lo.dep @go_include@ path/path.lo.dep
path/path.lo.dep: $(go_path_files) path/path.lo.dep: $(go_path_files)
$(BUILDDEPS) $(BUILDDEPS)
@ -2238,15 +2104,6 @@ unicode/check: $(CHECK_DEPS)
@$(CHECK) @$(CHECK)
.PHONY: unicode/check .PHONY: unicode/check
@go_include@ websocket/websocket.lo.dep
websocket/websocket.lo.dep: $(go_websocket_files)
$(BUILDDEPS)
websocket/websocket.lo: $(go_websocket_files)
$(BUILDPACKAGE)
websocket/check: $(CHECK_DEPS)
@$(CHECK)
.PHONY: websocket/check
@go_include@ archive/tar.lo.dep @go_include@ archive/tar.lo.dep
archive/tar.lo.dep: $(go_archive_tar_files) archive/tar.lo.dep: $(go_archive_tar_files)
$(BUILDDEPS) $(BUILDDEPS)
@ -2357,36 +2214,6 @@ crypto/aes/check: $(CHECK_DEPS)
@$(CHECK) @$(CHECK)
.PHONY: crypto/aes/check .PHONY: crypto/aes/check
@go_include@ crypto/bcrypt.lo.dep
crypto/bcrypt.lo.dep: $(go_crypto_bcrypt_files)
$(BUILDDEPS)
crypto/bcrypt.lo: $(go_crypto_bcrypt_files)
$(BUILDPACKAGE)
crypto/bcrypt/check: $(CHECK_DEPS)
@$(MKDIR_P) crypto/bcrypt
@$(CHECK)
.PHONY: crypto/bcrypt/check
@go_include@ crypto/blowfish.lo.dep
crypto/blowfish.lo.dep: $(go_crypto_blowfish_files)
$(BUILDDEPS)
crypto/blowfish.lo: $(go_crypto_blowfish_files)
$(BUILDPACKAGE)
crypto/blowfish/check: $(CHECK_DEPS)
@$(MKDIR_P) crypto/blowfish
@$(CHECK)
.PHONY: crypto/blowfish/check
@go_include@ crypto/cast5.lo.dep
crypto/cast5.lo.dep: $(go_crypto_cast5_files)
$(BUILDDEPS)
crypto/cast5.lo: $(go_crypto_cast5_files)
$(BUILDPACKAGE)
crypto/cast5/check: $(CHECK_DEPS)
@$(MKDIR_P) crypto/cast5
@$(CHECK)
.PHONY: crypto/cast5/check
@go_include@ crypto/cipher.lo.dep @go_include@ crypto/cipher.lo.dep
crypto/cipher.lo.dep: $(go_crypto_cipher_files) crypto/cipher.lo.dep: $(go_crypto_cipher_files)
$(BUILDDEPS) $(BUILDDEPS)
@ -2447,16 +2274,6 @@ crypto/hmac/check: $(CHECK_DEPS)
@$(CHECK) @$(CHECK)
.PHONY: crypto/hmac/check .PHONY: crypto/hmac/check
@go_include@ crypto/md4.lo.dep
crypto/md4.lo.dep: $(go_crypto_md4_files)
$(BUILDDEPS)
crypto/md4.lo: $(go_crypto_md4_files)
$(BUILDPACKAGE)
crypto/md4/check: $(CHECK_DEPS)
@$(MKDIR_P) crypto/md4
@$(CHECK)
.PHONY: crypto/md4/check
@go_include@ crypto/md5.lo.dep @go_include@ crypto/md5.lo.dep
crypto/md5.lo.dep: $(go_crypto_md5_files) crypto/md5.lo.dep: $(go_crypto_md5_files)
$(BUILDDEPS) $(BUILDDEPS)
@ -2467,26 +2284,6 @@ crypto/md5/check: $(CHECK_DEPS)
@$(CHECK) @$(CHECK)
.PHONY: crypto/md5/check .PHONY: crypto/md5/check
@go_include@ crypto/ocsp.lo.dep
crypto/ocsp.lo.dep: $(go_crypto_ocsp_files)
$(BUILDDEPS)
crypto/ocsp.lo: $(go_crypto_ocsp_files)
$(BUILDPACKAGE)
crypto/ocsp/check: $(CHECK_DEPS)
@$(MKDIR_P) crypto/ocsp
@$(CHECK)
.PHONY: crypto/ocsp/check
@go_include@ crypto/openpgp.lo.dep
crypto/openpgp.lo.dep: $(go_crypto_openpgp_files)
$(BUILDDEPS)
crypto/openpgp.lo: $(go_crypto_openpgp_files)
$(BUILDPACKAGE)
crypto/openpgp/check: $(CHECK_DEPS)
@$(MKDIR_P) crypto/openpgp
@$(CHECK)
.PHONY: crypto/openpgp/check
@go_include@ crypto/rand.lo.dep @go_include@ crypto/rand.lo.dep
crypto/rand.lo.dep: $(go_crypto_rand_files) crypto/rand.lo.dep: $(go_crypto_rand_files)
$(BUILDDEPS) $(BUILDDEPS)
@ -2507,16 +2304,6 @@ crypto/rc4/check: $(CHECK_DEPS)
@$(CHECK) @$(CHECK)
.PHONY: crypto/rc4/check .PHONY: crypto/rc4/check
@go_include@ crypto/ripemd160.lo.dep
crypto/ripemd160.lo.dep: $(go_crypto_ripemd160_files)
$(BUILDDEPS)
crypto/ripemd160.lo: $(go_crypto_ripemd160_files)
$(BUILDPACKAGE)
crypto/ripemd160/check: $(CHECK_DEPS)
@$(MKDIR_P) crypto/ripemd160
@$(CHECK)
.PHONY: crypto/ripemd160/check
@go_include@ crypto/rsa.lo.dep @go_include@ crypto/rsa.lo.dep
crypto/rsa.lo.dep: $(go_crypto_rsa_files) crypto/rsa.lo.dep: $(go_crypto_rsa_files)
$(BUILDDEPS) $(BUILDDEPS)
@ -2577,16 +2364,6 @@ crypto/tls/check: $(CHECK_DEPS)
@$(CHECK) @$(CHECK)
.PHONY: crypto/tls/check .PHONY: crypto/tls/check
@go_include@ crypto/twofish.lo.dep
crypto/twofish.lo.dep: $(go_crypto_twofish_files)
$(BUILDDEPS)
crypto/twofish.lo: $(go_crypto_twofish_files)
$(BUILDPACKAGE)
crypto/twofish/check: $(CHECK_DEPS)
@$(MKDIR_P) crypto/twofish
@$(CHECK)
.PHONY: crypto/twofish/check
@go_include@ crypto/x509.lo.dep @go_include@ crypto/x509.lo.dep
crypto/x509.lo.dep: $(go_crypto_x509_files) crypto/x509.lo.dep: $(go_crypto_x509_files)
$(BUILDDEPS) $(BUILDDEPS)
@ -2597,66 +2374,6 @@ crypto/x509/check: $(CHECK_DEPS)
@$(CHECK) @$(CHECK)
.PHONY: crypto/x509/check .PHONY: crypto/x509/check
@go_include@ crypto/xtea.lo.dep
crypto/xtea.lo.dep: $(go_crypto_xtea_files)
$(BUILDDEPS)
crypto/xtea.lo: $(go_crypto_xtea_files)
$(BUILDPACKAGE)
crypto/xtea/check: $(CHECK_DEPS)
@$(MKDIR_P) crypto/xtea
@$(CHECK)
.PHONY: crypto/xtea/check
@go_include@ crypto/openpgp/armor.lo.dep
crypto/openpgp/armor.lo.dep: $(go_crypto_openpgp_armor_files)
$(BUILDDEPS)
crypto/openpgp/armor.lo: $(go_crypto_openpgp_armor_files)
$(BUILDPACKAGE)
crypto/openpgp/armor/check: $(CHECK_DEPS)
@$(MKDIR_P) crypto/openpgp/armor
@$(CHECK)
.PHONY: crypto/openpgp/armor/check
@go_include@ crypto/openpgp/elgamal.lo.dep
crypto/openpgp/elgamal.lo.dep: $(go_crypto_openpgp_elgamal_files)
$(BUILDDEPS)
crypto/openpgp/elgamal.lo: $(go_crypto_openpgp_elgamal_files)
$(BUILDPACKAGE)
crypto/openpgp/elgamal/check: $(CHECK_DEPS)
@$(MKDIR_P) crypto/openpgp/elgamal
@$(CHECK)
.PHONY: crypto/openpgp/elgamal/check
@go_include@ crypto/openpgp/errors.lo.dep
crypto/openpgp/errors.lo.dep: $(go_crypto_openpgp_errors_files)
$(BUILDDEPS)
crypto/openpgp/errors.lo: $(go_crypto_openpgp_errors_files)
$(BUILDPACKAGE)
crypto/openpgp/errors/check: $(CHECK_DEPS)
@$(MKDIR_P) crypto/openpgp/errors
@$(CHECK)
.PHONY: crypto/openpgp/errors/check
@go_include@ crypto/openpgp/packet.lo.dep
crypto/openpgp/packet.lo.dep: $(go_crypto_openpgp_packet_files)
$(BUILDDEPS)
crypto/openpgp/packet.lo: $(go_crypto_openpgp_packet_files)
$(BUILDPACKAGE)
crypto/openpgp/packet/check: $(CHECK_DEPS)
@$(MKDIR_P) crypto/openpgp/packet
@$(CHECK)
.PHONY: crypto/openpgp/packet/check
@go_include@ crypto/openpgp/s2k.lo.dep
crypto/openpgp/s2k.lo.dep: $(go_crypto_openpgp_s2k_files)
$(BUILDDEPS)
crypto/openpgp/s2k.lo: $(go_crypto_openpgp_s2k_files)
$(BUILDPACKAGE)
crypto/openpgp/s2k/check: $(CHECK_DEPS)
@$(MKDIR_P) crypto/openpgp/s2k
@$(CHECK)
.PHONY: crypto/openpgp/s2k/check
@go_include@ crypto/x509/pkix.lo.dep @go_include@ crypto/x509/pkix.lo.dep
crypto/x509/pkix.lo.dep: $(go_crypto_x509_pkix_files) crypto/x509/pkix.lo.dep: $(go_crypto_x509_pkix_files)
$(BUILDDEPS) $(BUILDDEPS)
@ -2797,16 +2514,6 @@ encoding/csv/check: $(CHECK_DEPS)
@$(CHECK) @$(CHECK)
.PHONY: encoding/csv/check .PHONY: encoding/csv/check
@go_include@ encoding/git85.lo.dep
encoding/git85.lo.dep: $(go_encoding_git85_files)
$(BUILDDEPS)
encoding/git85.lo: $(go_encoding_git85_files)
$(BUILDPACKAGE)
encoding/git85/check: $(CHECK_DEPS)
@$(MKDIR_P) encoding/git85
@$(CHECK)
.PHONY: encoding/git85/check
@go_include@ encoding/gob.lo.dep @go_include@ encoding/gob.lo.dep
encoding/gob.lo.dep: $(go_encoding_gob_files) encoding/gob.lo.dep: $(go_encoding_gob_files)
$(BUILDDEPS) $(BUILDDEPS)
@ -2867,6 +2574,16 @@ exp/ebnf/check: $(CHECK_DEPS)
@$(CHECK) @$(CHECK)
.PHONY: exp/ebnf/check .PHONY: exp/ebnf/check
@go_include@ exp/html.lo.dep
exp/html.lo.dep: $(go_exp_html_files)
$(BUILDDEPS)
exp/html.lo: $(go_exp_html_files)
$(BUILDPACKAGE)
exp/html/check: $(CHECK_DEPS)
@$(MKDIR_P) exp/html
@$(CHECK)
.PHONY: exp/html/check
@go_include@ exp/norm.lo.dep @go_include@ exp/norm.lo.dep
exp/norm.lo.dep: $(go_exp_norm_files) exp/norm.lo.dep: $(go_exp_norm_files)
$(BUILDDEPS) $(BUILDDEPS)
@ -2887,26 +2604,6 @@ exp/proxy/check: $(CHECK_DEPS)
@$(CHECK) @$(CHECK)
.PHONY: exp/proxy/check .PHONY: exp/proxy/check
@go_include@ exp/spdy.lo.dep
exp/spdy.lo.dep: $(go_exp_spdy_files)
$(BUILDDEPS)
exp/spdy.lo: $(go_exp_spdy_files)
$(BUILDPACKAGE)
exp/spdy/check: $(CHECK_DEPS)
@$(MKDIR_P) exp/spdy
@$(CHECK)
.PHONY: exp/spdy/check
@go_include@ exp/ssh.lo.dep
exp/ssh.lo.dep: $(go_exp_ssh_files)
$(BUILDDEPS)
exp/ssh.lo: $(go_exp_ssh_files)
$(BUILDPACKAGE)
exp/ssh/check: $(CHECK_DEPS)
@$(MKDIR_P) exp/ssh
@$(CHECK)
.PHONY: exp/ssh/check
@go_include@ exp/terminal.lo.dep @go_include@ exp/terminal.lo.dep
exp/terminal.lo.dep: $(go_exp_terminal_files) exp/terminal.lo.dep: $(go_exp_terminal_files)
$(BUILDDEPS) $(BUILDDEPS)
@ -3218,12 +2915,6 @@ mime/multipart/check: $(CHECK_DEPS)
@$(CHECK) @$(CHECK)
.PHONY: mime/multipart/check .PHONY: mime/multipart/check
@go_include@ net/dict.lo.dep
net/dict.lo.dep: $(go_net_dict_files)
$(BUILDDEPS)
net/dict.lo: $(go_net_dict_files)
$(BUILDPACKAGE)
@go_include@ net/http.lo.dep @go_include@ net/http.lo.dep
net/http.lo.dep: $(go_net_http_files) net/http.lo.dep: $(go_net_http_files)
$(BUILDDEPS) $(BUILDDEPS)
@ -3582,8 +3273,6 @@ net.gox: net/net.lo
$(BUILDGOX) $(BUILDGOX)
os.gox: os/os.lo os.gox: os/os.lo
$(BUILDGOX) $(BUILDGOX)
patch.gox: patch/patch.lo
$(BUILDGOX)
path.gox: path/path.lo path.gox: path/path.lo
$(BUILDGOX) $(BUILDGOX)
reflect.gox: reflect/reflect.lo reflect.gox: reflect/reflect.lo
@ -3608,8 +3297,6 @@ time.gox: time/time.lo
$(BUILDGOX) $(BUILDGOX)
unicode.gox: unicode/unicode.lo unicode.gox: unicode/unicode.lo
$(BUILDGOX) $(BUILDGOX)
websocket.gox: websocket/websocket.lo
$(BUILDGOX)
archive/tar.gox: archive/tar.lo archive/tar.gox: archive/tar.lo
$(BUILDGOX) $(BUILDGOX)
@ -3636,12 +3323,6 @@ container/ring.gox: container/ring.lo
crypto/aes.gox: crypto/aes.lo crypto/aes.gox: crypto/aes.lo
$(BUILDGOX) $(BUILDGOX)
crypto/bcrypt.gox: crypto/bcrypt.lo
$(BUILDGOX)
crypto/blowfish.gox: crypto/blowfish.lo
$(BUILDGOX)
crypto/cast5.gox: crypto/cast5.lo
$(BUILDGOX)
crypto/cipher.gox: crypto/cipher.lo crypto/cipher.gox: crypto/cipher.lo
$(BUILDGOX) $(BUILDGOX)
crypto/des.gox: crypto/des.lo crypto/des.gox: crypto/des.lo
@ -3654,20 +3335,12 @@ crypto/elliptic.gox: crypto/elliptic.lo
$(BUILDGOX) $(BUILDGOX)
crypto/hmac.gox: crypto/hmac.lo crypto/hmac.gox: crypto/hmac.lo
$(BUILDGOX) $(BUILDGOX)
crypto/md4.gox: crypto/md4.lo
$(BUILDGOX)
crypto/md5.gox: crypto/md5.lo crypto/md5.gox: crypto/md5.lo
$(BUILDGOX) $(BUILDGOX)
crypto/ocsp.gox: crypto/ocsp.lo
$(BUILDGOX)
crypto/openpgp.gox: crypto/openpgp.lo
$(BUILDGOX)
crypto/rand.gox: crypto/rand.lo crypto/rand.gox: crypto/rand.lo
$(BUILDGOX) $(BUILDGOX)
crypto/rc4.gox: crypto/rc4.lo crypto/rc4.gox: crypto/rc4.lo
$(BUILDGOX) $(BUILDGOX)
crypto/ripemd160.gox: crypto/ripemd160.lo
$(BUILDGOX)
crypto/rsa.gox: crypto/rsa.lo crypto/rsa.gox: crypto/rsa.lo
$(BUILDGOX) $(BUILDGOX)
crypto/sha1.gox: crypto/sha1.lo crypto/sha1.gox: crypto/sha1.lo
@ -3680,23 +3353,8 @@ crypto/subtle.gox: crypto/subtle.lo
$(BUILDGOX) $(BUILDGOX)
crypto/tls.gox: crypto/tls.lo crypto/tls.gox: crypto/tls.lo
$(BUILDGOX) $(BUILDGOX)
crypto/twofish.gox: crypto/twofish.lo
$(BUILDGOX)
crypto/x509.gox: crypto/x509.lo crypto/x509.gox: crypto/x509.lo
$(BUILDGOX) $(BUILDGOX)
crypto/xtea.gox: crypto/xtea.lo
$(BUILDGOX)
crypto/openpgp/armor.gox: crypto/openpgp/armor.lo
$(BUILDGOX)
crypto/openpgp/elgamal.gox: crypto/openpgp/elgamal.lo
$(BUILDGOX)
crypto/openpgp/errors.gox: crypto/openpgp/errors.lo
$(BUILDGOX)
crypto/openpgp/packet.gox: crypto/openpgp/packet.lo
$(BUILDGOX)
crypto/openpgp/s2k.gox: crypto/openpgp/s2k.lo
$(BUILDGOX)
crypto/x509/pkix.gox: crypto/x509/pkix.lo crypto/x509/pkix.gox: crypto/x509/pkix.lo
$(BUILDGOX) $(BUILDGOX)
@ -3730,8 +3388,6 @@ encoding/binary.gox: encoding/binary.lo
$(BUILDGOX) $(BUILDGOX)
encoding/csv.gox: encoding/csv.lo encoding/csv.gox: encoding/csv.lo
$(BUILDGOX) $(BUILDGOX)
encoding/git85.gox: encoding/git85.lo
$(BUILDGOX)
encoding/gob.gox: encoding/gob.lo encoding/gob.gox: encoding/gob.lo
$(BUILDGOX) $(BUILDGOX)
encoding/hex.gox: encoding/hex.lo encoding/hex.gox: encoding/hex.lo
@ -3745,16 +3401,14 @@ encoding/xml.gox: encoding/xml.lo
exp/ebnf.gox: exp/ebnf.lo exp/ebnf.gox: exp/ebnf.lo
$(BUILDGOX) $(BUILDGOX)
exp/html.gox: exp/html.lo
$(BUILDGOX)
exp/inotify.gox: exp/inotify.lo exp/inotify.gox: exp/inotify.lo
$(BUILDGOX) $(BUILDGOX)
exp/norm.gox: exp/norm.lo exp/norm.gox: exp/norm.lo
$(BUILDGOX) $(BUILDGOX)
exp/proxy.gox: exp/proxy.lo exp/proxy.gox: exp/proxy.lo
$(BUILDGOX) $(BUILDGOX)
exp/spdy.gox: exp/spdy.lo
$(BUILDGOX)
exp/ssh.gox: exp/ssh.lo
$(BUILDGOX)
exp/terminal.gox: exp/terminal.lo exp/terminal.gox: exp/terminal.lo
$(BUILDGOX) $(BUILDGOX)
exp/types.gox: exp/types.lo exp/types.gox: exp/types.lo
@ -3823,8 +3477,6 @@ math/rand.gox: math/rand.lo
mime/multipart.gox: mime/multipart.lo mime/multipart.gox: mime/multipart.lo
$(BUILDGOX) $(BUILDGOX)
net/dict.gox: net/dict.lo
$(BUILDGOX)
net/http.gox: net/http.lo net/http.gox: net/http.lo
$(BUILDGOX) $(BUILDGOX)
net/mail.gox: net/mail.lo net/mail.gox: net/mail.lo
@ -3923,7 +3575,6 @@ TEST_PACKAGES = \
mime/check \ mime/check \
net/check \ net/check \
os/check \ os/check \
patch/check \
path/check \ path/check \
reflect/check \ reflect/check \
regexp/check \ regexp/check \
@ -3934,7 +3585,6 @@ TEST_PACKAGES = \
sync/check \ sync/check \
time/check \ time/check \
unicode/check \ unicode/check \
websocket/check \
archive/tar/check \ archive/tar/check \
archive/zip/check \ archive/zip/check \
compress/bzip2/check \ compress/bzip2/check \
@ -3946,35 +3596,22 @@ TEST_PACKAGES = \
container/list/check \ container/list/check \
container/ring/check \ container/ring/check \
crypto/aes/check \ crypto/aes/check \
crypto/bcrypt/check \
crypto/blowfish/check \
crypto/cast5/check \
crypto/cipher/check \ crypto/cipher/check \
crypto/des/check \ crypto/des/check \
crypto/dsa/check \ crypto/dsa/check \
crypto/ecdsa/check \ crypto/ecdsa/check \
crypto/elliptic/check \ crypto/elliptic/check \
crypto/hmac/check \ crypto/hmac/check \
crypto/md4/check \
crypto/md5/check \ crypto/md5/check \
crypto/ocsp/check \
crypto/openpgp/check \
crypto/rand/check \ crypto/rand/check \
crypto/rc4/check \ crypto/rc4/check \
crypto/ripemd160/check \
crypto/rsa/check \ crypto/rsa/check \
crypto/sha1/check \ crypto/sha1/check \
crypto/sha256/check \ crypto/sha256/check \
crypto/sha512/check \ crypto/sha512/check \
crypto/subtle/check \ crypto/subtle/check \
crypto/tls/check \ crypto/tls/check \
crypto/twofish/check \
crypto/x509/check \ crypto/x509/check \
crypto/xtea/check \
crypto/openpgp/armor/check \
crypto/openpgp/elgamal/check \
crypto/openpgp/packet/check \
crypto/openpgp/s2k/check \
database/sql/check \ database/sql/check \
database/sql/driver/check \ database/sql/driver/check \
debug/dwarf/check \ debug/dwarf/check \
@ -3987,18 +3624,16 @@ TEST_PACKAGES = \
encoding/base64/check \ encoding/base64/check \
encoding/binary/check \ encoding/binary/check \
encoding/csv/check \ encoding/csv/check \
encoding/git85/check \
encoding/gob/check \ encoding/gob/check \
encoding/hex/check \ encoding/hex/check \
encoding/json/check \ encoding/json/check \
encoding/pem/check \ encoding/pem/check \
encoding/xml/check \ encoding/xml/check \
exp/ebnf/check \ exp/ebnf/check \
exp/html/check \
$(exp_inotify_check) \ $(exp_inotify_check) \
exp/norm/check \ exp/norm/check \
exp/proxy/check \ exp/proxy/check \
exp/spdy/check \
exp/ssh/check \
exp/terminal/check \ exp/terminal/check \
exp/utf8string/check \ exp/utf8string/check \
html/template/check \ html/template/check \

View File

@ -97,7 +97,6 @@ am__installdirs = "$(DESTDIR)$(toolexeclibdir)" \
"$(DESTDIR)$(toolexeclibgocompressdir)" \ "$(DESTDIR)$(toolexeclibgocompressdir)" \
"$(DESTDIR)$(toolexeclibgocontainerdir)" \ "$(DESTDIR)$(toolexeclibgocontainerdir)" \
"$(DESTDIR)$(toolexeclibgocryptodir)" \ "$(DESTDIR)$(toolexeclibgocryptodir)" \
"$(DESTDIR)$(toolexeclibgocryptoopenpgpdir)" \
"$(DESTDIR)$(toolexeclibgocryptox509dir)" \ "$(DESTDIR)$(toolexeclibgocryptox509dir)" \
"$(DESTDIR)$(toolexeclibgodatabasedir)" \ "$(DESTDIR)$(toolexeclibgodatabasedir)" \
"$(DESTDIR)$(toolexeclibgodatabasesqldir)" \ "$(DESTDIR)$(toolexeclibgodatabasesqldir)" \
@ -138,31 +137,24 @@ am__DEPENDENCIES_2 = bufio/bufio.lo bytes/bytes.lo bytes/index.lo \
crypto/crypto.lo errors/errors.lo expvar/expvar.lo \ crypto/crypto.lo errors/errors.lo expvar/expvar.lo \
flag/flag.lo fmt/fmt.lo hash/hash.lo html/html.lo \ flag/flag.lo fmt/fmt.lo hash/hash.lo html/html.lo \
image/image.lo io/io.lo log/log.lo math/math.lo net/net.lo \ image/image.lo io/io.lo log/log.lo math/math.lo net/net.lo \
os/exec.lo os/os.lo patch/patch.lo path/path.lo \ os/exec.lo os/os.lo path/path.lo reflect/reflect.lo \
reflect/reflect.lo regexp/regexp.lo runtime/runtime.lo \ regexp/regexp.lo runtime/runtime.lo sort/sort.lo \
sort/sort.lo strconv/strconv.lo strings/strings.lo \ strconv/strconv.lo strings/strings.lo sync/sync.lo \
sync/sync.lo time/time.lo unicode/unicode.lo \ time/time.lo unicode/unicode.lo archive/tar.lo archive/zip.lo \
websocket/websocket.lo archive/tar.lo archive/zip.lo \
compress/bzip2.lo compress/flate.lo compress/gzip.lo \ compress/bzip2.lo compress/flate.lo compress/gzip.lo \
compress/lzw.lo compress/zlib.lo container/heap.lo \ compress/lzw.lo compress/zlib.lo container/heap.lo \
container/list.lo container/ring.lo crypto/aes.lo \ container/list.lo container/ring.lo crypto/aes.lo \
crypto/bcrypt.lo crypto/blowfish.lo crypto/cast5.lo \
crypto/cipher.lo crypto/des.lo crypto/dsa.lo crypto/ecdsa.lo \ crypto/cipher.lo crypto/des.lo crypto/dsa.lo crypto/ecdsa.lo \
crypto/elliptic.lo crypto/hmac.lo crypto/md4.lo crypto/md5.lo \ crypto/elliptic.lo crypto/hmac.lo crypto/md5.lo crypto/rand.lo \
crypto/ocsp.lo crypto/openpgp.lo crypto/rand.lo crypto/rc4.lo \ crypto/rc4.lo crypto/rsa.lo crypto/sha1.lo crypto/sha256.lo \
crypto/ripemd160.lo crypto/rsa.lo crypto/sha1.lo \ crypto/sha512.lo crypto/subtle.lo crypto/tls.lo crypto/x509.lo \
crypto/sha256.lo crypto/sha512.lo crypto/subtle.lo \ crypto/x509/pkix.lo database/sql.lo database/sql/driver.lo \
crypto/tls.lo crypto/twofish.lo crypto/x509.lo crypto/xtea.lo \ debug/dwarf.lo debug/elf.lo debug/gosym.lo debug/macho.lo \
crypto/openpgp/armor.lo crypto/openpgp/elgamal.lo \ debug/pe.lo encoding/ascii85.lo encoding/asn1.lo \
crypto/openpgp/errors.lo crypto/openpgp/packet.lo \ encoding/base32.lo encoding/base64.lo encoding/binary.lo \
crypto/openpgp/s2k.lo crypto/x509/pkix.lo database/sql.lo \ encoding/csv.lo encoding/gob.lo encoding/hex.lo \
database/sql/driver.lo debug/dwarf.lo debug/elf.lo \ encoding/json.lo encoding/pem.lo encoding/xml.lo exp/ebnf.lo \
debug/gosym.lo debug/macho.lo debug/pe.lo encoding/ascii85.lo \ exp/html.lo exp/norm.lo exp/proxy.lo exp/terminal.lo \
encoding/asn1.lo encoding/base32.lo encoding/base64.lo \
encoding/binary.lo encoding/csv.lo encoding/git85.lo \
encoding/gob.lo encoding/hex.lo encoding/json.lo \
encoding/pem.lo encoding/xml.lo exp/ebnf.lo exp/norm.lo \
exp/proxy.lo exp/spdy.lo exp/ssh.lo exp/terminal.lo \
exp/types.lo exp/utf8string.lo html/template.lo go/ast.lo \ exp/types.lo exp/utf8string.lo html/template.lo go/ast.lo \
go/build.lo go/doc.lo go/parser.lo go/printer.lo go/scanner.lo \ go/build.lo go/doc.lo go/parser.lo go/printer.lo go/scanner.lo \
go/token.lo hash/adler32.lo hash/crc32.lo hash/crc64.lo \ go/token.lo hash/adler32.lo hash/crc32.lo hash/crc64.lo \
@ -172,7 +164,7 @@ am__DEPENDENCIES_2 = bufio/bufio.lo bytes/bytes.lo bytes/index.lo \
image/jpeg.lo image/png.lo image/tiff.lo index/suffixarray.lo \ image/jpeg.lo image/png.lo image/tiff.lo index/suffixarray.lo \
io/ioutil.lo log/syslog.lo log/syslog/syslog_c.lo math/big.lo \ io/ioutil.lo log/syslog.lo log/syslog/syslog_c.lo math/big.lo \
math/cmplx.lo math/rand.lo mime/mime.lo mime/multipart.lo \ math/cmplx.lo math/rand.lo mime/mime.lo mime/multipart.lo \
net/dict.lo net/http.lo net/mail.lo net/rpc.lo net/smtp.lo \ net/http.lo net/mail.lo net/rpc.lo net/smtp.lo \
net/textproto.lo net/url.lo old/netchan.lo old/regexp.lo \ net/textproto.lo net/url.lo old/netchan.lo old/regexp.lo \
old/template.lo $(am__DEPENDENCIES_1) os/user.lo os/signal.lo \ old/template.lo $(am__DEPENDENCIES_1) os/user.lo os/signal.lo \
path/filepath.lo regexp/syntax.lo net/rpc/jsonrpc.lo \ path/filepath.lo regexp/syntax.lo net/rpc/jsonrpc.lo \
@ -289,21 +281,21 @@ RECURSIVE_TARGETS = all-recursive check-recursive dvi-recursive \
ps-recursive uninstall-recursive ps-recursive uninstall-recursive
DATA = $(toolexeclibgo_DATA) $(toolexeclibgoarchive_DATA) \ DATA = $(toolexeclibgo_DATA) $(toolexeclibgoarchive_DATA) \
$(toolexeclibgocompress_DATA) $(toolexeclibgocontainer_DATA) \ $(toolexeclibgocompress_DATA) $(toolexeclibgocontainer_DATA) \
$(toolexeclibgocrypto_DATA) $(toolexeclibgocryptoopenpgp_DATA) \ $(toolexeclibgocrypto_DATA) $(toolexeclibgocryptox509_DATA) \
$(toolexeclibgocryptox509_DATA) $(toolexeclibgodatabase_DATA) \ $(toolexeclibgodatabase_DATA) $(toolexeclibgodatabasesql_DATA) \
$(toolexeclibgodatabasesql_DATA) $(toolexeclibgodebug_DATA) \ $(toolexeclibgodebug_DATA) $(toolexeclibgoencoding_DATA) \
$(toolexeclibgoencoding_DATA) $(toolexeclibgoexp_DATA) \ $(toolexeclibgoexp_DATA) $(toolexeclibgogo_DATA) \
$(toolexeclibgogo_DATA) $(toolexeclibgohash_DATA) \ $(toolexeclibgohash_DATA) $(toolexeclibgohtml_DATA) \
$(toolexeclibgohtml_DATA) $(toolexeclibgoimage_DATA) \ $(toolexeclibgoimage_DATA) $(toolexeclibgoindex_DATA) \
$(toolexeclibgoindex_DATA) $(toolexeclibgoio_DATA) \ $(toolexeclibgoio_DATA) $(toolexeclibgolog_DATA) \
$(toolexeclibgolog_DATA) $(toolexeclibgomath_DATA) \ $(toolexeclibgomath_DATA) $(toolexeclibgomime_DATA) \
$(toolexeclibgomime_DATA) $(toolexeclibgonet_DATA) \ $(toolexeclibgonet_DATA) $(toolexeclibgonethttp_DATA) \
$(toolexeclibgonethttp_DATA) $(toolexeclibgonetrpc_DATA) \ $(toolexeclibgonetrpc_DATA) $(toolexeclibgoold_DATA) \
$(toolexeclibgoold_DATA) $(toolexeclibgoos_DATA) \ $(toolexeclibgoos_DATA) $(toolexeclibgopath_DATA) \
$(toolexeclibgopath_DATA) $(toolexeclibgoregexp_DATA) \ $(toolexeclibgoregexp_DATA) $(toolexeclibgoruntime_DATA) \
$(toolexeclibgoruntime_DATA) $(toolexeclibgosync_DATA) \ $(toolexeclibgosync_DATA) $(toolexeclibgotesting_DATA) \
$(toolexeclibgotesting_DATA) $(toolexeclibgotext_DATA) \ $(toolexeclibgotext_DATA) $(toolexeclibgotexttemplate_DATA) \
$(toolexeclibgotexttemplate_DATA) $(toolexeclibgounicode_DATA) $(toolexeclibgounicode_DATA)
RECURSIVE_CLEAN_TARGETS = mostlyclean-recursive clean-recursive \ RECURSIVE_CLEAN_TARGETS = mostlyclean-recursive clean-recursive \
distclean-recursive maintainer-clean-recursive distclean-recursive maintainer-clean-recursive
AM_RECURSIVE_TARGETS = $(RECURSIVE_TARGETS:-recursive=) \ AM_RECURSIVE_TARGETS = $(RECURSIVE_TARGETS:-recursive=) \
@ -587,7 +579,6 @@ toolexeclibgo_DATA = \
mime.gox \ mime.gox \
net.gox \ net.gox \
os.gox \ os.gox \
patch.gox \
path.gox \ path.gox \
reflect.gox \ reflect.gox \
regexp.gox \ regexp.gox \
@ -599,8 +590,7 @@ toolexeclibgo_DATA = \
syscall.gox \ syscall.gox \
testing.gox \ testing.gox \
time.gox \ time.gox \
unicode.gox \ unicode.gox
websocket.gox
toolexeclibgoarchivedir = $(toolexeclibgodir)/archive toolexeclibgoarchivedir = $(toolexeclibgodir)/archive
toolexeclibgoarchive_DATA = \ toolexeclibgoarchive_DATA = \
@ -624,39 +614,22 @@ toolexeclibgocontainer_DATA = \
toolexeclibgocryptodir = $(toolexeclibgodir)/crypto toolexeclibgocryptodir = $(toolexeclibgodir)/crypto
toolexeclibgocrypto_DATA = \ toolexeclibgocrypto_DATA = \
crypto/aes.gox \ crypto/aes.gox \
crypto/bcrypt.gox \
crypto/blowfish.gox \
crypto/cast5.gox \
crypto/cipher.gox \ crypto/cipher.gox \
crypto/des.gox \ crypto/des.gox \
crypto/dsa.gox \ crypto/dsa.gox \
crypto/ecdsa.gox \ crypto/ecdsa.gox \
crypto/elliptic.gox \ crypto/elliptic.gox \
crypto/hmac.gox \ crypto/hmac.gox \
crypto/md4.gox \
crypto/md5.gox \ crypto/md5.gox \
crypto/ocsp.gox \
crypto/openpgp.gox \
crypto/rand.gox \ crypto/rand.gox \
crypto/rc4.gox \ crypto/rc4.gox \
crypto/ripemd160.gox \
crypto/rsa.gox \ crypto/rsa.gox \
crypto/sha1.gox \ crypto/sha1.gox \
crypto/sha256.gox \ crypto/sha256.gox \
crypto/sha512.gox \ crypto/sha512.gox \
crypto/subtle.gox \ crypto/subtle.gox \
crypto/tls.gox \ crypto/tls.gox \
crypto/twofish.gox \ crypto/x509.gox
crypto/x509.gox \
crypto/xtea.gox
toolexeclibgocryptoopenpgpdir = $(toolexeclibgocryptodir)/openpgp
toolexeclibgocryptoopenpgp_DATA = \
crypto/openpgp/armor.gox \
crypto/openpgp/elgamal.gox \
crypto/openpgp/errors.gox \
crypto/openpgp/packet.gox \
crypto/openpgp/s2k.gox
toolexeclibgocryptox509dir = $(toolexeclibgocryptodir)/x509 toolexeclibgocryptox509dir = $(toolexeclibgocryptodir)/x509
toolexeclibgocryptox509_DATA = \ toolexeclibgocryptox509_DATA = \
@ -686,7 +659,6 @@ toolexeclibgoencoding_DATA = \
encoding/base64.gox \ encoding/base64.gox \
encoding/binary.gox \ encoding/binary.gox \
encoding/csv.gox \ encoding/csv.gox \
encoding/git85.gox \
encoding/gob.gox \ encoding/gob.gox \
encoding/hex.gox \ encoding/hex.gox \
encoding/json.gox \ encoding/json.gox \
@ -700,11 +672,10 @@ toolexeclibgoencoding_DATA = \
toolexeclibgoexpdir = $(toolexeclibgodir)/exp toolexeclibgoexpdir = $(toolexeclibgodir)/exp
toolexeclibgoexp_DATA = \ toolexeclibgoexp_DATA = \
exp/ebnf.gox \ exp/ebnf.gox \
exp/html.gox \
$(exp_inotify_gox) \ $(exp_inotify_gox) \
exp/norm.gox \ exp/norm.gox \
exp/proxy.gox \ exp/proxy.gox \
exp/spdy.gox \
exp/ssh.gox \
exp/terminal.gox \ exp/terminal.gox \
exp/types.gox \ exp/types.gox \
exp/utf8string.gox exp/utf8string.gox
@ -764,7 +735,6 @@ toolexeclibgomime_DATA = \
toolexeclibgonetdir = $(toolexeclibgodir)/net toolexeclibgonetdir = $(toolexeclibgodir)/net
toolexeclibgonet_DATA = \ toolexeclibgonet_DATA = \
net/dict.gox \
net/http.gox \ net/http.gox \
net/mail.gox \ net/mail.gox \
net/rpc.gox \ net/rpc.gox \
@ -963,16 +933,8 @@ go_hash_files = \
go/hash/hash.go go/hash/hash.go
go_html_files = \ go_html_files = \
go/html/const.go \
go/html/doc.go \
go/html/doctype.go \
go/html/entity.go \ go/html/entity.go \
go/html/escape.go \ go/html/escape.go
go/html/foreign.go \
go/html/node.go \
go/html/parse.go \
go/html/render.go \
go/html/token.go
go_image_files = \ go_image_files = \
go/image/format.go \ go/image/format.go \
@ -1146,12 +1108,6 @@ go_os_files = \
go/os/types.go \ go/os/types.go \
signal_unix.go signal_unix.go
go_patch_files = \
go/patch/apply.go \
go/patch/git.go \
go/patch/patch.go \
go/patch/textdiff.go
go_path_files = \ go_path_files = \
go/path/match.go \ go/path/match.go \
go/path/path.go go/path/path.go
@ -1237,13 +1193,6 @@ go_unicode_files = \
go/unicode/letter.go \ go/unicode/letter.go \
go/unicode/tables.go go/unicode/tables.go
go_websocket_files = \
go/websocket/client.go \
go/websocket/hixie.go \
go/websocket/hybi.go \
go/websocket/server.go \
go/websocket/websocket.go
go_archive_tar_files = \ go_archive_tar_files = \
go/archive/tar/common.go \ go/archive/tar/common.go \
go/archive/tar/reader.go \ go/archive/tar/reader.go \
@ -1266,8 +1215,7 @@ go_compress_flate_files = \
go/compress/flate/huffman_code.go \ go/compress/flate/huffman_code.go \
go/compress/flate/inflate.go \ go/compress/flate/inflate.go \
go/compress/flate/reverse_bits.go \ go/compress/flate/reverse_bits.go \
go/compress/flate/token.go \ go/compress/flate/token.go
go/compress/flate/util.go
go_compress_gzip_files = \ go_compress_gzip_files = \
go/compress/gzip/gzip.go \ go/compress/gzip/gzip.go \
@ -1295,18 +1243,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_bcrypt_files = \
go/crypto/bcrypt/base64.go \
go/crypto/bcrypt/bcrypt.go
go_crypto_blowfish_files = \
go/crypto/blowfish/block.go \
go/crypto/blowfish/const.go \
go/crypto/blowfish/cipher.go
go_crypto_cast5_files = \
go/crypto/cast5/cast5.go
go_crypto_cipher_files = \ go_crypto_cipher_files = \
go/crypto/cipher/cbc.go \ go/crypto/cipher/cbc.go \
go/crypto/cipher/cfb.go \ go/crypto/cipher/cfb.go \
@ -1334,23 +1270,10 @@ go_crypto_elliptic_files = \
go_crypto_hmac_files = \ go_crypto_hmac_files = \
go/crypto/hmac/hmac.go go/crypto/hmac/hmac.go
go_crypto_md4_files = \
go/crypto/md4/md4.go \
go/crypto/md4/md4block.go
go_crypto_md5_files = \ go_crypto_md5_files = \
go/crypto/md5/md5.go \ go/crypto/md5/md5.go \
go/crypto/md5/md5block.go go/crypto/md5/md5block.go
go_crypto_ocsp_files = \
go/crypto/ocsp/ocsp.go
go_crypto_openpgp_files = \
go/crypto/openpgp/canonical_text.go \
go/crypto/openpgp/keys.go \
go/crypto/openpgp/read.go \
go/crypto/openpgp/write.go
go_crypto_rand_files = \ go_crypto_rand_files = \
go/crypto/rand/rand.go \ go/crypto/rand/rand.go \
go/crypto/rand/rand_unix.go \ go/crypto/rand/rand_unix.go \
@ -1359,10 +1282,6 @@ go_crypto_rand_files = \
go_crypto_rc4_files = \ go_crypto_rc4_files = \
go/crypto/rc4/rc4.go go/crypto/rc4/rc4.go
go_crypto_ripemd160_files = \
go/crypto/ripemd160/ripemd160.go \
go/crypto/ripemd160/ripemd160block.go
go_crypto_rsa_files = \ go_crypto_rsa_files = \
go/crypto/rsa/pkcs1v15.go \ go/crypto/rsa/pkcs1v15.go \
go/crypto/rsa/rsa.go go/crypto/rsa/rsa.go
@ -1395,9 +1314,6 @@ go_crypto_tls_files = \
go/crypto/tls/root_unix.go \ go/crypto/tls/root_unix.go \
go/crypto/tls/tls.go go/crypto/tls/tls.go
go_crypto_twofish_files = \
go/crypto/twofish/twofish.go
go_crypto_x509_files = \ go_crypto_x509_files = \
go/crypto/x509/cert_pool.go \ go/crypto/x509/cert_pool.go \
go/crypto/x509/pkcs1.go \ go/crypto/x509/pkcs1.go \
@ -1405,37 +1321,6 @@ go_crypto_x509_files = \
go/crypto/x509/verify.go \ go/crypto/x509/verify.go \
go/crypto/x509/x509.go go/crypto/x509/x509.go
go_crypto_xtea_files = \
go/crypto/xtea/block.go \
go/crypto/xtea/cipher.go
go_crypto_openpgp_armor_files = \
go/crypto/openpgp/armor/armor.go \
go/crypto/openpgp/armor/encode.go
go_crypto_openpgp_elgamal_files = \
go/crypto/openpgp/elgamal/elgamal.go
go_crypto_openpgp_errors_files = \
go/crypto/openpgp/errors/errors.go
go_crypto_openpgp_packet_files = \
go/crypto/openpgp/packet/compressed.go \
go/crypto/openpgp/packet/encrypted_key.go \
go/crypto/openpgp/packet/literal.go \
go/crypto/openpgp/packet/one_pass_signature.go \
go/crypto/openpgp/packet/packet.go \
go/crypto/openpgp/packet/private_key.go \
go/crypto/openpgp/packet/public_key.go \
go/crypto/openpgp/packet/reader.go \
go/crypto/openpgp/packet/signature.go \
go/crypto/openpgp/packet/symmetric_key_encrypted.go \
go/crypto/openpgp/packet/symmetrically_encrypted.go \
go/crypto/openpgp/packet/userid.go
go_crypto_openpgp_s2k_files = \
go/crypto/openpgp/s2k/s2k.go
go_crypto_x509_pkix_files = \ go_crypto_x509_pkix_files = \
go/crypto/x509/pkix/pkix.go go/crypto/x509/pkix/pkix.go
@ -1493,9 +1378,6 @@ go_encoding_csv_files = \
go/encoding/csv/reader.go \ go/encoding/csv/reader.go \
go/encoding/csv/writer.go go/encoding/csv/writer.go
go_encoding_git85_files = \
go/encoding/git85/git.go
go_encoding_gob_files = \ go_encoding_gob_files = \
go/encoding/gob/decode.go \ go/encoding/gob/decode.go \
go/encoding/gob/decoder.go \ go/encoding/gob/decoder.go \
@ -1529,6 +1411,18 @@ go_exp_ebnf_files = \
go/exp/ebnf/ebnf.go \ go/exp/ebnf/ebnf.go \
go/exp/ebnf/parser.go go/exp/ebnf/parser.go
go_exp_html_files = \
go/exp/html/const.go \
go/exp/html/doc.go \
go/exp/html/doctype.go \
go/exp/html/entity.go \
go/exp/html/escape.go \
go/exp/html/foreign.go \
go/exp/html/node.go \
go/exp/html/parse.go \
go/exp/html/render.go \
go/exp/html/token.go
go_exp_inotify_files = \ go_exp_inotify_files = \
go/exp/inotify/inotify_linux.go go/exp/inotify/inotify_linux.go
@ -1547,25 +1441,6 @@ go_exp_proxy_files = \
go/exp/proxy/proxy.go \ go/exp/proxy/proxy.go \
go/exp/proxy/socks5.go go/exp/proxy/socks5.go
go_exp_spdy_files = \
go/exp/spdy/read.go \
go/exp/spdy/types.go \
go/exp/spdy/write.go
go_exp_ssh_files = \
go/exp/ssh/channel.go \
go/exp/ssh/cipher.go \
go/exp/ssh/client.go \
go/exp/ssh/client_auth.go \
go/exp/ssh/common.go \
go/exp/ssh/doc.go \
go/exp/ssh/messages.go \
go/exp/ssh/server.go \
go/exp/ssh/server_terminal.go \
go/exp/ssh/session.go \
go/exp/ssh/tcpip.go \
go/exp/ssh/transport.go
go_exp_terminal_files = \ go_exp_terminal_files = \
go/exp/terminal/terminal.go \ go/exp/terminal/terminal.go \
go/exp/terminal/util.go go/exp/terminal/util.go
@ -1721,9 +1596,6 @@ go_mime_multipart_files = \
go/mime/multipart/multipart.go \ go/mime/multipart/multipart.go \
go/mime/multipart/writer.go go/mime/multipart/writer.go
go_net_dict_files = \
go/net/dict/dict.go
go_net_http_files = \ go_net_http_files = \
go/net/http/chunked.go \ go/net/http/chunked.go \
go/net/http/client.go \ go/net/http/client.go \
@ -1988,7 +1860,6 @@ libgo_go_objs = \
net/net.lo \ net/net.lo \
os/exec.lo \ os/exec.lo \
os/os.lo \ os/os.lo \
patch/patch.lo \
path/path.lo \ path/path.lo \
reflect/reflect.lo \ reflect/reflect.lo \
regexp/regexp.lo \ regexp/regexp.lo \
@ -1999,7 +1870,6 @@ libgo_go_objs = \
sync/sync.lo \ sync/sync.lo \
time/time.lo \ time/time.lo \
unicode/unicode.lo \ unicode/unicode.lo \
websocket/websocket.lo \
archive/tar.lo \ archive/tar.lo \
archive/zip.lo \ archive/zip.lo \
compress/bzip2.lo \ compress/bzip2.lo \
@ -2011,36 +1881,22 @@ libgo_go_objs = \
container/list.lo \ container/list.lo \
container/ring.lo \ container/ring.lo \
crypto/aes.lo \ crypto/aes.lo \
crypto/bcrypt.lo \
crypto/blowfish.lo \
crypto/cast5.lo \
crypto/cipher.lo \ crypto/cipher.lo \
crypto/des.lo \ crypto/des.lo \
crypto/dsa.lo \ crypto/dsa.lo \
crypto/ecdsa.lo \ crypto/ecdsa.lo \
crypto/elliptic.lo \ crypto/elliptic.lo \
crypto/hmac.lo \ crypto/hmac.lo \
crypto/md4.lo \
crypto/md5.lo \ crypto/md5.lo \
crypto/ocsp.lo \
crypto/openpgp.lo \
crypto/rand.lo \ crypto/rand.lo \
crypto/rc4.lo \ crypto/rc4.lo \
crypto/ripemd160.lo \
crypto/rsa.lo \ crypto/rsa.lo \
crypto/sha1.lo \ crypto/sha1.lo \
crypto/sha256.lo \ crypto/sha256.lo \
crypto/sha512.lo \ crypto/sha512.lo \
crypto/subtle.lo \ crypto/subtle.lo \
crypto/tls.lo \ crypto/tls.lo \
crypto/twofish.lo \
crypto/x509.lo \ crypto/x509.lo \
crypto/xtea.lo \
crypto/openpgp/armor.lo \
crypto/openpgp/elgamal.lo \
crypto/openpgp/errors.lo \
crypto/openpgp/packet.lo \
crypto/openpgp/s2k.lo \
crypto/x509/pkix.lo \ crypto/x509/pkix.lo \
database/sql.lo \ database/sql.lo \
database/sql/driver.lo \ database/sql/driver.lo \
@ -2055,17 +1911,15 @@ libgo_go_objs = \
encoding/base64.lo \ encoding/base64.lo \
encoding/binary.lo \ encoding/binary.lo \
encoding/csv.lo \ encoding/csv.lo \
encoding/git85.lo \
encoding/gob.lo \ encoding/gob.lo \
encoding/hex.lo \ encoding/hex.lo \
encoding/json.lo \ encoding/json.lo \
encoding/pem.lo \ encoding/pem.lo \
encoding/xml.lo \ encoding/xml.lo \
exp/ebnf.lo \ exp/ebnf.lo \
exp/html.lo \
exp/norm.lo \ exp/norm.lo \
exp/proxy.lo \ exp/proxy.lo \
exp/spdy.lo \
exp/ssh.lo \
exp/terminal.lo \ exp/terminal.lo \
exp/types.lo \ exp/types.lo \
exp/utf8string.lo \ exp/utf8string.lo \
@ -2102,7 +1956,6 @@ libgo_go_objs = \
math/rand.lo \ math/rand.lo \
mime/mime.lo \ mime/mime.lo \
mime/multipart.lo \ mime/multipart.lo \
net/dict.lo \
net/http.lo \ net/http.lo \
net/mail.lo \ net/mail.lo \
net/rpc.lo \ net/rpc.lo \
@ -2211,7 +2064,6 @@ CHECK_DEPS = libgo.la libgobegin.a \
$(toolexeclibgocompress_DATA) \ $(toolexeclibgocompress_DATA) \
$(toolexeclibgocontainer_DATA) \ $(toolexeclibgocontainer_DATA) \
$(toolexeclibgocrypto_DATA) \ $(toolexeclibgocrypto_DATA) \
$(toolexeclibgocryptoopenpgp_DATA) \
$(toolexeclibgodebug_DATA) \ $(toolexeclibgodebug_DATA) \
$(toolexeclibgoencoding_DATA) \ $(toolexeclibgoencoding_DATA) \
$(toolexeclibgoexp_DATA) \ $(toolexeclibgoexp_DATA) \
@ -2260,7 +2112,6 @@ TEST_PACKAGES = \
mime/check \ mime/check \
net/check \ net/check \
os/check \ os/check \
patch/check \
path/check \ path/check \
reflect/check \ reflect/check \
regexp/check \ regexp/check \
@ -2271,7 +2122,6 @@ TEST_PACKAGES = \
sync/check \ sync/check \
time/check \ time/check \
unicode/check \ unicode/check \
websocket/check \
archive/tar/check \ archive/tar/check \
archive/zip/check \ archive/zip/check \
compress/bzip2/check \ compress/bzip2/check \
@ -2283,35 +2133,22 @@ TEST_PACKAGES = \
container/list/check \ container/list/check \
container/ring/check \ container/ring/check \
crypto/aes/check \ crypto/aes/check \
crypto/bcrypt/check \
crypto/blowfish/check \
crypto/cast5/check \
crypto/cipher/check \ crypto/cipher/check \
crypto/des/check \ crypto/des/check \
crypto/dsa/check \ crypto/dsa/check \
crypto/ecdsa/check \ crypto/ecdsa/check \
crypto/elliptic/check \ crypto/elliptic/check \
crypto/hmac/check \ crypto/hmac/check \
crypto/md4/check \
crypto/md5/check \ crypto/md5/check \
crypto/ocsp/check \
crypto/openpgp/check \
crypto/rand/check \ crypto/rand/check \
crypto/rc4/check \ crypto/rc4/check \
crypto/ripemd160/check \
crypto/rsa/check \ crypto/rsa/check \
crypto/sha1/check \ crypto/sha1/check \
crypto/sha256/check \ crypto/sha256/check \
crypto/sha512/check \ crypto/sha512/check \
crypto/subtle/check \ crypto/subtle/check \
crypto/tls/check \ crypto/tls/check \
crypto/twofish/check \
crypto/x509/check \ crypto/x509/check \
crypto/xtea/check \
crypto/openpgp/armor/check \
crypto/openpgp/elgamal/check \
crypto/openpgp/packet/check \
crypto/openpgp/s2k/check \
database/sql/check \ database/sql/check \
database/sql/driver/check \ database/sql/driver/check \
debug/dwarf/check \ debug/dwarf/check \
@ -2324,18 +2161,16 @@ TEST_PACKAGES = \
encoding/base64/check \ encoding/base64/check \
encoding/binary/check \ encoding/binary/check \
encoding/csv/check \ encoding/csv/check \
encoding/git85/check \
encoding/gob/check \ encoding/gob/check \
encoding/hex/check \ encoding/hex/check \
encoding/json/check \ encoding/json/check \
encoding/pem/check \ encoding/pem/check \
encoding/xml/check \ encoding/xml/check \
exp/ebnf/check \ exp/ebnf/check \
exp/html/check \
$(exp_inotify_check) \ $(exp_inotify_check) \
exp/norm/check \ exp/norm/check \
exp/proxy/check \ exp/proxy/check \
exp/spdy/check \
exp/ssh/check \
exp/terminal/check \ exp/terminal/check \
exp/utf8string/check \ exp/utf8string/check \
html/template/check \ html/template/check \
@ -3353,26 +3188,6 @@ uninstall-toolexeclibgocryptoDATA:
test -n "$$files" || exit 0; \ test -n "$$files" || exit 0; \
echo " ( cd '$(DESTDIR)$(toolexeclibgocryptodir)' && rm -f" $$files ")"; \ echo " ( cd '$(DESTDIR)$(toolexeclibgocryptodir)' && rm -f" $$files ")"; \
cd "$(DESTDIR)$(toolexeclibgocryptodir)" && rm -f $$files cd "$(DESTDIR)$(toolexeclibgocryptodir)" && rm -f $$files
install-toolexeclibgocryptoopenpgpDATA: $(toolexeclibgocryptoopenpgp_DATA)
@$(NORMAL_INSTALL)
test -z "$(toolexeclibgocryptoopenpgpdir)" || $(MKDIR_P) "$(DESTDIR)$(toolexeclibgocryptoopenpgpdir)"
@list='$(toolexeclibgocryptoopenpgp_DATA)'; test -n "$(toolexeclibgocryptoopenpgpdir)" || list=; \
for p in $$list; do \
if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \
echo "$$d$$p"; \
done | $(am__base_list) | \
while read files; do \
echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(toolexeclibgocryptoopenpgpdir)'"; \
$(INSTALL_DATA) $$files "$(DESTDIR)$(toolexeclibgocryptoopenpgpdir)" || exit $$?; \
done
uninstall-toolexeclibgocryptoopenpgpDATA:
@$(NORMAL_UNINSTALL)
@list='$(toolexeclibgocryptoopenpgp_DATA)'; test -n "$(toolexeclibgocryptoopenpgpdir)" || list=; \
files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \
test -n "$$files" || exit 0; \
echo " ( cd '$(DESTDIR)$(toolexeclibgocryptoopenpgpdir)' && rm -f" $$files ")"; \
cd "$(DESTDIR)$(toolexeclibgocryptoopenpgpdir)" && rm -f $$files
install-toolexeclibgocryptox509DATA: $(toolexeclibgocryptox509_DATA) install-toolexeclibgocryptox509DATA: $(toolexeclibgocryptox509_DATA)
@$(NORMAL_INSTALL) @$(NORMAL_INSTALL)
test -z "$(toolexeclibgocryptox509dir)" || $(MKDIR_P) "$(DESTDIR)$(toolexeclibgocryptox509dir)" test -z "$(toolexeclibgocryptox509dir)" || $(MKDIR_P) "$(DESTDIR)$(toolexeclibgocryptox509dir)"
@ -4250,7 +4065,7 @@ all-am: Makefile $(LIBRARIES) $(LTLIBRARIES) all-multi $(DATA) \
config.h config.h
installdirs: installdirs-recursive installdirs: installdirs-recursive
installdirs-am: installdirs-am:
for dir in "$(DESTDIR)$(toolexeclibdir)" "$(DESTDIR)$(toolexeclibdir)" "$(DESTDIR)$(toolexeclibgodir)" "$(DESTDIR)$(toolexeclibgoarchivedir)" "$(DESTDIR)$(toolexeclibgocompressdir)" "$(DESTDIR)$(toolexeclibgocontainerdir)" "$(DESTDIR)$(toolexeclibgocryptodir)" "$(DESTDIR)$(toolexeclibgocryptoopenpgpdir)" "$(DESTDIR)$(toolexeclibgocryptox509dir)" "$(DESTDIR)$(toolexeclibgodatabasedir)" "$(DESTDIR)$(toolexeclibgodatabasesqldir)" "$(DESTDIR)$(toolexeclibgodebugdir)" "$(DESTDIR)$(toolexeclibgoencodingdir)" "$(DESTDIR)$(toolexeclibgoexpdir)" "$(DESTDIR)$(toolexeclibgogodir)" "$(DESTDIR)$(toolexeclibgohashdir)" "$(DESTDIR)$(toolexeclibgohtmldir)" "$(DESTDIR)$(toolexeclibgoimagedir)" "$(DESTDIR)$(toolexeclibgoindexdir)" "$(DESTDIR)$(toolexeclibgoiodir)" "$(DESTDIR)$(toolexeclibgologdir)" "$(DESTDIR)$(toolexeclibgomathdir)" "$(DESTDIR)$(toolexeclibgomimedir)" "$(DESTDIR)$(toolexeclibgonetdir)" "$(DESTDIR)$(toolexeclibgonethttpdir)" "$(DESTDIR)$(toolexeclibgonetrpcdir)" "$(DESTDIR)$(toolexeclibgoolddir)" "$(DESTDIR)$(toolexeclibgoosdir)" "$(DESTDIR)$(toolexeclibgopathdir)" "$(DESTDIR)$(toolexeclibgoregexpdir)" "$(DESTDIR)$(toolexeclibgoruntimedir)" "$(DESTDIR)$(toolexeclibgosyncdir)" "$(DESTDIR)$(toolexeclibgotestingdir)" "$(DESTDIR)$(toolexeclibgotextdir)" "$(DESTDIR)$(toolexeclibgotexttemplatedir)" "$(DESTDIR)$(toolexeclibgounicodedir)"; do \ for dir in "$(DESTDIR)$(toolexeclibdir)" "$(DESTDIR)$(toolexeclibdir)" "$(DESTDIR)$(toolexeclibgodir)" "$(DESTDIR)$(toolexeclibgoarchivedir)" "$(DESTDIR)$(toolexeclibgocompressdir)" "$(DESTDIR)$(toolexeclibgocontainerdir)" "$(DESTDIR)$(toolexeclibgocryptodir)" "$(DESTDIR)$(toolexeclibgocryptox509dir)" "$(DESTDIR)$(toolexeclibgodatabasedir)" "$(DESTDIR)$(toolexeclibgodatabasesqldir)" "$(DESTDIR)$(toolexeclibgodebugdir)" "$(DESTDIR)$(toolexeclibgoencodingdir)" "$(DESTDIR)$(toolexeclibgoexpdir)" "$(DESTDIR)$(toolexeclibgogodir)" "$(DESTDIR)$(toolexeclibgohashdir)" "$(DESTDIR)$(toolexeclibgohtmldir)" "$(DESTDIR)$(toolexeclibgoimagedir)" "$(DESTDIR)$(toolexeclibgoindexdir)" "$(DESTDIR)$(toolexeclibgoiodir)" "$(DESTDIR)$(toolexeclibgologdir)" "$(DESTDIR)$(toolexeclibgomathdir)" "$(DESTDIR)$(toolexeclibgomimedir)" "$(DESTDIR)$(toolexeclibgonetdir)" "$(DESTDIR)$(toolexeclibgonethttpdir)" "$(DESTDIR)$(toolexeclibgonetrpcdir)" "$(DESTDIR)$(toolexeclibgoolddir)" "$(DESTDIR)$(toolexeclibgoosdir)" "$(DESTDIR)$(toolexeclibgopathdir)" "$(DESTDIR)$(toolexeclibgoregexpdir)" "$(DESTDIR)$(toolexeclibgoruntimedir)" "$(DESTDIR)$(toolexeclibgosyncdir)" "$(DESTDIR)$(toolexeclibgotestingdir)" "$(DESTDIR)$(toolexeclibgotextdir)" "$(DESTDIR)$(toolexeclibgotexttemplatedir)" "$(DESTDIR)$(toolexeclibgounicodedir)"; do \
test -z "$$dir" || $(MKDIR_P) "$$dir"; \ test -z "$$dir" || $(MKDIR_P) "$$dir"; \
done done
install: install-recursive install: install-recursive
@ -4316,7 +4131,6 @@ install-exec-am: install-multi install-toolexeclibLIBRARIES \
install-toolexeclibgocompressDATA \ install-toolexeclibgocompressDATA \
install-toolexeclibgocontainerDATA \ install-toolexeclibgocontainerDATA \
install-toolexeclibgocryptoDATA \ install-toolexeclibgocryptoDATA \
install-toolexeclibgocryptoopenpgpDATA \
install-toolexeclibgocryptox509DATA \ install-toolexeclibgocryptox509DATA \
install-toolexeclibgodatabaseDATA \ install-toolexeclibgodatabaseDATA \
install-toolexeclibgodatabasesqlDATA \ install-toolexeclibgodatabasesqlDATA \
@ -4382,7 +4196,6 @@ uninstall-am: uninstall-toolexeclibLIBRARIES \
uninstall-toolexeclibgocompressDATA \ uninstall-toolexeclibgocompressDATA \
uninstall-toolexeclibgocontainerDATA \ uninstall-toolexeclibgocontainerDATA \
uninstall-toolexeclibgocryptoDATA \ uninstall-toolexeclibgocryptoDATA \
uninstall-toolexeclibgocryptoopenpgpDATA \
uninstall-toolexeclibgocryptox509DATA \ uninstall-toolexeclibgocryptox509DATA \
uninstall-toolexeclibgodatabaseDATA \ uninstall-toolexeclibgodatabaseDATA \
uninstall-toolexeclibgodatabasesqlDATA \ uninstall-toolexeclibgodatabasesqlDATA \
@ -4431,7 +4244,6 @@ uninstall-am: uninstall-toolexeclibLIBRARIES \
install-toolexeclibgocompressDATA \ install-toolexeclibgocompressDATA \
install-toolexeclibgocontainerDATA \ install-toolexeclibgocontainerDATA \
install-toolexeclibgocryptoDATA \ install-toolexeclibgocryptoDATA \
install-toolexeclibgocryptoopenpgpDATA \
install-toolexeclibgocryptox509DATA \ install-toolexeclibgocryptox509DATA \
install-toolexeclibgodatabaseDATA \ install-toolexeclibgodatabaseDATA \
install-toolexeclibgodatabasesqlDATA \ install-toolexeclibgodatabasesqlDATA \
@ -4461,7 +4273,6 @@ uninstall-am: uninstall-toolexeclibLIBRARIES \
uninstall-toolexeclibgocompressDATA \ uninstall-toolexeclibgocompressDATA \
uninstall-toolexeclibgocontainerDATA \ uninstall-toolexeclibgocontainerDATA \
uninstall-toolexeclibgocryptoDATA \ uninstall-toolexeclibgocryptoDATA \
uninstall-toolexeclibgocryptoopenpgpDATA \
uninstall-toolexeclibgocryptox509DATA \ uninstall-toolexeclibgocryptox509DATA \
uninstall-toolexeclibgodatabaseDATA \ uninstall-toolexeclibgodatabaseDATA \
uninstall-toolexeclibgodatabasesqlDATA \ uninstall-toolexeclibgodatabasesqlDATA \
@ -4737,15 +4548,6 @@ signal_unix.go: $(srcdir)/go/os/mkunixsignals.sh sysinfo.go
$(SHELL) $(srcdir)/go/os/mkunixsignals.sh sysinfo.go > $@.tmp $(SHELL) $(srcdir)/go/os/mkunixsignals.sh sysinfo.go > $@.tmp
mv -f $@.tmp $@ mv -f $@.tmp $@
@go_include@ patch/patch.lo.dep
patch/patch.lo.dep: $(go_patch_files)
$(BUILDDEPS)
patch/patch.lo: $(go_patch_files)
$(BUILDPACKAGE)
patch/check: $(CHECK_DEPS)
@$(CHECK)
.PHONY: patch/check
@go_include@ path/path.lo.dep @go_include@ path/path.lo.dep
path/path.lo.dep: $(go_path_files) path/path.lo.dep: $(go_path_files)
$(BUILDDEPS) $(BUILDDEPS)
@ -4855,15 +4657,6 @@ unicode/check: $(CHECK_DEPS)
@$(CHECK) @$(CHECK)
.PHONY: unicode/check .PHONY: unicode/check
@go_include@ websocket/websocket.lo.dep
websocket/websocket.lo.dep: $(go_websocket_files)
$(BUILDDEPS)
websocket/websocket.lo: $(go_websocket_files)
$(BUILDPACKAGE)
websocket/check: $(CHECK_DEPS)
@$(CHECK)
.PHONY: websocket/check
@go_include@ archive/tar.lo.dep @go_include@ archive/tar.lo.dep
archive/tar.lo.dep: $(go_archive_tar_files) archive/tar.lo.dep: $(go_archive_tar_files)
$(BUILDDEPS) $(BUILDDEPS)
@ -4974,36 +4767,6 @@ crypto/aes/check: $(CHECK_DEPS)
@$(CHECK) @$(CHECK)
.PHONY: crypto/aes/check .PHONY: crypto/aes/check
@go_include@ crypto/bcrypt.lo.dep
crypto/bcrypt.lo.dep: $(go_crypto_bcrypt_files)
$(BUILDDEPS)
crypto/bcrypt.lo: $(go_crypto_bcrypt_files)
$(BUILDPACKAGE)
crypto/bcrypt/check: $(CHECK_DEPS)
@$(MKDIR_P) crypto/bcrypt
@$(CHECK)
.PHONY: crypto/bcrypt/check
@go_include@ crypto/blowfish.lo.dep
crypto/blowfish.lo.dep: $(go_crypto_blowfish_files)
$(BUILDDEPS)
crypto/blowfish.lo: $(go_crypto_blowfish_files)
$(BUILDPACKAGE)
crypto/blowfish/check: $(CHECK_DEPS)
@$(MKDIR_P) crypto/blowfish
@$(CHECK)
.PHONY: crypto/blowfish/check
@go_include@ crypto/cast5.lo.dep
crypto/cast5.lo.dep: $(go_crypto_cast5_files)
$(BUILDDEPS)
crypto/cast5.lo: $(go_crypto_cast5_files)
$(BUILDPACKAGE)
crypto/cast5/check: $(CHECK_DEPS)
@$(MKDIR_P) crypto/cast5
@$(CHECK)
.PHONY: crypto/cast5/check
@go_include@ crypto/cipher.lo.dep @go_include@ crypto/cipher.lo.dep
crypto/cipher.lo.dep: $(go_crypto_cipher_files) crypto/cipher.lo.dep: $(go_crypto_cipher_files)
$(BUILDDEPS) $(BUILDDEPS)
@ -5064,16 +4827,6 @@ crypto/hmac/check: $(CHECK_DEPS)
@$(CHECK) @$(CHECK)
.PHONY: crypto/hmac/check .PHONY: crypto/hmac/check
@go_include@ crypto/md4.lo.dep
crypto/md4.lo.dep: $(go_crypto_md4_files)
$(BUILDDEPS)
crypto/md4.lo: $(go_crypto_md4_files)
$(BUILDPACKAGE)
crypto/md4/check: $(CHECK_DEPS)
@$(MKDIR_P) crypto/md4
@$(CHECK)
.PHONY: crypto/md4/check
@go_include@ crypto/md5.lo.dep @go_include@ crypto/md5.lo.dep
crypto/md5.lo.dep: $(go_crypto_md5_files) crypto/md5.lo.dep: $(go_crypto_md5_files)
$(BUILDDEPS) $(BUILDDEPS)
@ -5084,26 +4837,6 @@ crypto/md5/check: $(CHECK_DEPS)
@$(CHECK) @$(CHECK)
.PHONY: crypto/md5/check .PHONY: crypto/md5/check
@go_include@ crypto/ocsp.lo.dep
crypto/ocsp.lo.dep: $(go_crypto_ocsp_files)
$(BUILDDEPS)
crypto/ocsp.lo: $(go_crypto_ocsp_files)
$(BUILDPACKAGE)
crypto/ocsp/check: $(CHECK_DEPS)
@$(MKDIR_P) crypto/ocsp
@$(CHECK)
.PHONY: crypto/ocsp/check
@go_include@ crypto/openpgp.lo.dep
crypto/openpgp.lo.dep: $(go_crypto_openpgp_files)
$(BUILDDEPS)
crypto/openpgp.lo: $(go_crypto_openpgp_files)
$(BUILDPACKAGE)
crypto/openpgp/check: $(CHECK_DEPS)
@$(MKDIR_P) crypto/openpgp
@$(CHECK)
.PHONY: crypto/openpgp/check
@go_include@ crypto/rand.lo.dep @go_include@ crypto/rand.lo.dep
crypto/rand.lo.dep: $(go_crypto_rand_files) crypto/rand.lo.dep: $(go_crypto_rand_files)
$(BUILDDEPS) $(BUILDDEPS)
@ -5124,16 +4857,6 @@ crypto/rc4/check: $(CHECK_DEPS)
@$(CHECK) @$(CHECK)
.PHONY: crypto/rc4/check .PHONY: crypto/rc4/check
@go_include@ crypto/ripemd160.lo.dep
crypto/ripemd160.lo.dep: $(go_crypto_ripemd160_files)
$(BUILDDEPS)
crypto/ripemd160.lo: $(go_crypto_ripemd160_files)
$(BUILDPACKAGE)
crypto/ripemd160/check: $(CHECK_DEPS)
@$(MKDIR_P) crypto/ripemd160
@$(CHECK)
.PHONY: crypto/ripemd160/check
@go_include@ crypto/rsa.lo.dep @go_include@ crypto/rsa.lo.dep
crypto/rsa.lo.dep: $(go_crypto_rsa_files) crypto/rsa.lo.dep: $(go_crypto_rsa_files)
$(BUILDDEPS) $(BUILDDEPS)
@ -5194,16 +4917,6 @@ crypto/tls/check: $(CHECK_DEPS)
@$(CHECK) @$(CHECK)
.PHONY: crypto/tls/check .PHONY: crypto/tls/check
@go_include@ crypto/twofish.lo.dep
crypto/twofish.lo.dep: $(go_crypto_twofish_files)
$(BUILDDEPS)
crypto/twofish.lo: $(go_crypto_twofish_files)
$(BUILDPACKAGE)
crypto/twofish/check: $(CHECK_DEPS)
@$(MKDIR_P) crypto/twofish
@$(CHECK)
.PHONY: crypto/twofish/check
@go_include@ crypto/x509.lo.dep @go_include@ crypto/x509.lo.dep
crypto/x509.lo.dep: $(go_crypto_x509_files) crypto/x509.lo.dep: $(go_crypto_x509_files)
$(BUILDDEPS) $(BUILDDEPS)
@ -5214,66 +4927,6 @@ crypto/x509/check: $(CHECK_DEPS)
@$(CHECK) @$(CHECK)
.PHONY: crypto/x509/check .PHONY: crypto/x509/check
@go_include@ crypto/xtea.lo.dep
crypto/xtea.lo.dep: $(go_crypto_xtea_files)
$(BUILDDEPS)
crypto/xtea.lo: $(go_crypto_xtea_files)
$(BUILDPACKAGE)
crypto/xtea/check: $(CHECK_DEPS)
@$(MKDIR_P) crypto/xtea
@$(CHECK)
.PHONY: crypto/xtea/check
@go_include@ crypto/openpgp/armor.lo.dep
crypto/openpgp/armor.lo.dep: $(go_crypto_openpgp_armor_files)
$(BUILDDEPS)
crypto/openpgp/armor.lo: $(go_crypto_openpgp_armor_files)
$(BUILDPACKAGE)
crypto/openpgp/armor/check: $(CHECK_DEPS)
@$(MKDIR_P) crypto/openpgp/armor
@$(CHECK)
.PHONY: crypto/openpgp/armor/check
@go_include@ crypto/openpgp/elgamal.lo.dep
crypto/openpgp/elgamal.lo.dep: $(go_crypto_openpgp_elgamal_files)
$(BUILDDEPS)
crypto/openpgp/elgamal.lo: $(go_crypto_openpgp_elgamal_files)
$(BUILDPACKAGE)
crypto/openpgp/elgamal/check: $(CHECK_DEPS)
@$(MKDIR_P) crypto/openpgp/elgamal
@$(CHECK)
.PHONY: crypto/openpgp/elgamal/check
@go_include@ crypto/openpgp/errors.lo.dep
crypto/openpgp/errors.lo.dep: $(go_crypto_openpgp_errors_files)
$(BUILDDEPS)
crypto/openpgp/errors.lo: $(go_crypto_openpgp_errors_files)
$(BUILDPACKAGE)
crypto/openpgp/errors/check: $(CHECK_DEPS)
@$(MKDIR_P) crypto/openpgp/errors
@$(CHECK)
.PHONY: crypto/openpgp/errors/check
@go_include@ crypto/openpgp/packet.lo.dep
crypto/openpgp/packet.lo.dep: $(go_crypto_openpgp_packet_files)
$(BUILDDEPS)
crypto/openpgp/packet.lo: $(go_crypto_openpgp_packet_files)
$(BUILDPACKAGE)
crypto/openpgp/packet/check: $(CHECK_DEPS)
@$(MKDIR_P) crypto/openpgp/packet
@$(CHECK)
.PHONY: crypto/openpgp/packet/check
@go_include@ crypto/openpgp/s2k.lo.dep
crypto/openpgp/s2k.lo.dep: $(go_crypto_openpgp_s2k_files)
$(BUILDDEPS)
crypto/openpgp/s2k.lo: $(go_crypto_openpgp_s2k_files)
$(BUILDPACKAGE)
crypto/openpgp/s2k/check: $(CHECK_DEPS)
@$(MKDIR_P) crypto/openpgp/s2k
@$(CHECK)
.PHONY: crypto/openpgp/s2k/check
@go_include@ crypto/x509/pkix.lo.dep @go_include@ crypto/x509/pkix.lo.dep
crypto/x509/pkix.lo.dep: $(go_crypto_x509_pkix_files) crypto/x509/pkix.lo.dep: $(go_crypto_x509_pkix_files)
$(BUILDDEPS) $(BUILDDEPS)
@ -5414,16 +5067,6 @@ encoding/csv/check: $(CHECK_DEPS)
@$(CHECK) @$(CHECK)
.PHONY: encoding/csv/check .PHONY: encoding/csv/check
@go_include@ encoding/git85.lo.dep
encoding/git85.lo.dep: $(go_encoding_git85_files)
$(BUILDDEPS)
encoding/git85.lo: $(go_encoding_git85_files)
$(BUILDPACKAGE)
encoding/git85/check: $(CHECK_DEPS)
@$(MKDIR_P) encoding/git85
@$(CHECK)
.PHONY: encoding/git85/check
@go_include@ encoding/gob.lo.dep @go_include@ encoding/gob.lo.dep
encoding/gob.lo.dep: $(go_encoding_gob_files) encoding/gob.lo.dep: $(go_encoding_gob_files)
$(BUILDDEPS) $(BUILDDEPS)
@ -5484,6 +5127,16 @@ exp/ebnf/check: $(CHECK_DEPS)
@$(CHECK) @$(CHECK)
.PHONY: exp/ebnf/check .PHONY: exp/ebnf/check
@go_include@ exp/html.lo.dep
exp/html.lo.dep: $(go_exp_html_files)
$(BUILDDEPS)
exp/html.lo: $(go_exp_html_files)
$(BUILDPACKAGE)
exp/html/check: $(CHECK_DEPS)
@$(MKDIR_P) exp/html
@$(CHECK)
.PHONY: exp/html/check
@go_include@ exp/norm.lo.dep @go_include@ exp/norm.lo.dep
exp/norm.lo.dep: $(go_exp_norm_files) exp/norm.lo.dep: $(go_exp_norm_files)
$(BUILDDEPS) $(BUILDDEPS)
@ -5504,26 +5157,6 @@ exp/proxy/check: $(CHECK_DEPS)
@$(CHECK) @$(CHECK)
.PHONY: exp/proxy/check .PHONY: exp/proxy/check
@go_include@ exp/spdy.lo.dep
exp/spdy.lo.dep: $(go_exp_spdy_files)
$(BUILDDEPS)
exp/spdy.lo: $(go_exp_spdy_files)
$(BUILDPACKAGE)
exp/spdy/check: $(CHECK_DEPS)
@$(MKDIR_P) exp/spdy
@$(CHECK)
.PHONY: exp/spdy/check
@go_include@ exp/ssh.lo.dep
exp/ssh.lo.dep: $(go_exp_ssh_files)
$(BUILDDEPS)
exp/ssh.lo: $(go_exp_ssh_files)
$(BUILDPACKAGE)
exp/ssh/check: $(CHECK_DEPS)
@$(MKDIR_P) exp/ssh
@$(CHECK)
.PHONY: exp/ssh/check
@go_include@ exp/terminal.lo.dep @go_include@ exp/terminal.lo.dep
exp/terminal.lo.dep: $(go_exp_terminal_files) exp/terminal.lo.dep: $(go_exp_terminal_files)
$(BUILDDEPS) $(BUILDDEPS)
@ -5835,12 +5468,6 @@ mime/multipart/check: $(CHECK_DEPS)
@$(CHECK) @$(CHECK)
.PHONY: mime/multipart/check .PHONY: mime/multipart/check
@go_include@ net/dict.lo.dep
net/dict.lo.dep: $(go_net_dict_files)
$(BUILDDEPS)
net/dict.lo: $(go_net_dict_files)
$(BUILDPACKAGE)
@go_include@ net/http.lo.dep @go_include@ net/http.lo.dep
net/http.lo.dep: $(go_net_http_files) net/http.lo.dep: $(go_net_http_files)
$(BUILDDEPS) $(BUILDDEPS)
@ -6194,8 +5821,6 @@ net.gox: net/net.lo
$(BUILDGOX) $(BUILDGOX)
os.gox: os/os.lo os.gox: os/os.lo
$(BUILDGOX) $(BUILDGOX)
patch.gox: patch/patch.lo
$(BUILDGOX)
path.gox: path/path.lo path.gox: path/path.lo
$(BUILDGOX) $(BUILDGOX)
reflect.gox: reflect/reflect.lo reflect.gox: reflect/reflect.lo
@ -6220,8 +5845,6 @@ time.gox: time/time.lo
$(BUILDGOX) $(BUILDGOX)
unicode.gox: unicode/unicode.lo unicode.gox: unicode/unicode.lo
$(BUILDGOX) $(BUILDGOX)
websocket.gox: websocket/websocket.lo
$(BUILDGOX)
archive/tar.gox: archive/tar.lo archive/tar.gox: archive/tar.lo
$(BUILDGOX) $(BUILDGOX)
@ -6248,12 +5871,6 @@ container/ring.gox: container/ring.lo
crypto/aes.gox: crypto/aes.lo crypto/aes.gox: crypto/aes.lo
$(BUILDGOX) $(BUILDGOX)
crypto/bcrypt.gox: crypto/bcrypt.lo
$(BUILDGOX)
crypto/blowfish.gox: crypto/blowfish.lo
$(BUILDGOX)
crypto/cast5.gox: crypto/cast5.lo
$(BUILDGOX)
crypto/cipher.gox: crypto/cipher.lo crypto/cipher.gox: crypto/cipher.lo
$(BUILDGOX) $(BUILDGOX)
crypto/des.gox: crypto/des.lo crypto/des.gox: crypto/des.lo
@ -6266,20 +5883,12 @@ crypto/elliptic.gox: crypto/elliptic.lo
$(BUILDGOX) $(BUILDGOX)
crypto/hmac.gox: crypto/hmac.lo crypto/hmac.gox: crypto/hmac.lo
$(BUILDGOX) $(BUILDGOX)
crypto/md4.gox: crypto/md4.lo
$(BUILDGOX)
crypto/md5.gox: crypto/md5.lo crypto/md5.gox: crypto/md5.lo
$(BUILDGOX) $(BUILDGOX)
crypto/ocsp.gox: crypto/ocsp.lo
$(BUILDGOX)
crypto/openpgp.gox: crypto/openpgp.lo
$(BUILDGOX)
crypto/rand.gox: crypto/rand.lo crypto/rand.gox: crypto/rand.lo
$(BUILDGOX) $(BUILDGOX)
crypto/rc4.gox: crypto/rc4.lo crypto/rc4.gox: crypto/rc4.lo
$(BUILDGOX) $(BUILDGOX)
crypto/ripemd160.gox: crypto/ripemd160.lo
$(BUILDGOX)
crypto/rsa.gox: crypto/rsa.lo crypto/rsa.gox: crypto/rsa.lo
$(BUILDGOX) $(BUILDGOX)
crypto/sha1.gox: crypto/sha1.lo crypto/sha1.gox: crypto/sha1.lo
@ -6292,23 +5901,8 @@ crypto/subtle.gox: crypto/subtle.lo
$(BUILDGOX) $(BUILDGOX)
crypto/tls.gox: crypto/tls.lo crypto/tls.gox: crypto/tls.lo
$(BUILDGOX) $(BUILDGOX)
crypto/twofish.gox: crypto/twofish.lo
$(BUILDGOX)
crypto/x509.gox: crypto/x509.lo crypto/x509.gox: crypto/x509.lo
$(BUILDGOX) $(BUILDGOX)
crypto/xtea.gox: crypto/xtea.lo
$(BUILDGOX)
crypto/openpgp/armor.gox: crypto/openpgp/armor.lo
$(BUILDGOX)
crypto/openpgp/elgamal.gox: crypto/openpgp/elgamal.lo
$(BUILDGOX)
crypto/openpgp/errors.gox: crypto/openpgp/errors.lo
$(BUILDGOX)
crypto/openpgp/packet.gox: crypto/openpgp/packet.lo
$(BUILDGOX)
crypto/openpgp/s2k.gox: crypto/openpgp/s2k.lo
$(BUILDGOX)
crypto/x509/pkix.gox: crypto/x509/pkix.lo crypto/x509/pkix.gox: crypto/x509/pkix.lo
$(BUILDGOX) $(BUILDGOX)
@ -6342,8 +5936,6 @@ encoding/binary.gox: encoding/binary.lo
$(BUILDGOX) $(BUILDGOX)
encoding/csv.gox: encoding/csv.lo encoding/csv.gox: encoding/csv.lo
$(BUILDGOX) $(BUILDGOX)
encoding/git85.gox: encoding/git85.lo
$(BUILDGOX)
encoding/gob.gox: encoding/gob.lo encoding/gob.gox: encoding/gob.lo
$(BUILDGOX) $(BUILDGOX)
encoding/hex.gox: encoding/hex.lo encoding/hex.gox: encoding/hex.lo
@ -6357,16 +5949,14 @@ encoding/xml.gox: encoding/xml.lo
exp/ebnf.gox: exp/ebnf.lo exp/ebnf.gox: exp/ebnf.lo
$(BUILDGOX) $(BUILDGOX)
exp/html.gox: exp/html.lo
$(BUILDGOX)
exp/inotify.gox: exp/inotify.lo exp/inotify.gox: exp/inotify.lo
$(BUILDGOX) $(BUILDGOX)
exp/norm.gox: exp/norm.lo exp/norm.gox: exp/norm.lo
$(BUILDGOX) $(BUILDGOX)
exp/proxy.gox: exp/proxy.lo exp/proxy.gox: exp/proxy.lo
$(BUILDGOX) $(BUILDGOX)
exp/spdy.gox: exp/spdy.lo
$(BUILDGOX)
exp/ssh.gox: exp/ssh.lo
$(BUILDGOX)
exp/terminal.gox: exp/terminal.lo exp/terminal.gox: exp/terminal.lo
$(BUILDGOX) $(BUILDGOX)
exp/types.gox: exp/types.lo exp/types.gox: exp/types.lo
@ -6435,8 +6025,6 @@ math/rand.gox: math/rand.lo
mime/multipart.gox: mime/multipart.lo mime/multipart.gox: mime/multipart.lo
$(BUILDGOX) $(BUILDGOX)
net/dict.gox: net/dict.lo
$(BUILDGOX)
net/http.gox: net/http.lo net/http.gox: net/http.lo
$(BUILDGOX) $(BUILDGOX)
net/mail.gox: net/mail.lo net/mail.gox: net/mail.lo

View File

@ -18,7 +18,7 @@ import (
) )
var ( var (
HeaderError = errors.New("invalid tar header") ErrHeader = errors.New("invalid tar header")
) )
// A Reader provides sequential access to the contents of a tar archive. // A Reader provides sequential access to the contents of a tar archive.
@ -123,13 +123,13 @@ func (tr *Reader) readHeader() *Header {
if bytes.Equal(header, zeroBlock[0:blockSize]) { if bytes.Equal(header, zeroBlock[0:blockSize]) {
tr.err = io.EOF tr.err = io.EOF
} else { } else {
tr.err = HeaderError // zero block and then non-zero block tr.err = ErrHeader // zero block and then non-zero block
} }
return nil return nil
} }
if !tr.verifyChecksum(header) { if !tr.verifyChecksum(header) {
tr.err = HeaderError tr.err = ErrHeader
return nil return nil
} }
@ -188,7 +188,7 @@ func (tr *Reader) readHeader() *Header {
} }
if tr.err != nil { if tr.err != nil {
tr.err = HeaderError tr.err = ErrHeader
return nil return nil
} }

View File

@ -240,31 +240,20 @@ func TestNonSeekable(t *testing.T) {
} }
defer f.Close() defer f.Close()
// pipe the data in type readerOnly struct {
r, w, err := os.Pipe() io.Reader
if err != nil {
t.Fatalf("Unexpected error %s", err)
} }
go func() { tr := NewReader(readerOnly{f})
rdbuf := make([]uint8, 1<<16)
for {
nr, err := f.Read(rdbuf)
w.Write(rdbuf[0:nr])
if err == io.EOF {
break
}
}
w.Close()
}()
tr := NewReader(r)
nread := 0 nread := 0
for ; ; nread++ { for ; ; nread++ {
hdr, err := tr.Next() _, err := tr.Next()
if hdr == nil || err == io.EOF { if err == io.EOF {
break break
} }
if err != nil {
t.Fatalf("Unexpected error: %v", err)
}
} }
if nread != len(test.headers) { if nread != len(test.headers) {

View File

@ -17,9 +17,9 @@ import (
) )
var ( var (
FormatError = errors.New("zip: not a valid zip file") ErrFormat = errors.New("zip: not a valid zip file")
UnsupportedMethod = errors.New("zip: unsupported compression algorithm") ErrAlgorithm = errors.New("zip: unsupported compression algorithm")
ChecksumError = errors.New("zip: checksum error") ErrChecksum = errors.New("zip: checksum error")
) )
type Reader struct { type Reader struct {
@ -90,12 +90,12 @@ func (z *Reader) init(r io.ReaderAt, size int64) error {
// The count of files inside a zip is truncated to fit in a uint16. // The count of files inside a zip is truncated to fit in a uint16.
// Gloss over this by reading headers until we encounter // Gloss over this by reading headers until we encounter
// a bad one, and then only report a FormatError or UnexpectedEOF if // a bad one, and then only report a ErrFormat or UnexpectedEOF if
// the file count modulo 65536 is incorrect. // the file count modulo 65536 is incorrect.
for { for {
f := &File{zipr: r, zipsize: size} f := &File{zipr: r, zipsize: size}
err = readDirectoryHeader(f, buf) err = readDirectoryHeader(f, buf)
if err == FormatError || err == io.ErrUnexpectedEOF { if err == ErrFormat || err == io.ErrUnexpectedEOF {
break break
} }
if err != nil { if err != nil {
@ -135,7 +135,7 @@ func (f *File) Open() (rc io.ReadCloser, err error) {
case Deflate: case Deflate:
rc = flate.NewReader(r) rc = flate.NewReader(r)
default: default:
err = UnsupportedMethod err = ErrAlgorithm
} }
if rc != nil { if rc != nil {
rc = &checksumReader{rc, crc32.NewIEEE(), f, r} rc = &checksumReader{rc, crc32.NewIEEE(), f, r}
@ -162,7 +162,7 @@ func (r *checksumReader) Read(b []byte) (n int, err error) {
} }
} }
if r.hash.Sum32() != r.f.CRC32 { if r.hash.Sum32() != r.f.CRC32 {
err = ChecksumError err = ErrChecksum
} }
return return
} }
@ -176,7 +176,7 @@ func readFileHeader(f *File, r io.Reader) error {
} }
c := binary.LittleEndian c := binary.LittleEndian
if sig := c.Uint32(b[:4]); sig != fileHeaderSignature { if sig := c.Uint32(b[:4]); sig != fileHeaderSignature {
return FormatError return ErrFormat
} }
f.ReaderVersion = c.Uint16(b[4:6]) f.ReaderVersion = c.Uint16(b[4:6])
f.Flags = c.Uint16(b[6:8]) f.Flags = c.Uint16(b[6:8])
@ -207,7 +207,7 @@ func (f *File) findBodyOffset() (int64, error) {
} }
c := binary.LittleEndian c := binary.LittleEndian
if sig := c.Uint32(b[:4]); sig != fileHeaderSignature { if sig := c.Uint32(b[:4]); sig != fileHeaderSignature {
return 0, FormatError return 0, ErrFormat
} }
filenameLen := int(c.Uint16(b[26:28])) filenameLen := int(c.Uint16(b[26:28]))
extraLen := int(c.Uint16(b[28:30])) extraLen := int(c.Uint16(b[28:30]))
@ -216,7 +216,7 @@ func (f *File) findBodyOffset() (int64, error) {
// readDirectoryHeader attempts to read a directory header from r. // readDirectoryHeader attempts to read a directory header from r.
// It returns io.ErrUnexpectedEOF if it cannot read a complete header, // It returns io.ErrUnexpectedEOF if it cannot read a complete header,
// and FormatError if it doesn't find a valid header signature. // and ErrFormat if it doesn't find a valid header signature.
func readDirectoryHeader(f *File, r io.Reader) error { func readDirectoryHeader(f *File, r io.Reader) error {
var b [directoryHeaderLen]byte var b [directoryHeaderLen]byte
if _, err := io.ReadFull(r, b[:]); err != nil { if _, err := io.ReadFull(r, b[:]); err != nil {
@ -224,7 +224,7 @@ func readDirectoryHeader(f *File, r io.Reader) error {
} }
c := binary.LittleEndian c := binary.LittleEndian
if sig := c.Uint32(b[:4]); sig != directoryHeaderSignature { if sig := c.Uint32(b[:4]); sig != directoryHeaderSignature {
return FormatError return ErrFormat
} }
f.CreatorVersion = c.Uint16(b[4:6]) f.CreatorVersion = c.Uint16(b[4:6])
f.ReaderVersion = c.Uint16(b[6:8]) f.ReaderVersion = c.Uint16(b[6:8])
@ -280,7 +280,7 @@ func readDirectoryEnd(r io.ReaderAt, size int64) (dir *directoryEnd, err error)
break break
} }
if i == 1 || bLen == size { if i == 1 || bLen == size {
return nil, FormatError return nil, ErrFormat
} }
} }

View File

@ -70,7 +70,7 @@ var tests = []ZipTest{
}, },
}, },
{Name: "readme.zip"}, {Name: "readme.zip"},
{Name: "readme.notzip", Error: FormatError}, {Name: "readme.notzip", Error: ErrFormat},
{ {
Name: "dd.zip", Name: "dd.zip",
File: []ZipTestFile{ File: []ZipTestFile{
@ -131,7 +131,7 @@ func readTestZip(t *testing.T, zt ZipTest) {
} }
// bail if file is not zip // bail if file is not zip
if err == FormatError { if err == ErrFormat {
return return
} }
defer func() { defer func() {
@ -184,8 +184,8 @@ func readTestZip(t *testing.T, zt ZipTest) {
} }
var b bytes.Buffer var b bytes.Buffer
_, err = io.Copy(&b, r) _, err = io.Copy(&b, r)
if err != ChecksumError { if err != ErrChecksum {
t.Errorf("%s: copy error=%v, want %v", z.File[0].Name, err, ChecksumError) t.Errorf("%s: copy error=%v, want %v", z.File[0].Name, err, ErrChecksum)
} }
} }
} }
@ -250,13 +250,9 @@ func readTestFile(t *testing.T, ft ZipTestFile, f *File) {
} }
func testFileMode(t *testing.T, f *File, want os.FileMode) { func testFileMode(t *testing.T, f *File, want os.FileMode) {
mode, err := f.Mode() mode := f.Mode()
if want == 0 { if want == 0 {
if err == nil {
t.Errorf("%s mode: got %v, want none", f.Name, mode) t.Errorf("%s mode: got %v, want none", f.Name, mode)
}
} else if err != nil {
t.Errorf("%s mode: %s", f.Name, err)
} else if mode != want { } else if mode != want {
t.Errorf("%s mode: want %v, got %v", f.Name, want, mode) t.Errorf("%s mode: want %v, got %v", f.Name, want, mode)
} }
@ -268,8 +264,8 @@ func TestInvalidFiles(t *testing.T) {
// zeroes // zeroes
_, err := NewReader(sliceReaderAt(b), size) _, err := NewReader(sliceReaderAt(b), size)
if err != FormatError { if err != ErrFormat {
t.Errorf("zeroes: error=%v, want %v", err, FormatError) t.Errorf("zeroes: error=%v, want %v", err, ErrFormat)
} }
// repeated directoryEndSignatures // repeated directoryEndSignatures
@ -279,8 +275,8 @@ func TestInvalidFiles(t *testing.T) {
copy(b[i:i+4], sig) copy(b[i:i+4], sig)
} }
_, err = NewReader(sliceReaderAt(b), size) _, err = NewReader(sliceReaderAt(b), size)
if err != FormatError { if err != ErrFormat {
t.Errorf("sigs: error=%v, want %v", err, FormatError) t.Errorf("sigs: error=%v, want %v", err, ErrFormat)
} }
} }

View File

@ -12,6 +12,7 @@ This package does not support ZIP64 or disk spanning.
package zip package zip
import ( import (
"errors"
"os" "os"
"time" "time"
) )
@ -55,6 +56,38 @@ type FileHeader struct {
Comment string Comment string
} }
// FileInfo returns an os.FileInfo for the FileHeader.
func (fh *FileHeader) FileInfo() os.FileInfo {
return headerFileInfo{fh}
}
// headerFileInfo implements os.FileInfo.
type headerFileInfo struct {
fh *FileHeader
}
func (fi headerFileInfo) Name() string { return fi.fh.Name }
func (fi headerFileInfo) Size() int64 { return int64(fi.fh.UncompressedSize) }
func (fi headerFileInfo) IsDir() bool { return fi.Mode().IsDir() }
func (fi headerFileInfo) ModTime() time.Time { return fi.fh.ModTime() }
func (fi headerFileInfo) Mode() os.FileMode { return fi.fh.Mode() }
// FileInfoHeader creates a partially-populated FileHeader from an
// os.FileInfo.
func FileInfoHeader(fi os.FileInfo) (*FileHeader, error) {
size := fi.Size()
if size > (1<<32 - 1) {
return nil, errors.New("zip: file over 4GB")
}
fh := &FileHeader{
Name: fi.Name(),
UncompressedSize: uint32(size),
}
fh.SetModTime(fi.ModTime())
fh.SetMode(fi.Mode())
return fh, nil
}
type directoryEnd struct { type directoryEnd struct {
diskNbr uint16 // unused diskNbr uint16 // unused
dirDiskNbr uint16 // unused dirDiskNbr uint16 // unused
@ -131,8 +164,7 @@ const (
) )
// Mode returns the permission and mode bits for the FileHeader. // Mode returns the permission and mode bits for the FileHeader.
// An error is returned in case the information is not available. func (h *FileHeader) Mode() (mode os.FileMode) {
func (h *FileHeader) Mode() (mode os.FileMode, err error) {
switch h.CreatorVersion >> 8 { switch h.CreatorVersion >> 8 {
case creatorUnix, creatorMacOSX: case creatorUnix, creatorMacOSX:
mode = unixModeToFileMode(h.ExternalAttrs >> 16) mode = unixModeToFileMode(h.ExternalAttrs >> 16)
@ -142,7 +174,7 @@ func (h *FileHeader) Mode() (mode os.FileMode, err error) {
if len(h.Name) > 0 && h.Name[len(h.Name)-1] == '/' { if len(h.Name) > 0 && h.Name[len(h.Name)-1] == '/' {
mode |= os.ModeDir mode |= os.ModeDir
} }
return mode, nil return mode
} }
// SetMode changes the permission and mode bits for the FileHeader. // SetMode changes the permission and mode bits for the FileHeader.

View File

@ -129,7 +129,7 @@ func (w *Writer) CreateHeader(fh *FileHeader) (io.Writer, error) {
case Deflate: case Deflate:
fw.comp = flate.NewWriter(fw.compCount, 5) fw.comp = flate.NewWriter(fw.compCount, 5)
default: default:
return nil, UnsupportedMethod return nil, ErrAlgorithm
} }
fw.rawCount = &countWriter{w: fw.comp} fw.rawCount = &countWriter{w: fw.comp}

View File

@ -10,6 +10,7 @@ import (
"bytes" "bytes"
"fmt" "fmt"
"io" "io"
"reflect"
"testing" "testing"
"time" "time"
) )
@ -66,3 +67,22 @@ func TestModTime(t *testing.T) {
t.Errorf("times don't match: got %s, want %s", outTime, testTime) t.Errorf("times don't match: got %s, want %s", outTime, testTime)
} }
} }
func TestFileHeaderRoundTrip(t *testing.T) {
fh := &FileHeader{
Name: "foo.txt",
UncompressedSize: 987654321,
ModifiedTime: 1234,
ModifiedDate: 5678,
}
fi := fh.FileInfo()
fh2, err := FileInfoHeader(fi)
// Ignore these fields:
fh2.CreatorVersion = 0
fh2.ExternalAttrs = 0
if !reflect.DeepEqual(fh, fh2) {
t.Errorf("mismatch\n input=%#v\noutput=%#v\nerr=%v", fh, fh2, err)
}
}

View File

@ -33,6 +33,9 @@ const (
opRead // Any other read operation. opRead // Any other read operation.
) )
// ErrTooLarge is passed to panic if memory cannot be allocated to store data in a buffer.
var ErrTooLarge = errors.New("bytes.Buffer: too large")
// Bytes returns a slice of the contents of the unread portion of the buffer; // Bytes returns a slice of the contents of the unread portion of the buffer;
// len(b.Bytes()) == b.Len(). If the caller changes the contents of the // len(b.Bytes()) == b.Len(). If the caller changes the contents of the
// returned slice, the contents of the buffer will change provided there // returned slice, the contents of the buffer will change provided there
@ -68,8 +71,9 @@ func (b *Buffer) Truncate(n int) {
// b.Reset() is the same as b.Truncate(0). // b.Reset() is the same as b.Truncate(0).
func (b *Buffer) Reset() { b.Truncate(0) } func (b *Buffer) Reset() { b.Truncate(0) }
// Grow buffer to guarantee space for n more bytes. // grow grows the buffer to guarantee space for n more bytes.
// Return index where bytes should be written. // It returns the index where bytes should be written.
// If the buffer can't grow it will panic with ErrTooLarge.
func (b *Buffer) grow(n int) int { func (b *Buffer) grow(n int) int {
m := b.Len() m := b.Len()
// If buffer is empty, reset to recover space. // If buffer is empty, reset to recover space.
@ -82,7 +86,7 @@ func (b *Buffer) grow(n int) int {
buf = b.bootstrap[0:] buf = b.bootstrap[0:]
} else { } else {
// not enough space anywhere // not enough space anywhere
buf = make([]byte, 2*cap(b.buf)+n) buf = makeSlice(2*cap(b.buf) + n)
copy(buf, b.buf[b.off:]) copy(buf, b.buf[b.off:])
} }
b.buf = buf b.buf = buf
@ -94,6 +98,8 @@ func (b *Buffer) grow(n int) int {
// Write appends the contents of p to the buffer. The return // Write appends the contents of p to the buffer. The return
// value n is the length of p; err is always nil. // value n is the length of p; err is always nil.
// If the buffer becomes too large, Write will panic with
// ErrTooLarge.
func (b *Buffer) Write(p []byte) (n int, err error) { func (b *Buffer) Write(p []byte) (n int, err error) {
b.lastRead = opInvalid b.lastRead = opInvalid
m := b.grow(len(p)) m := b.grow(len(p))
@ -102,6 +108,8 @@ func (b *Buffer) Write(p []byte) (n int, err error) {
// WriteString appends the contents of s to the buffer. The return // WriteString appends the contents of s to the buffer. The return
// value n is the length of s; err is always nil. // value n is the length of s; err is always nil.
// If the buffer becomes too large, WriteString will panic with
// ErrTooLarge.
func (b *Buffer) WriteString(s string) (n int, err error) { func (b *Buffer) WriteString(s string) (n int, err error) {
b.lastRead = opInvalid b.lastRead = opInvalid
m := b.grow(len(s)) m := b.grow(len(s))
@ -118,6 +126,8 @@ const MinRead = 512
// The return value n is the number of bytes read. // The return value n is the number of bytes read.
// Any error except io.EOF encountered during the read // Any error except io.EOF encountered during the read
// is also returned. // is also returned.
// If the buffer becomes too large, ReadFrom will panic with
// ErrTooLarge.
func (b *Buffer) ReadFrom(r io.Reader) (n int64, err error) { func (b *Buffer) ReadFrom(r io.Reader) (n int64, err error) {
b.lastRead = opInvalid b.lastRead = opInvalid
// If buffer is empty, reset to recover space. // If buffer is empty, reset to recover space.
@ -125,18 +135,16 @@ func (b *Buffer) ReadFrom(r io.Reader) (n int64, err error) {
b.Truncate(0) b.Truncate(0)
} }
for { for {
if cap(b.buf)-len(b.buf) < MinRead { if free := cap(b.buf) - len(b.buf); free < MinRead {
var newBuf []byte // not enough space at end
// can we get space without allocation? newBuf := b.buf
if b.off+cap(b.buf)-len(b.buf) >= MinRead { if b.off+free < MinRead {
// reuse beginning of buffer // not enough space using beginning of buffer;
newBuf = b.buf[0 : len(b.buf)-b.off] // double buffer capacity
} else { newBuf = makeSlice(2*cap(b.buf) + MinRead)
// not enough space at end; put space on end
newBuf = make([]byte, len(b.buf)-b.off, 2*(cap(b.buf)-b.off)+MinRead)
} }
copy(newBuf, b.buf[b.off:]) copy(newBuf, b.buf[b.off:])
b.buf = newBuf b.buf = newBuf[:len(b.buf)-b.off]
b.off = 0 b.off = 0
} }
m, e := r.Read(b.buf[len(b.buf):cap(b.buf)]) m, e := r.Read(b.buf[len(b.buf):cap(b.buf)])
@ -152,6 +160,18 @@ func (b *Buffer) ReadFrom(r io.Reader) (n int64, err error) {
return n, nil // err is EOF, so return nil explicitly return n, nil // err is EOF, so return nil explicitly
} }
// makeSlice allocates a slice of size n. If the allocation fails, it panics
// with ErrTooLarge.
func makeSlice(n int) []byte {
// If the make fails, give a known error.
defer func() {
if recover() != nil {
panic(ErrTooLarge)
}
}()
return make([]byte, n)
}
// WriteTo writes data to w until the buffer is drained or an error // WriteTo writes data to w until the buffer is drained or an error
// occurs. The return value n is the number of bytes written; it always // occurs. The return value n is the number of bytes written; it always
// fits into an int, but it is int64 to match the io.WriterTo interface. // fits into an int, but it is int64 to match the io.WriterTo interface.
@ -176,6 +196,8 @@ func (b *Buffer) WriteTo(w io.Writer) (n int64, err error) {
// WriteByte appends the byte c to the buffer. // WriteByte appends the byte c to the buffer.
// The returned error is always nil, but is included // The returned error is always nil, but is included
// to match bufio.Writer's WriteByte. // to match bufio.Writer's WriteByte.
// If the buffer becomes too large, WriteByte will panic with
// ErrTooLarge.
func (b *Buffer) WriteByte(c byte) error { func (b *Buffer) WriteByte(c byte) error {
b.lastRead = opInvalid b.lastRead = opInvalid
m := b.grow(1) m := b.grow(1)
@ -187,6 +209,8 @@ func (b *Buffer) WriteByte(c byte) error {
// code point r to the buffer, returning its length and // code point r to the buffer, returning its length and
// an error, which is always nil but is included // an error, which is always nil but is included
// to match bufio.Writer's WriteRune. // to match bufio.Writer's WriteRune.
// If the buffer becomes too large, WriteRune will panic with
// ErrTooLarge.
func (b *Buffer) WriteRune(r rune) (n int, err error) { func (b *Buffer) WriteRune(r rune) (n int, err error) {
if r < utf8.RuneSelf { if r < utf8.RuneSelf {
b.WriteByte(byte(r)) b.WriteByte(byte(r))

View File

@ -27,10 +27,12 @@ const (
// stop things from getting too large. // stop things from getting too large.
maxFlateBlockTokens = 1 << 14 maxFlateBlockTokens = 1 << 14
maxStoreBlockSize = 65535 maxStoreBlockSize = 65535
hashBits = 15 hashBits = 17
hashSize = 1 << hashBits hashSize = 1 << hashBits
hashMask = (1 << hashBits) - 1 hashMask = (1 << hashBits) - 1
hashShift = (hashBits + minMatchLength - 1) / minMatchLength hashShift = (hashBits + minMatchLength - 1) / minMatchLength
skipNever = math.MaxInt32
) )
type compressionLevel struct { type compressionLevel struct {
@ -45,12 +47,12 @@ var levels = []compressionLevel{
{3, 0, 32, 32, 6}, {3, 0, 32, 32, 6},
// Levels 4-9 use increasingly more lazy matching // Levels 4-9 use increasingly more lazy matching
// and increasingly stringent conditions for "good enough". // and increasingly stringent conditions for "good enough".
{4, 4, 16, 16, math.MaxInt32}, {4, 4, 16, 16, skipNever},
{8, 16, 32, 32, math.MaxInt32}, {8, 16, 32, 32, skipNever},
{8, 16, 128, 128, math.MaxInt32}, {8, 16, 128, 128, skipNever},
{8, 32, 128, 256, math.MaxInt32}, {8, 32, 128, 256, skipNever},
{32, 128, 258, 1024, math.MaxInt32}, {32, 128, 258, 1024, skipNever},
{32, 258, 258, 4096, math.MaxInt32}, {32, 258, 258, 4096, skipNever},
} }
type compressor struct { type compressor struct {
@ -71,6 +73,7 @@ type compressor struct {
chainHead int chainHead int
hashHead []int hashHead []int
hashPrev []int hashPrev []int
hashOffset int
// input window: unprocessed data is window[index:windowEnd] // input window: unprocessed data is window[index:windowEnd]
index int index int
@ -79,9 +82,8 @@ type compressor struct {
blockStart int // window index where current tokens start blockStart int // window index where current tokens start
byteAvailable bool // if true, still need to process window[index-1]. byteAvailable bool // if true, still need to process window[index-1].
// queued output tokens: tokens[:ti] // queued output tokens
tokens []token tokens []token
ti int
// deflate state // deflate state
length int length int
@ -100,22 +102,9 @@ func (d *compressor) fillDeflate(b []byte) int {
if d.blockStart >= windowSize { if d.blockStart >= windowSize {
d.blockStart -= windowSize d.blockStart -= windowSize
} else { } else {
d.blockStart = math.MaxInt32 d.blockStart = skipNever
}
for i, h := range d.hashHead {
v := h - windowSize
if v < -1 {
v = -1
}
d.hashHead[i] = v
}
for i, h := range d.hashPrev {
v := -h - windowSize
if v < -1 {
v = -1
}
d.hashPrev[i] = v
} }
d.hashOffset += windowSize
} }
n := copy(d.window[d.windowEnd:], b) n := copy(d.window[d.windowEnd:], b)
d.windowEnd += n d.windowEnd += n
@ -186,7 +175,7 @@ func (d *compressor) findMatch(pos int, prevHead int, prevLength int, lookahead
// hashPrev[i & windowMask] has already been overwritten, so stop now. // hashPrev[i & windowMask] has already been overwritten, so stop now.
break break
} }
if i = d.hashPrev[i&windowMask]; i < minIndex || i < 0 { if i = d.hashPrev[i&windowMask] - d.hashOffset; i < minIndex || i < 0 {
break break
} }
} }
@ -205,13 +194,12 @@ func (d *compressor) initDeflate() {
d.hashHead = make([]int, hashSize) d.hashHead = make([]int, hashSize)
d.hashPrev = make([]int, windowSize) d.hashPrev = make([]int, windowSize)
d.window = make([]byte, 2*windowSize) d.window = make([]byte, 2*windowSize)
fillInts(d.hashHead, -1) d.hashOffset = 1
d.tokens = make([]token, maxFlateBlockTokens, maxFlateBlockTokens+1) d.tokens = make([]token, 0, maxFlateBlockTokens+1)
d.length = minMatchLength - 1 d.length = minMatchLength - 1
d.offset = 0 d.offset = 0
d.byteAvailable = false d.byteAvailable = false
d.index = 0 d.index = 0
d.ti = 0
d.hash = 0 d.hash = 0
d.chainHead = -1 d.chainHead = -1
} }
@ -243,15 +231,14 @@ Loop:
// Flush current output block if any. // Flush current output block if any.
if d.byteAvailable { if d.byteAvailable {
// There is still one pending token that needs to be flushed // There is still one pending token that needs to be flushed
d.tokens[d.ti] = literalToken(uint32(d.window[d.index-1])) d.tokens = append(d.tokens, literalToken(uint32(d.window[d.index-1])))
d.ti++
d.byteAvailable = false d.byteAvailable = false
} }
if d.ti > 0 { if len(d.tokens) > 0 {
if d.err = d.writeBlock(d.tokens[0:d.ti], d.index, false); d.err != nil { if d.err = d.writeBlock(d.tokens, d.index, false); d.err != nil {
return return
} }
d.ti = 0 d.tokens = d.tokens[:0]
} }
break Loop break Loop
} }
@ -261,7 +248,7 @@ Loop:
d.hash = (d.hash<<hashShift + int(d.window[d.index+2])) & hashMask d.hash = (d.hash<<hashShift + int(d.window[d.index+2])) & hashMask
d.chainHead = d.hashHead[d.hash] d.chainHead = d.hashHead[d.hash]
d.hashPrev[d.index&windowMask] = d.chainHead d.hashPrev[d.index&windowMask] = d.chainHead
d.hashHead[d.hash] = d.index d.hashHead[d.hash] = d.index + d.hashOffset
} }
prevLength := d.length prevLength := d.length
prevOffset := d.offset prevOffset := d.offset
@ -272,34 +259,33 @@ Loop:
minIndex = 0 minIndex = 0
} }
if d.chainHead >= minIndex && if d.chainHead-d.hashOffset >= minIndex &&
(d.fastSkipHashing != 0 && lookahead > minMatchLength-1 || (d.fastSkipHashing != skipNever && lookahead > minMatchLength-1 ||
d.fastSkipHashing == 0 && lookahead > prevLength && prevLength < d.lazy) { d.fastSkipHashing == skipNever && lookahead > prevLength && prevLength < d.lazy) {
if newLength, newOffset, ok := d.findMatch(d.index, d.chainHead, minMatchLength-1, lookahead); ok { if newLength, newOffset, ok := d.findMatch(d.index, d.chainHead-d.hashOffset, minMatchLength-1, lookahead); ok {
d.length = newLength d.length = newLength
d.offset = newOffset d.offset = newOffset
} }
} }
if d.fastSkipHashing != 0 && d.length >= minMatchLength || if d.fastSkipHashing != skipNever && d.length >= minMatchLength ||
d.fastSkipHashing == 0 && prevLength >= minMatchLength && d.length <= prevLength { d.fastSkipHashing == skipNever && prevLength >= minMatchLength && d.length <= prevLength {
// There was a match at the previous step, and the current match is // There was a match at the previous step, and the current match is
// not better. Output the previous match. // not better. Output the previous match.
if d.fastSkipHashing != 0 { if d.fastSkipHashing != skipNever {
d.tokens[d.ti] = matchToken(uint32(d.length-minMatchLength), uint32(d.offset-minOffsetSize)) d.tokens = append(d.tokens, matchToken(uint32(d.length-minMatchLength), uint32(d.offset-minOffsetSize)))
} else { } else {
d.tokens[d.ti] = matchToken(uint32(prevLength-minMatchLength), uint32(prevOffset-minOffsetSize)) d.tokens = append(d.tokens, matchToken(uint32(prevLength-minMatchLength), uint32(prevOffset-minOffsetSize)))
} }
d.ti++
// Insert in the hash table all strings up to the end of the match. // Insert in the hash table all strings up to the end of the match.
// index and index-1 are already inserted. If there is not enough // index and index-1 are already inserted. If there is not enough
// lookahead, the last two strings are not inserted into the hash // lookahead, the last two strings are not inserted into the hash
// table. // table.
if d.length <= d.fastSkipHashing { if d.length <= d.fastSkipHashing {
var newIndex int var newIndex int
if d.fastSkipHashing != 0 { if d.fastSkipHashing != skipNever {
newIndex = d.index + d.length newIndex = d.index + d.length
} else { } else {
newIndex = prevLength - 1 newIndex = d.index + prevLength - 1
} }
for d.index++; d.index < newIndex; d.index++ { for d.index++; d.index < newIndex; d.index++ {
if d.index < d.maxInsertIndex { if d.index < d.maxInsertIndex {
@ -308,10 +294,10 @@ Loop:
// Our chain should point to the previous value. // Our chain should point to the previous value.
d.hashPrev[d.index&windowMask] = d.hashHead[d.hash] d.hashPrev[d.index&windowMask] = d.hashHead[d.hash]
// Set the head of the hash chain to us. // Set the head of the hash chain to us.
d.hashHead[d.hash] = d.index d.hashHead[d.hash] = d.index + d.hashOffset
} }
} }
if d.fastSkipHashing == 0 { if d.fastSkipHashing == skipNever {
d.byteAvailable = false d.byteAvailable = false
d.length = minMatchLength - 1 d.length = minMatchLength - 1
} }
@ -323,30 +309,29 @@ Loop:
d.hash = (int(d.window[d.index])<<hashShift + int(d.window[d.index+1])) d.hash = (int(d.window[d.index])<<hashShift + int(d.window[d.index+1]))
} }
} }
if d.ti == maxFlateBlockTokens { if len(d.tokens) == maxFlateBlockTokens {
// The block includes the current character // The block includes the current character
if d.err = d.writeBlock(d.tokens, d.index, false); d.err != nil { if d.err = d.writeBlock(d.tokens, d.index, false); d.err != nil {
return return
} }
d.ti = 0 d.tokens = d.tokens[:0]
} }
} else { } else {
if d.fastSkipHashing != 0 || d.byteAvailable { if d.fastSkipHashing != skipNever || d.byteAvailable {
i := d.index - 1 i := d.index - 1
if d.fastSkipHashing != 0 { if d.fastSkipHashing != skipNever {
i = d.index i = d.index
} }
d.tokens[d.ti] = literalToken(uint32(d.window[i])) d.tokens = append(d.tokens, literalToken(uint32(d.window[i])))
d.ti++ if len(d.tokens) == maxFlateBlockTokens {
if d.ti == maxFlateBlockTokens {
if d.err = d.writeBlock(d.tokens, i+1, false); d.err != nil { if d.err = d.writeBlock(d.tokens, i+1, false); d.err != nil {
return return
} }
d.ti = 0 d.tokens = d.tokens[:0]
} }
} }
d.index++ d.index++
if d.fastSkipHashing == 0 { if d.fastSkipHashing == skipNever {
d.byteAvailable = true d.byteAvailable = true
} }
} }

View File

@ -225,10 +225,17 @@ func testSync(t *testing.T, level int, input []byte, name string) {
} }
func testToFromWithLevel(t *testing.T, level int, input []byte, name string) error { func testToFromWithLevel(t *testing.T, level int, input []byte, name string) error {
return testToFromWithLevelAndLimit(t, level, input, name, -1)
}
func testToFromWithLevelAndLimit(t *testing.T, level int, input []byte, name string, limit int) error {
buffer := bytes.NewBuffer(nil) buffer := bytes.NewBuffer(nil)
w := NewWriter(buffer, level) w := NewWriter(buffer, level)
w.Write(input) w.Write(input)
w.Close() w.Close()
if limit > 0 && buffer.Len() > limit {
t.Errorf("level: %d, len(compress(data)) = %d > limit = %d", level, buffer.Len(), limit)
}
r := NewReader(buffer) r := NewReader(buffer)
out, err := ioutil.ReadAll(r) out, err := ioutil.ReadAll(r)
if err != nil { if err != nil {
@ -244,12 +251,16 @@ func testToFromWithLevel(t *testing.T, level int, input []byte, name string) err
return nil return nil
} }
func testToFrom(t *testing.T, input []byte, name string) { func testToFromWithLimit(t *testing.T, input []byte, name string, limit [10]int) {
for i := 0; i < 10; i++ { for i := 0; i < 10; i++ {
testToFromWithLevel(t, i, input, name) testToFromWithLevelAndLimit(t, i, input, name, limit[i])
} }
} }
func testToFrom(t *testing.T, input []byte, name string) {
testToFromWithLimit(t, input, name, [10]int{})
}
func TestDeflateInflate(t *testing.T) { func TestDeflateInflate(t *testing.T) {
for i, h := range deflateInflateTests { for i, h := range deflateInflateTests {
testToFrom(t, h.in, fmt.Sprintf("#%d", i)) testToFrom(t, h.in, fmt.Sprintf("#%d", i))
@ -265,12 +276,33 @@ func TestReverseBits(t *testing.T) {
} }
} }
type deflateInflateStringTest struct {
filename string
label string
limit [10]int
}
var deflateInflateStringTests = []deflateInflateStringTest{
{
"../testdata/e.txt",
"2.718281828...",
[...]int{10013, 5065, 5096, 5115, 5093, 5079, 5079, 5079, 5079, 5079},
},
{
"../testdata/Mark.Twain-Tom.Sawyer.txt",
"Mark.Twain-Tom.Sawyer",
[...]int{407330, 187598, 180361, 172974, 169160, 163476, 160936, 160506, 160295, 160295},
},
}
func TestDeflateInflateString(t *testing.T) { func TestDeflateInflateString(t *testing.T) {
gold, err := ioutil.ReadFile("../testdata/e.txt") for _, test := range deflateInflateStringTests {
gold, err := ioutil.ReadFile(test.filename)
if err != nil { if err != nil {
t.Error(err) t.Error(err)
} }
testToFromWithLevel(t, 1, gold, "2.718281828...") testToFromWithLimit(t, gold, test.label, test.limit)
}
} }
func TestReaderDict(t *testing.T) { func TestReaderDict(t *testing.T) {

View File

@ -193,15 +193,17 @@ func (w *huffmanBitWriter) writeBytes(bytes []byte) {
// numLiterals The number of literals in literalEncoding // numLiterals The number of literals in literalEncoding
// numOffsets The number of offsets in offsetEncoding // numOffsets The number of offsets in offsetEncoding
func (w *huffmanBitWriter) generateCodegen(numLiterals int, numOffsets int) { func (w *huffmanBitWriter) generateCodegen(numLiterals int, numOffsets int) {
fillInt32s(w.codegenFreq, 0) for i := range w.codegenFreq {
w.codegenFreq[i] = 0
}
// Note that we are using codegen both as a temporary variable for holding // Note that we are using codegen both as a temporary variable for holding
// a copy of the frequencies, and as the place where we put the result. // a copy of the frequencies, and as the place where we put the result.
// This is fine because the output is always shorter than the input used // This is fine because the output is always shorter than the input used
// so far. // so far.
codegen := w.codegen // cache codegen := w.codegen // cache
// Copy the concatenated code sizes to codegen. Put a marker at the end. // Copy the concatenated code sizes to codegen. Put a marker at the end.
copyUint8s(codegen[0:numLiterals], w.literalEncoding.codeBits) copy(codegen[0:numLiterals], w.literalEncoding.codeBits)
copyUint8s(codegen[numLiterals:numLiterals+numOffsets], w.offsetEncoding.codeBits) copy(codegen[numLiterals:numLiterals+numOffsets], w.offsetEncoding.codeBits)
codegen[numLiterals+numOffsets] = badCode codegen[numLiterals+numOffsets] = badCode
size := codegen[0] size := codegen[0]
@ -222,7 +224,10 @@ func (w *huffmanBitWriter) generateCodegen(numLiterals int, numOffsets int) {
w.codegenFreq[size]++ w.codegenFreq[size]++
count-- count--
for count >= 3 { for count >= 3 {
n := min(count, 6) n := 6
if n > count {
n = count
}
codegen[outIndex] = 16 codegen[outIndex] = 16
outIndex++ outIndex++
codegen[outIndex] = uint8(n - 3) codegen[outIndex] = uint8(n - 3)
@ -232,7 +237,10 @@ func (w *huffmanBitWriter) generateCodegen(numLiterals int, numOffsets int) {
} }
} else { } else {
for count >= 11 { for count >= 11 {
n := min(count, 138) n := 138
if n > count {
n = count
}
codegen[outIndex] = 18 codegen[outIndex] = 18
outIndex++ outIndex++
codegen[outIndex] = uint8(n - 11) codegen[outIndex] = uint8(n - 11)
@ -351,8 +359,12 @@ func (w *huffmanBitWriter) writeBlock(tokens []token, eof bool, input []byte) {
if w.err != nil { if w.err != nil {
return return
} }
fillInt32s(w.literalFreq, 0) for i := range w.literalFreq {
fillInt32s(w.offsetFreq, 0) w.literalFreq[i] = 0
}
for i := range w.offsetFreq {
w.offsetFreq[i] = 0
}
n := len(tokens) n := len(tokens)
tokens = tokens[0 : n+1] tokens = tokens[0 : n+1]

View File

@ -195,7 +195,9 @@ func (h *huffmanEncoder) bitCounts(list []literalNode, maxBits int32) []int32 {
// The tree can't have greater depth than n - 1, no matter what. This // The tree can't have greater depth than n - 1, no matter what. This
// saves a little bit of work in some small cases // saves a little bit of work in some small cases
maxBits = minInt32(maxBits, n-1) if maxBits > n-1 {
maxBits = n - 1
}
// Create information about each of the levels. // Create information about each of the levels.
// A bogus "Level 0" whose sole purpose is so that // A bogus "Level 0" whose sole purpose is so that

View File

@ -1,72 +0,0 @@
// 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 flate
func min(left int, right int) int {
if left < right {
return left
}
return right
}
func minInt32(left int32, right int32) int32 {
if left < right {
return left
}
return right
}
func max(left int, right int) int {
if left > right {
return left
}
return right
}
func fillInts(a []int, value int) {
for i := range a {
a[i] = value
}
}
func fillInt32s(a []int32, value int32) {
for i := range a {
a[i] = value
}
}
func fillBytes(a []byte, value byte) {
for i := range a {
a[i] = value
}
}
func fillInt8s(a []int8, value int8) {
for i := range a {
a[i] = value
}
}
func fillUint8s(a []uint8, value uint8) {
for i := range a {
a[i] = value
}
}
func copyInt8s(dst []int8, src []int8) int {
cnt := min(len(dst), len(src))
for i := 0; i < cnt; i++ {
dst[i] = src[i]
}
return cnt
}
func copyUint8s(dst []uint8, src []uint8) int {
cnt := min(len(dst), len(src))
for i := 0; i < cnt; i++ {
dst[i] = src[i]
}
return cnt
}

View File

@ -37,8 +37,8 @@ func makeReader(r io.Reader) flate.Reader {
return bufio.NewReader(r) return bufio.NewReader(r)
} }
var HeaderError = errors.New("invalid gzip header") var ErrHeader = errors.New("invalid gzip header")
var ChecksumError = errors.New("gzip checksum error") var ErrChecksum = errors.New("gzip checksum error")
// The gzip file stores a header giving metadata about the compressed file. // The gzip file stores a header giving metadata about the compressed file.
// That header is exposed as the fields of the Compressor and Decompressor structs. // That header is exposed as the fields of the Compressor and Decompressor structs.
@ -59,7 +59,7 @@ type Header struct {
// Only the first header is recorded in the Decompressor fields. // Only the first header is recorded in the Decompressor fields.
// //
// Gzip files store a length and checksum of the uncompressed data. // Gzip files store a length and checksum of the uncompressed data.
// The Decompressor will return a ChecksumError when Read // The Decompressor will return a ErrChecksum when Read
// reaches the end of the uncompressed data if it does not // reaches the end of the uncompressed data if it does not
// have the expected length or checksum. Clients should treat data // have the expected length or checksum. Clients should treat data
// returned by Read as tentative until they receive the successful // returned by Read as tentative until they receive the successful
@ -99,7 +99,7 @@ func (z *Decompressor) readString() (string, error) {
needconv := false needconv := false
for i := 0; ; i++ { for i := 0; ; i++ {
if i >= len(z.buf) { if i >= len(z.buf) {
return "", HeaderError return "", ErrHeader
} }
z.buf[i], err = z.r.ReadByte() z.buf[i], err = z.r.ReadByte()
if err != nil { if err != nil {
@ -137,7 +137,7 @@ func (z *Decompressor) readHeader(save bool) error {
return err return err
} }
if z.buf[0] != gzipID1 || z.buf[1] != gzipID2 || z.buf[2] != gzipDeflate { if z.buf[0] != gzipID1 || z.buf[1] != gzipID2 || z.buf[2] != gzipDeflate {
return HeaderError return ErrHeader
} }
z.flg = z.buf[3] z.flg = z.buf[3]
if save { if save {
@ -188,7 +188,7 @@ func (z *Decompressor) readHeader(save bool) error {
} }
sum := z.digest.Sum32() & 0xFFFF sum := z.digest.Sum32() & 0xFFFF
if n != sum { if n != sum {
return HeaderError return ErrHeader
} }
} }
@ -221,7 +221,7 @@ func (z *Decompressor) Read(p []byte) (n int, err error) {
crc32, isize := get4(z.buf[0:4]), get4(z.buf[4:8]) crc32, isize := get4(z.buf[0:4]), get4(z.buf[4:8])
sum := z.digest.Sum32() sum := z.digest.Sum32()
if sum != crc32 || isize != z.size { if sum != crc32 || isize != z.size {
z.err = ChecksumError z.err = ErrChecksum
return 0, z.err return 0, z.err
} }

View File

@ -232,7 +232,7 @@ var gunzipTests = []gunzipTest{
0x02, 0x00, 0x2d, 0x3b, 0x08, 0xaf, 0x0c, 0x00, 0x02, 0x00, 0x2d, 0x3b, 0x08, 0xaf, 0x0c, 0x00,
0x00, 0x00, 'g', 'a', 'r', 'b', 'a', 'g', 'e', '!', '!', '!', 0x00, 0x00, 'g', 'a', 'r', 'b', 'a', 'g', 'e', '!', '!', '!',
}, },
HeaderError, ErrHeader,
}, },
{ // has 1 non-empty fixed huffman block not enough header { // has 1 non-empty fixed huffman block not enough header
"hello.txt", "hello.txt",
@ -260,7 +260,7 @@ var gunzipTests = []gunzipTest{
0x02, 0x00, 0xff, 0xff, 0xff, 0xff, 0x0c, 0x00, 0x02, 0x00, 0xff, 0xff, 0xff, 0xff, 0x0c, 0x00,
0x00, 0x00, 0x00, 0x00,
}, },
ChecksumError, ErrChecksum,
}, },
{ // has 1 non-empty fixed huffman block but corrupt size { // has 1 non-empty fixed huffman block but corrupt size
"hello.txt", "hello.txt",
@ -274,7 +274,7 @@ var gunzipTests = []gunzipTest{
0x02, 0x00, 0x2d, 0x3b, 0x08, 0xaf, 0xff, 0x00, 0x02, 0x00, 0x2d, 0x3b, 0x08, 0xaf, 0xff, 0x00,
0x00, 0x00, 0x00, 0x00,
}, },
ChecksumError, ErrChecksum,
}, },
} }

File diff suppressed because it is too large Load Diff

View File

@ -34,9 +34,9 @@ import (
const zlibDeflate = 8 const zlibDeflate = 8
var ChecksumError = errors.New("zlib checksum error") var ErrChecksum = errors.New("zlib checksum error")
var HeaderError = errors.New("invalid zlib header") var ErrHeader = errors.New("invalid zlib header")
var DictionaryError = errors.New("invalid zlib dictionary") var ErrDictionary = errors.New("invalid zlib dictionary")
type reader struct { type reader struct {
r flate.Reader r flate.Reader
@ -68,7 +68,7 @@ func NewReaderDict(r io.Reader, dict []byte) (io.ReadCloser, error) {
} }
h := uint(z.scratch[0])<<8 | uint(z.scratch[1]) h := uint(z.scratch[0])<<8 | uint(z.scratch[1])
if (z.scratch[0]&0x0f != zlibDeflate) || (h%31 != 0) { if (z.scratch[0]&0x0f != zlibDeflate) || (h%31 != 0) {
return nil, HeaderError return nil, ErrHeader
} }
if z.scratch[1]&0x20 != 0 { if z.scratch[1]&0x20 != 0 {
_, err = io.ReadFull(z.r, z.scratch[0:4]) _, err = io.ReadFull(z.r, z.scratch[0:4])
@ -77,7 +77,7 @@ func NewReaderDict(r io.Reader, dict []byte) (io.ReadCloser, error) {
} }
checksum := uint32(z.scratch[0])<<24 | uint32(z.scratch[1])<<16 | uint32(z.scratch[2])<<8 | uint32(z.scratch[3]) checksum := uint32(z.scratch[0])<<24 | uint32(z.scratch[1])<<16 | uint32(z.scratch[2])<<8 | uint32(z.scratch[3])
if checksum != adler32.Checksum(dict) { if checksum != adler32.Checksum(dict) {
return nil, DictionaryError return nil, ErrDictionary
} }
z.decompressor = flate.NewReaderDict(z.r, dict) z.decompressor = flate.NewReaderDict(z.r, dict)
} else { } else {
@ -110,7 +110,7 @@ func (z *reader) Read(p []byte) (n int, err error) {
// ZLIB (RFC 1950) is big-endian, unlike GZIP (RFC 1952). // ZLIB (RFC 1950) is big-endian, unlike GZIP (RFC 1952).
checksum := uint32(z.scratch[0])<<24 | uint32(z.scratch[1])<<16 | uint32(z.scratch[2])<<8 | uint32(z.scratch[3]) checksum := uint32(z.scratch[0])<<24 | uint32(z.scratch[1])<<16 | uint32(z.scratch[2])<<8 | uint32(z.scratch[3])
if checksum != z.digest.Sum32() { if checksum != z.digest.Sum32() {
z.err = ChecksumError z.err = ErrChecksum
return 0, z.err return 0, z.err
} }
return return

View File

@ -45,14 +45,14 @@ var zlibTests = []zlibTest{
"", "",
[]byte{0x78, 0x9f, 0x03, 0x00, 0x00, 0x00, 0x00, 0x01}, []byte{0x78, 0x9f, 0x03, 0x00, 0x00, 0x00, 0x00, 0x01},
nil, nil,
HeaderError, ErrHeader,
}, },
{ {
"bad checksum", "bad checksum",
"", "",
[]byte{0x78, 0x9c, 0x03, 0x00, 0x00, 0x00, 0x00, 0xff}, []byte{0x78, 0x9c, 0x03, 0x00, 0x00, 0x00, 0x00, 0xff},
nil, nil,
ChecksumError, ErrChecksum,
}, },
{ {
"not enough data", "not enough data",
@ -95,7 +95,7 @@ var zlibTests = []zlibTest{
[]byte{ []byte{
0x48, 0x65, 0x6c, 0x6c, 0x48, 0x65, 0x6c, 0x6c,
}, },
DictionaryError, ErrDictionary,
}, },
} }

View File

@ -1,35 +0,0 @@
// 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 bcrypt
import "encoding/base64"
const alphabet = "./ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"
var bcEncoding = base64.NewEncoding(alphabet)
func base64Encode(src []byte) []byte {
n := bcEncoding.EncodedLen(len(src))
dst := make([]byte, n)
bcEncoding.Encode(dst, src)
for dst[n-1] == '=' {
n--
}
return dst[:n]
}
func base64Decode(src []byte) ([]byte, error) {
numOfEquals := 4 - (len(src) % 4)
for i := 0; i < numOfEquals; i++ {
src = append(src, '=')
}
dst := make([]byte, bcEncoding.DecodedLen(len(src)))
n, err := bcEncoding.Decode(dst, src)
if err != nil {
return nil, err
}
return dst[:n], nil
}

View File

@ -1,282 +0,0 @@
// 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 bcrypt implements Provos and Mazières's bcrypt adaptive hashing
// algorithm. See http://www.usenix.org/event/usenix99/provos/provos.pdf
package bcrypt
// The code is a port of Provos and Mazières's C implementation.
import (
"crypto/blowfish"
"crypto/rand"
"crypto/subtle"
"errors"
"fmt"
"io"
"strconv"
)
const (
MinCost int = 4 // the minimum allowable cost as passed in to GenerateFromPassword
MaxCost int = 31 // the maximum allowable cost as passed in to GenerateFromPassword
DefaultCost int = 10 // the cost that will actually be set if a cost below MinCost is passed into GenerateFromPassword
)
// The error returned from CompareHashAndPassword when a password and hash do
// not match.
var MismatchedHashAndPasswordError = errors.New("crypto/bcrypt: hashedPassword is not the hash of the given password")
// The error returned from CompareHashAndPassword when a hash is too short to
// be a bcrypt hash.
var HashTooShortError = errors.New("crypto/bcrypt: hashedSecret too short to be a bcrypted password")
// The error returned from CompareHashAndPassword when a hash was created with
// a bcrypt algorithm newer than this implementation.
type HashVersionTooNewError byte
func (hv HashVersionTooNewError) Error() string {
return fmt.Sprintf("crypto/bcrypt: bcrypt algorithm version '%c' requested is newer than current version '%c'", byte(hv), majorVersion)
}
// The error returned from CompareHashAndPassword when a hash starts with something other than '$'
type InvalidHashPrefixError byte
func (ih InvalidHashPrefixError) Error() string {
return fmt.Sprintf("crypto/bcrypt: bcrypt hashes must start with '$', but hashedSecret started with '%c'", byte(ih))
}
type InvalidCostError int
func (ic InvalidCostError) Error() string {
return fmt.Sprintf("crypto/bcrypt: cost %d is outside allowed range (%d,%d)", int(ic), int(MinCost), int(MaxCost))
}
const (
majorVersion = '2'
minorVersion = 'a'
maxSaltSize = 16
maxCryptedHashSize = 23
encodedSaltSize = 22
encodedHashSize = 31
minHashSize = 59
)
// magicCipherData is an IV for the 64 Blowfish encryption calls in
// bcrypt(). It's the string "OrpheanBeholderScryDoubt" in big-endian bytes.
var magicCipherData = []byte{
0x4f, 0x72, 0x70, 0x68,
0x65, 0x61, 0x6e, 0x42,
0x65, 0x68, 0x6f, 0x6c,
0x64, 0x65, 0x72, 0x53,
0x63, 0x72, 0x79, 0x44,
0x6f, 0x75, 0x62, 0x74,
}
type hashed struct {
hash []byte
salt []byte
cost uint32 // allowed range is MinCost to MaxCost
major byte
minor byte
}
// GenerateFromPassword returns the bcrypt hash of the password at the given
// cost. If the cost given is less than MinCost, the cost will be set to
// MinCost, instead. Use CompareHashAndPassword, as defined in this package,
// to compare the returned hashed password with its cleartext version.
func GenerateFromPassword(password []byte, cost int) ([]byte, error) {
p, err := newFromPassword(password, cost)
if err != nil {
return nil, err
}
return p.Hash(), nil
}
// CompareHashAndPassword compares a bcrypt hashed password with its possible
// plaintext equivalent. Note: Using bytes.Equal for this job is
// insecure. Returns nil on success, or an error on failure.
func CompareHashAndPassword(hashedPassword, password []byte) error {
p, err := newFromHash(hashedPassword)
if err != nil {
return err
}
otherHash, err := bcrypt(password, p.cost, p.salt)
if err != nil {
return err
}
otherP := &hashed{otherHash, p.salt, p.cost, p.major, p.minor}
if subtle.ConstantTimeCompare(p.Hash(), otherP.Hash()) == 1 {
return nil
}
return MismatchedHashAndPasswordError
}
func newFromPassword(password []byte, cost int) (*hashed, error) {
if cost < MinCost {
cost = DefaultCost
}
p := new(hashed)
p.major = majorVersion
p.minor = minorVersion
err := checkCost(cost)
if err != nil {
return nil, err
}
p.cost = uint32(cost)
unencodedSalt := make([]byte, maxSaltSize)
_, err = io.ReadFull(rand.Reader, unencodedSalt)
if err != nil {
return nil, err
}
p.salt = base64Encode(unencodedSalt)
hash, err := bcrypt(password, p.cost, p.salt)
if err != nil {
return nil, err
}
p.hash = hash
return p, err
}
func newFromHash(hashedSecret []byte) (*hashed, error) {
if len(hashedSecret) < minHashSize {
return nil, HashTooShortError
}
p := new(hashed)
n, err := p.decodeVersion(hashedSecret)
if err != nil {
return nil, err
}
hashedSecret = hashedSecret[n:]
n, err = p.decodeCost(hashedSecret)
if err != nil {
return nil, err
}
hashedSecret = hashedSecret[n:]
// The "+2" is here because we'll have to append at most 2 '=' to the salt
// when base64 decoding it in expensiveBlowfishSetup().
p.salt = make([]byte, encodedSaltSize, encodedSaltSize+2)
copy(p.salt, hashedSecret[:encodedSaltSize])
hashedSecret = hashedSecret[encodedSaltSize:]
p.hash = make([]byte, len(hashedSecret))
copy(p.hash, hashedSecret)
return p, nil
}
func bcrypt(password []byte, cost uint32, salt []byte) ([]byte, error) {
cipherData := make([]byte, len(magicCipherData))
copy(cipherData, magicCipherData)
c, err := expensiveBlowfishSetup(password, cost, salt)
if err != nil {
return nil, err
}
for i := 0; i < 24; i += 8 {
for j := 0; j < 64; j++ {
c.Encrypt(cipherData[i:i+8], cipherData[i:i+8])
}
}
// Bug compatibility with C bcrypt implementations. We only encode 23 of
// the 24 bytes encrypted.
hsh := base64Encode(cipherData[:maxCryptedHashSize])
return hsh, nil
}
func expensiveBlowfishSetup(key []byte, cost uint32, salt []byte) (*blowfish.Cipher, error) {
csalt, err := base64Decode(salt)
if err != nil {
return nil, err
}
// Bug compatibility with C bcrypt implementations. They use the trailing
// NULL in the key string during expansion.
ckey := append(key, 0)
c, err := blowfish.NewSaltedCipher(ckey, csalt)
if err != nil {
return nil, err
}
rounds := 1 << cost
for i := 0; i < rounds; i++ {
blowfish.ExpandKey(ckey, c)
blowfish.ExpandKey(csalt, c)
}
return c, nil
}
func (p *hashed) Hash() []byte {
arr := make([]byte, 60)
arr[0] = '$'
arr[1] = p.major
n := 2
if p.minor != 0 {
arr[2] = p.minor
n = 3
}
arr[n] = '$'
n += 1
copy(arr[n:], []byte(fmt.Sprintf("%02d", p.cost)))
n += 2
arr[n] = '$'
n += 1
copy(arr[n:], p.salt)
n += encodedSaltSize
copy(arr[n:], p.hash)
n += encodedHashSize
return arr[:n]
}
func (p *hashed) decodeVersion(sbytes []byte) (int, error) {
if sbytes[0] != '$' {
return -1, InvalidHashPrefixError(sbytes[0])
}
if sbytes[1] > majorVersion {
return -1, HashVersionTooNewError(sbytes[1])
}
p.major = sbytes[1]
n := 3
if sbytes[2] != '$' {
p.minor = sbytes[2]
n++
}
return n, nil
}
// sbytes should begin where decodeVersion left off.
func (p *hashed) decodeCost(sbytes []byte) (int, error) {
cost, err := strconv.Atoi(string(sbytes[0:2]))
if err != nil {
return -1, err
}
err = checkCost(cost)
if err != nil {
return -1, err
}
p.cost = uint32(cost)
return 3, nil
}
func (p *hashed) String() string {
return fmt.Sprintf("&{hash: %#v, salt: %#v, cost: %d, major: %c, minor: %c}", string(p.hash), p.salt, p.cost, p.major, p.minor)
}
func checkCost(cost int) error {
if cost < MinCost || cost > MaxCost {
return InvalidCostError(cost)
}
return nil
}

View File

@ -1,194 +0,0 @@
// 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 bcrypt
import (
"bytes"
"testing"
)
func TestBcryptingIsEasy(t *testing.T) {
pass := []byte("mypassword")
hp, err := GenerateFromPassword(pass, 0)
if err != nil {
t.Fatalf("GenerateFromPassword error: %s", err)
}
if CompareHashAndPassword(hp, pass) != nil {
t.Errorf("%v should hash %s correctly", hp, pass)
}
notPass := "notthepass"
err = CompareHashAndPassword(hp, []byte(notPass))
if err != MismatchedHashAndPasswordError {
t.Errorf("%v and %s should be mismatched", hp, notPass)
}
}
func TestBcryptingIsCorrect(t *testing.T) {
pass := []byte("allmine")
salt := []byte("XajjQvNhvvRt5GSeFk1xFe")
expectedHash := []byte("$2a$10$XajjQvNhvvRt5GSeFk1xFeyqRrsxkhBkUiQeg0dt.wU1qD4aFDcga")
hash, err := bcrypt(pass, 10, salt)
if err != nil {
t.Fatalf("bcrypt blew up: %v", err)
}
if !bytes.HasSuffix(expectedHash, hash) {
t.Errorf("%v should be the suffix of %v", hash, expectedHash)
}
h, err := newFromHash(expectedHash)
if err != nil {
t.Errorf("Unable to parse %s: %v", string(expectedHash), err)
}
// This is not the safe way to compare these hashes. We do this only for
// testing clarity. Use bcrypt.CompareHashAndPassword()
if err == nil && !bytes.Equal(expectedHash, h.Hash()) {
t.Errorf("Parsed hash %v should equal %v", h.Hash(), expectedHash)
}
}
func TestTooLongPasswordsWork(t *testing.T) {
salt := []byte("XajjQvNhvvRt5GSeFk1xFe")
// One byte over the usual 56 byte limit that blowfish has
tooLongPass := []byte("012345678901234567890123456789012345678901234567890123456")
tooLongExpected := []byte("$2a$10$XajjQvNhvvRt5GSeFk1xFe5l47dONXg781AmZtd869sO8zfsHuw7C")
hash, err := bcrypt(tooLongPass, 10, salt)
if err != nil {
t.Fatalf("bcrypt blew up on long password: %v", err)
}
if !bytes.HasSuffix(tooLongExpected, hash) {
t.Errorf("%v should be the suffix of %v", hash, tooLongExpected)
}
}
type InvalidHashTest struct {
err error
hash []byte
}
var invalidTests = []InvalidHashTest{
{HashTooShortError, []byte("$2a$10$fooo")},
{HashTooShortError, []byte("$2a")},
{HashVersionTooNewError('3'), []byte("$3a$10$sssssssssssssssssssssshhhhhhhhhhhhhhhhhhhhhhhhhhhhhhh")},
{InvalidHashPrefixError('%'), []byte("%2a$10$sssssssssssssssssssssshhhhhhhhhhhhhhhhhhhhhhhhhhhhhhh")},
{InvalidCostError(32), []byte("$2a$32$sssssssssssssssssssssshhhhhhhhhhhhhhhhhhhhhhhhhhhhhhh")},
}
func TestInvalidHashErrors(t *testing.T) {
check := func(name string, expected, err error) {
if err == nil {
t.Errorf("%s: Should have returned an error", name)
}
if err != nil && err != expected {
t.Errorf("%s gave err %v but should have given %v", name, err, expected)
}
}
for _, iht := range invalidTests {
_, err := newFromHash(iht.hash)
check("newFromHash", iht.err, err)
err = CompareHashAndPassword(iht.hash, []byte("anything"))
check("CompareHashAndPassword", iht.err, err)
}
}
func TestUnpaddedBase64Encoding(t *testing.T) {
original := []byte{101, 201, 101, 75, 19, 227, 199, 20, 239, 236, 133, 32, 30, 109, 243, 30}
encodedOriginal := []byte("XajjQvNhvvRt5GSeFk1xFe")
encoded := base64Encode(original)
if !bytes.Equal(encodedOriginal, encoded) {
t.Errorf("Encoded %v should have equaled %v", encoded, encodedOriginal)
}
decoded, err := base64Decode(encodedOriginal)
if err != nil {
t.Fatalf("base64Decode blew up: %s", err)
}
if !bytes.Equal(decoded, original) {
t.Errorf("Decoded %v should have equaled %v", decoded, original)
}
}
func TestCost(t *testing.T) {
if testing.Short() {
return
}
pass := []byte("mypassword")
for c := 0; c < MinCost; c++ {
p, _ := newFromPassword(pass, c)
if p.cost != uint32(DefaultCost) {
t.Errorf("newFromPassword should default costs below %d to %d, but was %d", MinCost, DefaultCost, p.cost)
}
}
p, _ := newFromPassword(pass, 14)
if p.cost != 14 {
t.Errorf("newFromPassword should default cost to 14, but was %d", p.cost)
}
hp, _ := newFromHash(p.Hash())
if p.cost != hp.cost {
t.Errorf("newFromHash should maintain the cost at %d, but was %d", p.cost, hp.cost)
}
_, err := newFromPassword(pass, 32)
if err == nil {
t.Fatalf("newFromPassword: should return a cost error")
}
if err != InvalidCostError(32) {
t.Errorf("newFromPassword: should return cost error, got %#v", err)
}
}
func TestCostReturnsWithLeadingZeroes(t *testing.T) {
hp, _ := newFromPassword([]byte("abcdefgh"), 7)
cost := hp.Hash()[4:7]
expected := []byte("07$")
if !bytes.Equal(expected, cost) {
t.Errorf("single digit costs in hash should have leading zeros: was %v instead of %v", cost, expected)
}
}
func TestMinorNotRequired(t *testing.T) {
noMinorHash := []byte("$2$10$XajjQvNhvvRt5GSeFk1xFeyqRrsxkhBkUiQeg0dt.wU1qD4aFDcga")
h, err := newFromHash(noMinorHash)
if err != nil {
t.Fatalf("No minor hash blew up: %s", err)
}
if h.minor != 0 {
t.Errorf("Should leave minor version at 0, but was %d", h.minor)
}
if !bytes.Equal(noMinorHash, h.Hash()) {
t.Errorf("Should generate hash %v, but created %v", noMinorHash, h.Hash())
}
}
func BenchmarkEqual(b *testing.B) {
b.StopTimer()
passwd := []byte("somepasswordyoulike")
hash, _ := GenerateFromPassword(passwd, 10)
b.StartTimer()
for i := 0; i < b.N; i++ {
CompareHashAndPassword(hash, passwd)
}
}
func BenchmarkGeneration(b *testing.B) {
b.StopTimer()
passwd := []byte("mylongpassword1234")
b.StartTimer()
for i := 0; i < b.N; i++ {
GenerateFromPassword(passwd, 10)
}
}

View File

@ -1,192 +0,0 @@
// 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 blowfish
// ExpandKey performs a key expansion on the given *Cipher. Specifically, it
// performs the Blowfish algorithm's key schedule which sets up the *Cipher's
// pi and substitution tables for calls to Encrypt. This is used, primarily,
// by the bcrypt package to reuse the Blowfish key schedule during its
// set up. It's unlikely that you need to use this directly.
func ExpandKey(key []byte, c *Cipher) {
j := 0
for i := 0; i < 18; i++ {
var d uint32
for k := 0; k < 4; k++ {
d = d<<8 | uint32(key[j])&0x000000FF
j++
if j >= len(key) {
j = 0
}
}
c.p[i] ^= d
}
var l, r uint32
for i := 0; i < 18; i += 2 {
l, r = encryptBlock(l, r, c)
c.p[i], c.p[i+1] = l, r
}
for i := 0; i < 256; i += 2 {
l, r = encryptBlock(l, r, c)
c.s0[i], c.s0[i+1] = l, r
}
for i := 0; i < 256; i += 2 {
l, r = encryptBlock(l, r, c)
c.s1[i], c.s1[i+1] = l, r
}
for i := 0; i < 256; i += 2 {
l, r = encryptBlock(l, r, c)
c.s2[i], c.s2[i+1] = l, r
}
for i := 0; i < 256; i += 2 {
l, r = encryptBlock(l, r, c)
c.s3[i], c.s3[i+1] = l, r
}
}
// This is similar to ExpandKey, but folds the salt during the key
// schedule. While ExpandKey is essentially expandKeyWithSalt with an all-zero
// salt passed in, reusing ExpandKey turns out to be a place of inefficiency
// and specializing it here is useful.
func expandKeyWithSalt(key []byte, salt []byte, c *Cipher) {
j := 0
expandedKey := make([]uint32, 18)
for i := 0; i < 18; i++ {
var d uint32
for k := 0; k < 4; k++ {
d = d<<8 | uint32(key[j])&0x000000FF
j++
if j >= len(key) {
j = 0
}
}
expandedKey[i] = d
c.p[i] ^= d
}
j = 0
expandedSalt := make([]uint32, 18)
for i := 0; i < 18; i++ {
var d uint32
for k := 0; k < 4; k++ {
d = d<<8 | uint32(salt[j])&0x000000FF
j++
if j >= len(salt) {
j = 0
}
}
expandedSalt[i] = d
}
var l, r uint32
for i := 0; i < 18; i += 2 {
l ^= expandedSalt[i&2]
r ^= expandedSalt[(i&2)+1]
l, r = encryptBlock(l, r, c)
c.p[i], c.p[i+1] = l, r
}
for i := 0; i < 256; i += 4 {
l ^= expandedSalt[2]
r ^= expandedSalt[3]
l, r = encryptBlock(l, r, c)
c.s0[i], c.s0[i+1] = l, r
l ^= expandedSalt[0]
r ^= expandedSalt[1]
l, r = encryptBlock(l, r, c)
c.s0[i+2], c.s0[i+3] = l, r
}
for i := 0; i < 256; i += 4 {
l ^= expandedSalt[2]
r ^= expandedSalt[3]
l, r = encryptBlock(l, r, c)
c.s1[i], c.s1[i+1] = l, r
l ^= expandedSalt[0]
r ^= expandedSalt[1]
l, r = encryptBlock(l, r, c)
c.s1[i+2], c.s1[i+3] = l, r
}
for i := 0; i < 256; i += 4 {
l ^= expandedSalt[2]
r ^= expandedSalt[3]
l, r = encryptBlock(l, r, c)
c.s2[i], c.s2[i+1] = l, r
l ^= expandedSalt[0]
r ^= expandedSalt[1]
l, r = encryptBlock(l, r, c)
c.s2[i+2], c.s2[i+3] = l, r
}
for i := 0; i < 256; i += 4 {
l ^= expandedSalt[2]
r ^= expandedSalt[3]
l, r = encryptBlock(l, r, c)
c.s3[i], c.s3[i+1] = l, r
l ^= expandedSalt[0]
r ^= expandedSalt[1]
l, r = encryptBlock(l, r, c)
c.s3[i+2], c.s3[i+3] = l, r
}
}
func encryptBlock(l, r uint32, c *Cipher) (uint32, uint32) {
xl, xr := l, r
xl ^= c.p[0]
xr ^= ((c.s0[byte(xl>>24)] + c.s1[byte(xl>>16)]) ^ c.s2[byte(xl>>8)]) + c.s3[byte(xl)] ^ c.p[1]
xl ^= ((c.s0[byte(xr>>24)] + c.s1[byte(xr>>16)]) ^ c.s2[byte(xr>>8)]) + c.s3[byte(xr)] ^ c.p[2]
xr ^= ((c.s0[byte(xl>>24)] + c.s1[byte(xl>>16)]) ^ c.s2[byte(xl>>8)]) + c.s3[byte(xl)] ^ c.p[3]
xl ^= ((c.s0[byte(xr>>24)] + c.s1[byte(xr>>16)]) ^ c.s2[byte(xr>>8)]) + c.s3[byte(xr)] ^ c.p[4]
xr ^= ((c.s0[byte(xl>>24)] + c.s1[byte(xl>>16)]) ^ c.s2[byte(xl>>8)]) + c.s3[byte(xl)] ^ c.p[5]
xl ^= ((c.s0[byte(xr>>24)] + c.s1[byte(xr>>16)]) ^ c.s2[byte(xr>>8)]) + c.s3[byte(xr)] ^ c.p[6]
xr ^= ((c.s0[byte(xl>>24)] + c.s1[byte(xl>>16)]) ^ c.s2[byte(xl>>8)]) + c.s3[byte(xl)] ^ c.p[7]
xl ^= ((c.s0[byte(xr>>24)] + c.s1[byte(xr>>16)]) ^ c.s2[byte(xr>>8)]) + c.s3[byte(xr)] ^ c.p[8]
xr ^= ((c.s0[byte(xl>>24)] + c.s1[byte(xl>>16)]) ^ c.s2[byte(xl>>8)]) + c.s3[byte(xl)] ^ c.p[9]
xl ^= ((c.s0[byte(xr>>24)] + c.s1[byte(xr>>16)]) ^ c.s2[byte(xr>>8)]) + c.s3[byte(xr)] ^ c.p[10]
xr ^= ((c.s0[byte(xl>>24)] + c.s1[byte(xl>>16)]) ^ c.s2[byte(xl>>8)]) + c.s3[byte(xl)] ^ c.p[11]
xl ^= ((c.s0[byte(xr>>24)] + c.s1[byte(xr>>16)]) ^ c.s2[byte(xr>>8)]) + c.s3[byte(xr)] ^ c.p[12]
xr ^= ((c.s0[byte(xl>>24)] + c.s1[byte(xl>>16)]) ^ c.s2[byte(xl>>8)]) + c.s3[byte(xl)] ^ c.p[13]
xl ^= ((c.s0[byte(xr>>24)] + c.s1[byte(xr>>16)]) ^ c.s2[byte(xr>>8)]) + c.s3[byte(xr)] ^ c.p[14]
xr ^= ((c.s0[byte(xl>>24)] + c.s1[byte(xl>>16)]) ^ c.s2[byte(xl>>8)]) + c.s3[byte(xl)] ^ c.p[15]
xl ^= ((c.s0[byte(xr>>24)] + c.s1[byte(xr>>16)]) ^ c.s2[byte(xr>>8)]) + c.s3[byte(xr)] ^ c.p[16]
xr ^= c.p[17]
return xr, xl
}
func decryptBlock(l, r uint32, c *Cipher) (uint32, uint32) {
xl, xr := l, r
xl ^= c.p[17]
xr ^= ((c.s0[byte(xl>>24)] + c.s1[byte(xl>>16)]) ^ c.s2[byte(xl>>8)]) + c.s3[byte(xl)] ^ c.p[16]
xl ^= ((c.s0[byte(xr>>24)] + c.s1[byte(xr>>16)]) ^ c.s2[byte(xr>>8)]) + c.s3[byte(xr)] ^ c.p[15]
xr ^= ((c.s0[byte(xl>>24)] + c.s1[byte(xl>>16)]) ^ c.s2[byte(xl>>8)]) + c.s3[byte(xl)] ^ c.p[14]
xl ^= ((c.s0[byte(xr>>24)] + c.s1[byte(xr>>16)]) ^ c.s2[byte(xr>>8)]) + c.s3[byte(xr)] ^ c.p[13]
xr ^= ((c.s0[byte(xl>>24)] + c.s1[byte(xl>>16)]) ^ c.s2[byte(xl>>8)]) + c.s3[byte(xl)] ^ c.p[12]
xl ^= ((c.s0[byte(xr>>24)] + c.s1[byte(xr>>16)]) ^ c.s2[byte(xr>>8)]) + c.s3[byte(xr)] ^ c.p[11]
xr ^= ((c.s0[byte(xl>>24)] + c.s1[byte(xl>>16)]) ^ c.s2[byte(xl>>8)]) + c.s3[byte(xl)] ^ c.p[10]
xl ^= ((c.s0[byte(xr>>24)] + c.s1[byte(xr>>16)]) ^ c.s2[byte(xr>>8)]) + c.s3[byte(xr)] ^ c.p[9]
xr ^= ((c.s0[byte(xl>>24)] + c.s1[byte(xl>>16)]) ^ c.s2[byte(xl>>8)]) + c.s3[byte(xl)] ^ c.p[8]
xl ^= ((c.s0[byte(xr>>24)] + c.s1[byte(xr>>16)]) ^ c.s2[byte(xr>>8)]) + c.s3[byte(xr)] ^ c.p[7]
xr ^= ((c.s0[byte(xl>>24)] + c.s1[byte(xl>>16)]) ^ c.s2[byte(xl>>8)]) + c.s3[byte(xl)] ^ c.p[6]
xl ^= ((c.s0[byte(xr>>24)] + c.s1[byte(xr>>16)]) ^ c.s2[byte(xr>>8)]) + c.s3[byte(xr)] ^ c.p[5]
xr ^= ((c.s0[byte(xl>>24)] + c.s1[byte(xl>>16)]) ^ c.s2[byte(xl>>8)]) + c.s3[byte(xl)] ^ c.p[4]
xl ^= ((c.s0[byte(xr>>24)] + c.s1[byte(xr>>16)]) ^ c.s2[byte(xr>>8)]) + c.s3[byte(xr)] ^ c.p[3]
xr ^= ((c.s0[byte(xl>>24)] + c.s1[byte(xl>>16)]) ^ c.s2[byte(xl>>8)]) + c.s3[byte(xl)] ^ c.p[2]
xl ^= ((c.s0[byte(xr>>24)] + c.s1[byte(xr>>16)]) ^ c.s2[byte(xr>>8)]) + c.s3[byte(xr)] ^ c.p[1]
xr ^= c.p[0]
return xr, xl
}
func zero(x []uint32) {
for i := range x {
x[i] = 0
}
}

View File

@ -1,210 +0,0 @@
// 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 blowfish
import (
"testing"
)
type CryptTest struct {
key []byte
in []byte
out []byte
}
// Test vector values are from http://www.schneier.com/code/vectors.txt.
var encryptTests = []CryptTest{
{
[]byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
[]byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
[]byte{0x4E, 0xF9, 0x97, 0x45, 0x61, 0x98, 0xDD, 0x78}},
{
[]byte{0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF},
[]byte{0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF},
[]byte{0x51, 0x86, 0x6F, 0xD5, 0xB8, 0x5E, 0xCB, 0x8A}},
{
[]byte{0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
[]byte{0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01},
[]byte{0x7D, 0x85, 0x6F, 0x9A, 0x61, 0x30, 0x63, 0xF2}},
{
[]byte{0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11},
[]byte{0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11},
[]byte{0x24, 0x66, 0xDD, 0x87, 0x8B, 0x96, 0x3C, 0x9D}},
{
[]byte{0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF},
[]byte{0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11},
[]byte{0x61, 0xF9, 0xC3, 0x80, 0x22, 0x81, 0xB0, 0x96}},
{
[]byte{0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11},
[]byte{0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF},
[]byte{0x7D, 0x0C, 0xC6, 0x30, 0xAF, 0xDA, 0x1E, 0xC7}},
{
[]byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
[]byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
[]byte{0x4E, 0xF9, 0x97, 0x45, 0x61, 0x98, 0xDD, 0x78}},
{
[]byte{0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10},
[]byte{0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF},
[]byte{0x0A, 0xCE, 0xAB, 0x0F, 0xC6, 0xA0, 0xA2, 0x8D}},
{
[]byte{0x7C, 0xA1, 0x10, 0x45, 0x4A, 0x1A, 0x6E, 0x57},
[]byte{0x01, 0xA1, 0xD6, 0xD0, 0x39, 0x77, 0x67, 0x42},
[]byte{0x59, 0xC6, 0x82, 0x45, 0xEB, 0x05, 0x28, 0x2B}},
{
[]byte{0x01, 0x31, 0xD9, 0x61, 0x9D, 0xC1, 0x37, 0x6E},
[]byte{0x5C, 0xD5, 0x4C, 0xA8, 0x3D, 0xEF, 0x57, 0xDA},
[]byte{0xB1, 0xB8, 0xCC, 0x0B, 0x25, 0x0F, 0x09, 0xA0}},
{
[]byte{0x07, 0xA1, 0x13, 0x3E, 0x4A, 0x0B, 0x26, 0x86},
[]byte{0x02, 0x48, 0xD4, 0x38, 0x06, 0xF6, 0x71, 0x72},
[]byte{0x17, 0x30, 0xE5, 0x77, 0x8B, 0xEA, 0x1D, 0xA4}},
{
[]byte{0x38, 0x49, 0x67, 0x4C, 0x26, 0x02, 0x31, 0x9E},
[]byte{0x51, 0x45, 0x4B, 0x58, 0x2D, 0xDF, 0x44, 0x0A},
[]byte{0xA2, 0x5E, 0x78, 0x56, 0xCF, 0x26, 0x51, 0xEB}},
{
[]byte{0x04, 0xB9, 0x15, 0xBA, 0x43, 0xFE, 0xB5, 0xB6},
[]byte{0x42, 0xFD, 0x44, 0x30, 0x59, 0x57, 0x7F, 0xA2},
[]byte{0x35, 0x38, 0x82, 0xB1, 0x09, 0xCE, 0x8F, 0x1A}},
{
[]byte{0x01, 0x13, 0xB9, 0x70, 0xFD, 0x34, 0xF2, 0xCE},
[]byte{0x05, 0x9B, 0x5E, 0x08, 0x51, 0xCF, 0x14, 0x3A},
[]byte{0x48, 0xF4, 0xD0, 0x88, 0x4C, 0x37, 0x99, 0x18}},
{
[]byte{0x01, 0x70, 0xF1, 0x75, 0x46, 0x8F, 0xB5, 0xE6},
[]byte{0x07, 0x56, 0xD8, 0xE0, 0x77, 0x47, 0x61, 0xD2},
[]byte{0x43, 0x21, 0x93, 0xB7, 0x89, 0x51, 0xFC, 0x98}},
{
[]byte{0x43, 0x29, 0x7F, 0xAD, 0x38, 0xE3, 0x73, 0xFE},
[]byte{0x76, 0x25, 0x14, 0xB8, 0x29, 0xBF, 0x48, 0x6A},
[]byte{0x13, 0xF0, 0x41, 0x54, 0xD6, 0x9D, 0x1A, 0xE5}},
{
[]byte{0x07, 0xA7, 0x13, 0x70, 0x45, 0xDA, 0x2A, 0x16},
[]byte{0x3B, 0xDD, 0x11, 0x90, 0x49, 0x37, 0x28, 0x02},
[]byte{0x2E, 0xED, 0xDA, 0x93, 0xFF, 0xD3, 0x9C, 0x79}},
{
[]byte{0x04, 0x68, 0x91, 0x04, 0xC2, 0xFD, 0x3B, 0x2F},
[]byte{0x26, 0x95, 0x5F, 0x68, 0x35, 0xAF, 0x60, 0x9A},
[]byte{0xD8, 0x87, 0xE0, 0x39, 0x3C, 0x2D, 0xA6, 0xE3}},
{
[]byte{0x37, 0xD0, 0x6B, 0xB5, 0x16, 0xCB, 0x75, 0x46},
[]byte{0x16, 0x4D, 0x5E, 0x40, 0x4F, 0x27, 0x52, 0x32},
[]byte{0x5F, 0x99, 0xD0, 0x4F, 0x5B, 0x16, 0x39, 0x69}},
{
[]byte{0x1F, 0x08, 0x26, 0x0D, 0x1A, 0xC2, 0x46, 0x5E},
[]byte{0x6B, 0x05, 0x6E, 0x18, 0x75, 0x9F, 0x5C, 0xCA},
[]byte{0x4A, 0x05, 0x7A, 0x3B, 0x24, 0xD3, 0x97, 0x7B}},
{
[]byte{0x58, 0x40, 0x23, 0x64, 0x1A, 0xBA, 0x61, 0x76},
[]byte{0x00, 0x4B, 0xD6, 0xEF, 0x09, 0x17, 0x60, 0x62},
[]byte{0x45, 0x20, 0x31, 0xC1, 0xE4, 0xFA, 0xDA, 0x8E}},
{
[]byte{0x02, 0x58, 0x16, 0x16, 0x46, 0x29, 0xB0, 0x07},
[]byte{0x48, 0x0D, 0x39, 0x00, 0x6E, 0xE7, 0x62, 0xF2},
[]byte{0x75, 0x55, 0xAE, 0x39, 0xF5, 0x9B, 0x87, 0xBD}},
{
[]byte{0x49, 0x79, 0x3E, 0xBC, 0x79, 0xB3, 0x25, 0x8F},
[]byte{0x43, 0x75, 0x40, 0xC8, 0x69, 0x8F, 0x3C, 0xFA},
[]byte{0x53, 0xC5, 0x5F, 0x9C, 0xB4, 0x9F, 0xC0, 0x19}},
{
[]byte{0x4F, 0xB0, 0x5E, 0x15, 0x15, 0xAB, 0x73, 0xA7},
[]byte{0x07, 0x2D, 0x43, 0xA0, 0x77, 0x07, 0x52, 0x92},
[]byte{0x7A, 0x8E, 0x7B, 0xFA, 0x93, 0x7E, 0x89, 0xA3}},
{
[]byte{0x49, 0xE9, 0x5D, 0x6D, 0x4C, 0xA2, 0x29, 0xBF},
[]byte{0x02, 0xFE, 0x55, 0x77, 0x81, 0x17, 0xF1, 0x2A},
[]byte{0xCF, 0x9C, 0x5D, 0x7A, 0x49, 0x86, 0xAD, 0xB5}},
{
[]byte{0x01, 0x83, 0x10, 0xDC, 0x40, 0x9B, 0x26, 0xD6},
[]byte{0x1D, 0x9D, 0x5C, 0x50, 0x18, 0xF7, 0x28, 0xC2},
[]byte{0xD1, 0xAB, 0xB2, 0x90, 0x65, 0x8B, 0xC7, 0x78}},
{
[]byte{0x1C, 0x58, 0x7F, 0x1C, 0x13, 0x92, 0x4F, 0xEF},
[]byte{0x30, 0x55, 0x32, 0x28, 0x6D, 0x6F, 0x29, 0x5A},
[]byte{0x55, 0xCB, 0x37, 0x74, 0xD1, 0x3E, 0xF2, 0x01}},
{
[]byte{0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01},
[]byte{0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF},
[]byte{0xFA, 0x34, 0xEC, 0x48, 0x47, 0xB2, 0x68, 0xB2}},
{
[]byte{0x1F, 0x1F, 0x1F, 0x1F, 0x0E, 0x0E, 0x0E, 0x0E},
[]byte{0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF},
[]byte{0xA7, 0x90, 0x79, 0x51, 0x08, 0xEA, 0x3C, 0xAE}},
{
[]byte{0xE0, 0xFE, 0xE0, 0xFE, 0xF1, 0xFE, 0xF1, 0xFE},
[]byte{0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF},
[]byte{0xC3, 0x9E, 0x07, 0x2D, 0x9F, 0xAC, 0x63, 0x1D}},
{
[]byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
[]byte{0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF},
[]byte{0x01, 0x49, 0x33, 0xE0, 0xCD, 0xAF, 0xF6, 0xE4}},
{
[]byte{0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF},
[]byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
[]byte{0xF2, 0x1E, 0x9A, 0x77, 0xB7, 0x1C, 0x49, 0xBC}},
{
[]byte{0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF},
[]byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
[]byte{0x24, 0x59, 0x46, 0x88, 0x57, 0x54, 0x36, 0x9A}},
{
[]byte{0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10},
[]byte{0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF},
[]byte{0x6B, 0x5C, 0x5A, 0x9C, 0x5D, 0x9E, 0x0A, 0x5A}},
}
func TestCipherEncrypt(t *testing.T) {
for i, tt := range encryptTests {
c, err := NewCipher(tt.key)
if err != nil {
t.Errorf("NewCipher(%d bytes) = %s", len(tt.key), err)
continue
}
ct := make([]byte, len(tt.out))
c.Encrypt(ct, tt.in)
for j, v := range ct {
if v != tt.out[j] {
t.Errorf("Cipher.Encrypt, test vector #%d: cipher-text[%d] = %#x, expected %#x", i, j, v, tt.out[j])
break
}
}
}
}
func TestCipherDecrypt(t *testing.T) {
for i, tt := range encryptTests {
c, err := NewCipher(tt.key)
if err != nil {
t.Errorf("NewCipher(%d bytes) = %s", len(tt.key), err)
continue
}
pt := make([]byte, len(tt.in))
c.Decrypt(pt, tt.out)
for j, v := range pt {
if v != tt.in[j] {
t.Errorf("Cipher.Decrypt, test vector #%d: plain-text[%d] = %#x, expected %#x", i, j, v, tt.in[j])
break
}
}
}
}
func TestSaltedCipherKeyLength(t *testing.T) {
var key []byte
for i := 0; i < 4; i++ {
_, err := NewSaltedCipher(key, []byte{'a'})
if err != KeySizeError(i) {
t.Errorf("NewSaltedCipher with short key, gave error %#v, expected %#v", err, KeySizeError(i))
}
key = append(key, 'a')
}
// A 57-byte key. One over the typical blowfish restriction.
key = []byte("012345678901234567890123456789012345678901234567890123456")
_, err := NewSaltedCipher(key, []byte{'a'})
if err != nil {
t.Errorf("NewSaltedCipher with long key, gave error %#v", err)
}
}

View File

@ -1,100 +0,0 @@
// 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 blowfish implements Bruce Schneier's Blowfish encryption algorithm.
package blowfish
// The code is a port of Bruce Schneier's C implementation.
// See http://www.schneier.com/blowfish.html.
import "strconv"
// The Blowfish block size in bytes.
const BlockSize = 8
// A Cipher is an instance of Blowfish encryption using a particular key.
type Cipher struct {
p [18]uint32
s0, s1, s2, s3 [256]uint32
}
type KeySizeError int
func (k KeySizeError) Error() string {
return "crypto/blowfish: invalid key size " + strconv.Itoa(int(k))
}
// NewCipher creates and returns a Cipher.
// The key argument should be the Blowfish key, 4 to 56 bytes.
func NewCipher(key []byte) (*Cipher, error) {
var result Cipher
k := len(key)
if k < 4 || k > 56 {
return nil, KeySizeError(k)
}
initCipher(key, &result)
ExpandKey(key, &result)
return &result, nil
}
// NewSaltedCipher creates a returns a Cipher that folds a salt into its key
// schedule. For most purposes, NewCipher, instead of NewSaltedCipher, is
// sufficient and desirable. For bcrypt compatiblity, the key can be over 56
// bytes.
func NewSaltedCipher(key, salt []byte) (*Cipher, error) {
var result Cipher
k := len(key)
if k < 4 {
return nil, KeySizeError(k)
}
initCipher(key, &result)
expandKeyWithSalt(key, salt, &result)
return &result, nil
}
// BlockSize returns the Blowfish block size, 8 bytes.
// It is necessary to satisfy the Block interface in the
// package "crypto/cipher".
func (c *Cipher) BlockSize() int { return BlockSize }
// Encrypt encrypts the 8-byte buffer src using the key k
// 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) {
l := uint32(src[0])<<24 | uint32(src[1])<<16 | uint32(src[2])<<8 | uint32(src[3])
r := uint32(src[4])<<24 | uint32(src[5])<<16 | uint32(src[6])<<8 | uint32(src[7])
l, r = encryptBlock(l, r, c)
dst[0], dst[1], dst[2], dst[3] = byte(l>>24), byte(l>>16), byte(l>>8), byte(l)
dst[4], dst[5], dst[6], dst[7] = byte(r>>24), byte(r>>16), byte(r>>8), byte(r)
}
// Decrypt decrypts the 8-byte buffer src using the key k
// and stores the result in dst.
func (c *Cipher) Decrypt(dst, src []byte) {
l := uint32(src[0])<<24 | uint32(src[1])<<16 | uint32(src[2])<<8 | uint32(src[3])
r := uint32(src[4])<<24 | uint32(src[5])<<16 | uint32(src[6])<<8 | uint32(src[7])
l, r = decryptBlock(l, r, c)
dst[0], dst[1], dst[2], dst[3] = byte(l>>24), byte(l>>16), byte(l>>8), byte(l)
dst[4], dst[5], dst[6], dst[7] = byte(r>>24), byte(r>>16), byte(r>>8), byte(r)
}
// Reset zeros the key data, so that it will no longer
// appear in the process's memory.
func (c *Cipher) Reset() {
zero(c.p[0:])
zero(c.s0[0:])
zero(c.s1[0:])
zero(c.s2[0:])
zero(c.s3[0:])
}
func initCipher(key []byte, c *Cipher) {
copy(c.p[0:], p[0:])
copy(c.s0[0:], s0[0:])
copy(c.s1[0:], s1[0:])
copy(c.s2[0:], s2[0:])
copy(c.s3[0:], s3[0:])
}

View File

@ -1,199 +0,0 @@
// Copyright 2010 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// The startup permutation array and substitution boxes.
// They are the hexadecimal digits of PI; see:
// http://www.schneier.com/code/constants.txt.
package blowfish
var s0 = [256]uint32{
0xd1310ba6, 0x98dfb5ac, 0x2ffd72db, 0xd01adfb7, 0xb8e1afed, 0x6a267e96,
0xba7c9045, 0xf12c7f99, 0x24a19947, 0xb3916cf7, 0x0801f2e2, 0x858efc16,
0x636920d8, 0x71574e69, 0xa458fea3, 0xf4933d7e, 0x0d95748f, 0x728eb658,
0x718bcd58, 0x82154aee, 0x7b54a41d, 0xc25a59b5, 0x9c30d539, 0x2af26013,
0xc5d1b023, 0x286085f0, 0xca417918, 0xb8db38ef, 0x8e79dcb0, 0x603a180e,
0x6c9e0e8b, 0xb01e8a3e, 0xd71577c1, 0xbd314b27, 0x78af2fda, 0x55605c60,
0xe65525f3, 0xaa55ab94, 0x57489862, 0x63e81440, 0x55ca396a, 0x2aab10b6,
0xb4cc5c34, 0x1141e8ce, 0xa15486af, 0x7c72e993, 0xb3ee1411, 0x636fbc2a,
0x2ba9c55d, 0x741831f6, 0xce5c3e16, 0x9b87931e, 0xafd6ba33, 0x6c24cf5c,
0x7a325381, 0x28958677, 0x3b8f4898, 0x6b4bb9af, 0xc4bfe81b, 0x66282193,
0x61d809cc, 0xfb21a991, 0x487cac60, 0x5dec8032, 0xef845d5d, 0xe98575b1,
0xdc262302, 0xeb651b88, 0x23893e81, 0xd396acc5, 0x0f6d6ff3, 0x83f44239,
0x2e0b4482, 0xa4842004, 0x69c8f04a, 0x9e1f9b5e, 0x21c66842, 0xf6e96c9a,
0x670c9c61, 0xabd388f0, 0x6a51a0d2, 0xd8542f68, 0x960fa728, 0xab5133a3,
0x6eef0b6c, 0x137a3be4, 0xba3bf050, 0x7efb2a98, 0xa1f1651d, 0x39af0176,
0x66ca593e, 0x82430e88, 0x8cee8619, 0x456f9fb4, 0x7d84a5c3, 0x3b8b5ebe,
0xe06f75d8, 0x85c12073, 0x401a449f, 0x56c16aa6, 0x4ed3aa62, 0x363f7706,
0x1bfedf72, 0x429b023d, 0x37d0d724, 0xd00a1248, 0xdb0fead3, 0x49f1c09b,
0x075372c9, 0x80991b7b, 0x25d479d8, 0xf6e8def7, 0xe3fe501a, 0xb6794c3b,
0x976ce0bd, 0x04c006ba, 0xc1a94fb6, 0x409f60c4, 0x5e5c9ec2, 0x196a2463,
0x68fb6faf, 0x3e6c53b5, 0x1339b2eb, 0x3b52ec6f, 0x6dfc511f, 0x9b30952c,
0xcc814544, 0xaf5ebd09, 0xbee3d004, 0xde334afd, 0x660f2807, 0x192e4bb3,
0xc0cba857, 0x45c8740f, 0xd20b5f39, 0xb9d3fbdb, 0x5579c0bd, 0x1a60320a,
0xd6a100c6, 0x402c7279, 0x679f25fe, 0xfb1fa3cc, 0x8ea5e9f8, 0xdb3222f8,
0x3c7516df, 0xfd616b15, 0x2f501ec8, 0xad0552ab, 0x323db5fa, 0xfd238760,
0x53317b48, 0x3e00df82, 0x9e5c57bb, 0xca6f8ca0, 0x1a87562e, 0xdf1769db,
0xd542a8f6, 0x287effc3, 0xac6732c6, 0x8c4f5573, 0x695b27b0, 0xbbca58c8,
0xe1ffa35d, 0xb8f011a0, 0x10fa3d98, 0xfd2183b8, 0x4afcb56c, 0x2dd1d35b,
0x9a53e479, 0xb6f84565, 0xd28e49bc, 0x4bfb9790, 0xe1ddf2da, 0xa4cb7e33,
0x62fb1341, 0xcee4c6e8, 0xef20cada, 0x36774c01, 0xd07e9efe, 0x2bf11fb4,
0x95dbda4d, 0xae909198, 0xeaad8e71, 0x6b93d5a0, 0xd08ed1d0, 0xafc725e0,
0x8e3c5b2f, 0x8e7594b7, 0x8ff6e2fb, 0xf2122b64, 0x8888b812, 0x900df01c,
0x4fad5ea0, 0x688fc31c, 0xd1cff191, 0xb3a8c1ad, 0x2f2f2218, 0xbe0e1777,
0xea752dfe, 0x8b021fa1, 0xe5a0cc0f, 0xb56f74e8, 0x18acf3d6, 0xce89e299,
0xb4a84fe0, 0xfd13e0b7, 0x7cc43b81, 0xd2ada8d9, 0x165fa266, 0x80957705,
0x93cc7314, 0x211a1477, 0xe6ad2065, 0x77b5fa86, 0xc75442f5, 0xfb9d35cf,
0xebcdaf0c, 0x7b3e89a0, 0xd6411bd3, 0xae1e7e49, 0x00250e2d, 0x2071b35e,
0x226800bb, 0x57b8e0af, 0x2464369b, 0xf009b91e, 0x5563911d, 0x59dfa6aa,
0x78c14389, 0xd95a537f, 0x207d5ba2, 0x02e5b9c5, 0x83260376, 0x6295cfa9,
0x11c81968, 0x4e734a41, 0xb3472dca, 0x7b14a94a, 0x1b510052, 0x9a532915,
0xd60f573f, 0xbc9bc6e4, 0x2b60a476, 0x81e67400, 0x08ba6fb5, 0x571be91f,
0xf296ec6b, 0x2a0dd915, 0xb6636521, 0xe7b9f9b6, 0xff34052e, 0xc5855664,
0x53b02d5d, 0xa99f8fa1, 0x08ba4799, 0x6e85076a,
}
var s1 = [256]uint32{
0x4b7a70e9, 0xb5b32944, 0xdb75092e, 0xc4192623, 0xad6ea6b0, 0x49a7df7d,
0x9cee60b8, 0x8fedb266, 0xecaa8c71, 0x699a17ff, 0x5664526c, 0xc2b19ee1,
0x193602a5, 0x75094c29, 0xa0591340, 0xe4183a3e, 0x3f54989a, 0x5b429d65,
0x6b8fe4d6, 0x99f73fd6, 0xa1d29c07, 0xefe830f5, 0x4d2d38e6, 0xf0255dc1,
0x4cdd2086, 0x8470eb26, 0x6382e9c6, 0x021ecc5e, 0x09686b3f, 0x3ebaefc9,
0x3c971814, 0x6b6a70a1, 0x687f3584, 0x52a0e286, 0xb79c5305, 0xaa500737,
0x3e07841c, 0x7fdeae5c, 0x8e7d44ec, 0x5716f2b8, 0xb03ada37, 0xf0500c0d,
0xf01c1f04, 0x0200b3ff, 0xae0cf51a, 0x3cb574b2, 0x25837a58, 0xdc0921bd,
0xd19113f9, 0x7ca92ff6, 0x94324773, 0x22f54701, 0x3ae5e581, 0x37c2dadc,
0xc8b57634, 0x9af3dda7, 0xa9446146, 0x0fd0030e, 0xecc8c73e, 0xa4751e41,
0xe238cd99, 0x3bea0e2f, 0x3280bba1, 0x183eb331, 0x4e548b38, 0x4f6db908,
0x6f420d03, 0xf60a04bf, 0x2cb81290, 0x24977c79, 0x5679b072, 0xbcaf89af,
0xde9a771f, 0xd9930810, 0xb38bae12, 0xdccf3f2e, 0x5512721f, 0x2e6b7124,
0x501adde6, 0x9f84cd87, 0x7a584718, 0x7408da17, 0xbc9f9abc, 0xe94b7d8c,
0xec7aec3a, 0xdb851dfa, 0x63094366, 0xc464c3d2, 0xef1c1847, 0x3215d908,
0xdd433b37, 0x24c2ba16, 0x12a14d43, 0x2a65c451, 0x50940002, 0x133ae4dd,
0x71dff89e, 0x10314e55, 0x81ac77d6, 0x5f11199b, 0x043556f1, 0xd7a3c76b,
0x3c11183b, 0x5924a509, 0xf28fe6ed, 0x97f1fbfa, 0x9ebabf2c, 0x1e153c6e,
0x86e34570, 0xeae96fb1, 0x860e5e0a, 0x5a3e2ab3, 0x771fe71c, 0x4e3d06fa,
0x2965dcb9, 0x99e71d0f, 0x803e89d6, 0x5266c825, 0x2e4cc978, 0x9c10b36a,
0xc6150eba, 0x94e2ea78, 0xa5fc3c53, 0x1e0a2df4, 0xf2f74ea7, 0x361d2b3d,
0x1939260f, 0x19c27960, 0x5223a708, 0xf71312b6, 0xebadfe6e, 0xeac31f66,
0xe3bc4595, 0xa67bc883, 0xb17f37d1, 0x018cff28, 0xc332ddef, 0xbe6c5aa5,
0x65582185, 0x68ab9802, 0xeecea50f, 0xdb2f953b, 0x2aef7dad, 0x5b6e2f84,
0x1521b628, 0x29076170, 0xecdd4775, 0x619f1510, 0x13cca830, 0xeb61bd96,
0x0334fe1e, 0xaa0363cf, 0xb5735c90, 0x4c70a239, 0xd59e9e0b, 0xcbaade14,
0xeecc86bc, 0x60622ca7, 0x9cab5cab, 0xb2f3846e, 0x648b1eaf, 0x19bdf0ca,
0xa02369b9, 0x655abb50, 0x40685a32, 0x3c2ab4b3, 0x319ee9d5, 0xc021b8f7,
0x9b540b19, 0x875fa099, 0x95f7997e, 0x623d7da8, 0xf837889a, 0x97e32d77,
0x11ed935f, 0x16681281, 0x0e358829, 0xc7e61fd6, 0x96dedfa1, 0x7858ba99,
0x57f584a5, 0x1b227263, 0x9b83c3ff, 0x1ac24696, 0xcdb30aeb, 0x532e3054,
0x8fd948e4, 0x6dbc3128, 0x58ebf2ef, 0x34c6ffea, 0xfe28ed61, 0xee7c3c73,
0x5d4a14d9, 0xe864b7e3, 0x42105d14, 0x203e13e0, 0x45eee2b6, 0xa3aaabea,
0xdb6c4f15, 0xfacb4fd0, 0xc742f442, 0xef6abbb5, 0x654f3b1d, 0x41cd2105,
0xd81e799e, 0x86854dc7, 0xe44b476a, 0x3d816250, 0xcf62a1f2, 0x5b8d2646,
0xfc8883a0, 0xc1c7b6a3, 0x7f1524c3, 0x69cb7492, 0x47848a0b, 0x5692b285,
0x095bbf00, 0xad19489d, 0x1462b174, 0x23820e00, 0x58428d2a, 0x0c55f5ea,
0x1dadf43e, 0x233f7061, 0x3372f092, 0x8d937e41, 0xd65fecf1, 0x6c223bdb,
0x7cde3759, 0xcbee7460, 0x4085f2a7, 0xce77326e, 0xa6078084, 0x19f8509e,
0xe8efd855, 0x61d99735, 0xa969a7aa, 0xc50c06c2, 0x5a04abfc, 0x800bcadc,
0x9e447a2e, 0xc3453484, 0xfdd56705, 0x0e1e9ec9, 0xdb73dbd3, 0x105588cd,
0x675fda79, 0xe3674340, 0xc5c43465, 0x713e38d8, 0x3d28f89e, 0xf16dff20,
0x153e21e7, 0x8fb03d4a, 0xe6e39f2b, 0xdb83adf7,
}
var s2 = [256]uint32{
0xe93d5a68, 0x948140f7, 0xf64c261c, 0x94692934, 0x411520f7, 0x7602d4f7,
0xbcf46b2e, 0xd4a20068, 0xd4082471, 0x3320f46a, 0x43b7d4b7, 0x500061af,
0x1e39f62e, 0x97244546, 0x14214f74, 0xbf8b8840, 0x4d95fc1d, 0x96b591af,
0x70f4ddd3, 0x66a02f45, 0xbfbc09ec, 0x03bd9785, 0x7fac6dd0, 0x31cb8504,
0x96eb27b3, 0x55fd3941, 0xda2547e6, 0xabca0a9a, 0x28507825, 0x530429f4,
0x0a2c86da, 0xe9b66dfb, 0x68dc1462, 0xd7486900, 0x680ec0a4, 0x27a18dee,
0x4f3ffea2, 0xe887ad8c, 0xb58ce006, 0x7af4d6b6, 0xaace1e7c, 0xd3375fec,
0xce78a399, 0x406b2a42, 0x20fe9e35, 0xd9f385b9, 0xee39d7ab, 0x3b124e8b,
0x1dc9faf7, 0x4b6d1856, 0x26a36631, 0xeae397b2, 0x3a6efa74, 0xdd5b4332,
0x6841e7f7, 0xca7820fb, 0xfb0af54e, 0xd8feb397, 0x454056ac, 0xba489527,
0x55533a3a, 0x20838d87, 0xfe6ba9b7, 0xd096954b, 0x55a867bc, 0xa1159a58,
0xcca92963, 0x99e1db33, 0xa62a4a56, 0x3f3125f9, 0x5ef47e1c, 0x9029317c,
0xfdf8e802, 0x04272f70, 0x80bb155c, 0x05282ce3, 0x95c11548, 0xe4c66d22,
0x48c1133f, 0xc70f86dc, 0x07f9c9ee, 0x41041f0f, 0x404779a4, 0x5d886e17,
0x325f51eb, 0xd59bc0d1, 0xf2bcc18f, 0x41113564, 0x257b7834, 0x602a9c60,
0xdff8e8a3, 0x1f636c1b, 0x0e12b4c2, 0x02e1329e, 0xaf664fd1, 0xcad18115,
0x6b2395e0, 0x333e92e1, 0x3b240b62, 0xeebeb922, 0x85b2a20e, 0xe6ba0d99,
0xde720c8c, 0x2da2f728, 0xd0127845, 0x95b794fd, 0x647d0862, 0xe7ccf5f0,
0x5449a36f, 0x877d48fa, 0xc39dfd27, 0xf33e8d1e, 0x0a476341, 0x992eff74,
0x3a6f6eab, 0xf4f8fd37, 0xa812dc60, 0xa1ebddf8, 0x991be14c, 0xdb6e6b0d,
0xc67b5510, 0x6d672c37, 0x2765d43b, 0xdcd0e804, 0xf1290dc7, 0xcc00ffa3,
0xb5390f92, 0x690fed0b, 0x667b9ffb, 0xcedb7d9c, 0xa091cf0b, 0xd9155ea3,
0xbb132f88, 0x515bad24, 0x7b9479bf, 0x763bd6eb, 0x37392eb3, 0xcc115979,
0x8026e297, 0xf42e312d, 0x6842ada7, 0xc66a2b3b, 0x12754ccc, 0x782ef11c,
0x6a124237, 0xb79251e7, 0x06a1bbe6, 0x4bfb6350, 0x1a6b1018, 0x11caedfa,
0x3d25bdd8, 0xe2e1c3c9, 0x44421659, 0x0a121386, 0xd90cec6e, 0xd5abea2a,
0x64af674e, 0xda86a85f, 0xbebfe988, 0x64e4c3fe, 0x9dbc8057, 0xf0f7c086,
0x60787bf8, 0x6003604d, 0xd1fd8346, 0xf6381fb0, 0x7745ae04, 0xd736fccc,
0x83426b33, 0xf01eab71, 0xb0804187, 0x3c005e5f, 0x77a057be, 0xbde8ae24,
0x55464299, 0xbf582e61, 0x4e58f48f, 0xf2ddfda2, 0xf474ef38, 0x8789bdc2,
0x5366f9c3, 0xc8b38e74, 0xb475f255, 0x46fcd9b9, 0x7aeb2661, 0x8b1ddf84,
0x846a0e79, 0x915f95e2, 0x466e598e, 0x20b45770, 0x8cd55591, 0xc902de4c,
0xb90bace1, 0xbb8205d0, 0x11a86248, 0x7574a99e, 0xb77f19b6, 0xe0a9dc09,
0x662d09a1, 0xc4324633, 0xe85a1f02, 0x09f0be8c, 0x4a99a025, 0x1d6efe10,
0x1ab93d1d, 0x0ba5a4df, 0xa186f20f, 0x2868f169, 0xdcb7da83, 0x573906fe,
0xa1e2ce9b, 0x4fcd7f52, 0x50115e01, 0xa70683fa, 0xa002b5c4, 0x0de6d027,
0x9af88c27, 0x773f8641, 0xc3604c06, 0x61a806b5, 0xf0177a28, 0xc0f586e0,
0x006058aa, 0x30dc7d62, 0x11e69ed7, 0x2338ea63, 0x53c2dd94, 0xc2c21634,
0xbbcbee56, 0x90bcb6de, 0xebfc7da1, 0xce591d76, 0x6f05e409, 0x4b7c0188,
0x39720a3d, 0x7c927c24, 0x86e3725f, 0x724d9db9, 0x1ac15bb4, 0xd39eb8fc,
0xed545578, 0x08fca5b5, 0xd83d7cd3, 0x4dad0fc4, 0x1e50ef5e, 0xb161e6f8,
0xa28514d9, 0x6c51133c, 0x6fd5c7e7, 0x56e14ec4, 0x362abfce, 0xddc6c837,
0xd79a3234, 0x92638212, 0x670efa8e, 0x406000e0,
}
var s3 = [256]uint32{
0x3a39ce37, 0xd3faf5cf, 0xabc27737, 0x5ac52d1b, 0x5cb0679e, 0x4fa33742,
0xd3822740, 0x99bc9bbe, 0xd5118e9d, 0xbf0f7315, 0xd62d1c7e, 0xc700c47b,
0xb78c1b6b, 0x21a19045, 0xb26eb1be, 0x6a366eb4, 0x5748ab2f, 0xbc946e79,
0xc6a376d2, 0x6549c2c8, 0x530ff8ee, 0x468dde7d, 0xd5730a1d, 0x4cd04dc6,
0x2939bbdb, 0xa9ba4650, 0xac9526e8, 0xbe5ee304, 0xa1fad5f0, 0x6a2d519a,
0x63ef8ce2, 0x9a86ee22, 0xc089c2b8, 0x43242ef6, 0xa51e03aa, 0x9cf2d0a4,
0x83c061ba, 0x9be96a4d, 0x8fe51550, 0xba645bd6, 0x2826a2f9, 0xa73a3ae1,
0x4ba99586, 0xef5562e9, 0xc72fefd3, 0xf752f7da, 0x3f046f69, 0x77fa0a59,
0x80e4a915, 0x87b08601, 0x9b09e6ad, 0x3b3ee593, 0xe990fd5a, 0x9e34d797,
0x2cf0b7d9, 0x022b8b51, 0x96d5ac3a, 0x017da67d, 0xd1cf3ed6, 0x7c7d2d28,
0x1f9f25cf, 0xadf2b89b, 0x5ad6b472, 0x5a88f54c, 0xe029ac71, 0xe019a5e6,
0x47b0acfd, 0xed93fa9b, 0xe8d3c48d, 0x283b57cc, 0xf8d56629, 0x79132e28,
0x785f0191, 0xed756055, 0xf7960e44, 0xe3d35e8c, 0x15056dd4, 0x88f46dba,
0x03a16125, 0x0564f0bd, 0xc3eb9e15, 0x3c9057a2, 0x97271aec, 0xa93a072a,
0x1b3f6d9b, 0x1e6321f5, 0xf59c66fb, 0x26dcf319, 0x7533d928, 0xb155fdf5,
0x03563482, 0x8aba3cbb, 0x28517711, 0xc20ad9f8, 0xabcc5167, 0xccad925f,
0x4de81751, 0x3830dc8e, 0x379d5862, 0x9320f991, 0xea7a90c2, 0xfb3e7bce,
0x5121ce64, 0x774fbe32, 0xa8b6e37e, 0xc3293d46, 0x48de5369, 0x6413e680,
0xa2ae0810, 0xdd6db224, 0x69852dfd, 0x09072166, 0xb39a460a, 0x6445c0dd,
0x586cdecf, 0x1c20c8ae, 0x5bbef7dd, 0x1b588d40, 0xccd2017f, 0x6bb4e3bb,
0xdda26a7e, 0x3a59ff45, 0x3e350a44, 0xbcb4cdd5, 0x72eacea8, 0xfa6484bb,
0x8d6612ae, 0xbf3c6f47, 0xd29be463, 0x542f5d9e, 0xaec2771b, 0xf64e6370,
0x740e0d8d, 0xe75b1357, 0xf8721671, 0xaf537d5d, 0x4040cb08, 0x4eb4e2cc,
0x34d2466a, 0x0115af84, 0xe1b00428, 0x95983a1d, 0x06b89fb4, 0xce6ea048,
0x6f3f3b82, 0x3520ab82, 0x011a1d4b, 0x277227f8, 0x611560b1, 0xe7933fdc,
0xbb3a792b, 0x344525bd, 0xa08839e1, 0x51ce794b, 0x2f32c9b7, 0xa01fbac9,
0xe01cc87e, 0xbcc7d1f6, 0xcf0111c3, 0xa1e8aac7, 0x1a908749, 0xd44fbd9a,
0xd0dadecb, 0xd50ada38, 0x0339c32a, 0xc6913667, 0x8df9317c, 0xe0b12b4f,
0xf79e59b7, 0x43f5bb3a, 0xf2d519ff, 0x27d9459c, 0xbf97222c, 0x15e6fc2a,
0x0f91fc71, 0x9b941525, 0xfae59361, 0xceb69ceb, 0xc2a86459, 0x12baa8d1,
0xb6c1075e, 0xe3056a0c, 0x10d25065, 0xcb03a442, 0xe0ec6e0e, 0x1698db3b,
0x4c98a0be, 0x3278e964, 0x9f1f9532, 0xe0d392df, 0xd3a0342b, 0x8971f21e,
0x1b0a7441, 0x4ba3348c, 0xc5be7120, 0xc37632d8, 0xdf359f8d, 0x9b992f2e,
0xe60b6f47, 0x0fe3f11d, 0xe54cda54, 0x1edad891, 0xce6279cf, 0xcd3e7e6f,
0x1618b166, 0xfd2c1d05, 0x848fd2c5, 0xf6fb2299, 0xf523f357, 0xa6327623,
0x93a83531, 0x56cccd02, 0xacf08162, 0x5a75ebb5, 0x6e163697, 0x88d273cc,
0xde966292, 0x81b949d0, 0x4c50901b, 0x71c65614, 0xe6c6c7bd, 0x327a140a,
0x45e1d006, 0xc3f27b9a, 0xc9aa53fd, 0x62a80f00, 0xbb25bfe2, 0x35bdd2f6,
0x71126905, 0xb2040222, 0xb6cbcf7c, 0xcd769c2b, 0x53113ec0, 0x1640e3d3,
0x38abbd60, 0x2547adf0, 0xba38209c, 0xf746ce76, 0x77afa1c5, 0x20756060,
0x85cbfe4e, 0x8ae88dd8, 0x7aaaf9b0, 0x4cf9aa7e, 0x1948c25c, 0x02fb8a8c,
0x01c36ae4, 0xd6ebe1f9, 0x90d4f869, 0xa65cdea0, 0x3f09252d, 0xc208e69f,
0xb74e6132, 0xce77e25b, 0x578fdfe3, 0x3ac372e6,
}
var p = [18]uint32{
0x243f6a88, 0x85a308d3, 0x13198a2e, 0x03707344, 0xa4093822, 0x299f31d0,
0x082efa98, 0xec4e6c89, 0x452821e6, 0x38d01377, 0xbe5466cf, 0x34e90c6c,
0xc0ac29b7, 0xc97c50dd, 0x3f84d5b5, 0xb5470917, 0x9216d5d9, 0x8979fb1b,
}

View File

@ -1,534 +0,0 @@
// 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 cast5 implements CAST5, as defined in RFC 2144. CAST5 is a common
// OpenPGP cipher.
package cast5
import "errors"
const BlockSize = 8
const KeySize = 16
type Cipher struct {
masking [16]uint32
rotate [16]uint8
}
func NewCipher(key []byte) (c *Cipher, err error) {
if len(key) != KeySize {
return nil, errors.New("CAST5: keys must be 16 bytes")
}
c = new(Cipher)
c.keySchedule(key)
return
}
func (c *Cipher) BlockSize() int {
return BlockSize
}
// Reset zeros the key material in memory.
func (c *Cipher) Reset() {
for i := 0; i < 16; i++ {
c.masking[i] = 0
c.rotate[i] = 0
}
}
func (c *Cipher) Encrypt(dst, src []byte) {
l := uint32(src[0])<<24 | uint32(src[1])<<16 | uint32(src[2])<<8 | uint32(src[3])
r := uint32(src[4])<<24 | uint32(src[5])<<16 | uint32(src[6])<<8 | uint32(src[7])
l, r = r, l^f1(r, c.masking[0], c.rotate[0])
l, r = r, l^f2(r, c.masking[1], c.rotate[1])
l, r = r, l^f3(r, c.masking[2], c.rotate[2])
l, r = r, l^f1(r, c.masking[3], c.rotate[3])
l, r = r, l^f2(r, c.masking[4], c.rotate[4])
l, r = r, l^f3(r, c.masking[5], c.rotate[5])
l, r = r, l^f1(r, c.masking[6], c.rotate[6])
l, r = r, l^f2(r, c.masking[7], c.rotate[7])
l, r = r, l^f3(r, c.masking[8], c.rotate[8])
l, r = r, l^f1(r, c.masking[9], c.rotate[9])
l, r = r, l^f2(r, c.masking[10], c.rotate[10])
l, r = r, l^f3(r, c.masking[11], c.rotate[11])
l, r = r, l^f1(r, c.masking[12], c.rotate[12])
l, r = r, l^f2(r, c.masking[13], c.rotate[13])
l, r = r, l^f3(r, c.masking[14], c.rotate[14])
l, r = r, l^f1(r, c.masking[15], c.rotate[15])
dst[0] = uint8(r >> 24)
dst[1] = uint8(r >> 16)
dst[2] = uint8(r >> 8)
dst[3] = uint8(r)
dst[4] = uint8(l >> 24)
dst[5] = uint8(l >> 16)
dst[6] = uint8(l >> 8)
dst[7] = uint8(l)
}
func (c *Cipher) Decrypt(dst, src []byte) {
l := uint32(src[0])<<24 | uint32(src[1])<<16 | uint32(src[2])<<8 | uint32(src[3])
r := uint32(src[4])<<24 | uint32(src[5])<<16 | uint32(src[6])<<8 | uint32(src[7])
l, r = r, l^f1(r, c.masking[15], c.rotate[15])
l, r = r, l^f3(r, c.masking[14], c.rotate[14])
l, r = r, l^f2(r, c.masking[13], c.rotate[13])
l, r = r, l^f1(r, c.masking[12], c.rotate[12])
l, r = r, l^f3(r, c.masking[11], c.rotate[11])
l, r = r, l^f2(r, c.masking[10], c.rotate[10])
l, r = r, l^f1(r, c.masking[9], c.rotate[9])
l, r = r, l^f3(r, c.masking[8], c.rotate[8])
l, r = r, l^f2(r, c.masking[7], c.rotate[7])
l, r = r, l^f1(r, c.masking[6], c.rotate[6])
l, r = r, l^f3(r, c.masking[5], c.rotate[5])
l, r = r, l^f2(r, c.masking[4], c.rotate[4])
l, r = r, l^f1(r, c.masking[3], c.rotate[3])
l, r = r, l^f3(r, c.masking[2], c.rotate[2])
l, r = r, l^f2(r, c.masking[1], c.rotate[1])
l, r = r, l^f1(r, c.masking[0], c.rotate[0])
dst[0] = uint8(r >> 24)
dst[1] = uint8(r >> 16)
dst[2] = uint8(r >> 8)
dst[3] = uint8(r)
dst[4] = uint8(l >> 24)
dst[5] = uint8(l >> 16)
dst[6] = uint8(l >> 8)
dst[7] = uint8(l)
}
type keyScheduleA [4][7]uint8
type keyScheduleB [4][5]uint8
// keyScheduleRound contains the magic values for a round of the key schedule.
// The keyScheduleA deals with the lines like:
// z0z1z2z3 = x0x1x2x3 ^ S5[xD] ^ S6[xF] ^ S7[xC] ^ S8[xE] ^ S7[x8]
// Conceptually, both x and z are in the same array, x first. The first
// element describes which word of this array gets written to and the
// second, which word gets read. So, for the line above, it's "4, 0", because
// it's writing to the first word of z, which, being after x, is word 4, and
// reading from the first word of x: word 0.
//
// Next are the indexes into the S-boxes. Now the array is treated as bytes. So
// "xD" is 0xd. The first byte of z is written as "16 + 0", just to be clear
// that it's z that we're indexing.
//
// keyScheduleB deals with lines like:
// K1 = S5[z8] ^ S6[z9] ^ S7[z7] ^ S8[z6] ^ S5[z2]
// "K1" is ignored because key words are always written in order. So the five
// elements are the S-box indexes. They use the same form as in keyScheduleA,
// above.
type keyScheduleRound struct{}
type keySchedule []keyScheduleRound
var schedule = []struct {
a keyScheduleA
b keyScheduleB
}{
{
keyScheduleA{
{4, 0, 0xd, 0xf, 0xc, 0xe, 0x8},
{5, 2, 16 + 0, 16 + 2, 16 + 1, 16 + 3, 0xa},
{6, 3, 16 + 7, 16 + 6, 16 + 5, 16 + 4, 9},
{7, 1, 16 + 0xa, 16 + 9, 16 + 0xb, 16 + 8, 0xb},
},
keyScheduleB{
{16 + 8, 16 + 9, 16 + 7, 16 + 6, 16 + 2},
{16 + 0xa, 16 + 0xb, 16 + 5, 16 + 4, 16 + 6},
{16 + 0xc, 16 + 0xd, 16 + 3, 16 + 2, 16 + 9},
{16 + 0xe, 16 + 0xf, 16 + 1, 16 + 0, 16 + 0xc},
},
},
{
keyScheduleA{
{0, 6, 16 + 5, 16 + 7, 16 + 4, 16 + 6, 16 + 0},
{1, 4, 0, 2, 1, 3, 16 + 2},
{2, 5, 7, 6, 5, 4, 16 + 1},
{3, 7, 0xa, 9, 0xb, 8, 16 + 3},
},
keyScheduleB{
{3, 2, 0xc, 0xd, 8},
{1, 0, 0xe, 0xf, 0xd},
{7, 6, 8, 9, 3},
{5, 4, 0xa, 0xb, 7},
},
},
{
keyScheduleA{
{4, 0, 0xd, 0xf, 0xc, 0xe, 8},
{5, 2, 16 + 0, 16 + 2, 16 + 1, 16 + 3, 0xa},
{6, 3, 16 + 7, 16 + 6, 16 + 5, 16 + 4, 9},
{7, 1, 16 + 0xa, 16 + 9, 16 + 0xb, 16 + 8, 0xb},
},
keyScheduleB{
{16 + 3, 16 + 2, 16 + 0xc, 16 + 0xd, 16 + 9},
{16 + 1, 16 + 0, 16 + 0xe, 16 + 0xf, 16 + 0xc},
{16 + 7, 16 + 6, 16 + 8, 16 + 9, 16 + 2},
{16 + 5, 16 + 4, 16 + 0xa, 16 + 0xb, 16 + 6},
},
},
{
keyScheduleA{
{0, 6, 16 + 5, 16 + 7, 16 + 4, 16 + 6, 16 + 0},
{1, 4, 0, 2, 1, 3, 16 + 2},
{2, 5, 7, 6, 5, 4, 16 + 1},
{3, 7, 0xa, 9, 0xb, 8, 16 + 3},
},
keyScheduleB{
{8, 9, 7, 6, 3},
{0xa, 0xb, 5, 4, 7},
{0xc, 0xd, 3, 2, 8},
{0xe, 0xf, 1, 0, 0xd},
},
},
}
func (c *Cipher) keySchedule(in []byte) {
var t [8]uint32
var k [32]uint32
for i := 0; i < 4; i++ {
j := i * 4
t[i] = uint32(in[j])<<24 | uint32(in[j+1])<<16 | uint32(in[j+2])<<8 | uint32(in[j+3])
}
x := []byte{6, 7, 4, 5}
ki := 0
for half := 0; half < 2; half++ {
for _, round := range schedule {
for j := 0; j < 4; j++ {
var a [7]uint8
copy(a[:], round.a[j][:])
w := t[a[1]]
w ^= sBox[4][(t[a[2]>>2]>>(24-8*(a[2]&3)))&0xff]
w ^= sBox[5][(t[a[3]>>2]>>(24-8*(a[3]&3)))&0xff]
w ^= sBox[6][(t[a[4]>>2]>>(24-8*(a[4]&3)))&0xff]
w ^= sBox[7][(t[a[5]>>2]>>(24-8*(a[5]&3)))&0xff]
w ^= sBox[x[j]][(t[a[6]>>2]>>(24-8*(a[6]&3)))&0xff]
t[a[0]] = w
}
for j := 0; j < 4; j++ {
var b [5]uint8
copy(b[:], round.b[j][:])
w := sBox[4][(t[b[0]>>2]>>(24-8*(b[0]&3)))&0xff]
w ^= sBox[5][(t[b[1]>>2]>>(24-8*(b[1]&3)))&0xff]
w ^= sBox[6][(t[b[2]>>2]>>(24-8*(b[2]&3)))&0xff]
w ^= sBox[7][(t[b[3]>>2]>>(24-8*(b[3]&3)))&0xff]
w ^= sBox[4+j][(t[b[4]>>2]>>(24-8*(b[4]&3)))&0xff]
k[ki] = w
ki++
}
}
}
for i := 0; i < 16; i++ {
c.masking[i] = k[i]
c.rotate[i] = uint8(k[16+i] & 0x1f)
}
}
// These are the three 'f' functions. See RFC 2144, section 2.2.
func f1(d, m uint32, r uint8) uint32 {
t := m + d
I := (t << r) | (t >> (32 - r))
return ((sBox[0][I>>24] ^ sBox[1][(I>>16)&0xff]) - sBox[2][(I>>8)&0xff]) + sBox[3][I&0xff]
}
func f2(d, m uint32, r uint8) uint32 {
t := m ^ d
I := (t << r) | (t >> (32 - r))
return ((sBox[0][I>>24] - sBox[1][(I>>16)&0xff]) + sBox[2][(I>>8)&0xff]) ^ sBox[3][I&0xff]
}
func f3(d, m uint32, r uint8) uint32 {
t := m - d
I := (t << r) | (t >> (32 - r))
return ((sBox[0][I>>24] + sBox[1][(I>>16)&0xff]) ^ sBox[2][(I>>8)&0xff]) - sBox[3][I&0xff]
}
var sBox = [8][256]uint32{
{
0x30fb40d4, 0x9fa0ff0b, 0x6beccd2f, 0x3f258c7a, 0x1e213f2f, 0x9c004dd3, 0x6003e540, 0xcf9fc949,
0xbfd4af27, 0x88bbbdb5, 0xe2034090, 0x98d09675, 0x6e63a0e0, 0x15c361d2, 0xc2e7661d, 0x22d4ff8e,
0x28683b6f, 0xc07fd059, 0xff2379c8, 0x775f50e2, 0x43c340d3, 0xdf2f8656, 0x887ca41a, 0xa2d2bd2d,
0xa1c9e0d6, 0x346c4819, 0x61b76d87, 0x22540f2f, 0x2abe32e1, 0xaa54166b, 0x22568e3a, 0xa2d341d0,
0x66db40c8, 0xa784392f, 0x004dff2f, 0x2db9d2de, 0x97943fac, 0x4a97c1d8, 0x527644b7, 0xb5f437a7,
0xb82cbaef, 0xd751d159, 0x6ff7f0ed, 0x5a097a1f, 0x827b68d0, 0x90ecf52e, 0x22b0c054, 0xbc8e5935,
0x4b6d2f7f, 0x50bb64a2, 0xd2664910, 0xbee5812d, 0xb7332290, 0xe93b159f, 0xb48ee411, 0x4bff345d,
0xfd45c240, 0xad31973f, 0xc4f6d02e, 0x55fc8165, 0xd5b1caad, 0xa1ac2dae, 0xa2d4b76d, 0xc19b0c50,
0x882240f2, 0x0c6e4f38, 0xa4e4bfd7, 0x4f5ba272, 0x564c1d2f, 0xc59c5319, 0xb949e354, 0xb04669fe,
0xb1b6ab8a, 0xc71358dd, 0x6385c545, 0x110f935d, 0x57538ad5, 0x6a390493, 0xe63d37e0, 0x2a54f6b3,
0x3a787d5f, 0x6276a0b5, 0x19a6fcdf, 0x7a42206a, 0x29f9d4d5, 0xf61b1891, 0xbb72275e, 0xaa508167,
0x38901091, 0xc6b505eb, 0x84c7cb8c, 0x2ad75a0f, 0x874a1427, 0xa2d1936b, 0x2ad286af, 0xaa56d291,
0xd7894360, 0x425c750d, 0x93b39e26, 0x187184c9, 0x6c00b32d, 0x73e2bb14, 0xa0bebc3c, 0x54623779,
0x64459eab, 0x3f328b82, 0x7718cf82, 0x59a2cea6, 0x04ee002e, 0x89fe78e6, 0x3fab0950, 0x325ff6c2,
0x81383f05, 0x6963c5c8, 0x76cb5ad6, 0xd49974c9, 0xca180dcf, 0x380782d5, 0xc7fa5cf6, 0x8ac31511,
0x35e79e13, 0x47da91d0, 0xf40f9086, 0xa7e2419e, 0x31366241, 0x051ef495, 0xaa573b04, 0x4a805d8d,
0x548300d0, 0x00322a3c, 0xbf64cddf, 0xba57a68e, 0x75c6372b, 0x50afd341, 0xa7c13275, 0x915a0bf5,
0x6b54bfab, 0x2b0b1426, 0xab4cc9d7, 0x449ccd82, 0xf7fbf265, 0xab85c5f3, 0x1b55db94, 0xaad4e324,
0xcfa4bd3f, 0x2deaa3e2, 0x9e204d02, 0xc8bd25ac, 0xeadf55b3, 0xd5bd9e98, 0xe31231b2, 0x2ad5ad6c,
0x954329de, 0xadbe4528, 0xd8710f69, 0xaa51c90f, 0xaa786bf6, 0x22513f1e, 0xaa51a79b, 0x2ad344cc,
0x7b5a41f0, 0xd37cfbad, 0x1b069505, 0x41ece491, 0xb4c332e6, 0x032268d4, 0xc9600acc, 0xce387e6d,
0xbf6bb16c, 0x6a70fb78, 0x0d03d9c9, 0xd4df39de, 0xe01063da, 0x4736f464, 0x5ad328d8, 0xb347cc96,
0x75bb0fc3, 0x98511bfb, 0x4ffbcc35, 0xb58bcf6a, 0xe11f0abc, 0xbfc5fe4a, 0xa70aec10, 0xac39570a,
0x3f04442f, 0x6188b153, 0xe0397a2e, 0x5727cb79, 0x9ceb418f, 0x1cacd68d, 0x2ad37c96, 0x0175cb9d,
0xc69dff09, 0xc75b65f0, 0xd9db40d8, 0xec0e7779, 0x4744ead4, 0xb11c3274, 0xdd24cb9e, 0x7e1c54bd,
0xf01144f9, 0xd2240eb1, 0x9675b3fd, 0xa3ac3755, 0xd47c27af, 0x51c85f4d, 0x56907596, 0xa5bb15e6,
0x580304f0, 0xca042cf1, 0x011a37ea, 0x8dbfaadb, 0x35ba3e4a, 0x3526ffa0, 0xc37b4d09, 0xbc306ed9,
0x98a52666, 0x5648f725, 0xff5e569d, 0x0ced63d0, 0x7c63b2cf, 0x700b45e1, 0xd5ea50f1, 0x85a92872,
0xaf1fbda7, 0xd4234870, 0xa7870bf3, 0x2d3b4d79, 0x42e04198, 0x0cd0ede7, 0x26470db8, 0xf881814c,
0x474d6ad7, 0x7c0c5e5c, 0xd1231959, 0x381b7298, 0xf5d2f4db, 0xab838653, 0x6e2f1e23, 0x83719c9e,
0xbd91e046, 0x9a56456e, 0xdc39200c, 0x20c8c571, 0x962bda1c, 0xe1e696ff, 0xb141ab08, 0x7cca89b9,
0x1a69e783, 0x02cc4843, 0xa2f7c579, 0x429ef47d, 0x427b169c, 0x5ac9f049, 0xdd8f0f00, 0x5c8165bf,
},
{
0x1f201094, 0xef0ba75b, 0x69e3cf7e, 0x393f4380, 0xfe61cf7a, 0xeec5207a, 0x55889c94, 0x72fc0651,
0xada7ef79, 0x4e1d7235, 0xd55a63ce, 0xde0436ba, 0x99c430ef, 0x5f0c0794, 0x18dcdb7d, 0xa1d6eff3,
0xa0b52f7b, 0x59e83605, 0xee15b094, 0xe9ffd909, 0xdc440086, 0xef944459, 0xba83ccb3, 0xe0c3cdfb,
0xd1da4181, 0x3b092ab1, 0xf997f1c1, 0xa5e6cf7b, 0x01420ddb, 0xe4e7ef5b, 0x25a1ff41, 0xe180f806,
0x1fc41080, 0x179bee7a, 0xd37ac6a9, 0xfe5830a4, 0x98de8b7f, 0x77e83f4e, 0x79929269, 0x24fa9f7b,
0xe113c85b, 0xacc40083, 0xd7503525, 0xf7ea615f, 0x62143154, 0x0d554b63, 0x5d681121, 0xc866c359,
0x3d63cf73, 0xcee234c0, 0xd4d87e87, 0x5c672b21, 0x071f6181, 0x39f7627f, 0x361e3084, 0xe4eb573b,
0x602f64a4, 0xd63acd9c, 0x1bbc4635, 0x9e81032d, 0x2701f50c, 0x99847ab4, 0xa0e3df79, 0xba6cf38c,
0x10843094, 0x2537a95e, 0xf46f6ffe, 0xa1ff3b1f, 0x208cfb6a, 0x8f458c74, 0xd9e0a227, 0x4ec73a34,
0xfc884f69, 0x3e4de8df, 0xef0e0088, 0x3559648d, 0x8a45388c, 0x1d804366, 0x721d9bfd, 0xa58684bb,
0xe8256333, 0x844e8212, 0x128d8098, 0xfed33fb4, 0xce280ae1, 0x27e19ba5, 0xd5a6c252, 0xe49754bd,
0xc5d655dd, 0xeb667064, 0x77840b4d, 0xa1b6a801, 0x84db26a9, 0xe0b56714, 0x21f043b7, 0xe5d05860,
0x54f03084, 0x066ff472, 0xa31aa153, 0xdadc4755, 0xb5625dbf, 0x68561be6, 0x83ca6b94, 0x2d6ed23b,
0xeccf01db, 0xa6d3d0ba, 0xb6803d5c, 0xaf77a709, 0x33b4a34c, 0x397bc8d6, 0x5ee22b95, 0x5f0e5304,
0x81ed6f61, 0x20e74364, 0xb45e1378, 0xde18639b, 0x881ca122, 0xb96726d1, 0x8049a7e8, 0x22b7da7b,
0x5e552d25, 0x5272d237, 0x79d2951c, 0xc60d894c, 0x488cb402, 0x1ba4fe5b, 0xa4b09f6b, 0x1ca815cf,
0xa20c3005, 0x8871df63, 0xb9de2fcb, 0x0cc6c9e9, 0x0beeff53, 0xe3214517, 0xb4542835, 0x9f63293c,
0xee41e729, 0x6e1d2d7c, 0x50045286, 0x1e6685f3, 0xf33401c6, 0x30a22c95, 0x31a70850, 0x60930f13,
0x73f98417, 0xa1269859, 0xec645c44, 0x52c877a9, 0xcdff33a6, 0xa02b1741, 0x7cbad9a2, 0x2180036f,
0x50d99c08, 0xcb3f4861, 0xc26bd765, 0x64a3f6ab, 0x80342676, 0x25a75e7b, 0xe4e6d1fc, 0x20c710e6,
0xcdf0b680, 0x17844d3b, 0x31eef84d, 0x7e0824e4, 0x2ccb49eb, 0x846a3bae, 0x8ff77888, 0xee5d60f6,
0x7af75673, 0x2fdd5cdb, 0xa11631c1, 0x30f66f43, 0xb3faec54, 0x157fd7fa, 0xef8579cc, 0xd152de58,
0xdb2ffd5e, 0x8f32ce19, 0x306af97a, 0x02f03ef8, 0x99319ad5, 0xc242fa0f, 0xa7e3ebb0, 0xc68e4906,
0xb8da230c, 0x80823028, 0xdcdef3c8, 0xd35fb171, 0x088a1bc8, 0xbec0c560, 0x61a3c9e8, 0xbca8f54d,
0xc72feffa, 0x22822e99, 0x82c570b4, 0xd8d94e89, 0x8b1c34bc, 0x301e16e6, 0x273be979, 0xb0ffeaa6,
0x61d9b8c6, 0x00b24869, 0xb7ffce3f, 0x08dc283b, 0x43daf65a, 0xf7e19798, 0x7619b72f, 0x8f1c9ba4,
0xdc8637a0, 0x16a7d3b1, 0x9fc393b7, 0xa7136eeb, 0xc6bcc63e, 0x1a513742, 0xef6828bc, 0x520365d6,
0x2d6a77ab, 0x3527ed4b, 0x821fd216, 0x095c6e2e, 0xdb92f2fb, 0x5eea29cb, 0x145892f5, 0x91584f7f,
0x5483697b, 0x2667a8cc, 0x85196048, 0x8c4bacea, 0x833860d4, 0x0d23e0f9, 0x6c387e8a, 0x0ae6d249,
0xb284600c, 0xd835731d, 0xdcb1c647, 0xac4c56ea, 0x3ebd81b3, 0x230eabb0, 0x6438bc87, 0xf0b5b1fa,
0x8f5ea2b3, 0xfc184642, 0x0a036b7a, 0x4fb089bd, 0x649da589, 0xa345415e, 0x5c038323, 0x3e5d3bb9,
0x43d79572, 0x7e6dd07c, 0x06dfdf1e, 0x6c6cc4ef, 0x7160a539, 0x73bfbe70, 0x83877605, 0x4523ecf1,
},
{
0x8defc240, 0x25fa5d9f, 0xeb903dbf, 0xe810c907, 0x47607fff, 0x369fe44b, 0x8c1fc644, 0xaececa90,
0xbeb1f9bf, 0xeefbcaea, 0xe8cf1950, 0x51df07ae, 0x920e8806, 0xf0ad0548, 0xe13c8d83, 0x927010d5,
0x11107d9f, 0x07647db9, 0xb2e3e4d4, 0x3d4f285e, 0xb9afa820, 0xfade82e0, 0xa067268b, 0x8272792e,
0x553fb2c0, 0x489ae22b, 0xd4ef9794, 0x125e3fbc, 0x21fffcee, 0x825b1bfd, 0x9255c5ed, 0x1257a240,
0x4e1a8302, 0xbae07fff, 0x528246e7, 0x8e57140e, 0x3373f7bf, 0x8c9f8188, 0xa6fc4ee8, 0xc982b5a5,
0xa8c01db7, 0x579fc264, 0x67094f31, 0xf2bd3f5f, 0x40fff7c1, 0x1fb78dfc, 0x8e6bd2c1, 0x437be59b,
0x99b03dbf, 0xb5dbc64b, 0x638dc0e6, 0x55819d99, 0xa197c81c, 0x4a012d6e, 0xc5884a28, 0xccc36f71,
0xb843c213, 0x6c0743f1, 0x8309893c, 0x0feddd5f, 0x2f7fe850, 0xd7c07f7e, 0x02507fbf, 0x5afb9a04,
0xa747d2d0, 0x1651192e, 0xaf70bf3e, 0x58c31380, 0x5f98302e, 0x727cc3c4, 0x0a0fb402, 0x0f7fef82,
0x8c96fdad, 0x5d2c2aae, 0x8ee99a49, 0x50da88b8, 0x8427f4a0, 0x1eac5790, 0x796fb449, 0x8252dc15,
0xefbd7d9b, 0xa672597d, 0xada840d8, 0x45f54504, 0xfa5d7403, 0xe83ec305, 0x4f91751a, 0x925669c2,
0x23efe941, 0xa903f12e, 0x60270df2, 0x0276e4b6, 0x94fd6574, 0x927985b2, 0x8276dbcb, 0x02778176,
0xf8af918d, 0x4e48f79e, 0x8f616ddf, 0xe29d840e, 0x842f7d83, 0x340ce5c8, 0x96bbb682, 0x93b4b148,
0xef303cab, 0x984faf28, 0x779faf9b, 0x92dc560d, 0x224d1e20, 0x8437aa88, 0x7d29dc96, 0x2756d3dc,
0x8b907cee, 0xb51fd240, 0xe7c07ce3, 0xe566b4a1, 0xc3e9615e, 0x3cf8209d, 0x6094d1e3, 0xcd9ca341,
0x5c76460e, 0x00ea983b, 0xd4d67881, 0xfd47572c, 0xf76cedd9, 0xbda8229c, 0x127dadaa, 0x438a074e,
0x1f97c090, 0x081bdb8a, 0x93a07ebe, 0xb938ca15, 0x97b03cff, 0x3dc2c0f8, 0x8d1ab2ec, 0x64380e51,
0x68cc7bfb, 0xd90f2788, 0x12490181, 0x5de5ffd4, 0xdd7ef86a, 0x76a2e214, 0xb9a40368, 0x925d958f,
0x4b39fffa, 0xba39aee9, 0xa4ffd30b, 0xfaf7933b, 0x6d498623, 0x193cbcfa, 0x27627545, 0x825cf47a,
0x61bd8ba0, 0xd11e42d1, 0xcead04f4, 0x127ea392, 0x10428db7, 0x8272a972, 0x9270c4a8, 0x127de50b,
0x285ba1c8, 0x3c62f44f, 0x35c0eaa5, 0xe805d231, 0x428929fb, 0xb4fcdf82, 0x4fb66a53, 0x0e7dc15b,
0x1f081fab, 0x108618ae, 0xfcfd086d, 0xf9ff2889, 0x694bcc11, 0x236a5cae, 0x12deca4d, 0x2c3f8cc5,
0xd2d02dfe, 0xf8ef5896, 0xe4cf52da, 0x95155b67, 0x494a488c, 0xb9b6a80c, 0x5c8f82bc, 0x89d36b45,
0x3a609437, 0xec00c9a9, 0x44715253, 0x0a874b49, 0xd773bc40, 0x7c34671c, 0x02717ef6, 0x4feb5536,
0xa2d02fff, 0xd2bf60c4, 0xd43f03c0, 0x50b4ef6d, 0x07478cd1, 0x006e1888, 0xa2e53f55, 0xb9e6d4bc,
0xa2048016, 0x97573833, 0xd7207d67, 0xde0f8f3d, 0x72f87b33, 0xabcc4f33, 0x7688c55d, 0x7b00a6b0,
0x947b0001, 0x570075d2, 0xf9bb88f8, 0x8942019e, 0x4264a5ff, 0x856302e0, 0x72dbd92b, 0xee971b69,
0x6ea22fde, 0x5f08ae2b, 0xaf7a616d, 0xe5c98767, 0xcf1febd2, 0x61efc8c2, 0xf1ac2571, 0xcc8239c2,
0x67214cb8, 0xb1e583d1, 0xb7dc3e62, 0x7f10bdce, 0xf90a5c38, 0x0ff0443d, 0x606e6dc6, 0x60543a49,
0x5727c148, 0x2be98a1d, 0x8ab41738, 0x20e1be24, 0xaf96da0f, 0x68458425, 0x99833be5, 0x600d457d,
0x282f9350, 0x8334b362, 0xd91d1120, 0x2b6d8da0, 0x642b1e31, 0x9c305a00, 0x52bce688, 0x1b03588a,
0xf7baefd5, 0x4142ed9c, 0xa4315c11, 0x83323ec5, 0xdfef4636, 0xa133c501, 0xe9d3531c, 0xee353783,
},
{
0x9db30420, 0x1fb6e9de, 0xa7be7bef, 0xd273a298, 0x4a4f7bdb, 0x64ad8c57, 0x85510443, 0xfa020ed1,
0x7e287aff, 0xe60fb663, 0x095f35a1, 0x79ebf120, 0xfd059d43, 0x6497b7b1, 0xf3641f63, 0x241e4adf,
0x28147f5f, 0x4fa2b8cd, 0xc9430040, 0x0cc32220, 0xfdd30b30, 0xc0a5374f, 0x1d2d00d9, 0x24147b15,
0xee4d111a, 0x0fca5167, 0x71ff904c, 0x2d195ffe, 0x1a05645f, 0x0c13fefe, 0x081b08ca, 0x05170121,
0x80530100, 0xe83e5efe, 0xac9af4f8, 0x7fe72701, 0xd2b8ee5f, 0x06df4261, 0xbb9e9b8a, 0x7293ea25,
0xce84ffdf, 0xf5718801, 0x3dd64b04, 0xa26f263b, 0x7ed48400, 0x547eebe6, 0x446d4ca0, 0x6cf3d6f5,
0x2649abdf, 0xaea0c7f5, 0x36338cc1, 0x503f7e93, 0xd3772061, 0x11b638e1, 0x72500e03, 0xf80eb2bb,
0xabe0502e, 0xec8d77de, 0x57971e81, 0xe14f6746, 0xc9335400, 0x6920318f, 0x081dbb99, 0xffc304a5,
0x4d351805, 0x7f3d5ce3, 0xa6c866c6, 0x5d5bcca9, 0xdaec6fea, 0x9f926f91, 0x9f46222f, 0x3991467d,
0xa5bf6d8e, 0x1143c44f, 0x43958302, 0xd0214eeb, 0x022083b8, 0x3fb6180c, 0x18f8931e, 0x281658e6,
0x26486e3e, 0x8bd78a70, 0x7477e4c1, 0xb506e07c, 0xf32d0a25, 0x79098b02, 0xe4eabb81, 0x28123b23,
0x69dead38, 0x1574ca16, 0xdf871b62, 0x211c40b7, 0xa51a9ef9, 0x0014377b, 0x041e8ac8, 0x09114003,
0xbd59e4d2, 0xe3d156d5, 0x4fe876d5, 0x2f91a340, 0x557be8de, 0x00eae4a7, 0x0ce5c2ec, 0x4db4bba6,
0xe756bdff, 0xdd3369ac, 0xec17b035, 0x06572327, 0x99afc8b0, 0x56c8c391, 0x6b65811c, 0x5e146119,
0x6e85cb75, 0xbe07c002, 0xc2325577, 0x893ff4ec, 0x5bbfc92d, 0xd0ec3b25, 0xb7801ab7, 0x8d6d3b24,
0x20c763ef, 0xc366a5fc, 0x9c382880, 0x0ace3205, 0xaac9548a, 0xeca1d7c7, 0x041afa32, 0x1d16625a,
0x6701902c, 0x9b757a54, 0x31d477f7, 0x9126b031, 0x36cc6fdb, 0xc70b8b46, 0xd9e66a48, 0x56e55a79,
0x026a4ceb, 0x52437eff, 0x2f8f76b4, 0x0df980a5, 0x8674cde3, 0xedda04eb, 0x17a9be04, 0x2c18f4df,
0xb7747f9d, 0xab2af7b4, 0xefc34d20, 0x2e096b7c, 0x1741a254, 0xe5b6a035, 0x213d42f6, 0x2c1c7c26,
0x61c2f50f, 0x6552daf9, 0xd2c231f8, 0x25130f69, 0xd8167fa2, 0x0418f2c8, 0x001a96a6, 0x0d1526ab,
0x63315c21, 0x5e0a72ec, 0x49bafefd, 0x187908d9, 0x8d0dbd86, 0x311170a7, 0x3e9b640c, 0xcc3e10d7,
0xd5cad3b6, 0x0caec388, 0xf73001e1, 0x6c728aff, 0x71eae2a1, 0x1f9af36e, 0xcfcbd12f, 0xc1de8417,
0xac07be6b, 0xcb44a1d8, 0x8b9b0f56, 0x013988c3, 0xb1c52fca, 0xb4be31cd, 0xd8782806, 0x12a3a4e2,
0x6f7de532, 0x58fd7eb6, 0xd01ee900, 0x24adffc2, 0xf4990fc5, 0x9711aac5, 0x001d7b95, 0x82e5e7d2,
0x109873f6, 0x00613096, 0xc32d9521, 0xada121ff, 0x29908415, 0x7fbb977f, 0xaf9eb3db, 0x29c9ed2a,
0x5ce2a465, 0xa730f32c, 0xd0aa3fe8, 0x8a5cc091, 0xd49e2ce7, 0x0ce454a9, 0xd60acd86, 0x015f1919,
0x77079103, 0xdea03af6, 0x78a8565e, 0xdee356df, 0x21f05cbe, 0x8b75e387, 0xb3c50651, 0xb8a5c3ef,
0xd8eeb6d2, 0xe523be77, 0xc2154529, 0x2f69efdf, 0xafe67afb, 0xf470c4b2, 0xf3e0eb5b, 0xd6cc9876,
0x39e4460c, 0x1fda8538, 0x1987832f, 0xca007367, 0xa99144f8, 0x296b299e, 0x492fc295, 0x9266beab,
0xb5676e69, 0x9bd3ddda, 0xdf7e052f, 0xdb25701c, 0x1b5e51ee, 0xf65324e6, 0x6afce36c, 0x0316cc04,
0x8644213e, 0xb7dc59d0, 0x7965291f, 0xccd6fd43, 0x41823979, 0x932bcdf6, 0xb657c34d, 0x4edfd282,
0x7ae5290c, 0x3cb9536b, 0x851e20fe, 0x9833557e, 0x13ecf0b0, 0xd3ffb372, 0x3f85c5c1, 0x0aef7ed2,
},
{
0x7ec90c04, 0x2c6e74b9, 0x9b0e66df, 0xa6337911, 0xb86a7fff, 0x1dd358f5, 0x44dd9d44, 0x1731167f,
0x08fbf1fa, 0xe7f511cc, 0xd2051b00, 0x735aba00, 0x2ab722d8, 0x386381cb, 0xacf6243a, 0x69befd7a,
0xe6a2e77f, 0xf0c720cd, 0xc4494816, 0xccf5c180, 0x38851640, 0x15b0a848, 0xe68b18cb, 0x4caadeff,
0x5f480a01, 0x0412b2aa, 0x259814fc, 0x41d0efe2, 0x4e40b48d, 0x248eb6fb, 0x8dba1cfe, 0x41a99b02,
0x1a550a04, 0xba8f65cb, 0x7251f4e7, 0x95a51725, 0xc106ecd7, 0x97a5980a, 0xc539b9aa, 0x4d79fe6a,
0xf2f3f763, 0x68af8040, 0xed0c9e56, 0x11b4958b, 0xe1eb5a88, 0x8709e6b0, 0xd7e07156, 0x4e29fea7,
0x6366e52d, 0x02d1c000, 0xc4ac8e05, 0x9377f571, 0x0c05372a, 0x578535f2, 0x2261be02, 0xd642a0c9,
0xdf13a280, 0x74b55bd2, 0x682199c0, 0xd421e5ec, 0x53fb3ce8, 0xc8adedb3, 0x28a87fc9, 0x3d959981,
0x5c1ff900, 0xfe38d399, 0x0c4eff0b, 0x062407ea, 0xaa2f4fb1, 0x4fb96976, 0x90c79505, 0xb0a8a774,
0xef55a1ff, 0xe59ca2c2, 0xa6b62d27, 0xe66a4263, 0xdf65001f, 0x0ec50966, 0xdfdd55bc, 0x29de0655,
0x911e739a, 0x17af8975, 0x32c7911c, 0x89f89468, 0x0d01e980, 0x524755f4, 0x03b63cc9, 0x0cc844b2,
0xbcf3f0aa, 0x87ac36e9, 0xe53a7426, 0x01b3d82b, 0x1a9e7449, 0x64ee2d7e, 0xcddbb1da, 0x01c94910,
0xb868bf80, 0x0d26f3fd, 0x9342ede7, 0x04a5c284, 0x636737b6, 0x50f5b616, 0xf24766e3, 0x8eca36c1,
0x136e05db, 0xfef18391, 0xfb887a37, 0xd6e7f7d4, 0xc7fb7dc9, 0x3063fcdf, 0xb6f589de, 0xec2941da,
0x26e46695, 0xb7566419, 0xf654efc5, 0xd08d58b7, 0x48925401, 0xc1bacb7f, 0xe5ff550f, 0xb6083049,
0x5bb5d0e8, 0x87d72e5a, 0xab6a6ee1, 0x223a66ce, 0xc62bf3cd, 0x9e0885f9, 0x68cb3e47, 0x086c010f,
0xa21de820, 0xd18b69de, 0xf3f65777, 0xfa02c3f6, 0x407edac3, 0xcbb3d550, 0x1793084d, 0xb0d70eba,
0x0ab378d5, 0xd951fb0c, 0xded7da56, 0x4124bbe4, 0x94ca0b56, 0x0f5755d1, 0xe0e1e56e, 0x6184b5be,
0x580a249f, 0x94f74bc0, 0xe327888e, 0x9f7b5561, 0xc3dc0280, 0x05687715, 0x646c6bd7, 0x44904db3,
0x66b4f0a3, 0xc0f1648a, 0x697ed5af, 0x49e92ff6, 0x309e374f, 0x2cb6356a, 0x85808573, 0x4991f840,
0x76f0ae02, 0x083be84d, 0x28421c9a, 0x44489406, 0x736e4cb8, 0xc1092910, 0x8bc95fc6, 0x7d869cf4,
0x134f616f, 0x2e77118d, 0xb31b2be1, 0xaa90b472, 0x3ca5d717, 0x7d161bba, 0x9cad9010, 0xaf462ba2,
0x9fe459d2, 0x45d34559, 0xd9f2da13, 0xdbc65487, 0xf3e4f94e, 0x176d486f, 0x097c13ea, 0x631da5c7,
0x445f7382, 0x175683f4, 0xcdc66a97, 0x70be0288, 0xb3cdcf72, 0x6e5dd2f3, 0x20936079, 0x459b80a5,
0xbe60e2db, 0xa9c23101, 0xeba5315c, 0x224e42f2, 0x1c5c1572, 0xf6721b2c, 0x1ad2fff3, 0x8c25404e,
0x324ed72f, 0x4067b7fd, 0x0523138e, 0x5ca3bc78, 0xdc0fd66e, 0x75922283, 0x784d6b17, 0x58ebb16e,
0x44094f85, 0x3f481d87, 0xfcfeae7b, 0x77b5ff76, 0x8c2302bf, 0xaaf47556, 0x5f46b02a, 0x2b092801,
0x3d38f5f7, 0x0ca81f36, 0x52af4a8a, 0x66d5e7c0, 0xdf3b0874, 0x95055110, 0x1b5ad7a8, 0xf61ed5ad,
0x6cf6e479, 0x20758184, 0xd0cefa65, 0x88f7be58, 0x4a046826, 0x0ff6f8f3, 0xa09c7f70, 0x5346aba0,
0x5ce96c28, 0xe176eda3, 0x6bac307f, 0x376829d2, 0x85360fa9, 0x17e3fe2a, 0x24b79767, 0xf5a96b20,
0xd6cd2595, 0x68ff1ebf, 0x7555442c, 0xf19f06be, 0xf9e0659a, 0xeeb9491d, 0x34010718, 0xbb30cab8,
0xe822fe15, 0x88570983, 0x750e6249, 0xda627e55, 0x5e76ffa8, 0xb1534546, 0x6d47de08, 0xefe9e7d4,
},
{
0xf6fa8f9d, 0x2cac6ce1, 0x4ca34867, 0xe2337f7c, 0x95db08e7, 0x016843b4, 0xeced5cbc, 0x325553ac,
0xbf9f0960, 0xdfa1e2ed, 0x83f0579d, 0x63ed86b9, 0x1ab6a6b8, 0xde5ebe39, 0xf38ff732, 0x8989b138,
0x33f14961, 0xc01937bd, 0xf506c6da, 0xe4625e7e, 0xa308ea99, 0x4e23e33c, 0x79cbd7cc, 0x48a14367,
0xa3149619, 0xfec94bd5, 0xa114174a, 0xeaa01866, 0xa084db2d, 0x09a8486f, 0xa888614a, 0x2900af98,
0x01665991, 0xe1992863, 0xc8f30c60, 0x2e78ef3c, 0xd0d51932, 0xcf0fec14, 0xf7ca07d2, 0xd0a82072,
0xfd41197e, 0x9305a6b0, 0xe86be3da, 0x74bed3cd, 0x372da53c, 0x4c7f4448, 0xdab5d440, 0x6dba0ec3,
0x083919a7, 0x9fbaeed9, 0x49dbcfb0, 0x4e670c53, 0x5c3d9c01, 0x64bdb941, 0x2c0e636a, 0xba7dd9cd,
0xea6f7388, 0xe70bc762, 0x35f29adb, 0x5c4cdd8d, 0xf0d48d8c, 0xb88153e2, 0x08a19866, 0x1ae2eac8,
0x284caf89, 0xaa928223, 0x9334be53, 0x3b3a21bf, 0x16434be3, 0x9aea3906, 0xefe8c36e, 0xf890cdd9,
0x80226dae, 0xc340a4a3, 0xdf7e9c09, 0xa694a807, 0x5b7c5ecc, 0x221db3a6, 0x9a69a02f, 0x68818a54,
0xceb2296f, 0x53c0843a, 0xfe893655, 0x25bfe68a, 0xb4628abc, 0xcf222ebf, 0x25ac6f48, 0xa9a99387,
0x53bddb65, 0xe76ffbe7, 0xe967fd78, 0x0ba93563, 0x8e342bc1, 0xe8a11be9, 0x4980740d, 0xc8087dfc,
0x8de4bf99, 0xa11101a0, 0x7fd37975, 0xda5a26c0, 0xe81f994f, 0x9528cd89, 0xfd339fed, 0xb87834bf,
0x5f04456d, 0x22258698, 0xc9c4c83b, 0x2dc156be, 0x4f628daa, 0x57f55ec5, 0xe2220abe, 0xd2916ebf,
0x4ec75b95, 0x24f2c3c0, 0x42d15d99, 0xcd0d7fa0, 0x7b6e27ff, 0xa8dc8af0, 0x7345c106, 0xf41e232f,
0x35162386, 0xe6ea8926, 0x3333b094, 0x157ec6f2, 0x372b74af, 0x692573e4, 0xe9a9d848, 0xf3160289,
0x3a62ef1d, 0xa787e238, 0xf3a5f676, 0x74364853, 0x20951063, 0x4576698d, 0xb6fad407, 0x592af950,
0x36f73523, 0x4cfb6e87, 0x7da4cec0, 0x6c152daa, 0xcb0396a8, 0xc50dfe5d, 0xfcd707ab, 0x0921c42f,
0x89dff0bb, 0x5fe2be78, 0x448f4f33, 0x754613c9, 0x2b05d08d, 0x48b9d585, 0xdc049441, 0xc8098f9b,
0x7dede786, 0xc39a3373, 0x42410005, 0x6a091751, 0x0ef3c8a6, 0x890072d6, 0x28207682, 0xa9a9f7be,
0xbf32679d, 0xd45b5b75, 0xb353fd00, 0xcbb0e358, 0x830f220a, 0x1f8fb214, 0xd372cf08, 0xcc3c4a13,
0x8cf63166, 0x061c87be, 0x88c98f88, 0x6062e397, 0x47cf8e7a, 0xb6c85283, 0x3cc2acfb, 0x3fc06976,
0x4e8f0252, 0x64d8314d, 0xda3870e3, 0x1e665459, 0xc10908f0, 0x513021a5, 0x6c5b68b7, 0x822f8aa0,
0x3007cd3e, 0x74719eef, 0xdc872681, 0x073340d4, 0x7e432fd9, 0x0c5ec241, 0x8809286c, 0xf592d891,
0x08a930f6, 0x957ef305, 0xb7fbffbd, 0xc266e96f, 0x6fe4ac98, 0xb173ecc0, 0xbc60b42a, 0x953498da,
0xfba1ae12, 0x2d4bd736, 0x0f25faab, 0xa4f3fceb, 0xe2969123, 0x257f0c3d, 0x9348af49, 0x361400bc,
0xe8816f4a, 0x3814f200, 0xa3f94043, 0x9c7a54c2, 0xbc704f57, 0xda41e7f9, 0xc25ad33a, 0x54f4a084,
0xb17f5505, 0x59357cbe, 0xedbd15c8, 0x7f97c5ab, 0xba5ac7b5, 0xb6f6deaf, 0x3a479c3a, 0x5302da25,
0x653d7e6a, 0x54268d49, 0x51a477ea, 0x5017d55b, 0xd7d25d88, 0x44136c76, 0x0404a8c8, 0xb8e5a121,
0xb81a928a, 0x60ed5869, 0x97c55b96, 0xeaec991b, 0x29935913, 0x01fdb7f1, 0x088e8dfa, 0x9ab6f6f5,
0x3b4cbf9f, 0x4a5de3ab, 0xe6051d35, 0xa0e1d855, 0xd36b4cf1, 0xf544edeb, 0xb0e93524, 0xbebb8fbd,
0xa2d762cf, 0x49c92f54, 0x38b5f331, 0x7128a454, 0x48392905, 0xa65b1db8, 0x851c97bd, 0xd675cf2f,
},
{
0x85e04019, 0x332bf567, 0x662dbfff, 0xcfc65693, 0x2a8d7f6f, 0xab9bc912, 0xde6008a1, 0x2028da1f,
0x0227bce7, 0x4d642916, 0x18fac300, 0x50f18b82, 0x2cb2cb11, 0xb232e75c, 0x4b3695f2, 0xb28707de,
0xa05fbcf6, 0xcd4181e9, 0xe150210c, 0xe24ef1bd, 0xb168c381, 0xfde4e789, 0x5c79b0d8, 0x1e8bfd43,
0x4d495001, 0x38be4341, 0x913cee1d, 0x92a79c3f, 0x089766be, 0xbaeeadf4, 0x1286becf, 0xb6eacb19,
0x2660c200, 0x7565bde4, 0x64241f7a, 0x8248dca9, 0xc3b3ad66, 0x28136086, 0x0bd8dfa8, 0x356d1cf2,
0x107789be, 0xb3b2e9ce, 0x0502aa8f, 0x0bc0351e, 0x166bf52a, 0xeb12ff82, 0xe3486911, 0xd34d7516,
0x4e7b3aff, 0x5f43671b, 0x9cf6e037, 0x4981ac83, 0x334266ce, 0x8c9341b7, 0xd0d854c0, 0xcb3a6c88,
0x47bc2829, 0x4725ba37, 0xa66ad22b, 0x7ad61f1e, 0x0c5cbafa, 0x4437f107, 0xb6e79962, 0x42d2d816,
0x0a961288, 0xe1a5c06e, 0x13749e67, 0x72fc081a, 0xb1d139f7, 0xf9583745, 0xcf19df58, 0xbec3f756,
0xc06eba30, 0x07211b24, 0x45c28829, 0xc95e317f, 0xbc8ec511, 0x38bc46e9, 0xc6e6fa14, 0xbae8584a,
0xad4ebc46, 0x468f508b, 0x7829435f, 0xf124183b, 0x821dba9f, 0xaff60ff4, 0xea2c4e6d, 0x16e39264,
0x92544a8b, 0x009b4fc3, 0xaba68ced, 0x9ac96f78, 0x06a5b79a, 0xb2856e6e, 0x1aec3ca9, 0xbe838688,
0x0e0804e9, 0x55f1be56, 0xe7e5363b, 0xb3a1f25d, 0xf7debb85, 0x61fe033c, 0x16746233, 0x3c034c28,
0xda6d0c74, 0x79aac56c, 0x3ce4e1ad, 0x51f0c802, 0x98f8f35a, 0x1626a49f, 0xeed82b29, 0x1d382fe3,
0x0c4fb99a, 0xbb325778, 0x3ec6d97b, 0x6e77a6a9, 0xcb658b5c, 0xd45230c7, 0x2bd1408b, 0x60c03eb7,
0xb9068d78, 0xa33754f4, 0xf430c87d, 0xc8a71302, 0xb96d8c32, 0xebd4e7be, 0xbe8b9d2d, 0x7979fb06,
0xe7225308, 0x8b75cf77, 0x11ef8da4, 0xe083c858, 0x8d6b786f, 0x5a6317a6, 0xfa5cf7a0, 0x5dda0033,
0xf28ebfb0, 0xf5b9c310, 0xa0eac280, 0x08b9767a, 0xa3d9d2b0, 0x79d34217, 0x021a718d, 0x9ac6336a,
0x2711fd60, 0x438050e3, 0x069908a8, 0x3d7fedc4, 0x826d2bef, 0x4eeb8476, 0x488dcf25, 0x36c9d566,
0x28e74e41, 0xc2610aca, 0x3d49a9cf, 0xbae3b9df, 0xb65f8de6, 0x92aeaf64, 0x3ac7d5e6, 0x9ea80509,
0xf22b017d, 0xa4173f70, 0xdd1e16c3, 0x15e0d7f9, 0x50b1b887, 0x2b9f4fd5, 0x625aba82, 0x6a017962,
0x2ec01b9c, 0x15488aa9, 0xd716e740, 0x40055a2c, 0x93d29a22, 0xe32dbf9a, 0x058745b9, 0x3453dc1e,
0xd699296e, 0x496cff6f, 0x1c9f4986, 0xdfe2ed07, 0xb87242d1, 0x19de7eae, 0x053e561a, 0x15ad6f8c,
0x66626c1c, 0x7154c24c, 0xea082b2a, 0x93eb2939, 0x17dcb0f0, 0x58d4f2ae, 0x9ea294fb, 0x52cf564c,
0x9883fe66, 0x2ec40581, 0x763953c3, 0x01d6692e, 0xd3a0c108, 0xa1e7160e, 0xe4f2dfa6, 0x693ed285,
0x74904698, 0x4c2b0edd, 0x4f757656, 0x5d393378, 0xa132234f, 0x3d321c5d, 0xc3f5e194, 0x4b269301,
0xc79f022f, 0x3c997e7e, 0x5e4f9504, 0x3ffafbbd, 0x76f7ad0e, 0x296693f4, 0x3d1fce6f, 0xc61e45be,
0xd3b5ab34, 0xf72bf9b7, 0x1b0434c0, 0x4e72b567, 0x5592a33d, 0xb5229301, 0xcfd2a87f, 0x60aeb767,
0x1814386b, 0x30bcc33d, 0x38a0c07d, 0xfd1606f2, 0xc363519b, 0x589dd390, 0x5479f8e6, 0x1cb8d647,
0x97fd61a9, 0xea7759f4, 0x2d57539d, 0x569a58cf, 0xe84e63ad, 0x462e1b78, 0x6580f87e, 0xf3817914,
0x91da55f4, 0x40a230f3, 0xd1988f35, 0xb6e318d2, 0x3ffa50bc, 0x3d40f021, 0xc3c0bdae, 0x4958c24c,
0x518f36b2, 0x84b1d370, 0x0fedce83, 0x878ddada, 0xf2a279c7, 0x94e01be8, 0x90716f4b, 0x954b8aa3,
},
{
0xe216300d, 0xbbddfffc, 0xa7ebdabd, 0x35648095, 0x7789f8b7, 0xe6c1121b, 0x0e241600, 0x052ce8b5,
0x11a9cfb0, 0xe5952f11, 0xece7990a, 0x9386d174, 0x2a42931c, 0x76e38111, 0xb12def3a, 0x37ddddfc,
0xde9adeb1, 0x0a0cc32c, 0xbe197029, 0x84a00940, 0xbb243a0f, 0xb4d137cf, 0xb44e79f0, 0x049eedfd,
0x0b15a15d, 0x480d3168, 0x8bbbde5a, 0x669ded42, 0xc7ece831, 0x3f8f95e7, 0x72df191b, 0x7580330d,
0x94074251, 0x5c7dcdfa, 0xabbe6d63, 0xaa402164, 0xb301d40a, 0x02e7d1ca, 0x53571dae, 0x7a3182a2,
0x12a8ddec, 0xfdaa335d, 0x176f43e8, 0x71fb46d4, 0x38129022, 0xce949ad4, 0xb84769ad, 0x965bd862,
0x82f3d055, 0x66fb9767, 0x15b80b4e, 0x1d5b47a0, 0x4cfde06f, 0xc28ec4b8, 0x57e8726e, 0x647a78fc,
0x99865d44, 0x608bd593, 0x6c200e03, 0x39dc5ff6, 0x5d0b00a3, 0xae63aff2, 0x7e8bd632, 0x70108c0c,
0xbbd35049, 0x2998df04, 0x980cf42a, 0x9b6df491, 0x9e7edd53, 0x06918548, 0x58cb7e07, 0x3b74ef2e,
0x522fffb1, 0xd24708cc, 0x1c7e27cd, 0xa4eb215b, 0x3cf1d2e2, 0x19b47a38, 0x424f7618, 0x35856039,
0x9d17dee7, 0x27eb35e6, 0xc9aff67b, 0x36baf5b8, 0x09c467cd, 0xc18910b1, 0xe11dbf7b, 0x06cd1af8,
0x7170c608, 0x2d5e3354, 0xd4de495a, 0x64c6d006, 0xbcc0c62c, 0x3dd00db3, 0x708f8f34, 0x77d51b42,
0x264f620f, 0x24b8d2bf, 0x15c1b79e, 0x46a52564, 0xf8d7e54e, 0x3e378160, 0x7895cda5, 0x859c15a5,
0xe6459788, 0xc37bc75f, 0xdb07ba0c, 0x0676a3ab, 0x7f229b1e, 0x31842e7b, 0x24259fd7, 0xf8bef472,
0x835ffcb8, 0x6df4c1f2, 0x96f5b195, 0xfd0af0fc, 0xb0fe134c, 0xe2506d3d, 0x4f9b12ea, 0xf215f225,
0xa223736f, 0x9fb4c428, 0x25d04979, 0x34c713f8, 0xc4618187, 0xea7a6e98, 0x7cd16efc, 0x1436876c,
0xf1544107, 0xbedeee14, 0x56e9af27, 0xa04aa441, 0x3cf7c899, 0x92ecbae6, 0xdd67016d, 0x151682eb,
0xa842eedf, 0xfdba60b4, 0xf1907b75, 0x20e3030f, 0x24d8c29e, 0xe139673b, 0xefa63fb8, 0x71873054,
0xb6f2cf3b, 0x9f326442, 0xcb15a4cc, 0xb01a4504, 0xf1e47d8d, 0x844a1be5, 0xbae7dfdc, 0x42cbda70,
0xcd7dae0a, 0x57e85b7a, 0xd53f5af6, 0x20cf4d8c, 0xcea4d428, 0x79d130a4, 0x3486ebfb, 0x33d3cddc,
0x77853b53, 0x37effcb5, 0xc5068778, 0xe580b3e6, 0x4e68b8f4, 0xc5c8b37e, 0x0d809ea2, 0x398feb7c,
0x132a4f94, 0x43b7950e, 0x2fee7d1c, 0x223613bd, 0xdd06caa2, 0x37df932b, 0xc4248289, 0xacf3ebc3,
0x5715f6b7, 0xef3478dd, 0xf267616f, 0xc148cbe4, 0x9052815e, 0x5e410fab, 0xb48a2465, 0x2eda7fa4,
0xe87b40e4, 0xe98ea084, 0x5889e9e1, 0xefd390fc, 0xdd07d35b, 0xdb485694, 0x38d7e5b2, 0x57720101,
0x730edebc, 0x5b643113, 0x94917e4f, 0x503c2fba, 0x646f1282, 0x7523d24a, 0xe0779695, 0xf9c17a8f,
0x7a5b2121, 0xd187b896, 0x29263a4d, 0xba510cdf, 0x81f47c9f, 0xad1163ed, 0xea7b5965, 0x1a00726e,
0x11403092, 0x00da6d77, 0x4a0cdd61, 0xad1f4603, 0x605bdfb0, 0x9eedc364, 0x22ebe6a8, 0xcee7d28a,
0xa0e736a0, 0x5564a6b9, 0x10853209, 0xc7eb8f37, 0x2de705ca, 0x8951570f, 0xdf09822b, 0xbd691a6c,
0xaa12e4f2, 0x87451c0f, 0xe0f6a27a, 0x3ada4819, 0x4cf1764f, 0x0d771c2b, 0x67cdb156, 0x350d8384,
0x5938fa0f, 0x42399ef3, 0x36997b07, 0x0e84093d, 0x4aa93e61, 0x8360d87b, 0x1fa98b0c, 0x1149382c,
0xe97625a5, 0x0614d1b7, 0x0e25244b, 0x0c768347, 0x589e8d82, 0x0d2059d1, 0xa466bb1e, 0xf8da0a82,
0x04f19130, 0xba6e4ec0, 0x99265164, 0x1ee7230d, 0x50b2ad80, 0xeaee6801, 0x8db2a283, 0xea8bf59e,
},
}

View File

@ -1,104 +0,0 @@
// 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 cast5
import (
"bytes"
"encoding/hex"
"testing"
)
// This test vector is taken from RFC 2144, App B.1.
// Since the other two test vectors are for reduced-round variants, we can't
// use them.
var basicTests = []struct {
key, plainText, cipherText string
}{
{
"0123456712345678234567893456789a",
"0123456789abcdef",
"238b4fe5847e44b2",
},
}
func TestBasic(t *testing.T) {
for i, test := range basicTests {
key, _ := hex.DecodeString(test.key)
plainText, _ := hex.DecodeString(test.plainText)
expected, _ := hex.DecodeString(test.cipherText)
c, err := NewCipher(key)
if err != nil {
t.Errorf("#%d: failed to create Cipher: %s", i, err)
continue
}
var cipherText [BlockSize]byte
c.Encrypt(cipherText[:], plainText)
if !bytes.Equal(cipherText[:], expected) {
t.Errorf("#%d: got:%x want:%x", i, cipherText, expected)
}
var plainTextAgain [BlockSize]byte
c.Decrypt(plainTextAgain[:], cipherText[:])
if !bytes.Equal(plainTextAgain[:], plainText) {
t.Errorf("#%d: got:%x want:%x", i, plainTextAgain, plainText)
}
}
}
// TestFull performs the test specified in RFC 2144, App B.2.
// However, due to the length of time taken, it's disabled here and a more
// limited version is included, below.
func TestFull(t *testing.T) {
// This is too slow for normal testing
return
a, b := iterate(1000000)
const expectedA = "eea9d0a249fd3ba6b3436fb89d6dca92"
const expectedB = "b2c95eb00c31ad7180ac05b8e83d696e"
if hex.EncodeToString(a) != expectedA {
t.Errorf("a: got:%x want:%s", a, expectedA)
}
if hex.EncodeToString(b) != expectedB {
t.Errorf("b: got:%x want:%s", b, expectedB)
}
}
func iterate(iterations int) ([]byte, []byte) {
const initValueHex = "0123456712345678234567893456789a"
initValue, _ := hex.DecodeString(initValueHex)
var a, b [16]byte
copy(a[:], initValue)
copy(b[:], initValue)
for i := 0; i < iterations; i++ {
c, _ := NewCipher(b[:])
c.Encrypt(a[:8], a[:8])
c.Encrypt(a[8:], a[8:])
c, _ = NewCipher(a[:])
c.Encrypt(b[:8], b[:8])
c.Encrypt(b[8:], b[8:])
}
return a[:], b[:]
}
func TestLimited(t *testing.T) {
a, b := iterate(1000)
const expectedA = "23f73b14b02a2ad7dfb9f2c35644798d"
const expectedB = "e5bf37eff14c456a40b21ce369370a9f"
if hex.EncodeToString(a) != expectedA {
t.Errorf("a: got:%x want:%s", a, expectedA)
}
if hex.EncodeToString(b) != expectedB {
t.Errorf("b: got:%x want:%s", b, expectedB)
}
}

View File

@ -35,11 +35,11 @@ func (invalidPublicKeyError) Error() string {
return "crypto/dsa: invalid public key" return "crypto/dsa: invalid public key"
} }
// InvalidPublicKeyError results when a public key is not usable by this code. // ErrInvalidPublicKey results when a public key is not usable by this code.
// FIPS is quite strict about the format of DSA keys, but other code may be // FIPS is quite strict about the format of DSA keys, but other code may be
// less so. Thus, when using keys which may have been generated by other code, // less so. Thus, when using keys which may have been generated by other code,
// this error must be handled. // this error must be handled.
var InvalidPublicKeyError = invalidPublicKeyError(0) var ErrInvalidPublicKey error = invalidPublicKeyError(0)
// ParameterSizes is a enumeration of the acceptable bit lengths of the primes // ParameterSizes is a enumeration of the acceptable bit lengths of the primes
// in a set of DSA parameters. See FIPS 186-3, section 4.2. // in a set of DSA parameters. See FIPS 186-3, section 4.2.
@ -194,7 +194,7 @@ func Sign(rand io.Reader, priv *PrivateKey, hash []byte) (r, s *big.Int, err err
n := priv.Q.BitLen() n := priv.Q.BitLen()
if n&7 != 0 { if n&7 != 0 {
err = InvalidPublicKeyError err = ErrInvalidPublicKey
return return
} }
n >>= 3 n >>= 3

View File

@ -1,118 +0,0 @@
// 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 md4 implements the MD4 hash algorithm as defined in RFC 1320.
package md4
import (
"crypto"
"hash"
)
func init() {
crypto.RegisterHash(crypto.MD4, New)
}
// The size of an MD4 checksum in bytes.
const Size = 16
// The blocksize of MD4 in bytes.
const BlockSize = 64
const (
_Chunk = 64
_Init0 = 0x67452301
_Init1 = 0xEFCDAB89
_Init2 = 0x98BADCFE
_Init3 = 0x10325476
)
// digest represents the partial evaluation of a checksum.
type digest struct {
s [4]uint32
x [_Chunk]byte
nx int
len uint64
}
func (d *digest) Reset() {
d.s[0] = _Init0
d.s[1] = _Init1
d.s[2] = _Init2
d.s[3] = _Init3
d.nx = 0
d.len = 0
}
// New returns a new hash.Hash computing the MD4 checksum.
func New() hash.Hash {
d := new(digest)
d.Reset()
return d
}
func (d *digest) Size() int { return Size }
func (d *digest) BlockSize() int { return BlockSize }
func (d *digest) Write(p []byte) (nn int, err error) {
nn = len(p)
d.len += uint64(nn)
if d.nx > 0 {
n := len(p)
if n > _Chunk-d.nx {
n = _Chunk - d.nx
}
for i := 0; i < n; i++ {
d.x[d.nx+i] = p[i]
}
d.nx += n
if d.nx == _Chunk {
_Block(d, d.x[0:])
d.nx = 0
}
p = p[n:]
}
n := _Block(d, p)
p = p[n:]
if len(p) > 0 {
d.nx = copy(d.x[:], p)
}
return
}
func (d0 *digest) Sum(in []byte) []byte {
// Make a copy of d0, so that caller can keep writing and summing.
d := new(digest)
*d = *d0
// Padding. Add a 1 bit and 0 bits until 56 bytes mod 64.
len := d.len
var tmp [64]byte
tmp[0] = 0x80
if len%64 < 56 {
d.Write(tmp[0 : 56-len%64])
} else {
d.Write(tmp[0 : 64+56-len%64])
}
// Length in bits.
len <<= 3
for i := uint(0); i < 8; i++ {
tmp[i] = byte(len >> (8 * i))
}
d.Write(tmp[0:8])
if d.nx != 0 {
panic("d.nx != 0")
}
for _, s := range d.s {
in = append(in, byte(s>>0))
in = append(in, byte(s>>8))
in = append(in, byte(s>>16))
in = append(in, byte(s>>24))
}
return in
}

View File

@ -1,71 +0,0 @@
// 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 md4
import (
"fmt"
"io"
"testing"
)
type md4Test struct {
out string
in string
}
var golden = []md4Test{
{"31d6cfe0d16ae931b73c59d7e0c089c0", ""},
{"bde52cb31de33e46245e05fbdbd6fb24", "a"},
{"ec388dd78999dfc7cf4632465693b6bf", "ab"},
{"a448017aaf21d8525fc10ae87aa6729d", "abc"},
{"41decd8f579255c5200f86a4bb3ba740", "abcd"},
{"9803f4a34e8eb14f96adba49064a0c41", "abcde"},
{"804e7f1c2586e50b49ac65db5b645131", "abcdef"},
{"752f4adfe53d1da0241b5bc216d098fc", "abcdefg"},
{"ad9daf8d49d81988590a6f0e745d15dd", "abcdefgh"},
{"1e4e28b05464316b56402b3815ed2dfd", "abcdefghi"},
{"dc959c6f5d6f9e04e4380777cc964b3d", "abcdefghij"},
{"1b5701e265778898ef7de5623bbe7cc0", "Discard medicine more than two years old."},
{"d7f087e090fe7ad4a01cb59dacc9a572", "He who has a shady past knows that nice guys finish last."},
{"a6f8fd6df617c72837592fc3570595c9", "I wouldn't marry him with a ten foot pole."},
{"c92a84a9526da8abc240c05d6b1a1ce0", "Free! Free!/A trip/to Mars/for 900/empty jars/Burma Shave"},
{"f6013160c4dcb00847069fee3bb09803", "The days of the digital watch are numbered. -Tom Stoppard"},
{"2c3bb64f50b9107ed57640fe94bec09f", "Nepal premier won't resign."},
{"45b7d8a32c7806f2f7f897332774d6e4", "For every action there is an equal and opposite government program."},
{"b5b4f9026b175c62d7654bdc3a1cd438", "His money is twice tainted: 'taint yours and 'taint mine."},
{"caf44e80f2c20ce19b5ba1cab766e7bd", "There is no reason for any individual to have a computer in their home. -Ken Olsen, 1977"},
{"191fae6707f496aa54a6bce9f2ecf74d", "It's a tiny change to the code and not completely disgusting. - Bob Manchek"},
{"9ddc753e7a4ccee6081cd1b45b23a834", "size: a.out: bad magic"},
{"8d050f55b1cadb9323474564be08a521", "The major problem is with sendmail. -Mark Horton"},
{"ad6e2587f74c3e3cc19146f6127fa2e3", "Give me a rock, paper and scissors and I will move the world. CCFestoon"},
{"1d616d60a5fabe85589c3f1566ca7fca", "If the enemy is within range, then so are you."},
{"aec3326a4f496a2ced65a1963f84577f", "It's well we cannot hear the screams/That we create in others' dreams."},
{"77b4fd762d6b9245e61c50bf6ebf118b", "You remind me of a TV show, but that's all right: I watch it anyway."},
{"e8f48c726bae5e516f6ddb1a4fe62438", "C is as portable as Stonehedge!!"},
{"a3a84366e7219e887423b01f9be7166e", "Even if I could be Shakespeare, I think I should still choose to be Faraday. - A. Huxley"},
{"a6b7aa35157e984ef5d9b7f32e5fbb52", "The fugacity of a constituent in a mixture of gases at a given temperature is proportional to its mole fraction. Lewis-Randall Rule"},
{"75661f0545955f8f9abeeb17845f3fd6", "How can you write a big system without C++? -Paul Glick"},
}
func TestGolden(t *testing.T) {
for i := 0; i < len(golden); i++ {
g := golden[i]
c := New()
for j := 0; j < 3; j++ {
if j < 2 {
io.WriteString(c, g.in)
} else {
io.WriteString(c, g.in[0:len(g.in)/2])
c.Sum(nil)
io.WriteString(c, g.in[len(g.in)/2:])
}
s := fmt.Sprintf("%x", c.Sum(nil))
if s != g.out {
t.Fatalf("md4[%d](%s) = %s want %s", j, g.in, s, g.out)
}
c.Reset()
}
}
}

View File

@ -1,89 +0,0 @@
// 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.
// MD4 block step.
// In its own file so that a faster assembly or C version
// can be substituted easily.
package md4
var shift1 = []uint{3, 7, 11, 19}
var shift2 = []uint{3, 5, 9, 13}
var shift3 = []uint{3, 9, 11, 15}
var xIndex2 = []uint{0, 4, 8, 12, 1, 5, 9, 13, 2, 6, 10, 14, 3, 7, 11, 15}
var xIndex3 = []uint{0, 8, 4, 12, 2, 10, 6, 14, 1, 9, 5, 13, 3, 11, 7, 15}
func _Block(dig *digest, p []byte) int {
a := dig.s[0]
b := dig.s[1]
c := dig.s[2]
d := dig.s[3]
n := 0
var X [16]uint32
for len(p) >= _Chunk {
aa, bb, cc, dd := a, b, c, d
j := 0
for i := 0; i < 16; i++ {
X[i] = uint32(p[j]) | uint32(p[j+1])<<8 | uint32(p[j+2])<<16 | uint32(p[j+3])<<24
j += 4
}
// If this needs to be made faster in the future,
// the usual trick is to unroll each of these
// loops by a factor of 4; that lets you replace
// the shift[] lookups with constants and,
// with suitable variable renaming in each
// unrolled body, delete the a, b, c, d = d, a, b, c
// (or you can let the optimizer do the renaming).
//
// The index variables are uint so that % by a power
// of two can be optimized easily by a compiler.
// Round 1.
for i := uint(0); i < 16; i++ {
x := i
s := shift1[i%4]
f := ((c ^ d) & b) ^ d
a += f + X[x]
a = a<<s | a>>(32-s)
a, b, c, d = d, a, b, c
}
// Round 2.
for i := uint(0); i < 16; i++ {
x := xIndex2[i]
s := shift2[i%4]
g := (b & c) | (b & d) | (c & d)
a += g + X[x] + 0x5a827999
a = a<<s | a>>(32-s)
a, b, c, d = d, a, b, c
}
// Round 3.
for i := uint(0); i < 16; i++ {
x := xIndex3[i]
s := shift3[i%4]
h := b ^ c ^ d
a += h + X[x] + 0x6ed9eba1
a = a<<s | a>>(32-s)
a, b, c, d = d, a, b, c
}
a += aa
b += bb
c += cc
d += dd
p = p[_Chunk:]
n += _Chunk
}
dig.s[0] = a
dig.s[1] = b
dig.s[2] = c
dig.s[3] = d
return n
}

View File

@ -1,191 +0,0 @@
// 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 ocsp parses OCSP responses as specified in RFC 2560. OCSP responses
// are signed messages attesting to the validity of a certificate for a small
// period of time. This is used to manage revocation for X.509 certificates.
package ocsp
import (
"crypto"
"crypto/rsa"
_ "crypto/sha1"
"crypto/x509"
"crypto/x509/pkix"
"encoding/asn1"
"time"
)
var idPKIXOCSPBasic = asn1.ObjectIdentifier([]int{1, 3, 6, 1, 5, 5, 7, 48, 1, 1})
var idSHA1WithRSA = asn1.ObjectIdentifier([]int{1, 2, 840, 113549, 1, 1, 5})
// These are internal structures that reflect the ASN.1 structure of an OCSP
// response. See RFC 2560, section 4.2.
const (
ocspSuccess = 0
ocspMalformed = 1
ocspInternalError = 2
ocspTryLater = 3
ocspSigRequired = 4
ocspUnauthorized = 5
)
type certID struct {
HashAlgorithm pkix.AlgorithmIdentifier
NameHash []byte
IssuerKeyHash []byte
SerialNumber asn1.RawValue
}
type responseASN1 struct {
Status asn1.Enumerated
Response responseBytes `asn1:"explicit,tag:0"`
}
type responseBytes struct {
ResponseType asn1.ObjectIdentifier
Response []byte
}
type basicResponse struct {
TBSResponseData responseData
SignatureAlgorithm pkix.AlgorithmIdentifier
Signature asn1.BitString
Certificates []asn1.RawValue `asn1:"explicit,tag:0,optional"`
}
type responseData struct {
Raw asn1.RawContent
Version int `asn1:"optional,default:1,explicit,tag:0"`
RequestorName pkix.RDNSequence `asn1:"optional,explicit,tag:1"`
KeyHash []byte `asn1:"optional,explicit,tag:2"`
ProducedAt time.Time
Responses []singleResponse
}
type singleResponse struct {
CertID certID
Good asn1.Flag `asn1:"explicit,tag:0,optional"`
Revoked revokedInfo `asn1:"explicit,tag:1,optional"`
Unknown asn1.Flag `asn1:"explicit,tag:2,optional"`
ThisUpdate time.Time
NextUpdate time.Time `asn1:"explicit,tag:0,optional"`
}
type revokedInfo struct {
RevocationTime time.Time
Reason int `asn1:"explicit,tag:0,optional"`
}
// This is the exposed reflection of the internal OCSP structures.
const (
// Good means that the certificate is valid.
Good = iota
// Revoked means that the certificate has been deliberately revoked.
Revoked = iota
// Unknown means that the OCSP responder doesn't know about the certificate.
Unknown = iota
// ServerFailed means that the OCSP responder failed to process the request.
ServerFailed = iota
)
// Response represents an OCSP response. See RFC 2560.
type Response struct {
// Status is one of {Good, Revoked, Unknown, ServerFailed}
Status int
SerialNumber []byte
ProducedAt, ThisUpdate, NextUpdate, RevokedAt time.Time
RevocationReason int
Certificate *x509.Certificate
}
// ParseError results from an invalid OCSP response.
type ParseError string
func (p ParseError) Error() string {
return string(p)
}
// ParseResponse parses an OCSP response in DER form. It only supports
// responses for a single certificate and only those using RSA signatures.
// Non-RSA responses will result in an x509.UnsupportedAlgorithmError.
// Signature errors or parse failures will result in a ParseError.
func ParseResponse(bytes []byte) (*Response, error) {
var resp responseASN1
rest, err := asn1.Unmarshal(bytes, &resp)
if err != nil {
return nil, err
}
if len(rest) > 0 {
return nil, ParseError("trailing data in OCSP response")
}
ret := new(Response)
if resp.Status != ocspSuccess {
ret.Status = ServerFailed
return ret, nil
}
if !resp.Response.ResponseType.Equal(idPKIXOCSPBasic) {
return nil, ParseError("bad OCSP response type")
}
var basicResp basicResponse
rest, err = asn1.Unmarshal(resp.Response.Response, &basicResp)
if err != nil {
return nil, err
}
if len(basicResp.Certificates) != 1 {
return nil, ParseError("OCSP response contains bad number of certificates")
}
if len(basicResp.TBSResponseData.Responses) != 1 {
return nil, ParseError("OCSP response contains bad number of responses")
}
ret.Certificate, err = x509.ParseCertificate(basicResp.Certificates[0].FullBytes)
if err != nil {
return nil, err
}
if ret.Certificate.PublicKeyAlgorithm != x509.RSA || !basicResp.SignatureAlgorithm.Algorithm.Equal(idSHA1WithRSA) {
return nil, x509.UnsupportedAlgorithmError{}
}
hashType := crypto.SHA1
h := hashType.New()
pub := ret.Certificate.PublicKey.(*rsa.PublicKey)
h.Write(basicResp.TBSResponseData.Raw)
digest := h.Sum(nil)
signature := basicResp.Signature.RightAlign()
if rsa.VerifyPKCS1v15(pub, hashType, digest, signature) != nil {
return nil, ParseError("bad OCSP signature")
}
r := basicResp.TBSResponseData.Responses[0]
ret.SerialNumber = r.CertID.SerialNumber.Bytes
switch {
case bool(r.Good):
ret.Status = Good
case bool(r.Unknown):
ret.Status = Unknown
default:
ret.Status = Revoked
ret.RevokedAt = r.Revoked.RevocationTime
ret.RevocationReason = r.Revoked.Reason
}
ret.ProducedAt = basicResp.TBSResponseData.ProducedAt
ret.ThisUpdate = r.ThisUpdate
ret.NextUpdate = r.NextUpdate
return ret, nil
}

View File

@ -1,107 +0,0 @@
// 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 ocsp
import (
"bytes"
"encoding/hex"
"reflect"
"testing"
"time"
)
func TestOCSPDecode(t *testing.T) {
responseBytes, _ := hex.DecodeString(ocspResponseHex)
resp, err := ParseResponse(responseBytes)
if err != nil {
t.Error(err)
}
expected := Response{
Status: 0,
SerialNumber: []byte{0x1, 0xd0, 0xfa},
RevocationReason: 0,
ThisUpdate: time.Date(2010, 7, 7, 15, 1, 5, 0, time.UTC),
NextUpdate: time.Date(2010, 7, 7, 18, 35, 17, 0, time.UTC),
}
if !reflect.DeepEqual(resp.ThisUpdate, expected.ThisUpdate) {
t.Errorf("resp.ThisUpdate: got %d, want %d", resp.ThisUpdate, expected.ThisUpdate)
}
if !reflect.DeepEqual(resp.NextUpdate, expected.NextUpdate) {
t.Errorf("resp.NextUpdate: got %d, want %d", resp.NextUpdate, expected.NextUpdate)
}
if resp.Status != expected.Status {
t.Errorf("resp.Status: got %d, want %d", resp.Status, expected.Status)
}
if !bytes.Equal(resp.SerialNumber, expected.SerialNumber) {
t.Errorf("resp.SerialNumber: got %x, want %x", resp.SerialNumber, expected.SerialNumber)
}
if resp.RevocationReason != expected.RevocationReason {
t.Errorf("resp.RevocationReason: got %d, want %d", resp.RevocationReason, expected.RevocationReason)
}
}
// This OCSP response was taken from Thawte's public OCSP responder.
// To recreate:
// $ openssl s_client -tls1 -showcerts -servername www.google.com -connect www.google.com:443
// Copy and paste the first certificate into /tmp/cert.crt and the second into
// /tmp/intermediate.crt
// $ openssl ocsp -issuer /tmp/intermediate.crt -cert /tmp/cert.crt -url http://ocsp.thawte.com -resp_text -respout /tmp/ocsp.der
// Then hex encode the result:
// $ python -c 'print file("/tmp/ocsp.der", "r").read().encode("hex")'
const ocspResponseHex = "308206bc0a0100a08206b5308206b106092b0601050507300101048206a23082069e3081" +
"c9a14e304c310b300906035504061302494c31163014060355040a130d5374617274436f" +
"6d204c74642e312530230603550403131c5374617274436f6d20436c6173732031204f43" +
"5350205369676e6572180f32303130303730373137333531375a30663064303c30090605" +
"2b0e03021a050004146568874f40750f016a3475625e1f5c93e5a26d580414eb4234d098" +
"b0ab9ff41b6b08f7cc642eef0e2c45020301d0fa8000180f323031303037303731353031" +
"30355aa011180f32303130303730373138333531375a300d06092a864886f70d01010505" +
"000382010100ab557ff070d1d7cebbb5f0ec91a15c3fed22eb2e1b8244f1b84545f013a4" +
"fb46214c5e3fbfbebb8a56acc2b9db19f68fd3c3201046b3824d5ba689f99864328710cb" +
"467195eb37d84f539e49f859316b32964dc3e47e36814ce94d6c56dd02733b1d0802f7ff" +
"4eebdbbd2927dcf580f16cbc290f91e81b53cb365e7223f1d6e20a88ea064104875e0145" +
"672b20fc14829d51ca122f5f5d77d3ad6c83889c55c7dc43680ba2fe3cef8b05dbcabdc0" +
"d3e09aaf9725597f8c858c2fa38c0d6aed2e6318194420dd1a1137445d13e1c97ab47896" +
"17a4e08925f46f867b72e3a4dc1f08cb870b2b0717f7207faa0ac512e628a029aba7457a" +
"e63dcf3281e2162d9349a08204ba308204b6308204b23082039aa003020102020101300d" +
"06092a864886f70d010105050030818c310b300906035504061302494c31163014060355" +
"040a130d5374617274436f6d204c74642e312b3029060355040b13225365637572652044" +
"69676974616c204365727469666963617465205369676e696e6731383036060355040313" +
"2f5374617274436f6d20436c6173732031205072696d61727920496e7465726d65646961" +
"746520536572766572204341301e170d3037313032353030323330365a170d3132313032" +
"333030323330365a304c310b300906035504061302494c31163014060355040a130d5374" +
"617274436f6d204c74642e312530230603550403131c5374617274436f6d20436c617373" +
"2031204f435350205369676e657230820122300d06092a864886f70d0101010500038201" +
"0f003082010a0282010100b9561b4c45318717178084e96e178df2255e18ed8d8ecc7c2b" +
"7b51a6c1c2e6bf0aa3603066f132fe10ae97b50e99fa24b83fc53dd2777496387d14e1c3" +
"a9b6a4933e2ac12413d085570a95b8147414a0bc007c7bcf222446ef7f1a156d7ea1c577" +
"fc5f0facdfd42eb0f5974990cb2f5cefebceef4d1bdc7ae5c1075c5a99a93171f2b0845b" +
"4ff0864e973fcfe32f9d7511ff87a3e943410c90a4493a306b6944359340a9ca96f02b66" +
"ce67f028df2980a6aaee8d5d5d452b8b0eb93f923cc1e23fcccbdbe7ffcb114d08fa7a6a" +
"3c404f825d1a0e715935cf623a8c7b59670014ed0622f6089a9447a7a19010f7fe58f841" +
"29a2765ea367824d1c3bb2fda308530203010001a382015c30820158300c0603551d1301" +
"01ff04023000300b0603551d0f0404030203a8301e0603551d250417301506082b060105" +
"0507030906092b0601050507300105301d0603551d0e0416041445e0a36695414c5dd449" +
"bc00e33cdcdbd2343e173081a80603551d230481a030819d8014eb4234d098b0ab9ff41b" +
"6b08f7cc642eef0e2c45a18181a47f307d310b300906035504061302494c311630140603" +
"55040a130d5374617274436f6d204c74642e312b3029060355040b132253656375726520" +
"4469676974616c204365727469666963617465205369676e696e67312930270603550403" +
"13205374617274436f6d2043657274696669636174696f6e20417574686f726974798201" +
"0a30230603551d12041c301a8618687474703a2f2f7777772e737461727473736c2e636f" +
"6d2f302c06096086480186f842010d041f161d5374617274436f6d205265766f63617469" +
"6f6e20417574686f72697479300d06092a864886f70d01010505000382010100182d2215" +
"8f0fc0291324fa8574c49bb8ff2835085adcbf7b7fc4191c397ab6951328253fffe1e5ec" +
"2a7da0d50fca1a404e6968481366939e666c0a6209073eca57973e2fefa9ed1718e8176f" +
"1d85527ff522c08db702e3b2b180f1cbff05d98128252cf0f450f7dd2772f4188047f19d" +
"c85317366f94bc52d60f453a550af58e308aaab00ced33040b62bf37f5b1ab2a4f7f0f80" +
"f763bf4d707bc8841d7ad9385ee2a4244469260b6f2bf085977af9074796048ecc2f9d48" +
"a1d24ce16e41a9941568fec5b42771e118f16c106a54ccc339a4b02166445a167902e75e" +
"6d8620b0825dcd18a069b90fd851d10fa8effd409deec02860d26d8d833f304b10669b42"

View File

@ -1,219 +0,0 @@
// 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 armor implements OpenPGP ASCII Armor, see RFC 4880. OpenPGP Armor is
// very similar to PEM except that it has an additional CRC checksum.
package armor
import (
"bufio"
"bytes"
"crypto/openpgp/errors"
"encoding/base64"
"io"
)
// A Block represents an OpenPGP armored structure.
//
// The encoded form is:
// -----BEGIN Type-----
// Headers
//
// base64-encoded Bytes
// '=' base64 encoded checksum
// -----END Type-----
// where Headers is a possibly empty sequence of Key: Value lines.
//
// Since the armored data can be very large, this package presents a streaming
// interface.
type Block struct {
Type string // The type, taken from the preamble (i.e. "PGP SIGNATURE").
Header map[string]string // Optional headers.
Body io.Reader // A Reader from which the contents can be read
lReader lineReader
oReader openpgpReader
}
var ArmorCorrupt error = errors.StructuralError("armor invalid")
const crc24Init = 0xb704ce
const crc24Poly = 0x1864cfb
const crc24Mask = 0xffffff
// crc24 calculates the OpenPGP checksum as specified in RFC 4880, section 6.1
func crc24(crc uint32, d []byte) uint32 {
for _, b := range d {
crc ^= uint32(b) << 16
for i := 0; i < 8; i++ {
crc <<= 1
if crc&0x1000000 != 0 {
crc ^= crc24Poly
}
}
}
return crc
}
var armorStart = []byte("-----BEGIN ")
var armorEnd = []byte("-----END ")
var armorEndOfLine = []byte("-----")
// lineReader wraps a line based reader. It watches for the end of an armor
// block and records the expected CRC value.
type lineReader struct {
in *bufio.Reader
buf []byte
eof bool
crc uint32
}
func (l *lineReader) Read(p []byte) (n int, err error) {
if l.eof {
return 0, io.EOF
}
if len(l.buf) > 0 {
n = copy(p, l.buf)
l.buf = l.buf[n:]
return
}
line, isPrefix, err := l.in.ReadLine()
if err != nil {
return
}
if isPrefix {
return 0, ArmorCorrupt
}
if len(line) == 5 && line[0] == '=' {
// This is the checksum line
var expectedBytes [3]byte
var m int
m, err = base64.StdEncoding.Decode(expectedBytes[0:], line[1:])
if m != 3 || err != nil {
return
}
l.crc = uint32(expectedBytes[0])<<16 |
uint32(expectedBytes[1])<<8 |
uint32(expectedBytes[2])
line, _, err = l.in.ReadLine()
if err != nil && err != io.EOF {
return
}
if !bytes.HasPrefix(line, armorEnd) {
return 0, ArmorCorrupt
}
l.eof = true
return 0, io.EOF
}
if len(line) > 64 {
return 0, ArmorCorrupt
}
n = copy(p, line)
bytesToSave := len(line) - n
if bytesToSave > 0 {
if cap(l.buf) < bytesToSave {
l.buf = make([]byte, 0, bytesToSave)
}
l.buf = l.buf[0:bytesToSave]
copy(l.buf, line[n:])
}
return
}
// openpgpReader passes Read calls to the underlying base64 decoder, but keeps
// a running CRC of the resulting data and checks the CRC against the value
// found by the lineReader at EOF.
type openpgpReader struct {
lReader *lineReader
b64Reader io.Reader
currentCRC uint32
}
func (r *openpgpReader) Read(p []byte) (n int, err error) {
n, err = r.b64Reader.Read(p)
r.currentCRC = crc24(r.currentCRC, p[:n])
if err == io.EOF {
if r.lReader.crc != uint32(r.currentCRC&crc24Mask) {
return 0, ArmorCorrupt
}
}
return
}
// Decode reads a PGP armored block from the given Reader. It will ignore
// leading garbage. If it doesn't find a block, it will return nil, io.EOF. The
// given Reader is not usable after calling this function: an arbitrary amount
// of data may have been read past the end of the block.
func Decode(in io.Reader) (p *Block, err error) {
r, _ := bufio.NewReaderSize(in, 100)
var line []byte
ignoreNext := false
TryNextBlock:
p = nil
// Skip leading garbage
for {
ignoreThis := ignoreNext
line, ignoreNext, err = r.ReadLine()
if err != nil {
return
}
if ignoreNext || ignoreThis {
continue
}
line = bytes.TrimSpace(line)
if len(line) > len(armorStart)+len(armorEndOfLine) && bytes.HasPrefix(line, armorStart) {
break
}
}
p = new(Block)
p.Type = string(line[len(armorStart) : len(line)-len(armorEndOfLine)])
p.Header = make(map[string]string)
nextIsContinuation := false
var lastKey string
// Read headers
for {
isContinuation := nextIsContinuation
line, nextIsContinuation, err = r.ReadLine()
if err != nil {
p = nil
return
}
if isContinuation {
p.Header[lastKey] += string(line)
continue
}
line = bytes.TrimSpace(line)
if len(line) == 0 {
break
}
i := bytes.Index(line, []byte(": "))
if i == -1 {
goto TryNextBlock
}
lastKey = string(line[:i])
p.Header[lastKey] = string(line[i+2:])
}
p.lReader.in = r
p.oReader.currentCRC = crc24Init
p.oReader.lReader = &p.lReader
p.oReader.b64Reader = base64.NewDecoder(base64.StdEncoding, &p.lReader)
p.Body = &p.oReader
return
}

View File

@ -1,95 +0,0 @@
// 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 armor
import (
"bytes"
"hash/adler32"
"io/ioutil"
"testing"
)
func TestDecodeEncode(t *testing.T) {
buf := bytes.NewBuffer([]byte(armorExample1))
result, err := Decode(buf)
if err != nil {
t.Error(err)
}
expectedType := "PGP SIGNATURE"
if result.Type != expectedType {
t.Errorf("result.Type: got:%s want:%s", result.Type, expectedType)
}
if len(result.Header) != 1 {
t.Errorf("len(result.Header): got:%d want:1", len(result.Header))
}
v, ok := result.Header["Version"]
if !ok || v != "GnuPG v1.4.10 (GNU/Linux)" {
t.Errorf("result.Header: got:%#v", result.Header)
}
contents, err := ioutil.ReadAll(result.Body)
if err != nil {
t.Error(err)
}
if adler32.Checksum(contents) != 0x27b144be {
t.Errorf("contents: got: %x", contents)
}
buf = bytes.NewBuffer(nil)
w, err := Encode(buf, result.Type, result.Header)
if err != nil {
t.Error(err)
}
_, err = w.Write(contents)
if err != nil {
t.Error(err)
}
w.Close()
if !bytes.Equal(buf.Bytes(), []byte(armorExample1)) {
t.Errorf("got: %s\nwant: %s", string(buf.Bytes()), armorExample1)
}
}
func TestLongHeader(t *testing.T) {
buf := bytes.NewBuffer([]byte(armorLongLine))
result, err := Decode(buf)
if err != nil {
t.Error(err)
return
}
value, ok := result.Header["Version"]
if !ok {
t.Errorf("missing Version header")
}
if value != longValueExpected {
t.Errorf("got: %s want: %s", value, longValueExpected)
}
}
const armorExample1 = `-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.10 (GNU/Linux)
iJwEAAECAAYFAk1Fv/0ACgkQo01+GMIMMbsYTwQAiAw+QAaNfY6WBdplZ/uMAccm
4g+81QPmTSGHnetSb6WBiY13kVzK4HQiZH8JSkmmroMLuGeJwsRTEL4wbjRyUKEt
p1xwUZDECs234F1xiG5enc5SGlRtP7foLBz9lOsjx+LEcA4sTl5/2eZR9zyFZqWW
TxRjs+fJCIFuo71xb1g=
=/teI
-----END PGP SIGNATURE-----`
const armorLongLine = `-----BEGIN PGP SIGNATURE-----
Version: 0123456789abcdefghijklmnopqrstuvwxyz0123456789abcdefghijklmnopqrstuvwxyz0123456789abcdefghijklmnopqrstuvwxyz0123456789abcdefghijklmnopqrstuvwxyz0123456789abcdefghijklmnopqrstuvwxyz0123456789abcdefghijklmnopqrstuvwxyz0123456789abcdefghijklmnopqrstuvwxyz0123456789abcdefghijklmnopqrstuvwxyz0123456789abcdefghijklmnopqrstuvwxyz
iQEcBAABAgAGBQJMtFESAAoJEKsQXJGvOPsVj40H/1WW6jaMXv4BW+1ueDSMDwM8
kx1fLOXbVM5/Kn5LStZNt1jWWnpxdz7eq3uiqeCQjmqUoRde3YbB2EMnnwRbAhpp
cacnAvy9ZQ78OTxUdNW1mhX5bS6q1MTEJnl+DcyigD70HG/yNNQD7sOPMdYQw0TA
byQBwmLwmTsuZsrYqB68QyLHI+DUugn+kX6Hd2WDB62DKa2suoIUIHQQCd/ofwB3
WfCYInXQKKOSxu2YOg2Eb4kLNhSMc1i9uKUWAH+sdgJh7NBgdoE4MaNtBFkHXRvv
okWuf3+xA9ksp1npSY/mDvgHijmjvtpRDe6iUeqfCn8N9u9CBg8geANgaG8+QA4=
=wfQG
-----END PGP SIGNATURE-----`
const longValueExpected = "0123456789abcdefghijklmnopqrstuvwxyz0123456789abcdefghijklmnopqrstuvwxyz0123456789abcdefghijklmnopqrstuvwxyz0123456789abcdefghijklmnopqrstuvwxyz0123456789abcdefghijklmnopqrstuvwxyz0123456789abcdefghijklmnopqrstuvwxyz0123456789abcdefghijklmnopqrstuvwxyz0123456789abcdefghijklmnopqrstuvwxyz0123456789abcdefghijklmnopqrstuvwxyz"

View File

@ -1,160 +0,0 @@
// 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 armor
import (
"encoding/base64"
"io"
)
var armorHeaderSep = []byte(": ")
var blockEnd = []byte("\n=")
var newline = []byte("\n")
var armorEndOfLineOut = []byte("-----\n")
// writeSlices writes its arguments to the given Writer.
func writeSlices(out io.Writer, slices ...[]byte) (err error) {
for _, s := range slices {
_, err = out.Write(s)
if err != nil {
return err
}
}
return
}
// lineBreaker breaks data across several lines, all of the same byte length
// (except possibly the last). Lines are broken with a single '\n'.
type lineBreaker struct {
lineLength int
line []byte
used int
out io.Writer
haveWritten bool
}
func newLineBreaker(out io.Writer, lineLength int) *lineBreaker {
return &lineBreaker{
lineLength: lineLength,
line: make([]byte, lineLength),
used: 0,
out: out,
}
}
func (l *lineBreaker) Write(b []byte) (n int, err error) {
n = len(b)
if n == 0 {
return
}
if l.used == 0 && l.haveWritten {
_, err = l.out.Write([]byte{'\n'})
if err != nil {
return
}
}
if l.used+len(b) < l.lineLength {
l.used += copy(l.line[l.used:], b)
return
}
l.haveWritten = true
_, err = l.out.Write(l.line[0:l.used])
if err != nil {
return
}
excess := l.lineLength - l.used
l.used = 0
_, err = l.out.Write(b[0:excess])
if err != nil {
return
}
_, err = l.Write(b[excess:])
return
}
func (l *lineBreaker) Close() (err error) {
if l.used > 0 {
_, err = l.out.Write(l.line[0:l.used])
if err != nil {
return
}
}
return
}
// encoding keeps track of a running CRC24 over the data which has been written
// to it and outputs a OpenPGP checksum when closed, followed by an armor
// trailer.
//
// It's built into a stack of io.Writers:
// encoding -> base64 encoder -> lineBreaker -> out
type encoding struct {
out io.Writer
breaker *lineBreaker
b64 io.WriteCloser
crc uint32
blockType []byte
}
func (e *encoding) Write(data []byte) (n int, err error) {
e.crc = crc24(e.crc, data)
return e.b64.Write(data)
}
func (e *encoding) Close() (err error) {
err = e.b64.Close()
if err != nil {
return
}
e.breaker.Close()
var checksumBytes [3]byte
checksumBytes[0] = byte(e.crc >> 16)
checksumBytes[1] = byte(e.crc >> 8)
checksumBytes[2] = byte(e.crc)
var b64ChecksumBytes [4]byte
base64.StdEncoding.Encode(b64ChecksumBytes[:], checksumBytes[:])
return writeSlices(e.out, blockEnd, b64ChecksumBytes[:], newline, armorEnd, e.blockType, armorEndOfLine)
}
// Encode returns a WriteCloser which will encode the data written to it in
// OpenPGP armor.
func Encode(out io.Writer, blockType string, headers map[string]string) (w io.WriteCloser, err error) {
bType := []byte(blockType)
err = writeSlices(out, armorStart, bType, armorEndOfLineOut)
if err != nil {
return
}
for k, v := range headers {
err = writeSlices(out, []byte(k), armorHeaderSep, []byte(v), newline)
if err != nil {
return
}
}
_, err = out.Write(newline)
if err != nil {
return
}
e := &encoding{
out: out,
breaker: newLineBreaker(out, 64),
crc: crc24Init,
blockType: bType,
}
e.b64 = base64.NewEncoder(base64.StdEncoding, e.breaker)
return e, nil
}

View File

@ -1,59 +0,0 @@
// 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 openpgp
import "hash"
// NewCanonicalTextHash reformats text written to it into the canonical
// form and then applies the hash h. See RFC 4880, section 5.2.1.
func NewCanonicalTextHash(h hash.Hash) hash.Hash {
return &canonicalTextHash{h, 0}
}
type canonicalTextHash struct {
h hash.Hash
s int
}
var newline = []byte{'\r', '\n'}
func (cth *canonicalTextHash) Write(buf []byte) (int, error) {
start := 0
for i, c := range buf {
switch cth.s {
case 0:
if c == '\r' {
cth.s = 1
} else if c == '\n' {
cth.h.Write(buf[start:i])
cth.h.Write(newline)
start = i + 1
}
case 1:
cth.s = 0
}
}
cth.h.Write(buf[start:])
return len(buf), nil
}
func (cth *canonicalTextHash) Sum(in []byte) []byte {
return cth.h.Sum(in)
}
func (cth *canonicalTextHash) Reset() {
cth.h.Reset()
cth.s = 0
}
func (cth *canonicalTextHash) Size() int {
return cth.h.Size()
}
func (cth *canonicalTextHash) BlockSize() int {
return cth.h.BlockSize()
}

View File

@ -1,52 +0,0 @@
// 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 openpgp
import (
"bytes"
"testing"
)
type recordingHash struct {
buf *bytes.Buffer
}
func (r recordingHash) Write(b []byte) (n int, err error) {
return r.buf.Write(b)
}
func (r recordingHash) Sum(in []byte) []byte {
return append(in, r.buf.Bytes()...)
}
func (r recordingHash) Reset() {
panic("shouldn't be called")
}
func (r recordingHash) Size() int {
panic("shouldn't be called")
}
func (r recordingHash) BlockSize() int {
panic("shouldn't be called")
}
func testCanonicalText(t *testing.T, input, expected string) {
r := recordingHash{bytes.NewBuffer(nil)}
c := NewCanonicalTextHash(r)
c.Write([]byte(input))
result := c.Sum(nil)
if expected != string(result) {
t.Errorf("input: %x got: %x want: %x", input, result, expected)
}
}
func TestCanonicalText(t *testing.T) {
testCanonicalText(t, "foo\n", "foo\r\n")
testCanonicalText(t, "foo", "foo")
testCanonicalText(t, "foo\r\n", "foo\r\n")
testCanonicalText(t, "foo\r\nbar", "foo\r\nbar")
testCanonicalText(t, "foo\r\nbar\n\n", "foo\r\nbar\r\n\r\n")
}

View File

@ -1,122 +0,0 @@
// 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 elgamal implements ElGamal encryption, suitable for OpenPGP,
// as specified in "A Public-Key Cryptosystem and a Signature Scheme Based on
// Discrete Logarithms," IEEE Transactions on Information Theory, v. IT-31,
// n. 4, 1985, pp. 469-472.
//
// This form of ElGamal embeds PKCS#1 v1.5 padding, which may make it
// unsuitable for other protocols. RSA should be used in preference in any
// case.
package elgamal
import (
"crypto/rand"
"crypto/subtle"
"errors"
"io"
"math/big"
)
// PublicKey represents an ElGamal public key.
type PublicKey struct {
G, P, Y *big.Int
}
// PrivateKey represents an ElGamal private key.
type PrivateKey struct {
PublicKey
X *big.Int
}
// Encrypt encrypts the given message to the given public key. The result is a
// pair of integers. Errors can result from reading random, or because msg is
// too large to be encrypted to the public key.
func Encrypt(random io.Reader, pub *PublicKey, msg []byte) (c1, c2 *big.Int, err error) {
pLen := (pub.P.BitLen() + 7) / 8
if len(msg) > pLen-11 {
err = errors.New("elgamal: message too long")
return
}
// EM = 0x02 || PS || 0x00 || M
em := make([]byte, pLen-1)
em[0] = 2
ps, mm := em[1:len(em)-len(msg)-1], em[len(em)-len(msg):]
err = nonZeroRandomBytes(ps, random)
if err != nil {
return
}
em[len(em)-len(msg)-1] = 0
copy(mm, msg)
m := new(big.Int).SetBytes(em)
k, err := rand.Int(random, pub.P)
if err != nil {
return
}
c1 = new(big.Int).Exp(pub.G, k, pub.P)
s := new(big.Int).Exp(pub.Y, k, pub.P)
c2 = s.Mul(s, m)
c2.Mod(c2, pub.P)
return
}
// Decrypt takes two integers, resulting from an ElGamal encryption, and
// returns the plaintext of the message. An error can result only if the
// ciphertext is invalid. Users should keep in mind that this is a padding
// oracle and thus, if exposed to an adaptive chosen ciphertext attack, can
// be used to break the cryptosystem. See ``Chosen Ciphertext Attacks
// Against Protocols Based on the RSA Encryption Standard PKCS #1'', Daniel
// Bleichenbacher, Advances in Cryptology (Crypto '98),
func Decrypt(priv *PrivateKey, c1, c2 *big.Int) (msg []byte, err error) {
s := new(big.Int).Exp(c1, priv.X, priv.P)
s.ModInverse(s, priv.P)
s.Mul(s, c2)
s.Mod(s, priv.P)
em := s.Bytes()
firstByteIsTwo := subtle.ConstantTimeByteEq(em[0], 2)
// The remainder of the plaintext must be a string of non-zero random
// octets, followed by a 0, followed by the message.
// lookingForIndex: 1 iff we are still looking for the zero.
// index: the offset of the first zero byte.
var lookingForIndex, index int
lookingForIndex = 1
for i := 1; i < len(em); i++ {
equals0 := subtle.ConstantTimeByteEq(em[i], 0)
index = subtle.ConstantTimeSelect(lookingForIndex&equals0, i, index)
lookingForIndex = subtle.ConstantTimeSelect(equals0, 0, lookingForIndex)
}
if firstByteIsTwo != 1 || lookingForIndex != 0 || index < 9 {
return nil, errors.New("elgamal: decryption error")
}
return em[index+1:], nil
}
// nonZeroRandomBytes fills the given slice with non-zero random octets.
func nonZeroRandomBytes(s []byte, rand io.Reader) (err error) {
_, err = io.ReadFull(rand, s)
if err != nil {
return
}
for i := 0; i < len(s); i++ {
for s[i] == 0 {
_, err = io.ReadFull(rand, s[i:i+1])
if err != nil {
return
}
}
}
return
}

View File

@ -1,49 +0,0 @@
// 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 elgamal
import (
"bytes"
"crypto/rand"
"math/big"
"testing"
)
// This is the 1024-bit MODP group from RFC 5114, section 2.1:
const primeHex = "B10B8F96A080E01DDE92DE5EAE5D54EC52C99FBCFB06A3C69A6A9DCA52D23B616073E28675A23D189838EF1E2EE652C013ECB4AEA906112324975C3CD49B83BFACCBDD7D90C4BD7098488E9C219A73724EFFD6FAE5644738FAA31A4FF55BCCC0A151AF5F0DC8B4BD45BF37DF365C1A65E68CFDA76D4DA708DF1FB2BC2E4A4371"
const generatorHex = "A4D1CBD5C3FD34126765A442EFB99905F8104DD258AC507FD6406CFF14266D31266FEA1E5C41564B777E690F5504F213160217B4B01B886A5E91547F9E2749F4D7FBD7D3B9A92EE1909D0D2263F80A76A6A24C087A091F531DBF0A0169B6A28AD662A4D18E73AFA32D779D5918D08BC8858F4DCEF97C2A24855E6EEB22B3B2E5"
func fromHex(hex string) *big.Int {
n, ok := new(big.Int).SetString(hex, 16)
if !ok {
panic("failed to parse hex number")
}
return n
}
func TestEncryptDecrypt(t *testing.T) {
priv := &PrivateKey{
PublicKey: PublicKey{
G: fromHex(generatorHex),
P: fromHex(primeHex),
},
X: fromHex("42"),
}
priv.Y = new(big.Int).Exp(priv.G, priv.X, priv.P)
message := []byte("hello world")
c1, c2, err := Encrypt(rand.Reader, &priv.PublicKey, message)
if err != nil {
t.Errorf("error encrypting: %s", err)
}
message2, err := Decrypt(priv, c1, c2)
if err != nil {
t.Errorf("error decrypting: %s", err)
}
if !bytes.Equal(message2, message) {
t.Errorf("decryption failed, got: %x, want: %x", message2, message)
}
}

View File

@ -1,64 +0,0 @@
// 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 errors contains common error types for the OpenPGP packages.
package errors
import (
"strconv"
)
// A StructuralError is returned when OpenPGP data is found to be syntactically
// invalid.
type StructuralError string
func (s StructuralError) Error() string {
return "OpenPGP data invalid: " + string(s)
}
// UnsupportedError indicates that, although the OpenPGP data is valid, it
// makes use of currently unimplemented features.
type UnsupportedError string
func (s UnsupportedError) Error() string {
return "OpenPGP feature unsupported: " + string(s)
}
// InvalidArgumentError indicates that the caller is in error and passed an
// incorrect value.
type InvalidArgumentError string
func (i InvalidArgumentError) Error() string {
return "OpenPGP argument invalid: " + string(i)
}
// SignatureError indicates that a syntactically valid signature failed to
// validate.
type SignatureError string
func (b SignatureError) Error() string {
return "OpenPGP signature invalid: " + string(b)
}
type keyIncorrectError int
func (ki keyIncorrectError) Error() string {
return "the given key was incorrect"
}
var KeyIncorrectError = keyIncorrectError(0)
type unknownIssuerError int
func (unknownIssuerError) Error() string {
return "signature make by unknown entity"
}
var UnknownIssuerError = unknownIssuerError(0)
type UnknownPacketTypeError uint8
func (upte UnknownPacketTypeError) Error() string {
return "unknown OpenPGP packet type: " + strconv.Itoa(int(upte))
}

View File

@ -1,546 +0,0 @@
// 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 openpgp
import (
"crypto"
"crypto/openpgp/armor"
"crypto/openpgp/errors"
"crypto/openpgp/packet"
"crypto/rand"
"crypto/rsa"
"io"
"time"
)
// PublicKeyType is the armor type for a PGP public key.
var PublicKeyType = "PGP PUBLIC KEY BLOCK"
// PrivateKeyType is the armor type for a PGP private key.
var PrivateKeyType = "PGP PRIVATE KEY BLOCK"
// An Entity represents the components of an OpenPGP key: a primary public key
// (which must be a signing key), one or more identities claimed by that key,
// and zero or more subkeys, which may be encryption keys.
type Entity struct {
PrimaryKey *packet.PublicKey
PrivateKey *packet.PrivateKey
Identities map[string]*Identity // indexed by Identity.Name
Subkeys []Subkey
}
// An Identity represents an identity claimed by an Entity and zero or more
// assertions by other entities about that claim.
type Identity struct {
Name string // by convention, has the form "Full Name (comment) <email@example.com>"
UserId *packet.UserId
SelfSignature *packet.Signature
Signatures []*packet.Signature
}
// A Subkey is an additional public key in an Entity. Subkeys can be used for
// encryption.
type Subkey struct {
PublicKey *packet.PublicKey
PrivateKey *packet.PrivateKey
Sig *packet.Signature
}
// A Key identifies a specific public key in an Entity. This is either the
// Entity's primary key or a subkey.
type Key struct {
Entity *Entity
PublicKey *packet.PublicKey
PrivateKey *packet.PrivateKey
SelfSignature *packet.Signature
}
// A KeyRing provides access to public and private keys.
type KeyRing interface {
// KeysById returns the set of keys that have the given key id.
KeysById(id uint64) []Key
// DecryptionKeys returns all private keys that are valid for
// decryption.
DecryptionKeys() []Key
}
// primaryIdentity returns the Identity marked as primary or the first identity
// if none are so marked.
func (e *Entity) primaryIdentity() *Identity {
var firstIdentity *Identity
for _, ident := range e.Identities {
if firstIdentity == nil {
firstIdentity = ident
}
if ident.SelfSignature.IsPrimaryId != nil && *ident.SelfSignature.IsPrimaryId {
return ident
}
}
return firstIdentity
}
// encryptionKey returns the best candidate Key for encrypting a message to the
// given Entity.
func (e *Entity) encryptionKey() Key {
candidateSubkey := -1
for i, subkey := range e.Subkeys {
if subkey.Sig.FlagsValid && subkey.Sig.FlagEncryptCommunications && subkey.PublicKey.PubKeyAlgo.CanEncrypt() {
candidateSubkey = i
break
}
}
i := e.primaryIdentity()
if e.PrimaryKey.PubKeyAlgo.CanEncrypt() {
// If we don't have any candidate subkeys for encryption and
// the primary key doesn't have any usage metadata then we
// assume that the primary key is ok. Or, if the primary key is
// marked as ok to encrypt to, then we can obviously use it.
if candidateSubkey == -1 && !i.SelfSignature.FlagsValid || i.SelfSignature.FlagEncryptCommunications && i.SelfSignature.FlagsValid {
return Key{e, e.PrimaryKey, e.PrivateKey, i.SelfSignature}
}
}
if candidateSubkey != -1 {
subkey := e.Subkeys[candidateSubkey]
return Key{e, subkey.PublicKey, subkey.PrivateKey, subkey.Sig}
}
// This Entity appears to be signing only.
return Key{}
}
// signingKey return the best candidate Key for signing a message with this
// Entity.
func (e *Entity) signingKey() Key {
candidateSubkey := -1
for i, subkey := range e.Subkeys {
if subkey.Sig.FlagsValid && subkey.Sig.FlagSign && subkey.PublicKey.PubKeyAlgo.CanSign() {
candidateSubkey = i
break
}
}
i := e.primaryIdentity()
// If we have no candidate subkey then we assume that it's ok to sign
// with the primary key.
if candidateSubkey == -1 || i.SelfSignature.FlagsValid && i.SelfSignature.FlagSign {
return Key{e, e.PrimaryKey, e.PrivateKey, i.SelfSignature}
}
subkey := e.Subkeys[candidateSubkey]
return Key{e, subkey.PublicKey, subkey.PrivateKey, subkey.Sig}
}
// An EntityList contains one or more Entities.
type EntityList []*Entity
// KeysById returns the set of keys that have the given key id.
func (el EntityList) KeysById(id uint64) (keys []Key) {
for _, e := range el {
if e.PrimaryKey.KeyId == id {
var selfSig *packet.Signature
for _, ident := range e.Identities {
if selfSig == nil {
selfSig = ident.SelfSignature
} else if ident.SelfSignature.IsPrimaryId != nil && *ident.SelfSignature.IsPrimaryId {
selfSig = ident.SelfSignature
break
}
}
keys = append(keys, Key{e, e.PrimaryKey, e.PrivateKey, selfSig})
}
for _, subKey := range e.Subkeys {
if subKey.PublicKey.KeyId == id {
keys = append(keys, Key{e, subKey.PublicKey, subKey.PrivateKey, subKey.Sig})
}
}
}
return
}
// DecryptionKeys returns all private keys that are valid for decryption.
func (el EntityList) DecryptionKeys() (keys []Key) {
for _, e := range el {
for _, subKey := range e.Subkeys {
if subKey.PrivateKey != nil && (!subKey.Sig.FlagsValid || subKey.Sig.FlagEncryptStorage || subKey.Sig.FlagEncryptCommunications) {
keys = append(keys, Key{e, subKey.PublicKey, subKey.PrivateKey, subKey.Sig})
}
}
}
return
}
// ReadArmoredKeyRing reads one or more public/private keys from an armor keyring file.
func ReadArmoredKeyRing(r io.Reader) (EntityList, error) {
block, err := armor.Decode(r)
if err == io.EOF {
return nil, errors.InvalidArgumentError("no armored data found")
}
if err != nil {
return nil, err
}
if block.Type != PublicKeyType && block.Type != PrivateKeyType {
return nil, errors.InvalidArgumentError("expected public or private key block, got: " + block.Type)
}
return ReadKeyRing(block.Body)
}
// ReadKeyRing reads one or more public/private keys. Unsupported keys are
// ignored as long as at least a single valid key is found.
func ReadKeyRing(r io.Reader) (el EntityList, err error) {
packets := packet.NewReader(r)
var lastUnsupportedError error
for {
var e *Entity
e, err = readEntity(packets)
if err != nil {
if _, ok := err.(errors.UnsupportedError); ok {
lastUnsupportedError = err
err = readToNextPublicKey(packets)
}
if err == io.EOF {
err = nil
break
}
if err != nil {
el = nil
break
}
} else {
el = append(el, e)
}
}
if len(el) == 0 && err == nil {
err = lastUnsupportedError
}
return
}
// readToNextPublicKey reads packets until the start of the entity and leaves
// the first packet of the new entity in the Reader.
func readToNextPublicKey(packets *packet.Reader) (err error) {
var p packet.Packet
for {
p, err = packets.Next()
if err == io.EOF {
return
} else if err != nil {
if _, ok := err.(errors.UnsupportedError); ok {
err = nil
continue
}
return
}
if pk, ok := p.(*packet.PublicKey); ok && !pk.IsSubkey {
packets.Unread(p)
return
}
}
panic("unreachable")
}
// readEntity reads an entity (public key, identities, subkeys etc) from the
// given Reader.
func readEntity(packets *packet.Reader) (*Entity, error) {
e := new(Entity)
e.Identities = make(map[string]*Identity)
p, err := packets.Next()
if err != nil {
return nil, err
}
var ok bool
if e.PrimaryKey, ok = p.(*packet.PublicKey); !ok {
if e.PrivateKey, ok = p.(*packet.PrivateKey); !ok {
packets.Unread(p)
return nil, errors.StructuralError("first packet was not a public/private key")
} else {
e.PrimaryKey = &e.PrivateKey.PublicKey
}
}
if !e.PrimaryKey.PubKeyAlgo.CanSign() {
return nil, errors.StructuralError("primary key cannot be used for signatures")
}
var current *Identity
EachPacket:
for {
p, err := packets.Next()
if err == io.EOF {
break
} else if err != nil {
return nil, err
}
switch pkt := p.(type) {
case *packet.UserId:
current = new(Identity)
current.Name = pkt.Id
current.UserId = pkt
e.Identities[pkt.Id] = current
for {
p, err = packets.Next()
if err == io.EOF {
return nil, io.ErrUnexpectedEOF
} else if err != nil {
return nil, err
}
sig, ok := p.(*packet.Signature)
if !ok {
return nil, errors.StructuralError("user ID packet not followed by self-signature")
}
if (sig.SigType == packet.SigTypePositiveCert || sig.SigType == packet.SigTypeGenericCert) && sig.IssuerKeyId != nil && *sig.IssuerKeyId == e.PrimaryKey.KeyId {
if err = e.PrimaryKey.VerifyUserIdSignature(pkt.Id, sig); err != nil {
return nil, errors.StructuralError("user ID self-signature invalid: " + err.Error())
}
current.SelfSignature = sig
break
}
current.Signatures = append(current.Signatures, sig)
}
case *packet.Signature:
if current == nil {
return nil, errors.StructuralError("signature packet found before user id packet")
}
current.Signatures = append(current.Signatures, pkt)
case *packet.PrivateKey:
if pkt.IsSubkey == false {
packets.Unread(p)
break EachPacket
}
err = addSubkey(e, packets, &pkt.PublicKey, pkt)
if err != nil {
return nil, err
}
case *packet.PublicKey:
if pkt.IsSubkey == false {
packets.Unread(p)
break EachPacket
}
err = addSubkey(e, packets, pkt, nil)
if err != nil {
return nil, err
}
default:
// we ignore unknown packets
}
}
if len(e.Identities) == 0 {
return nil, errors.StructuralError("entity without any identities")
}
return e, nil
}
func addSubkey(e *Entity, packets *packet.Reader, pub *packet.PublicKey, priv *packet.PrivateKey) error {
var subKey Subkey
subKey.PublicKey = pub
subKey.PrivateKey = priv
p, err := packets.Next()
if err == io.EOF {
return io.ErrUnexpectedEOF
}
if err != nil {
return errors.StructuralError("subkey signature invalid: " + err.Error())
}
var ok bool
subKey.Sig, ok = p.(*packet.Signature)
if !ok {
return errors.StructuralError("subkey packet not followed by signature")
}
if subKey.Sig.SigType != packet.SigTypeSubkeyBinding {
return errors.StructuralError("subkey signature with wrong type")
}
err = e.PrimaryKey.VerifyKeySignature(subKey.PublicKey, subKey.Sig)
if err != nil {
return errors.StructuralError("subkey signature invalid: " + err.Error())
}
e.Subkeys = append(e.Subkeys, subKey)
return nil
}
const defaultRSAKeyBits = 2048
// NewEntity returns an Entity that contains a fresh RSA/RSA keypair with a
// single identity composed of the given full name, comment and email, any of
// which may be empty but must not contain any of "()<>\x00".
func NewEntity(rand io.Reader, currentTime time.Time, name, comment, email string) (*Entity, error) {
uid := packet.NewUserId(name, comment, email)
if uid == nil {
return nil, errors.InvalidArgumentError("user id field contained invalid characters")
}
signingPriv, err := rsa.GenerateKey(rand, defaultRSAKeyBits)
if err != nil {
return nil, err
}
encryptingPriv, err := rsa.GenerateKey(rand, defaultRSAKeyBits)
if err != nil {
return nil, err
}
e := &Entity{
PrimaryKey: packet.NewRSAPublicKey(currentTime, &signingPriv.PublicKey),
PrivateKey: packet.NewRSAPrivateKey(currentTime, signingPriv),
Identities: make(map[string]*Identity),
}
isPrimaryId := true
e.Identities[uid.Id] = &Identity{
Name: uid.Name,
UserId: uid,
SelfSignature: &packet.Signature{
CreationTime: currentTime,
SigType: packet.SigTypePositiveCert,
PubKeyAlgo: packet.PubKeyAlgoRSA,
Hash: crypto.SHA256,
IsPrimaryId: &isPrimaryId,
FlagsValid: true,
FlagSign: true,
FlagCertify: true,
IssuerKeyId: &e.PrimaryKey.KeyId,
},
}
e.Subkeys = make([]Subkey, 1)
e.Subkeys[0] = Subkey{
PublicKey: packet.NewRSAPublicKey(currentTime, &encryptingPriv.PublicKey),
PrivateKey: packet.NewRSAPrivateKey(currentTime, encryptingPriv),
Sig: &packet.Signature{
CreationTime: currentTime,
SigType: packet.SigTypeSubkeyBinding,
PubKeyAlgo: packet.PubKeyAlgoRSA,
Hash: crypto.SHA256,
FlagsValid: true,
FlagEncryptStorage: true,
FlagEncryptCommunications: true,
IssuerKeyId: &e.PrimaryKey.KeyId,
},
}
e.Subkeys[0].PublicKey.IsSubkey = true
e.Subkeys[0].PrivateKey.IsSubkey = true
return e, nil
}
// SerializePrivate serializes an Entity, including private key material, to
// the given Writer. For now, it must only be used on an Entity returned from
// NewEntity.
func (e *Entity) SerializePrivate(w io.Writer) (err error) {
err = e.PrivateKey.Serialize(w)
if err != nil {
return
}
for _, ident := range e.Identities {
err = ident.UserId.Serialize(w)
if err != nil {
return
}
err = ident.SelfSignature.SignUserId(rand.Reader, ident.UserId.Id, e.PrimaryKey, e.PrivateKey)
if err != nil {
return
}
err = ident.SelfSignature.Serialize(w)
if err != nil {
return
}
}
for _, subkey := range e.Subkeys {
err = subkey.PrivateKey.Serialize(w)
if err != nil {
return
}
err = subkey.Sig.SignKey(rand.Reader, subkey.PublicKey, e.PrivateKey)
if err != nil {
return
}
err = subkey.Sig.Serialize(w)
if err != nil {
return
}
}
return nil
}
// Serialize writes the public part of the given Entity to w. (No private
// key material will be output).
func (e *Entity) Serialize(w io.Writer) error {
err := e.PrimaryKey.Serialize(w)
if err != nil {
return err
}
for _, ident := range e.Identities {
err = ident.UserId.Serialize(w)
if err != nil {
return err
}
err = ident.SelfSignature.Serialize(w)
if err != nil {
return err
}
for _, sig := range ident.Signatures {
err = sig.Serialize(w)
if err != nil {
return err
}
}
}
for _, subkey := range e.Subkeys {
err = subkey.PublicKey.Serialize(w)
if err != nil {
return err
}
err = subkey.Sig.Serialize(w)
if err != nil {
return err
}
}
return nil
}
// SignIdentity adds a signature to e, from signer, attesting that identity is
// associated with e. The provided identity must already be an element of
// e.Identities and the private key of signer must have been decrypted if
// necessary.
func (e *Entity) SignIdentity(identity string, signer *Entity) error {
if signer.PrivateKey == nil {
return errors.InvalidArgumentError("signing Entity must have a private key")
}
if signer.PrivateKey.Encrypted {
return errors.InvalidArgumentError("signing Entity's private key must be decrypted")
}
ident, ok := e.Identities[identity]
if !ok {
return errors.InvalidArgumentError("given identity string not found in Entity")
}
sig := &packet.Signature{
SigType: packet.SigTypeGenericCert,
PubKeyAlgo: signer.PrivateKey.PubKeyAlgo,
Hash: crypto.SHA256,
CreationTime: time.Now(),
IssuerKeyId: &signer.PrivateKey.KeyId,
}
if err := sig.SignKey(rand.Reader, e.PrimaryKey, signer.PrivateKey); err != nil {
return err
}
ident.Signatures = append(ident.Signatures, sig)
return nil
}

View File

@ -1,38 +0,0 @@
// 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 packet
import (
"compress/flate"
"compress/zlib"
"crypto/openpgp/errors"
"io"
"strconv"
)
// Compressed represents a compressed OpenPGP packet. The decompressed contents
// will contain more OpenPGP packets. See RFC 4880, section 5.6.
type Compressed struct {
Body io.Reader
}
func (c *Compressed) parse(r io.Reader) error {
var buf [1]byte
_, err := readFull(r, buf[:])
if err != nil {
return err
}
switch buf[0] {
case 1:
c.Body = flate.NewReader(r)
case 2:
c.Body, err = zlib.NewReader(r)
default:
err = errors.UnsupportedError("unknown compression algorithm: " + strconv.Itoa(int(buf[0])))
}
return err
}

View File

@ -1,41 +0,0 @@
// 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 packet
import (
"bytes"
"encoding/hex"
"io"
"io/ioutil"
"testing"
)
func TestCompressed(t *testing.T) {
packet, err := Read(readerFromHex(compressedHex))
if err != nil {
t.Errorf("failed to read Compressed: %s", err)
return
}
c, ok := packet.(*Compressed)
if !ok {
t.Error("didn't find Compressed packet")
return
}
contents, err := ioutil.ReadAll(c.Body)
if err != nil && err != io.EOF {
t.Error(err)
return
}
expected, _ := hex.DecodeString(compressedExpectedHex)
if !bytes.Equal(expected, contents) {
t.Errorf("got:%x want:%x", contents, expected)
}
}
const compressedHex = "a3013b2d90c4e02b72e25f727e5e496a5e49b11e1700"
const compressedExpectedHex = "cb1062004d14c8fe636f6e74656e74732e0a"

View File

@ -1,167 +0,0 @@
// 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 packet
import (
"crypto/openpgp/elgamal"
"crypto/openpgp/errors"
"crypto/rand"
"crypto/rsa"
"encoding/binary"
"io"
"math/big"
"strconv"
)
const encryptedKeyVersion = 3
// EncryptedKey represents a public-key encrypted session key. See RFC 4880,
// section 5.1.
type EncryptedKey struct {
KeyId uint64
Algo PublicKeyAlgorithm
CipherFunc CipherFunction // only valid after a successful Decrypt
Key []byte // only valid after a successful Decrypt
encryptedMPI1, encryptedMPI2 []byte
}
func (e *EncryptedKey) parse(r io.Reader) (err error) {
var buf [10]byte
_, err = readFull(r, buf[:])
if err != nil {
return
}
if buf[0] != encryptedKeyVersion {
return errors.UnsupportedError("unknown EncryptedKey version " + strconv.Itoa(int(buf[0])))
}
e.KeyId = binary.BigEndian.Uint64(buf[1:9])
e.Algo = PublicKeyAlgorithm(buf[9])
switch e.Algo {
case PubKeyAlgoRSA, PubKeyAlgoRSAEncryptOnly:
e.encryptedMPI1, _, err = readMPI(r)
case PubKeyAlgoElGamal:
e.encryptedMPI1, _, err = readMPI(r)
if err != nil {
return
}
e.encryptedMPI2, _, err = readMPI(r)
}
_, err = consumeAll(r)
return
}
func checksumKeyMaterial(key []byte) uint16 {
var checksum uint16
for _, v := range key {
checksum += uint16(v)
}
return checksum
}
// Decrypt decrypts an encrypted session key with the given private key. The
// private key must have been decrypted first.
func (e *EncryptedKey) Decrypt(priv *PrivateKey) error {
var err error
var b []byte
// TODO(agl): use session key decryption routines here to avoid
// padding oracle attacks.
switch priv.PubKeyAlgo {
case PubKeyAlgoRSA, PubKeyAlgoRSAEncryptOnly:
b, err = rsa.DecryptPKCS1v15(rand.Reader, priv.PrivateKey.(*rsa.PrivateKey), e.encryptedMPI1)
case PubKeyAlgoElGamal:
c1 := new(big.Int).SetBytes(e.encryptedMPI1)
c2 := new(big.Int).SetBytes(e.encryptedMPI2)
b, err = elgamal.Decrypt(priv.PrivateKey.(*elgamal.PrivateKey), c1, c2)
default:
err = errors.InvalidArgumentError("cannot decrypted encrypted session key with private key of type " + strconv.Itoa(int(priv.PubKeyAlgo)))
}
if err != nil {
return err
}
e.CipherFunc = CipherFunction(b[0])
e.Key = b[1 : len(b)-2]
expectedChecksum := uint16(b[len(b)-2])<<8 | uint16(b[len(b)-1])
checksum := checksumKeyMaterial(e.Key)
if checksum != expectedChecksum {
return errors.StructuralError("EncryptedKey checksum incorrect")
}
return nil
}
// SerializeEncryptedKey serializes an encrypted key packet to w that contains
// key, encrypted to pub.
func SerializeEncryptedKey(w io.Writer, rand io.Reader, pub *PublicKey, cipherFunc CipherFunction, key []byte) error {
var buf [10]byte
buf[0] = encryptedKeyVersion
binary.BigEndian.PutUint64(buf[1:9], pub.KeyId)
buf[9] = byte(pub.PubKeyAlgo)
keyBlock := make([]byte, 1 /* cipher type */ +len(key)+2 /* checksum */ )
keyBlock[0] = byte(cipherFunc)
copy(keyBlock[1:], key)
checksum := checksumKeyMaterial(key)
keyBlock[1+len(key)] = byte(checksum >> 8)
keyBlock[1+len(key)+1] = byte(checksum)
switch pub.PubKeyAlgo {
case PubKeyAlgoRSA, PubKeyAlgoRSAEncryptOnly:
return serializeEncryptedKeyRSA(w, rand, buf, pub.PublicKey.(*rsa.PublicKey), keyBlock)
case PubKeyAlgoElGamal:
return serializeEncryptedKeyElGamal(w, rand, buf, pub.PublicKey.(*elgamal.PublicKey), keyBlock)
case PubKeyAlgoDSA, PubKeyAlgoRSASignOnly:
return errors.InvalidArgumentError("cannot encrypt to public key of type " + strconv.Itoa(int(pub.PubKeyAlgo)))
}
return errors.UnsupportedError("encrypting a key to public key of type " + strconv.Itoa(int(pub.PubKeyAlgo)))
}
func serializeEncryptedKeyRSA(w io.Writer, rand io.Reader, header [10]byte, pub *rsa.PublicKey, keyBlock []byte) error {
cipherText, err := rsa.EncryptPKCS1v15(rand, pub, keyBlock)
if err != nil {
return errors.InvalidArgumentError("RSA encryption failed: " + err.Error())
}
packetLen := 10 /* header length */ + 2 /* mpi size */ + len(cipherText)
err = serializeHeader(w, packetTypeEncryptedKey, packetLen)
if err != nil {
return err
}
_, err = w.Write(header[:])
if err != nil {
return err
}
return writeMPI(w, 8*uint16(len(cipherText)), cipherText)
}
func serializeEncryptedKeyElGamal(w io.Writer, rand io.Reader, header [10]byte, pub *elgamal.PublicKey, keyBlock []byte) error {
c1, c2, err := elgamal.Encrypt(rand, pub, keyBlock)
if err != nil {
return errors.InvalidArgumentError("ElGamal encryption failed: " + err.Error())
}
packetLen := 10 /* header length */
packetLen += 2 /* mpi size */ + (c1.BitLen()+7)/8
packetLen += 2 /* mpi size */ + (c2.BitLen()+7)/8
err = serializeHeader(w, packetTypeEncryptedKey, packetLen)
if err != nil {
return err
}
_, err = w.Write(header[:])
if err != nil {
return err
}
err = writeBig(w, c1)
if err != nil {
return err
}
return writeBig(w, c2)
}

View File

@ -1,126 +0,0 @@
// 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 packet
import (
"bytes"
"crypto/rand"
"crypto/rsa"
"fmt"
"math/big"
"testing"
)
func bigFromBase10(s string) *big.Int {
b, ok := new(big.Int).SetString(s, 10)
if !ok {
panic("bigFromBase10 failed")
}
return b
}
var encryptedKeyPub = rsa.PublicKey{
E: 65537,
N: bigFromBase10("115804063926007623305902631768113868327816898845124614648849934718568541074358183759250136204762053879858102352159854352727097033322663029387610959884180306668628526686121021235757016368038585212410610742029286439607686208110250133174279811431933746643015923132833417396844716207301518956640020862630546868823"),
}
var encryptedKeyRSAPriv = &rsa.PrivateKey{
PublicKey: encryptedKeyPub,
D: bigFromBase10("32355588668219869544751561565313228297765464314098552250409557267371233892496951383426602439009993875125222579159850054973310859166139474359774543943714622292329487391199285040721944491839695981199720170366763547754915493640685849961780092241140181198779299712578774460837139360803883139311171713302987058393"),
}
var encryptedKeyPriv = &PrivateKey{
PublicKey: PublicKey{
PubKeyAlgo: PubKeyAlgoRSA,
},
PrivateKey: encryptedKeyRSAPriv,
}
func TestDecryptingEncryptedKey(t *testing.T) {
const encryptedKeyHex = "c18c032a67d68660df41c70104005789d0de26b6a50c985a02a13131ca829c413a35d0e6fa8d6842599252162808ac7439c72151c8c6183e76923fe3299301414d0c25a2f06a2257db3839e7df0ec964773f6e4c4ac7ff3b48c444237166dd46ba8ff443a5410dc670cb486672fdbe7c9dfafb75b4fea83af3a204fe2a7dfa86bd20122b4f3d2646cbeecb8f7be8"
const expectedKeyHex = "d930363f7e0308c333b9618617ea728963d8df993665ae7be1092d4926fd864b"
p, err := Read(readerFromHex(encryptedKeyHex))
if err != nil {
t.Errorf("error from Read: %s", err)
return
}
ek, ok := p.(*EncryptedKey)
if !ok {
t.Errorf("didn't parse an EncryptedKey, got %#v", p)
return
}
if ek.KeyId != 0x2a67d68660df41c7 || ek.Algo != PubKeyAlgoRSA {
t.Errorf("unexpected EncryptedKey contents: %#v", ek)
return
}
err = ek.Decrypt(encryptedKeyPriv)
if err != nil {
t.Errorf("error from Decrypt: %s", err)
return
}
if ek.CipherFunc != CipherAES256 {
t.Errorf("unexpected EncryptedKey contents: %#v", ek)
return
}
keyHex := fmt.Sprintf("%x", ek.Key)
if keyHex != expectedKeyHex {
t.Errorf("bad key, got %s want %x", keyHex, expectedKeyHex)
}
}
func TestEncryptingEncryptedKey(t *testing.T) {
key := []byte{1, 2, 3, 4}
const expectedKeyHex = "01020304"
const keyId = 42
pub := &PublicKey{
PublicKey: &encryptedKeyPub,
KeyId: keyId,
PubKeyAlgo: PubKeyAlgoRSAEncryptOnly,
}
buf := new(bytes.Buffer)
err := SerializeEncryptedKey(buf, rand.Reader, pub, CipherAES128, key)
if err != nil {
t.Errorf("error writing encrypted key packet: %s", err)
}
p, err := Read(buf)
if err != nil {
t.Errorf("error from Read: %s", err)
return
}
ek, ok := p.(*EncryptedKey)
if !ok {
t.Errorf("didn't parse an EncryptedKey, got %#v", p)
return
}
if ek.KeyId != keyId || ek.Algo != PubKeyAlgoRSAEncryptOnly {
t.Errorf("unexpected EncryptedKey contents: %#v", ek)
return
}
err = ek.Decrypt(encryptedKeyPriv)
if err != nil {
t.Errorf("error from Decrypt: %s", err)
return
}
if ek.CipherFunc != CipherAES128 {
t.Errorf("unexpected EncryptedKey contents: %#v", ek)
return
}
keyHex := fmt.Sprintf("%x", ek.Key)
if keyHex != expectedKeyHex {
t.Errorf("bad key, got %s want %x", keyHex, expectedKeyHex)
}
}

View File

@ -1,89 +0,0 @@
// 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 packet
import (
"encoding/binary"
"io"
)
// LiteralData represents an encrypted file. See RFC 4880, section 5.9.
type LiteralData struct {
IsBinary bool
FileName string
Time uint32 // Unix epoch time. Either creation time or modification time. 0 means undefined.
Body io.Reader
}
// ForEyesOnly returns whether the contents of the LiteralData have been marked
// as especially sensitive.
func (l *LiteralData) ForEyesOnly() bool {
return l.FileName == "_CONSOLE"
}
func (l *LiteralData) parse(r io.Reader) (err error) {
var buf [256]byte
_, err = readFull(r, buf[:2])
if err != nil {
return
}
l.IsBinary = buf[0] == 'b'
fileNameLen := int(buf[1])
_, err = readFull(r, buf[:fileNameLen])
if err != nil {
return
}
l.FileName = string(buf[:fileNameLen])
_, err = readFull(r, buf[:4])
if err != nil {
return
}
l.Time = binary.BigEndian.Uint32(buf[:4])
l.Body = r
return
}
// SerializeLiteral serializes a literal data packet to w and returns a
// WriteCloser to which the data itself can be written and which MUST be closed
// on completion. The fileName is truncated to 255 bytes.
func SerializeLiteral(w io.WriteCloser, isBinary bool, fileName string, time uint32) (plaintext io.WriteCloser, err error) {
var buf [4]byte
buf[0] = 't'
if isBinary {
buf[0] = 'b'
}
if len(fileName) > 255 {
fileName = fileName[:255]
}
buf[1] = byte(len(fileName))
inner, err := serializeStreamHeader(w, packetTypeLiteralData)
if err != nil {
return
}
_, err = inner.Write(buf[:2])
if err != nil {
return
}
_, err = inner.Write([]byte(fileName))
if err != nil {
return
}
binary.BigEndian.PutUint32(buf[:], time)
_, err = inner.Write(buf[:])
if err != nil {
return
}
plaintext = inner
return
}

View File

@ -1,73 +0,0 @@
// 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 packet
import (
"crypto"
"crypto/openpgp/errors"
"crypto/openpgp/s2k"
"encoding/binary"
"io"
"strconv"
)
// OnePassSignature represents a one-pass signature packet. See RFC 4880,
// section 5.4.
type OnePassSignature struct {
SigType SignatureType
Hash crypto.Hash
PubKeyAlgo PublicKeyAlgorithm
KeyId uint64
IsLast bool
}
const onePassSignatureVersion = 3
func (ops *OnePassSignature) parse(r io.Reader) (err error) {
var buf [13]byte
_, err = readFull(r, buf[:])
if err != nil {
return
}
if buf[0] != onePassSignatureVersion {
err = errors.UnsupportedError("one-pass-signature packet version " + strconv.Itoa(int(buf[0])))
}
var ok bool
ops.Hash, ok = s2k.HashIdToHash(buf[2])
if !ok {
return errors.UnsupportedError("hash function: " + strconv.Itoa(int(buf[2])))
}
ops.SigType = SignatureType(buf[1])
ops.PubKeyAlgo = PublicKeyAlgorithm(buf[3])
ops.KeyId = binary.BigEndian.Uint64(buf[4:12])
ops.IsLast = buf[12] != 0
return
}
// Serialize marshals the given OnePassSignature to w.
func (ops *OnePassSignature) Serialize(w io.Writer) error {
var buf [13]byte
buf[0] = onePassSignatureVersion
buf[1] = uint8(ops.SigType)
var ok bool
buf[2], ok = s2k.HashToHashId(ops.Hash)
if !ok {
return errors.UnsupportedError("hash type: " + strconv.Itoa(int(ops.Hash)))
}
buf[3] = uint8(ops.PubKeyAlgo)
binary.BigEndian.PutUint64(buf[4:12], ops.KeyId)
if ops.IsLast {
buf[12] = 1
}
if err := serializeHeader(w, packetTypeOnePassSignature, len(buf)); err != nil {
return err
}
_, err := w.Write(buf[:])
return err
}

View File

@ -1,482 +0,0 @@
// 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 packet implements parsing and serialization of OpenPGP packets, as
// specified in RFC 4880.
package packet
import (
"crypto/aes"
"crypto/cast5"
"crypto/cipher"
"crypto/openpgp/errors"
"io"
"math/big"
)
// readFull is the same as io.ReadFull except that reading zero bytes returns
// ErrUnexpectedEOF rather than EOF.
func readFull(r io.Reader, buf []byte) (n int, err error) {
n, err = io.ReadFull(r, buf)
if err == io.EOF {
err = io.ErrUnexpectedEOF
}
return
}
// readLength reads an OpenPGP length from r. See RFC 4880, section 4.2.2.
func readLength(r io.Reader) (length int64, isPartial bool, err error) {
var buf [4]byte
_, err = readFull(r, buf[:1])
if err != nil {
return
}
switch {
case buf[0] < 192:
length = int64(buf[0])
case buf[0] < 224:
length = int64(buf[0]-192) << 8
_, err = readFull(r, buf[0:1])
if err != nil {
return
}
length += int64(buf[0]) + 192
case buf[0] < 255:
length = int64(1) << (buf[0] & 0x1f)
isPartial = true
default:
_, err = readFull(r, buf[0:4])
if err != nil {
return
}
length = int64(buf[0])<<24 |
int64(buf[1])<<16 |
int64(buf[2])<<8 |
int64(buf[3])
}
return
}
// partialLengthReader wraps an io.Reader and handles OpenPGP partial lengths.
// The continuation lengths are parsed and removed from the stream and EOF is
// returned at the end of the packet. See RFC 4880, section 4.2.2.4.
type partialLengthReader struct {
r io.Reader
remaining int64
isPartial bool
}
func (r *partialLengthReader) Read(p []byte) (n int, err error) {
for r.remaining == 0 {
if !r.isPartial {
return 0, io.EOF
}
r.remaining, r.isPartial, err = readLength(r.r)
if err != nil {
return 0, err
}
}
toRead := int64(len(p))
if toRead > r.remaining {
toRead = r.remaining
}
n, err = r.r.Read(p[:int(toRead)])
r.remaining -= int64(n)
if n < int(toRead) && err == io.EOF {
err = io.ErrUnexpectedEOF
}
return
}
// partialLengthWriter writes a stream of data using OpenPGP partial lengths.
// See RFC 4880, section 4.2.2.4.
type partialLengthWriter struct {
w io.WriteCloser
lengthByte [1]byte
}
func (w *partialLengthWriter) Write(p []byte) (n int, err error) {
for len(p) > 0 {
for power := uint(14); power < 32; power-- {
l := 1 << power
if len(p) >= l {
w.lengthByte[0] = 224 + uint8(power)
_, err = w.w.Write(w.lengthByte[:])
if err != nil {
return
}
var m int
m, err = w.w.Write(p[:l])
n += m
if err != nil {
return
}
p = p[l:]
break
}
}
}
return
}
func (w *partialLengthWriter) Close() error {
w.lengthByte[0] = 0
_, err := w.w.Write(w.lengthByte[:])
if err != nil {
return err
}
return w.w.Close()
}
// A spanReader is an io.LimitReader, but it returns ErrUnexpectedEOF if the
// underlying Reader returns EOF before the limit has been reached.
type spanReader struct {
r io.Reader
n int64
}
func (l *spanReader) Read(p []byte) (n int, err error) {
if l.n <= 0 {
return 0, io.EOF
}
if int64(len(p)) > l.n {
p = p[0:l.n]
}
n, err = l.r.Read(p)
l.n -= int64(n)
if l.n > 0 && err == io.EOF {
err = io.ErrUnexpectedEOF
}
return
}
// readHeader parses a packet header and returns an io.Reader which will return
// the contents of the packet. See RFC 4880, section 4.2.
func readHeader(r io.Reader) (tag packetType, length int64, contents io.Reader, err error) {
var buf [4]byte
_, err = io.ReadFull(r, buf[:1])
if err != nil {
return
}
if buf[0]&0x80 == 0 {
err = errors.StructuralError("tag byte does not have MSB set")
return
}
if buf[0]&0x40 == 0 {
// Old format packet
tag = packetType((buf[0] & 0x3f) >> 2)
lengthType := buf[0] & 3
if lengthType == 3 {
length = -1
contents = r
return
}
lengthBytes := 1 << lengthType
_, err = readFull(r, buf[0:lengthBytes])
if err != nil {
return
}
for i := 0; i < lengthBytes; i++ {
length <<= 8
length |= int64(buf[i])
}
contents = &spanReader{r, length}
return
}
// New format packet
tag = packetType(buf[0] & 0x3f)
length, isPartial, err := readLength(r)
if err != nil {
return
}
if isPartial {
contents = &partialLengthReader{
remaining: length,
isPartial: true,
r: r,
}
length = -1
} else {
contents = &spanReader{r, length}
}
return
}
// serializeHeader writes an OpenPGP packet header to w. See RFC 4880, section
// 4.2.
func serializeHeader(w io.Writer, ptype packetType, length int) (err error) {
var buf [6]byte
var n int
buf[0] = 0x80 | 0x40 | byte(ptype)
if length < 192 {
buf[1] = byte(length)
n = 2
} else if length < 8384 {
length -= 192
buf[1] = 192 + byte(length>>8)
buf[2] = byte(length)
n = 3
} else {
buf[1] = 255
buf[2] = byte(length >> 24)
buf[3] = byte(length >> 16)
buf[4] = byte(length >> 8)
buf[5] = byte(length)
n = 6
}
_, err = w.Write(buf[:n])
return
}
// serializeStreamHeader writes an OpenPGP packet header to w where the
// length of the packet is unknown. It returns a io.WriteCloser which can be
// used to write the contents of the packet. See RFC 4880, section 4.2.
func serializeStreamHeader(w io.WriteCloser, ptype packetType) (out io.WriteCloser, err error) {
var buf [1]byte
buf[0] = 0x80 | 0x40 | byte(ptype)
_, err = w.Write(buf[:])
if err != nil {
return
}
out = &partialLengthWriter{w: w}
return
}
// Packet represents an OpenPGP packet. Users are expected to try casting
// instances of this interface to specific packet types.
type Packet interface {
parse(io.Reader) error
}
// consumeAll reads from the given Reader until error, returning the number of
// bytes read.
func consumeAll(r io.Reader) (n int64, err error) {
var m int
var buf [1024]byte
for {
m, err = r.Read(buf[:])
n += int64(m)
if err == io.EOF {
err = nil
return
}
if err != nil {
return
}
}
panic("unreachable")
}
// packetType represents the numeric ids of the different OpenPGP packet types. See
// http://www.iana.org/assignments/pgp-parameters/pgp-parameters.xhtml#pgp-parameters-2
type packetType uint8
const (
packetTypeEncryptedKey packetType = 1
packetTypeSignature packetType = 2
packetTypeSymmetricKeyEncrypted packetType = 3
packetTypeOnePassSignature packetType = 4
packetTypePrivateKey packetType = 5
packetTypePublicKey packetType = 6
packetTypePrivateSubkey packetType = 7
packetTypeCompressed packetType = 8
packetTypeSymmetricallyEncrypted packetType = 9
packetTypeLiteralData packetType = 11
packetTypeUserId packetType = 13
packetTypePublicSubkey packetType = 14
packetTypeSymmetricallyEncryptedMDC packetType = 18
)
// Read reads a single OpenPGP packet from the given io.Reader. If there is an
// error parsing a packet, the whole packet is consumed from the input.
func Read(r io.Reader) (p Packet, err error) {
tag, _, contents, err := readHeader(r)
if err != nil {
return
}
switch tag {
case packetTypeEncryptedKey:
p = new(EncryptedKey)
case packetTypeSignature:
p = new(Signature)
case packetTypeSymmetricKeyEncrypted:
p = new(SymmetricKeyEncrypted)
case packetTypeOnePassSignature:
p = new(OnePassSignature)
case packetTypePrivateKey, packetTypePrivateSubkey:
pk := new(PrivateKey)
if tag == packetTypePrivateSubkey {
pk.IsSubkey = true
}
p = pk
case packetTypePublicKey, packetTypePublicSubkey:
pk := new(PublicKey)
if tag == packetTypePublicSubkey {
pk.IsSubkey = true
}
p = pk
case packetTypeCompressed:
p = new(Compressed)
case packetTypeSymmetricallyEncrypted:
p = new(SymmetricallyEncrypted)
case packetTypeLiteralData:
p = new(LiteralData)
case packetTypeUserId:
p = new(UserId)
case packetTypeSymmetricallyEncryptedMDC:
se := new(SymmetricallyEncrypted)
se.MDC = true
p = se
default:
err = errors.UnknownPacketTypeError(tag)
}
if p != nil {
err = p.parse(contents)
}
if err != nil {
consumeAll(contents)
}
return
}
// SignatureType represents the different semantic meanings of an OpenPGP
// signature. See RFC 4880, section 5.2.1.
type SignatureType uint8
const (
SigTypeBinary SignatureType = 0
SigTypeText = 1
SigTypeGenericCert = 0x10
SigTypePersonaCert = 0x11
SigTypeCasualCert = 0x12
SigTypePositiveCert = 0x13
SigTypeSubkeyBinding = 0x18
)
// PublicKeyAlgorithm represents the different public key system specified for
// OpenPGP. See
// http://www.iana.org/assignments/pgp-parameters/pgp-parameters.xhtml#pgp-parameters-12
type PublicKeyAlgorithm uint8
const (
PubKeyAlgoRSA PublicKeyAlgorithm = 1
PubKeyAlgoRSAEncryptOnly PublicKeyAlgorithm = 2
PubKeyAlgoRSASignOnly PublicKeyAlgorithm = 3
PubKeyAlgoElGamal PublicKeyAlgorithm = 16
PubKeyAlgoDSA PublicKeyAlgorithm = 17
)
// CanEncrypt returns true if it's possible to encrypt a message to a public
// key of the given type.
func (pka PublicKeyAlgorithm) CanEncrypt() bool {
switch pka {
case PubKeyAlgoRSA, PubKeyAlgoRSAEncryptOnly, PubKeyAlgoElGamal:
return true
}
return false
}
// CanSign returns true if it's possible for a public key of the given type to
// sign a message.
func (pka PublicKeyAlgorithm) CanSign() bool {
switch pka {
case PubKeyAlgoRSA, PubKeyAlgoRSASignOnly, PubKeyAlgoDSA:
return true
}
return false
}
// CipherFunction represents the different block ciphers specified for OpenPGP. See
// http://www.iana.org/assignments/pgp-parameters/pgp-parameters.xhtml#pgp-parameters-13
type CipherFunction uint8
const (
CipherCAST5 CipherFunction = 3
CipherAES128 CipherFunction = 7
CipherAES192 CipherFunction = 8
CipherAES256 CipherFunction = 9
)
// KeySize returns the key size, in bytes, of cipher.
func (cipher CipherFunction) KeySize() int {
switch cipher {
case CipherCAST5:
return cast5.KeySize
case CipherAES128:
return 16
case CipherAES192:
return 24
case CipherAES256:
return 32
}
return 0
}
// blockSize returns the block size, in bytes, of cipher.
func (cipher CipherFunction) blockSize() int {
switch cipher {
case CipherCAST5:
return 8
case CipherAES128, CipherAES192, CipherAES256:
return 16
}
return 0
}
// new returns a fresh instance of the given cipher.
func (cipher CipherFunction) new(key []byte) (block cipher.Block) {
switch cipher {
case CipherCAST5:
block, _ = cast5.NewCipher(key)
case CipherAES128, CipherAES192, CipherAES256:
block, _ = aes.NewCipher(key)
}
return
}
// readMPI reads a big integer from r. The bit length returned is the bit
// length that was specified in r. This is preserved so that the integer can be
// reserialized exactly.
func readMPI(r io.Reader) (mpi []byte, bitLength uint16, err error) {
var buf [2]byte
_, err = readFull(r, buf[0:])
if err != nil {
return
}
bitLength = uint16(buf[0])<<8 | uint16(buf[1])
numBytes := (int(bitLength) + 7) / 8
mpi = make([]byte, numBytes)
_, err = readFull(r, mpi)
return
}
// mpiLength returns the length of the given *big.Int when serialized as an
// MPI.
func mpiLength(n *big.Int) (mpiLengthInBytes int) {
mpiLengthInBytes = 2 /* MPI length */
mpiLengthInBytes += (n.BitLen() + 7) / 8
return
}
// writeMPI serializes a big integer to w.
func writeMPI(w io.Writer, bitLength uint16, mpiBytes []byte) (err error) {
_, err = w.Write([]byte{byte(bitLength >> 8), byte(bitLength)})
if err == nil {
_, err = w.Write(mpiBytes)
}
return
}
// writeBig serializes a *big.Int to w.
func writeBig(w io.Writer, i *big.Int) error {
return writeMPI(w, uint16(i.BitLen()), i.Bytes())
}

View File

@ -1,255 +0,0 @@
// 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 packet
import (
"bytes"
"crypto/openpgp/errors"
"encoding/hex"
"fmt"
"io"
"io/ioutil"
"testing"
)
func TestReadFull(t *testing.T) {
var out [4]byte
b := bytes.NewBufferString("foo")
n, err := readFull(b, out[:3])
if n != 3 || err != nil {
t.Errorf("full read failed n:%d err:%s", n, err)
}
b = bytes.NewBufferString("foo")
n, err = readFull(b, out[:4])
if n != 3 || err != io.ErrUnexpectedEOF {
t.Errorf("partial read failed n:%d err:%s", n, err)
}
b = bytes.NewBuffer(nil)
n, err = readFull(b, out[:3])
if n != 0 || err != io.ErrUnexpectedEOF {
t.Errorf("empty read failed n:%d err:%s", n, err)
}
}
func readerFromHex(s string) io.Reader {
data, err := hex.DecodeString(s)
if err != nil {
panic("readerFromHex: bad input")
}
return bytes.NewBuffer(data)
}
var readLengthTests = []struct {
hexInput string
length int64
isPartial bool
err error
}{
{"", 0, false, io.ErrUnexpectedEOF},
{"1f", 31, false, nil},
{"c0", 0, false, io.ErrUnexpectedEOF},
{"c101", 256 + 1 + 192, false, nil},
{"e0", 1, true, nil},
{"e1", 2, true, nil},
{"e2", 4, true, nil},
{"ff", 0, false, io.ErrUnexpectedEOF},
{"ff00", 0, false, io.ErrUnexpectedEOF},
{"ff0000", 0, false, io.ErrUnexpectedEOF},
{"ff000000", 0, false, io.ErrUnexpectedEOF},
{"ff00000000", 0, false, nil},
{"ff01020304", 16909060, false, nil},
}
func TestReadLength(t *testing.T) {
for i, test := range readLengthTests {
length, isPartial, err := readLength(readerFromHex(test.hexInput))
if test.err != nil {
if err != test.err {
t.Errorf("%d: expected different error got:%s want:%s", i, err, test.err)
}
continue
}
if err != nil {
t.Errorf("%d: unexpected error: %s", i, err)
continue
}
if length != test.length || isPartial != test.isPartial {
t.Errorf("%d: bad result got:(%d,%t) want:(%d,%t)", i, length, isPartial, test.length, test.isPartial)
}
}
}
var partialLengthReaderTests = []struct {
hexInput string
err error
hexOutput string
}{
{"e0", io.ErrUnexpectedEOF, ""},
{"e001", io.ErrUnexpectedEOF, ""},
{"e0010102", nil, "0102"},
{"ff00000000", nil, ""},
{"e10102e1030400", nil, "01020304"},
{"e101", io.ErrUnexpectedEOF, ""},
}
func TestPartialLengthReader(t *testing.T) {
for i, test := range partialLengthReaderTests {
r := &partialLengthReader{readerFromHex(test.hexInput), 0, true}
out, err := ioutil.ReadAll(r)
if test.err != nil {
if err != test.err {
t.Errorf("%d: expected different error got:%s want:%s", i, err, test.err)
}
continue
}
if err != nil {
t.Errorf("%d: unexpected error: %s", i, err)
continue
}
got := fmt.Sprintf("%x", out)
if got != test.hexOutput {
t.Errorf("%d: got:%s want:%s", i, test.hexOutput, got)
}
}
}
var readHeaderTests = []struct {
hexInput string
structuralError bool
unexpectedEOF bool
tag int
length int64
hexOutput string
}{
{"", false, false, 0, 0, ""},
{"7f", true, false, 0, 0, ""},
// Old format headers
{"80", false, true, 0, 0, ""},
{"8001", false, true, 0, 1, ""},
{"800102", false, false, 0, 1, "02"},
{"81000102", false, false, 0, 1, "02"},
{"820000000102", false, false, 0, 1, "02"},
{"860000000102", false, false, 1, 1, "02"},
{"83010203", false, false, 0, -1, "010203"},
// New format headers
{"c0", false, true, 0, 0, ""},
{"c000", false, false, 0, 0, ""},
{"c00102", false, false, 0, 1, "02"},
{"c0020203", false, false, 0, 2, "0203"},
{"c00202", false, true, 0, 2, ""},
{"c3020203", false, false, 3, 2, "0203"},
}
func TestReadHeader(t *testing.T) {
for i, test := range readHeaderTests {
tag, length, contents, err := readHeader(readerFromHex(test.hexInput))
if test.structuralError {
if _, ok := err.(errors.StructuralError); ok {
continue
}
t.Errorf("%d: expected StructuralError, got:%s", i, err)
continue
}
if err != nil {
if len(test.hexInput) == 0 && err == io.EOF {
continue
}
if !test.unexpectedEOF || err != io.ErrUnexpectedEOF {
t.Errorf("%d: unexpected error from readHeader: %s", i, err)
}
continue
}
if int(tag) != test.tag || length != test.length {
t.Errorf("%d: got:(%d,%d) want:(%d,%d)", i, int(tag), length, test.tag, test.length)
continue
}
body, err := ioutil.ReadAll(contents)
if err != nil {
if !test.unexpectedEOF || err != io.ErrUnexpectedEOF {
t.Errorf("%d: unexpected error from contents: %s", i, err)
}
continue
}
if test.unexpectedEOF {
t.Errorf("%d: expected ErrUnexpectedEOF from contents but got no error", i)
continue
}
got := fmt.Sprintf("%x", body)
if got != test.hexOutput {
t.Errorf("%d: got:%s want:%s", i, got, test.hexOutput)
}
}
}
func TestSerializeHeader(t *testing.T) {
tag := packetTypePublicKey
lengths := []int{0, 1, 2, 64, 192, 193, 8000, 8384, 8385, 10000}
for _, length := range lengths {
buf := bytes.NewBuffer(nil)
serializeHeader(buf, tag, length)
tag2, length2, _, err := readHeader(buf)
if err != nil {
t.Errorf("length %d, err: %s", length, err)
}
if tag2 != tag {
t.Errorf("length %d, tag incorrect (got %d, want %d)", length, tag2, tag)
}
if int(length2) != length {
t.Errorf("length %d, length incorrect (got %d)", length, length2)
}
}
}
func TestPartialLengths(t *testing.T) {
buf := bytes.NewBuffer(nil)
w := new(partialLengthWriter)
w.w = noOpCloser{buf}
const maxChunkSize = 64
var b [maxChunkSize]byte
var n uint8
for l := 1; l <= maxChunkSize; l++ {
for i := 0; i < l; i++ {
b[i] = n
n++
}
m, err := w.Write(b[:l])
if m != l {
t.Errorf("short write got: %d want: %d", m, l)
}
if err != nil {
t.Errorf("error from write: %s", err)
}
}
w.Close()
want := (maxChunkSize * (maxChunkSize + 1)) / 2
copyBuf := bytes.NewBuffer(nil)
r := &partialLengthReader{buf, 0, true}
m, err := io.Copy(copyBuf, r)
if m != int64(want) {
t.Errorf("short copy got: %d want: %d", m, want)
}
if err != nil {
t.Errorf("error from copy: %s", err)
}
copyBytes := copyBuf.Bytes()
for i := 0; i < want; i++ {
if copyBytes[i] != uint8(i) {
t.Errorf("bad pattern in copy at %d", i)
break
}
}
}

View File

@ -1,310 +0,0 @@
// 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 packet
import (
"bytes"
"crypto/cipher"
"crypto/dsa"
"crypto/openpgp/elgamal"
"crypto/openpgp/errors"
"crypto/openpgp/s2k"
"crypto/rsa"
"crypto/sha1"
"io"
"io/ioutil"
"math/big"
"strconv"
"time"
)
// PrivateKey represents a possibly encrypted private key. See RFC 4880,
// section 5.5.3.
type PrivateKey struct {
PublicKey
Encrypted bool // if true then the private key is unavailable until Decrypt has been called.
encryptedData []byte
cipher CipherFunction
s2k func(out, in []byte)
PrivateKey interface{} // An *rsa.PrivateKey or *dsa.PrivateKey.
sha1Checksum bool
iv []byte
}
func NewRSAPrivateKey(currentTime time.Time, priv *rsa.PrivateKey) *PrivateKey {
pk := new(PrivateKey)
pk.PublicKey = *NewRSAPublicKey(currentTime, &priv.PublicKey)
pk.PrivateKey = priv
return pk
}
func NewDSAPrivateKey(currentTime time.Time, priv *dsa.PrivateKey) *PrivateKey {
pk := new(PrivateKey)
pk.PublicKey = *NewDSAPublicKey(currentTime, &priv.PublicKey)
pk.PrivateKey = priv
return pk
}
func (pk *PrivateKey) parse(r io.Reader) (err error) {
err = (&pk.PublicKey).parse(r)
if err != nil {
return
}
var buf [1]byte
_, err = readFull(r, buf[:])
if err != nil {
return
}
s2kType := buf[0]
switch s2kType {
case 0:
pk.s2k = nil
pk.Encrypted = false
case 254, 255:
_, err = readFull(r, buf[:])
if err != nil {
return
}
pk.cipher = CipherFunction(buf[0])
pk.Encrypted = true
pk.s2k, err = s2k.Parse(r)
if err != nil {
return
}
if s2kType == 254 {
pk.sha1Checksum = true
}
default:
return errors.UnsupportedError("deprecated s2k function in private key")
}
if pk.Encrypted {
blockSize := pk.cipher.blockSize()
if blockSize == 0 {
return errors.UnsupportedError("unsupported cipher in private key: " + strconv.Itoa(int(pk.cipher)))
}
pk.iv = make([]byte, blockSize)
_, err = readFull(r, pk.iv)
if err != nil {
return
}
}
pk.encryptedData, err = ioutil.ReadAll(r)
if err != nil {
return
}
if !pk.Encrypted {
return pk.parsePrivateKey(pk.encryptedData)
}
return
}
func mod64kHash(d []byte) uint16 {
var h uint16
for _, b := range d {
h += uint16(b)
}
return h
}
func (pk *PrivateKey) Serialize(w io.Writer) (err error) {
// TODO(agl): support encrypted private keys
buf := bytes.NewBuffer(nil)
err = pk.PublicKey.serializeWithoutHeaders(buf)
if err != nil {
return
}
buf.WriteByte(0 /* no encryption */ )
privateKeyBuf := bytes.NewBuffer(nil)
switch priv := pk.PrivateKey.(type) {
case *rsa.PrivateKey:
err = serializeRSAPrivateKey(privateKeyBuf, priv)
case *dsa.PrivateKey:
err = serializeDSAPrivateKey(privateKeyBuf, priv)
default:
err = errors.InvalidArgumentError("unknown private key type")
}
if err != nil {
return
}
ptype := packetTypePrivateKey
contents := buf.Bytes()
privateKeyBytes := privateKeyBuf.Bytes()
if pk.IsSubkey {
ptype = packetTypePrivateSubkey
}
err = serializeHeader(w, ptype, len(contents)+len(privateKeyBytes)+2)
if err != nil {
return
}
_, err = w.Write(contents)
if err != nil {
return
}
_, err = w.Write(privateKeyBytes)
if err != nil {
return
}
checksum := mod64kHash(privateKeyBytes)
var checksumBytes [2]byte
checksumBytes[0] = byte(checksum >> 8)
checksumBytes[1] = byte(checksum)
_, err = w.Write(checksumBytes[:])
return
}
func serializeRSAPrivateKey(w io.Writer, priv *rsa.PrivateKey) error {
err := writeBig(w, priv.D)
if err != nil {
return err
}
err = writeBig(w, priv.Primes[1])
if err != nil {
return err
}
err = writeBig(w, priv.Primes[0])
if err != nil {
return err
}
return writeBig(w, priv.Precomputed.Qinv)
}
func serializeDSAPrivateKey(w io.Writer, priv *dsa.PrivateKey) error {
return writeBig(w, priv.X)
}
// Decrypt decrypts an encrypted private key using a passphrase.
func (pk *PrivateKey) Decrypt(passphrase []byte) error {
if !pk.Encrypted {
return nil
}
key := make([]byte, pk.cipher.KeySize())
pk.s2k(key, passphrase)
block := pk.cipher.new(key)
cfb := cipher.NewCFBDecrypter(block, pk.iv)
data := pk.encryptedData
cfb.XORKeyStream(data, data)
if pk.sha1Checksum {
if len(data) < sha1.Size {
return errors.StructuralError("truncated private key data")
}
h := sha1.New()
h.Write(data[:len(data)-sha1.Size])
sum := h.Sum(nil)
if !bytes.Equal(sum, data[len(data)-sha1.Size:]) {
return errors.StructuralError("private key checksum failure")
}
data = data[:len(data)-sha1.Size]
} else {
if len(data) < 2 {
return errors.StructuralError("truncated private key data")
}
var sum uint16
for i := 0; i < len(data)-2; i++ {
sum += uint16(data[i])
}
if data[len(data)-2] != uint8(sum>>8) ||
data[len(data)-1] != uint8(sum) {
return errors.StructuralError("private key checksum failure")
}
data = data[:len(data)-2]
}
return pk.parsePrivateKey(data)
}
func (pk *PrivateKey) parsePrivateKey(data []byte) (err error) {
switch pk.PublicKey.PubKeyAlgo {
case PubKeyAlgoRSA, PubKeyAlgoRSASignOnly, PubKeyAlgoRSAEncryptOnly:
return pk.parseRSAPrivateKey(data)
case PubKeyAlgoDSA:
return pk.parseDSAPrivateKey(data)
case PubKeyAlgoElGamal:
return pk.parseElGamalPrivateKey(data)
}
panic("impossible")
}
func (pk *PrivateKey) parseRSAPrivateKey(data []byte) (err error) {
rsaPub := pk.PublicKey.PublicKey.(*rsa.PublicKey)
rsaPriv := new(rsa.PrivateKey)
rsaPriv.PublicKey = *rsaPub
buf := bytes.NewBuffer(data)
d, _, err := readMPI(buf)
if err != nil {
return
}
p, _, err := readMPI(buf)
if err != nil {
return
}
q, _, err := readMPI(buf)
if err != nil {
return
}
rsaPriv.D = new(big.Int).SetBytes(d)
rsaPriv.Primes = make([]*big.Int, 2)
rsaPriv.Primes[0] = new(big.Int).SetBytes(p)
rsaPriv.Primes[1] = new(big.Int).SetBytes(q)
rsaPriv.Precompute()
pk.PrivateKey = rsaPriv
pk.Encrypted = false
pk.encryptedData = nil
return nil
}
func (pk *PrivateKey) parseDSAPrivateKey(data []byte) (err error) {
dsaPub := pk.PublicKey.PublicKey.(*dsa.PublicKey)
dsaPriv := new(dsa.PrivateKey)
dsaPriv.PublicKey = *dsaPub
buf := bytes.NewBuffer(data)
x, _, err := readMPI(buf)
if err != nil {
return
}
dsaPriv.X = new(big.Int).SetBytes(x)
pk.PrivateKey = dsaPriv
pk.Encrypted = false
pk.encryptedData = nil
return nil
}
func (pk *PrivateKey) parseElGamalPrivateKey(data []byte) (err error) {
pub := pk.PublicKey.PublicKey.(*elgamal.PublicKey)
priv := new(elgamal.PrivateKey)
priv.PublicKey = *pub
buf := bytes.NewBuffer(data)
x, _, err := readMPI(buf)
if err != nil {
return
}
priv.X = new(big.Int).SetBytes(x)
pk.PrivateKey = priv
pk.Encrypted = false
pk.encryptedData = nil
return nil
}

View File

@ -1,58 +0,0 @@
// 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 packet
import (
"testing"
"time"
)
var privateKeyTests = []struct {
privateKeyHex string
creationTime time.Time
}{
{
privKeyRSAHex,
time.Unix(0x4cc349a8, 0),
},
{
privKeyElGamalHex,
time.Unix(0x4df9ee1a, 0),
},
}
func TestPrivateKeyRead(t *testing.T) {
for i, test := range privateKeyTests {
packet, err := Read(readerFromHex(test.privateKeyHex))
if err != nil {
t.Errorf("#%d: failed to parse: %s", i, err)
continue
}
privKey := packet.(*PrivateKey)
if !privKey.Encrypted {
t.Errorf("#%d: private key isn't encrypted", i)
continue
}
err = privKey.Decrypt([]byte("testing"))
if err != nil {
t.Errorf("#%d: failed to decrypt: %s", i, err)
continue
}
if !privKey.CreationTime.Equal(test.creationTime) || privKey.Encrypted {
t.Errorf("#%d: bad result, got: %#v", i, privKey)
}
}
}
// Generated with `gpg --export-secret-keys "Test Key 2"`
const privKeyRSAHex = "9501fe044cc349a8010400b70ca0010e98c090008d45d1ee8f9113bd5861fd57b88bacb7c68658747663f1e1a3b5a98f32fda6472373c024b97359cd2efc88ff60f77751adfbf6af5e615e6a1408cfad8bf0cea30b0d5f53aa27ad59089ba9b15b7ebc2777a25d7b436144027e3bcd203909f147d0e332b240cf63d3395f5dfe0df0a6c04e8655af7eacdf0011010001fe0303024a252e7d475fd445607de39a265472aa74a9320ba2dac395faa687e9e0336aeb7e9a7397e511b5afd9dc84557c80ac0f3d4d7bfec5ae16f20d41c8c84a04552a33870b930420e230e179564f6d19bb153145e76c33ae993886c388832b0fa042ddda7f133924f3854481533e0ede31d51278c0519b29abc3bf53da673e13e3e1214b52413d179d7f66deee35cac8eacb060f78379d70ef4af8607e68131ff529439668fc39c9ce6dfef8a5ac234d234802cbfb749a26107db26406213ae5c06d4673253a3cbee1fcbae58d6ab77e38d6e2c0e7c6317c48e054edadb5a40d0d48acb44643d998139a8a66bb820be1f3f80185bc777d14b5954b60effe2448a036d565c6bc0b915fcea518acdd20ab07bc1529f561c58cd044f723109b93f6fd99f876ff891d64306b5d08f48bab59f38695e9109c4dec34013ba3153488ce070268381ba923ee1eb77125b36afcb4347ec3478c8f2735b06ef17351d872e577fa95d0c397c88c71b59629a36aec"
// Generated by `gpg --export-secret-keys` followed by a manual extraction of
// the ElGamal subkey from the packets.
const privKeyElGamalHex = "9d0157044df9ee1a100400eb8e136a58ec39b582629cdadf830bc64e0a94ed8103ca8bb247b27b11b46d1d25297ef4bcc3071785ba0c0bedfe89eabc5287fcc0edf81ab5896c1c8e4b20d27d79813c7aede75320b33eaeeaa586edc00fd1036c10133e6ba0ff277245d0d59d04b2b3421b7244aca5f4a8d870c6f1c1fbff9e1c26699a860b9504f35ca1d700030503fd1ededd3b840795be6d9ccbe3c51ee42e2f39233c432b831ddd9c4e72b7025a819317e47bf94f9ee316d7273b05d5fcf2999c3a681f519b1234bbfa6d359b4752bd9c3f77d6b6456cde152464763414ca130f4e91d91041432f90620fec0e6d6b5116076c2985d5aeaae13be492b9b329efcaf7ee25120159a0a30cd976b42d7afe030302dae7eb80db744d4960c4df930d57e87fe81412eaace9f900e6c839817a614ddb75ba6603b9417c33ea7b6c93967dfa2bcff3fa3c74a5ce2c962db65b03aece14c96cbd0038fc"

View File

@ -1,414 +0,0 @@
// 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 packet
import (
"crypto/dsa"
"crypto/openpgp/elgamal"
"crypto/openpgp/errors"
"crypto/rsa"
"crypto/sha1"
"encoding/binary"
"fmt"
"hash"
"io"
"math/big"
"strconv"
"time"
)
// PublicKey represents an OpenPGP public key. See RFC 4880, section 5.5.2.
type PublicKey struct {
CreationTime time.Time
PubKeyAlgo PublicKeyAlgorithm
PublicKey interface{} // Either a *rsa.PublicKey or *dsa.PublicKey
Fingerprint [20]byte
KeyId uint64
IsSubkey bool
n, e, p, q, g, y parsedMPI
}
func fromBig(n *big.Int) parsedMPI {
return parsedMPI{
bytes: n.Bytes(),
bitLength: uint16(n.BitLen()),
}
}
// NewRSAPublicKey returns a PublicKey that wraps the given rsa.PublicKey.
func NewRSAPublicKey(creationTime time.Time, pub *rsa.PublicKey) *PublicKey {
pk := &PublicKey{
CreationTime: creationTime,
PubKeyAlgo: PubKeyAlgoRSA,
PublicKey: pub,
n: fromBig(pub.N),
e: fromBig(big.NewInt(int64(pub.E))),
}
pk.setFingerPrintAndKeyId()
return pk
}
// NewDSAPublicKey returns a PublicKey that wraps the given rsa.PublicKey.
func NewDSAPublicKey(creationTime time.Time, pub *dsa.PublicKey) *PublicKey {
pk := &PublicKey{
CreationTime: creationTime,
PubKeyAlgo: PubKeyAlgoDSA,
PublicKey: pub,
p: fromBig(pub.P),
q: fromBig(pub.Q),
g: fromBig(pub.G),
y: fromBig(pub.Y),
}
pk.setFingerPrintAndKeyId()
return pk
}
func (pk *PublicKey) parse(r io.Reader) (err error) {
// RFC 4880, section 5.5.2
var buf [6]byte
_, err = readFull(r, buf[:])
if err != nil {
return
}
if buf[0] != 4 {
return errors.UnsupportedError("public key version")
}
pk.CreationTime = time.Unix(int64(uint32(buf[1])<<24|uint32(buf[2])<<16|uint32(buf[3])<<8|uint32(buf[4])), 0)
pk.PubKeyAlgo = PublicKeyAlgorithm(buf[5])
switch pk.PubKeyAlgo {
case PubKeyAlgoRSA, PubKeyAlgoRSAEncryptOnly, PubKeyAlgoRSASignOnly:
err = pk.parseRSA(r)
case PubKeyAlgoDSA:
err = pk.parseDSA(r)
case PubKeyAlgoElGamal:
err = pk.parseElGamal(r)
default:
err = errors.UnsupportedError("public key type: " + strconv.Itoa(int(pk.PubKeyAlgo)))
}
if err != nil {
return
}
pk.setFingerPrintAndKeyId()
return
}
func (pk *PublicKey) setFingerPrintAndKeyId() {
// RFC 4880, section 12.2
fingerPrint := sha1.New()
pk.SerializeSignaturePrefix(fingerPrint)
pk.serializeWithoutHeaders(fingerPrint)
copy(pk.Fingerprint[:], fingerPrint.Sum(nil))
pk.KeyId = binary.BigEndian.Uint64(pk.Fingerprint[12:20])
}
// parseRSA parses RSA public key material from the given Reader. See RFC 4880,
// section 5.5.2.
func (pk *PublicKey) parseRSA(r io.Reader) (err error) {
pk.n.bytes, pk.n.bitLength, err = readMPI(r)
if err != nil {
return
}
pk.e.bytes, pk.e.bitLength, err = readMPI(r)
if err != nil {
return
}
if len(pk.e.bytes) > 3 {
err = errors.UnsupportedError("large public exponent")
return
}
rsa := &rsa.PublicKey{
N: new(big.Int).SetBytes(pk.n.bytes),
E: 0,
}
for i := 0; i < len(pk.e.bytes); i++ {
rsa.E <<= 8
rsa.E |= int(pk.e.bytes[i])
}
pk.PublicKey = rsa
return
}
// parseDSA parses DSA public key material from the given Reader. See RFC 4880,
// section 5.5.2.
func (pk *PublicKey) parseDSA(r io.Reader) (err error) {
pk.p.bytes, pk.p.bitLength, err = readMPI(r)
if err != nil {
return
}
pk.q.bytes, pk.q.bitLength, err = readMPI(r)
if err != nil {
return
}
pk.g.bytes, pk.g.bitLength, err = readMPI(r)
if err != nil {
return
}
pk.y.bytes, pk.y.bitLength, err = readMPI(r)
if err != nil {
return
}
dsa := new(dsa.PublicKey)
dsa.P = new(big.Int).SetBytes(pk.p.bytes)
dsa.Q = new(big.Int).SetBytes(pk.q.bytes)
dsa.G = new(big.Int).SetBytes(pk.g.bytes)
dsa.Y = new(big.Int).SetBytes(pk.y.bytes)
pk.PublicKey = dsa
return
}
// parseElGamal parses ElGamal public key material from the given Reader. See
// RFC 4880, section 5.5.2.
func (pk *PublicKey) parseElGamal(r io.Reader) (err error) {
pk.p.bytes, pk.p.bitLength, err = readMPI(r)
if err != nil {
return
}
pk.g.bytes, pk.g.bitLength, err = readMPI(r)
if err != nil {
return
}
pk.y.bytes, pk.y.bitLength, err = readMPI(r)
if err != nil {
return
}
elgamal := new(elgamal.PublicKey)
elgamal.P = new(big.Int).SetBytes(pk.p.bytes)
elgamal.G = new(big.Int).SetBytes(pk.g.bytes)
elgamal.Y = new(big.Int).SetBytes(pk.y.bytes)
pk.PublicKey = elgamal
return
}
// SerializeSignaturePrefix writes the prefix for this public key to the given Writer.
// The prefix is used when calculating a signature over this public key. See
// RFC 4880, section 5.2.4.
func (pk *PublicKey) SerializeSignaturePrefix(h hash.Hash) {
var pLength uint16
switch pk.PubKeyAlgo {
case PubKeyAlgoRSA, PubKeyAlgoRSAEncryptOnly, PubKeyAlgoRSASignOnly:
pLength += 2 + uint16(len(pk.n.bytes))
pLength += 2 + uint16(len(pk.e.bytes))
case PubKeyAlgoDSA:
pLength += 2 + uint16(len(pk.p.bytes))
pLength += 2 + uint16(len(pk.q.bytes))
pLength += 2 + uint16(len(pk.g.bytes))
pLength += 2 + uint16(len(pk.y.bytes))
case PubKeyAlgoElGamal:
pLength += 2 + uint16(len(pk.p.bytes))
pLength += 2 + uint16(len(pk.g.bytes))
pLength += 2 + uint16(len(pk.y.bytes))
default:
panic("unknown public key algorithm")
}
pLength += 6
h.Write([]byte{0x99, byte(pLength >> 8), byte(pLength)})
return
}
func (pk *PublicKey) Serialize(w io.Writer) (err error) {
length := 6 // 6 byte header
switch pk.PubKeyAlgo {
case PubKeyAlgoRSA, PubKeyAlgoRSAEncryptOnly, PubKeyAlgoRSASignOnly:
length += 2 + len(pk.n.bytes)
length += 2 + len(pk.e.bytes)
case PubKeyAlgoDSA:
length += 2 + len(pk.p.bytes)
length += 2 + len(pk.q.bytes)
length += 2 + len(pk.g.bytes)
length += 2 + len(pk.y.bytes)
case PubKeyAlgoElGamal:
length += 2 + len(pk.p.bytes)
length += 2 + len(pk.g.bytes)
length += 2 + len(pk.y.bytes)
default:
panic("unknown public key algorithm")
}
packetType := packetTypePublicKey
if pk.IsSubkey {
packetType = packetTypePublicSubkey
}
err = serializeHeader(w, packetType, length)
if err != nil {
return
}
return pk.serializeWithoutHeaders(w)
}
// serializeWithoutHeaders marshals the PublicKey to w in the form of an
// OpenPGP public key packet, not including the packet header.
func (pk *PublicKey) serializeWithoutHeaders(w io.Writer) (err error) {
var buf [6]byte
buf[0] = 4
t := uint32(pk.CreationTime.Unix())
buf[1] = byte(t >> 24)
buf[2] = byte(t >> 16)
buf[3] = byte(t >> 8)
buf[4] = byte(t)
buf[5] = byte(pk.PubKeyAlgo)
_, err = w.Write(buf[:])
if err != nil {
return
}
switch pk.PubKeyAlgo {
case PubKeyAlgoRSA, PubKeyAlgoRSAEncryptOnly, PubKeyAlgoRSASignOnly:
return writeMPIs(w, pk.n, pk.e)
case PubKeyAlgoDSA:
return writeMPIs(w, pk.p, pk.q, pk.g, pk.y)
case PubKeyAlgoElGamal:
return writeMPIs(w, pk.p, pk.g, pk.y)
}
return errors.InvalidArgumentError("bad public-key algorithm")
}
// CanSign returns true iff this public key can generate signatures
func (pk *PublicKey) CanSign() bool {
return pk.PubKeyAlgo != PubKeyAlgoRSAEncryptOnly && pk.PubKeyAlgo != PubKeyAlgoElGamal
}
// VerifySignature returns nil iff sig is a valid signature, made by this
// public key, of the data hashed into signed. signed is mutated by this call.
func (pk *PublicKey) VerifySignature(signed hash.Hash, sig *Signature) (err error) {
if !pk.CanSign() {
return errors.InvalidArgumentError("public key cannot generate signatures")
}
signed.Write(sig.HashSuffix)
hashBytes := signed.Sum(nil)
if hashBytes[0] != sig.HashTag[0] || hashBytes[1] != sig.HashTag[1] {
return errors.SignatureError("hash tag doesn't match")
}
if pk.PubKeyAlgo != sig.PubKeyAlgo {
return errors.InvalidArgumentError("public key and signature use different algorithms")
}
switch pk.PubKeyAlgo {
case PubKeyAlgoRSA, PubKeyAlgoRSASignOnly:
rsaPublicKey, _ := pk.PublicKey.(*rsa.PublicKey)
err = rsa.VerifyPKCS1v15(rsaPublicKey, sig.Hash, hashBytes, sig.RSASignature.bytes)
if err != nil {
return errors.SignatureError("RSA verification failure")
}
return nil
case PubKeyAlgoDSA:
dsaPublicKey, _ := pk.PublicKey.(*dsa.PublicKey)
// Need to truncate hashBytes to match FIPS 186-3 section 4.6.
subgroupSize := (dsaPublicKey.Q.BitLen() + 7) / 8
if len(hashBytes) > subgroupSize {
hashBytes = hashBytes[:subgroupSize]
}
if !dsa.Verify(dsaPublicKey, hashBytes, new(big.Int).SetBytes(sig.DSASigR.bytes), new(big.Int).SetBytes(sig.DSASigS.bytes)) {
return errors.SignatureError("DSA verification failure")
}
return nil
default:
panic("shouldn't happen")
}
panic("unreachable")
}
// keySignatureHash returns a Hash of the message that needs to be signed for
// pk to assert a subkey relationship to signed.
func keySignatureHash(pk, signed *PublicKey, sig *Signature) (h hash.Hash, err error) {
h = sig.Hash.New()
if h == nil {
return nil, errors.UnsupportedError("hash function")
}
// RFC 4880, section 5.2.4
pk.SerializeSignaturePrefix(h)
pk.serializeWithoutHeaders(h)
signed.SerializeSignaturePrefix(h)
signed.serializeWithoutHeaders(h)
return
}
// VerifyKeySignature returns nil iff sig is a valid signature, made by this
// public key, of signed.
func (pk *PublicKey) VerifyKeySignature(signed *PublicKey, sig *Signature) (err error) {
h, err := keySignatureHash(pk, signed, sig)
if err != nil {
return err
}
return pk.VerifySignature(h, sig)
}
// userIdSignatureHash returns a Hash of the message that needs to be signed
// to assert that pk is a valid key for id.
func userIdSignatureHash(id string, pk *PublicKey, sig *Signature) (h hash.Hash, err error) {
h = sig.Hash.New()
if h == nil {
return nil, errors.UnsupportedError("hash function")
}
// RFC 4880, section 5.2.4
pk.SerializeSignaturePrefix(h)
pk.serializeWithoutHeaders(h)
var buf [5]byte
buf[0] = 0xb4
buf[1] = byte(len(id) >> 24)
buf[2] = byte(len(id) >> 16)
buf[3] = byte(len(id) >> 8)
buf[4] = byte(len(id))
h.Write(buf[:])
h.Write([]byte(id))
return
}
// VerifyUserIdSignature returns nil iff sig is a valid signature, made by this
// public key, of id.
func (pk *PublicKey) VerifyUserIdSignature(id string, sig *Signature) (err error) {
h, err := userIdSignatureHash(id, pk, sig)
if err != nil {
return err
}
return pk.VerifySignature(h, sig)
}
// KeyIdString returns the public key's fingerprint in capital hex
// (e.g. "6C7EE1B8621CC013").
func (pk *PublicKey) KeyIdString() string {
return fmt.Sprintf("%X", pk.Fingerprint[12:20])
}
// KeyIdShortString returns the short form of public key's fingerprint
// in capital hex, as shown by gpg --list-keys (e.g. "621CC013").
func (pk *PublicKey) KeyIdShortString() string {
return fmt.Sprintf("%X", pk.Fingerprint[16:20])
}
// A parsedMPI is used to store the contents of a big integer, along with the
// bit length that was specified in the original input. This allows the MPI to
// be reserialized exactly.
type parsedMPI struct {
bytes []byte
bitLength uint16
}
// writeMPIs is a utility function for serializing several big integers to the
// given Writer.
func writeMPIs(w io.Writer, mpis ...parsedMPI) (err error) {
for _, mpi := range mpis {
err = writeMPI(w, mpi.bitLength, mpi.bytes)
if err != nil {
return
}
}
return
}

View File

@ -1,99 +0,0 @@
// 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 packet
import (
"bytes"
"encoding/hex"
"testing"
"time"
)
var pubKeyTests = []struct {
hexData string
hexFingerprint string
creationTime time.Time
pubKeyAlgo PublicKeyAlgorithm
keyId uint64
keyIdString string
keyIdShort string
}{
{rsaPkDataHex, rsaFingerprintHex, time.Unix(0x4d3c5c10, 0), PubKeyAlgoRSA, 0xa34d7e18c20c31bb, "A34D7E18C20C31BB", "C20C31BB"},
{dsaPkDataHex, dsaFingerprintHex, time.Unix(0x4d432f89, 0), PubKeyAlgoDSA, 0x8e8fbe54062f19ed, "8E8FBE54062F19ED", "062F19ED"},
}
func TestPublicKeyRead(t *testing.T) {
for i, test := range pubKeyTests {
packet, err := Read(readerFromHex(test.hexData))
if err != nil {
t.Errorf("#%d: Read error: %s", i, err)
continue
}
pk, ok := packet.(*PublicKey)
if !ok {
t.Errorf("#%d: failed to parse, got: %#v", i, packet)
continue
}
if pk.PubKeyAlgo != test.pubKeyAlgo {
t.Errorf("#%d: bad public key algorithm got:%x want:%x", i, pk.PubKeyAlgo, test.pubKeyAlgo)
}
if !pk.CreationTime.Equal(test.creationTime) {
t.Errorf("#%d: bad creation time got:%v want:%v", i, pk.CreationTime, test.creationTime)
}
expectedFingerprint, _ := hex.DecodeString(test.hexFingerprint)
if !bytes.Equal(expectedFingerprint, pk.Fingerprint[:]) {
t.Errorf("#%d: bad fingerprint got:%x want:%x", i, pk.Fingerprint[:], expectedFingerprint)
}
if pk.KeyId != test.keyId {
t.Errorf("#%d: bad keyid got:%x want:%x", i, pk.KeyId, test.keyId)
}
if g, e := pk.KeyIdString(), test.keyIdString; g != e {
t.Errorf("#%d: bad KeyIdString got:%q want:%q", i, g, e)
}
if g, e := pk.KeyIdShortString(), test.keyIdShort; g != e {
t.Errorf("#%d: bad KeyIdShortString got:%q want:%q", i, g, e)
}
}
}
func TestPublicKeySerialize(t *testing.T) {
for i, test := range pubKeyTests {
packet, err := Read(readerFromHex(test.hexData))
if err != nil {
t.Errorf("#%d: Read error: %s", i, err)
continue
}
pk, ok := packet.(*PublicKey)
if !ok {
t.Errorf("#%d: failed to parse, got: %#v", i, packet)
continue
}
serializeBuf := bytes.NewBuffer(nil)
err = pk.Serialize(serializeBuf)
if err != nil {
t.Errorf("#%d: failed to serialize: %s", i, err)
continue
}
packet, err = Read(serializeBuf)
if err != nil {
t.Errorf("#%d: Read error (from serialized data): %s", i, err)
continue
}
pk, ok = packet.(*PublicKey)
if !ok {
t.Errorf("#%d: failed to parse serialized data, got: %#v", i, packet)
continue
}
}
}
const rsaFingerprintHex = "5fb74b1d03b1e3cb31bc2f8aa34d7e18c20c31bb"
const rsaPkDataHex = "988d044d3c5c10010400b1d13382944bd5aba23a4312968b5095d14f947f600eb478e14a6fcb16b0e0cac764884909c020bc495cfcc39a935387c661507bdb236a0612fb582cac3af9b29cc2c8c70090616c41b662f4da4c1201e195472eb7f4ae1ccbcbf9940fe21d985e379a5563dde5b9a23d35f1cfaa5790da3b79db26f23695107bfaca8e7b5bcd0011010001"
const dsaFingerprintHex = "eece4c094db002103714c63c8e8fbe54062f19ed"
const dsaPkDataHex = "9901a2044d432f89110400cd581334f0d7a1e1bdc8b9d6d8c0baf68793632735d2bb0903224cbaa1dfbf35a60ee7a13b92643421e1eb41aa8d79bea19a115a677f6b8ba3c7818ce53a6c2a24a1608bd8b8d6e55c5090cbde09dd26e356267465ae25e69ec8bdd57c7bbb2623e4d73336f73a0a9098f7f16da2e25252130fd694c0e8070c55a812a423ae7f00a0ebf50e70c2f19c3520a551bd4b08d30f23530d3d03ff7d0bf4a53a64a09dc5e6e6e35854b7d70c882b0c60293401958b1bd9e40abec3ea05ba87cf64899299d4bd6aa7f459c201d3fbbd6c82004bdc5e8a9eb8082d12054cc90fa9d4ec251a843236a588bf49552441817436c4f43326966fe85447d4e6d0acf8fa1ef0f014730770603ad7634c3088dc52501c237328417c31c89ed70400b2f1a98b0bf42f11fefc430704bebbaa41d9f355600c3facee1e490f64208e0e094ea55e3a598a219a58500bf78ac677b670a14f4e47e9cf8eab4f368cc1ddcaa18cc59309d4cc62dd4f680e73e6cc3e1ce87a84d0925efbcb26c575c093fc42eecf45135fabf6403a25c2016e1774c0484e440a18319072c617cc97ac0a3bb0"

View File

@ -1,62 +0,0 @@
// 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 packet
import (
"crypto/openpgp/errors"
"io"
)
// Reader reads packets from an io.Reader and allows packets to be 'unread' so
// that they result from the next call to Next.
type Reader struct {
q []Packet
readers []io.Reader
}
// Next returns the most recently unread Packet, or reads another packet from
// the top-most io.Reader. Unknown packet types are skipped.
func (r *Reader) Next() (p Packet, err error) {
if len(r.q) > 0 {
p = r.q[len(r.q)-1]
r.q = r.q[:len(r.q)-1]
return
}
for len(r.readers) > 0 {
p, err = Read(r.readers[len(r.readers)-1])
if err == nil {
return
}
if err == io.EOF {
r.readers = r.readers[:len(r.readers)-1]
continue
}
if _, ok := err.(errors.UnknownPacketTypeError); !ok {
return nil, err
}
}
return nil, io.EOF
}
// Push causes the Reader to start reading from a new io.Reader. When an EOF
// error is seen from the new io.Reader, it is popped and the Reader continues
// to read from the next most recent io.Reader.
func (r *Reader) Push(reader io.Reader) {
r.readers = append(r.readers, reader)
}
// Unread causes the given Packet to be returned from the next call to Next.
func (r *Reader) Unread(p Packet) {
r.q = append(r.q, p)
}
func NewReader(r io.Reader) *Reader {
return &Reader{
q: nil,
readers: []io.Reader{r},
}
}

View File

@ -1,611 +0,0 @@
// 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 packet
import (
"crypto"
"crypto/dsa"
"crypto/openpgp/errors"
"crypto/openpgp/s2k"
"crypto/rsa"
"encoding/binary"
"hash"
"io"
"strconv"
"time"
)
// Signature represents a signature. See RFC 4880, section 5.2.
type Signature struct {
SigType SignatureType
PubKeyAlgo PublicKeyAlgorithm
Hash crypto.Hash
// HashSuffix is extra data that is hashed in after the signed data.
HashSuffix []byte
// HashTag contains the first two bytes of the hash for fast rejection
// of bad signed data.
HashTag [2]byte
CreationTime time.Time
RSASignature parsedMPI
DSASigR, DSASigS parsedMPI
// rawSubpackets contains the unparsed subpackets, in order.
rawSubpackets []outputSubpacket
// The following are optional so are nil when not included in the
// signature.
SigLifetimeSecs, KeyLifetimeSecs *uint32
PreferredSymmetric, PreferredHash, PreferredCompression []uint8
IssuerKeyId *uint64
IsPrimaryId *bool
// FlagsValid is set if any flags were given. See RFC 4880, section
// 5.2.3.21 for details.
FlagsValid bool
FlagCertify, FlagSign, FlagEncryptCommunications, FlagEncryptStorage bool
outSubpackets []outputSubpacket
}
func (sig *Signature) parse(r io.Reader) (err error) {
// RFC 4880, section 5.2.3
var buf [5]byte
_, err = readFull(r, buf[:1])
if err != nil {
return
}
if buf[0] != 4 {
err = errors.UnsupportedError("signature packet version " + strconv.Itoa(int(buf[0])))
return
}
_, err = readFull(r, buf[:5])
if err != nil {
return
}
sig.SigType = SignatureType(buf[0])
sig.PubKeyAlgo = PublicKeyAlgorithm(buf[1])
switch sig.PubKeyAlgo {
case PubKeyAlgoRSA, PubKeyAlgoRSASignOnly, PubKeyAlgoDSA:
default:
err = errors.UnsupportedError("public key algorithm " + strconv.Itoa(int(sig.PubKeyAlgo)))
return
}
var ok bool
sig.Hash, ok = s2k.HashIdToHash(buf[2])
if !ok {
return errors.UnsupportedError("hash function " + strconv.Itoa(int(buf[2])))
}
hashedSubpacketsLength := int(buf[3])<<8 | int(buf[4])
l := 6 + hashedSubpacketsLength
sig.HashSuffix = make([]byte, l+6)
sig.HashSuffix[0] = 4
copy(sig.HashSuffix[1:], buf[:5])
hashedSubpackets := sig.HashSuffix[6:l]
_, err = readFull(r, hashedSubpackets)
if err != nil {
return
}
// See RFC 4880, section 5.2.4
trailer := sig.HashSuffix[l:]
trailer[0] = 4
trailer[1] = 0xff
trailer[2] = uint8(l >> 24)
trailer[3] = uint8(l >> 16)
trailer[4] = uint8(l >> 8)
trailer[5] = uint8(l)
err = parseSignatureSubpackets(sig, hashedSubpackets, true)
if err != nil {
return
}
_, err = readFull(r, buf[:2])
if err != nil {
return
}
unhashedSubpacketsLength := int(buf[0])<<8 | int(buf[1])
unhashedSubpackets := make([]byte, unhashedSubpacketsLength)
_, err = readFull(r, unhashedSubpackets)
if err != nil {
return
}
err = parseSignatureSubpackets(sig, unhashedSubpackets, false)
if err != nil {
return
}
_, err = readFull(r, sig.HashTag[:2])
if err != nil {
return
}
switch sig.PubKeyAlgo {
case PubKeyAlgoRSA, PubKeyAlgoRSASignOnly:
sig.RSASignature.bytes, sig.RSASignature.bitLength, err = readMPI(r)
case PubKeyAlgoDSA:
sig.DSASigR.bytes, sig.DSASigR.bitLength, err = readMPI(r)
if err == nil {
sig.DSASigS.bytes, sig.DSASigS.bitLength, err = readMPI(r)
}
default:
panic("unreachable")
}
return
}
// parseSignatureSubpackets parses subpackets of the main signature packet. See
// RFC 4880, section 5.2.3.1.
func parseSignatureSubpackets(sig *Signature, subpackets []byte, isHashed bool) (err error) {
for len(subpackets) > 0 {
subpackets, err = parseSignatureSubpacket(sig, subpackets, isHashed)
if err != nil {
return
}
}
if sig.CreationTime.IsZero() {
err = errors.StructuralError("no creation time in signature")
}
return
}
type signatureSubpacketType uint8
const (
creationTimeSubpacket signatureSubpacketType = 2
signatureExpirationSubpacket signatureSubpacketType = 3
keyExpirationSubpacket signatureSubpacketType = 9
prefSymmetricAlgosSubpacket signatureSubpacketType = 11
issuerSubpacket signatureSubpacketType = 16
prefHashAlgosSubpacket signatureSubpacketType = 21
prefCompressionSubpacket signatureSubpacketType = 22
primaryUserIdSubpacket signatureSubpacketType = 25
keyFlagsSubpacket signatureSubpacketType = 27
)
// parseSignatureSubpacket parses a single subpacket. len(subpacket) is >= 1.
func parseSignatureSubpacket(sig *Signature, subpacket []byte, isHashed bool) (rest []byte, err error) {
// RFC 4880, section 5.2.3.1
var (
length uint32
packetType signatureSubpacketType
isCritical bool
)
switch {
case subpacket[0] < 192:
length = uint32(subpacket[0])
subpacket = subpacket[1:]
case subpacket[0] < 255:
if len(subpacket) < 2 {
goto Truncated
}
length = uint32(subpacket[0]-192)<<8 + uint32(subpacket[1]) + 192
subpacket = subpacket[2:]
default:
if len(subpacket) < 5 {
goto Truncated
}
length = uint32(subpacket[1])<<24 |
uint32(subpacket[2])<<16 |
uint32(subpacket[3])<<8 |
uint32(subpacket[4])
subpacket = subpacket[5:]
}
if length > uint32(len(subpacket)) {
goto Truncated
}
rest = subpacket[length:]
subpacket = subpacket[:length]
if len(subpacket) == 0 {
err = errors.StructuralError("zero length signature subpacket")
return
}
packetType = signatureSubpacketType(subpacket[0] & 0x7f)
isCritical = subpacket[0]&0x80 == 0x80
subpacket = subpacket[1:]
sig.rawSubpackets = append(sig.rawSubpackets, outputSubpacket{isHashed, packetType, isCritical, subpacket})
switch packetType {
case creationTimeSubpacket:
if !isHashed {
err = errors.StructuralError("signature creation time in non-hashed area")
return
}
if len(subpacket) != 4 {
err = errors.StructuralError("signature creation time not four bytes")
return
}
t := binary.BigEndian.Uint32(subpacket)
sig.CreationTime = time.Unix(int64(t), 0)
case signatureExpirationSubpacket:
// Signature expiration time, section 5.2.3.10
if !isHashed {
return
}
if len(subpacket) != 4 {
err = errors.StructuralError("expiration subpacket with bad length")
return
}
sig.SigLifetimeSecs = new(uint32)
*sig.SigLifetimeSecs = binary.BigEndian.Uint32(subpacket)
case keyExpirationSubpacket:
// Key expiration time, section 5.2.3.6
if !isHashed {
return
}
if len(subpacket) != 4 {
err = errors.StructuralError("key expiration subpacket with bad length")
return
}
sig.KeyLifetimeSecs = new(uint32)
*sig.KeyLifetimeSecs = binary.BigEndian.Uint32(subpacket)
case prefSymmetricAlgosSubpacket:
// Preferred symmetric algorithms, section 5.2.3.7
if !isHashed {
return
}
sig.PreferredSymmetric = make([]byte, len(subpacket))
copy(sig.PreferredSymmetric, subpacket)
case issuerSubpacket:
// Issuer, section 5.2.3.5
if len(subpacket) != 8 {
err = errors.StructuralError("issuer subpacket with bad length")
return
}
sig.IssuerKeyId = new(uint64)
*sig.IssuerKeyId = binary.BigEndian.Uint64(subpacket)
case prefHashAlgosSubpacket:
// Preferred hash algorithms, section 5.2.3.8
if !isHashed {
return
}
sig.PreferredHash = make([]byte, len(subpacket))
copy(sig.PreferredHash, subpacket)
case prefCompressionSubpacket:
// Preferred compression algorithms, section 5.2.3.9
if !isHashed {
return
}
sig.PreferredCompression = make([]byte, len(subpacket))
copy(sig.PreferredCompression, subpacket)
case primaryUserIdSubpacket:
// Primary User ID, section 5.2.3.19
if !isHashed {
return
}
if len(subpacket) != 1 {
err = errors.StructuralError("primary user id subpacket with bad length")
return
}
sig.IsPrimaryId = new(bool)
if subpacket[0] > 0 {
*sig.IsPrimaryId = true
}
case keyFlagsSubpacket:
// Key flags, section 5.2.3.21
if !isHashed {
return
}
if len(subpacket) == 0 {
err = errors.StructuralError("empty key flags subpacket")
return
}
sig.FlagsValid = true
if subpacket[0]&1 != 0 {
sig.FlagCertify = true
}
if subpacket[0]&2 != 0 {
sig.FlagSign = true
}
if subpacket[0]&4 != 0 {
sig.FlagEncryptCommunications = true
}
if subpacket[0]&8 != 0 {
sig.FlagEncryptStorage = true
}
default:
if isCritical {
err = errors.UnsupportedError("unknown critical signature subpacket type " + strconv.Itoa(int(packetType)))
return
}
}
return
Truncated:
err = errors.StructuralError("signature subpacket truncated")
return
}
// subpacketLengthLength returns the length, in bytes, of an encoded length value.
func subpacketLengthLength(length int) int {
if length < 192 {
return 1
}
if length < 16320 {
return 2
}
return 5
}
// serializeSubpacketLength marshals the given length into to.
func serializeSubpacketLength(to []byte, length int) int {
if length < 192 {
to[0] = byte(length)
return 1
}
if length < 16320 {
length -= 192
to[0] = byte(length >> 8)
to[1] = byte(length)
return 2
}
to[0] = 255
to[1] = byte(length >> 24)
to[2] = byte(length >> 16)
to[3] = byte(length >> 8)
to[4] = byte(length)
return 5
}
// subpacketsLength returns the serialized length, in bytes, of the given
// subpackets.
func subpacketsLength(subpackets []outputSubpacket, hashed bool) (length int) {
for _, subpacket := range subpackets {
if subpacket.hashed == hashed {
length += subpacketLengthLength(len(subpacket.contents) + 1)
length += 1 // type byte
length += len(subpacket.contents)
}
}
return
}
// serializeSubpackets marshals the given subpackets into to.
func serializeSubpackets(to []byte, subpackets []outputSubpacket, hashed bool) {
for _, subpacket := range subpackets {
if subpacket.hashed == hashed {
n := serializeSubpacketLength(to, len(subpacket.contents)+1)
to[n] = byte(subpacket.subpacketType)
to = to[1+n:]
n = copy(to, subpacket.contents)
to = to[n:]
}
}
return
}
// buildHashSuffix constructs the HashSuffix member of sig in preparation for signing.
func (sig *Signature) buildHashSuffix() (err error) {
hashedSubpacketsLen := subpacketsLength(sig.outSubpackets, true)
var ok bool
l := 6 + hashedSubpacketsLen
sig.HashSuffix = make([]byte, l+6)
sig.HashSuffix[0] = 4
sig.HashSuffix[1] = uint8(sig.SigType)
sig.HashSuffix[2] = uint8(sig.PubKeyAlgo)
sig.HashSuffix[3], ok = s2k.HashToHashId(sig.Hash)
if !ok {
sig.HashSuffix = nil
return errors.InvalidArgumentError("hash cannot be represented in OpenPGP: " + strconv.Itoa(int(sig.Hash)))
}
sig.HashSuffix[4] = byte(hashedSubpacketsLen >> 8)
sig.HashSuffix[5] = byte(hashedSubpacketsLen)
serializeSubpackets(sig.HashSuffix[6:l], sig.outSubpackets, true)
trailer := sig.HashSuffix[l:]
trailer[0] = 4
trailer[1] = 0xff
trailer[2] = byte(l >> 24)
trailer[3] = byte(l >> 16)
trailer[4] = byte(l >> 8)
trailer[5] = byte(l)
return
}
func (sig *Signature) signPrepareHash(h hash.Hash) (digest []byte, err error) {
err = sig.buildHashSuffix()
if err != nil {
return
}
h.Write(sig.HashSuffix)
digest = h.Sum(nil)
copy(sig.HashTag[:], digest)
return
}
// Sign signs a message with a private key. The hash, h, must contain
// the hash of the message to be signed and will be mutated by this function.
// On success, the signature is stored in sig. Call Serialize to write it out.
func (sig *Signature) Sign(rand io.Reader, h hash.Hash, priv *PrivateKey) (err error) {
sig.outSubpackets = sig.buildSubpackets()
digest, err := sig.signPrepareHash(h)
if err != nil {
return
}
switch priv.PubKeyAlgo {
case PubKeyAlgoRSA, PubKeyAlgoRSASignOnly:
sig.RSASignature.bytes, err = rsa.SignPKCS1v15(rand, priv.PrivateKey.(*rsa.PrivateKey), sig.Hash, digest)
sig.RSASignature.bitLength = uint16(8 * len(sig.RSASignature.bytes))
case PubKeyAlgoDSA:
dsaPriv := priv.PrivateKey.(*dsa.PrivateKey)
// Need to truncate hashBytes to match FIPS 186-3 section 4.6.
subgroupSize := (dsaPriv.Q.BitLen() + 7) / 8
if len(digest) > subgroupSize {
digest = digest[:subgroupSize]
}
r, s, err := dsa.Sign(rand, dsaPriv, digest)
if err == nil {
sig.DSASigR.bytes = r.Bytes()
sig.DSASigR.bitLength = uint16(8 * len(sig.DSASigR.bytes))
sig.DSASigS.bytes = s.Bytes()
sig.DSASigS.bitLength = uint16(8 * len(sig.DSASigS.bytes))
}
default:
err = errors.UnsupportedError("public key algorithm: " + strconv.Itoa(int(sig.PubKeyAlgo)))
}
return
}
// SignUserId computes a signature from priv, asserting that pub is a valid
// key for the identity id. On success, the signature is stored in sig. Call
// Serialize to write it out.
func (sig *Signature) SignUserId(rand io.Reader, id string, pub *PublicKey, priv *PrivateKey) error {
h, err := userIdSignatureHash(id, pub, sig)
if err != nil {
return nil
}
return sig.Sign(rand, h, priv)
}
// SignKey computes a signature from priv, asserting that pub is a subkey. On
// success, the signature is stored in sig. Call Serialize to write it out.
func (sig *Signature) SignKey(rand io.Reader, pub *PublicKey, priv *PrivateKey) error {
h, err := keySignatureHash(&priv.PublicKey, pub, sig)
if err != nil {
return err
}
return sig.Sign(rand, h, priv)
}
// Serialize marshals sig to w. SignRSA or SignDSA must have been called first.
func (sig *Signature) Serialize(w io.Writer) (err error) {
if len(sig.outSubpackets) == 0 {
sig.outSubpackets = sig.rawSubpackets
}
if sig.RSASignature.bytes == nil && sig.DSASigR.bytes == nil {
return errors.InvalidArgumentError("Signature: need to call SignRSA or SignDSA before Serialize")
}
sigLength := 0
switch sig.PubKeyAlgo {
case PubKeyAlgoRSA, PubKeyAlgoRSASignOnly:
sigLength = 2 + len(sig.RSASignature.bytes)
case PubKeyAlgoDSA:
sigLength = 2 + len(sig.DSASigR.bytes)
sigLength += 2 + len(sig.DSASigS.bytes)
default:
panic("impossible")
}
unhashedSubpacketsLen := subpacketsLength(sig.outSubpackets, false)
length := len(sig.HashSuffix) - 6 /* trailer not included */ +
2 /* length of unhashed subpackets */ + unhashedSubpacketsLen +
2 /* hash tag */ + sigLength
err = serializeHeader(w, packetTypeSignature, length)
if err != nil {
return
}
_, err = w.Write(sig.HashSuffix[:len(sig.HashSuffix)-6])
if err != nil {
return
}
unhashedSubpackets := make([]byte, 2+unhashedSubpacketsLen)
unhashedSubpackets[0] = byte(unhashedSubpacketsLen >> 8)
unhashedSubpackets[1] = byte(unhashedSubpacketsLen)
serializeSubpackets(unhashedSubpackets[2:], sig.outSubpackets, false)
_, err = w.Write(unhashedSubpackets)
if err != nil {
return
}
_, err = w.Write(sig.HashTag[:])
if err != nil {
return
}
switch sig.PubKeyAlgo {
case PubKeyAlgoRSA, PubKeyAlgoRSASignOnly:
err = writeMPIs(w, sig.RSASignature)
case PubKeyAlgoDSA:
err = writeMPIs(w, sig.DSASigR, sig.DSASigS)
default:
panic("impossible")
}
return
}
// outputSubpacket represents a subpacket to be marshaled.
type outputSubpacket struct {
hashed bool // true if this subpacket is in the hashed area.
subpacketType signatureSubpacketType
isCritical bool
contents []byte
}
func (sig *Signature) buildSubpackets() (subpackets []outputSubpacket) {
creationTime := make([]byte, 4)
binary.BigEndian.PutUint32(creationTime, uint32(sig.CreationTime.Unix()))
subpackets = append(subpackets, outputSubpacket{true, creationTimeSubpacket, false, creationTime})
if sig.IssuerKeyId != nil {
keyId := make([]byte, 8)
binary.BigEndian.PutUint64(keyId, *sig.IssuerKeyId)
subpackets = append(subpackets, outputSubpacket{true, issuerSubpacket, false, keyId})
}
if sig.SigLifetimeSecs != nil && *sig.SigLifetimeSecs != 0 {
sigLifetime := make([]byte, 4)
binary.BigEndian.PutUint32(sigLifetime, *sig.SigLifetimeSecs)
subpackets = append(subpackets, outputSubpacket{true, signatureExpirationSubpacket, true, sigLifetime})
}
// Key flags may only appear in self-signatures or certification signatures.
if sig.FlagsValid {
var flags byte
if sig.FlagCertify {
flags |= 1
}
if sig.FlagSign {
flags |= 2
}
if sig.FlagEncryptCommunications {
flags |= 4
}
if sig.FlagEncryptStorage {
flags |= 8
}
subpackets = append(subpackets, outputSubpacket{true, keyFlagsSubpacket, false, []byte{flags}})
}
// The following subpackets may only appear in self-signatures
if sig.KeyLifetimeSecs != nil && *sig.KeyLifetimeSecs != 0 {
keyLifetime := make([]byte, 4)
binary.BigEndian.PutUint32(keyLifetime, *sig.KeyLifetimeSecs)
subpackets = append(subpackets, outputSubpacket{true, keyExpirationSubpacket, true, keyLifetime})
}
if sig.IsPrimaryId != nil && *sig.IsPrimaryId {
subpackets = append(subpackets, outputSubpacket{true, primaryUserIdSubpacket, false, []byte{1}})
}
if len(sig.PreferredSymmetric) > 0 {
subpackets = append(subpackets, outputSubpacket{true, prefSymmetricAlgosSubpacket, false, sig.PreferredSymmetric})
}
if len(sig.PreferredHash) > 0 {
subpackets = append(subpackets, outputSubpacket{true, prefHashAlgosSubpacket, false, sig.PreferredHash})
}
if len(sig.PreferredCompression) > 0 {
subpackets = append(subpackets, outputSubpacket{true, prefCompressionSubpacket, false, sig.PreferredCompression})
}
return
}

View File

@ -1,42 +0,0 @@
// 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 packet
import (
"bytes"
"crypto"
"encoding/hex"
"testing"
)
func TestSignatureRead(t *testing.T) {
packet, err := Read(readerFromHex(signatureDataHex))
if err != nil {
t.Error(err)
return
}
sig, ok := packet.(*Signature)
if !ok || sig.SigType != SigTypeBinary || sig.PubKeyAlgo != PubKeyAlgoRSA || sig.Hash != crypto.SHA1 {
t.Errorf("failed to parse, got: %#v", packet)
}
}
func TestSignatureReserialize(t *testing.T) {
packet, _ := Read(readerFromHex(signatureDataHex))
sig := packet.(*Signature)
out := new(bytes.Buffer)
err := sig.Serialize(out)
if err != nil {
t.Errorf("error reserializing: %s", err)
return
}
expected, _ := hex.DecodeString(signatureDataHex)
if !bytes.Equal(expected, out.Bytes()) {
t.Errorf("output doesn't match input (got vs expected):\n%s\n%s", hex.Dump(out.Bytes()), hex.Dump(expected))
}
}
const signatureDataHex = "c2c05c04000102000605024cb45112000a0910ab105c91af38fb158f8d07ff5596ea368c5efe015bed6e78348c0f033c931d5f2ce5db54ce7f2a7e4b4ad64db758d65a7a71773edeab7ba2a9e0908e6a94a1175edd86c1d843279f045b021a6971a72702fcbd650efc393c5474d5b59a15f96d2eaad4c4c426797e0dcca2803ef41c6ff234d403eec38f31d610c344c06f2401c262f0993b2e66cad8a81ebc4322c723e0d4ba09fe917e8777658307ad8329adacba821420741009dfe87f007759f0982275d028a392c6ed983a0d846f890b36148c7358bdb8a516007fac760261ecd06076813831a36d0459075d1befa245ae7f7fb103d92ca759e9498fe60ef8078a39a3beda510deea251ea9f0a7f0df6ef42060f20780360686f3e400e"

View File

@ -1,161 +0,0 @@
// 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 packet
import (
"bytes"
"crypto/cipher"
"crypto/openpgp/errors"
"crypto/openpgp/s2k"
"io"
"strconv"
)
// This is the largest session key that we'll support. Since no 512-bit cipher
// has even been seriously used, this is comfortably large.
const maxSessionKeySizeInBytes = 64
// SymmetricKeyEncrypted represents a passphrase protected session key. See RFC
// 4880, section 5.3.
type SymmetricKeyEncrypted struct {
CipherFunc CipherFunction
Encrypted bool
Key []byte // Empty unless Encrypted is false.
s2k func(out, in []byte)
encryptedKey []byte
}
const symmetricKeyEncryptedVersion = 4
func (ske *SymmetricKeyEncrypted) parse(r io.Reader) (err error) {
// RFC 4880, section 5.3.
var buf [2]byte
_, err = readFull(r, buf[:])
if err != nil {
return
}
if buf[0] != symmetricKeyEncryptedVersion {
return errors.UnsupportedError("SymmetricKeyEncrypted version")
}
ske.CipherFunc = CipherFunction(buf[1])
if ske.CipherFunc.KeySize() == 0 {
return errors.UnsupportedError("unknown cipher: " + strconv.Itoa(int(buf[1])))
}
ske.s2k, err = s2k.Parse(r)
if err != nil {
return
}
encryptedKey := make([]byte, maxSessionKeySizeInBytes)
// The session key may follow. We just have to try and read to find
// out. If it exists then we limit it to maxSessionKeySizeInBytes.
n, err := readFull(r, encryptedKey)
if err != nil && err != io.ErrUnexpectedEOF {
return
}
err = nil
if n != 0 {
if n == maxSessionKeySizeInBytes {
return errors.UnsupportedError("oversized encrypted session key")
}
ske.encryptedKey = encryptedKey[:n]
}
ske.Encrypted = true
return
}
// Decrypt attempts to decrypt an encrypted session key. If it returns nil,
// ske.Key will contain the session key.
func (ske *SymmetricKeyEncrypted) Decrypt(passphrase []byte) error {
if !ske.Encrypted {
return nil
}
key := make([]byte, ske.CipherFunc.KeySize())
ske.s2k(key, passphrase)
if len(ske.encryptedKey) == 0 {
ske.Key = key
} else {
// the IV is all zeros
iv := make([]byte, ske.CipherFunc.blockSize())
c := cipher.NewCFBDecrypter(ske.CipherFunc.new(key), iv)
c.XORKeyStream(ske.encryptedKey, ske.encryptedKey)
ske.CipherFunc = CipherFunction(ske.encryptedKey[0])
if ske.CipherFunc.blockSize() == 0 {
return errors.UnsupportedError("unknown cipher: " + strconv.Itoa(int(ske.CipherFunc)))
}
ske.CipherFunc = CipherFunction(ske.encryptedKey[0])
ske.Key = ske.encryptedKey[1:]
if len(ske.Key)%ske.CipherFunc.blockSize() != 0 {
ske.Key = nil
return errors.StructuralError("length of decrypted key not a multiple of block size")
}
}
ske.Encrypted = false
return nil
}
// SerializeSymmetricKeyEncrypted serializes a symmetric key packet to w. The
// packet contains a random session key, encrypted by a key derived from the
// given passphrase. The session key is returned and must be passed to
// SerializeSymmetricallyEncrypted.
func SerializeSymmetricKeyEncrypted(w io.Writer, rand io.Reader, passphrase []byte, cipherFunc CipherFunction) (key []byte, err error) {
keySize := cipherFunc.KeySize()
if keySize == 0 {
return nil, errors.UnsupportedError("unknown cipher: " + strconv.Itoa(int(cipherFunc)))
}
s2kBuf := new(bytes.Buffer)
keyEncryptingKey := make([]byte, keySize)
// s2k.Serialize salts and stretches the passphrase, and writes the
// resulting key to keyEncryptingKey and the s2k descriptor to s2kBuf.
err = s2k.Serialize(s2kBuf, keyEncryptingKey, rand, passphrase)
if err != nil {
return
}
s2kBytes := s2kBuf.Bytes()
packetLength := 2 /* header */ + len(s2kBytes) + 1 /* cipher type */ + keySize
err = serializeHeader(w, packetTypeSymmetricKeyEncrypted, packetLength)
if err != nil {
return
}
var buf [2]byte
buf[0] = symmetricKeyEncryptedVersion
buf[1] = byte(cipherFunc)
_, err = w.Write(buf[:])
if err != nil {
return
}
_, err = w.Write(s2kBytes)
if err != nil {
return
}
sessionKey := make([]byte, keySize)
_, err = io.ReadFull(rand, sessionKey)
if err != nil {
return
}
iv := make([]byte, cipherFunc.blockSize())
c := cipher.NewCFBEncrypter(cipherFunc.new(keyEncryptingKey), iv)
encryptedCipherAndKey := make([]byte, keySize+1)
c.XORKeyStream(encryptedCipherAndKey, buf[1:])
c.XORKeyStream(encryptedCipherAndKey[1:], sessionKey)
_, err = w.Write(encryptedCipherAndKey)
if err != nil {
return
}
key = sessionKey
return
}

View File

@ -1,101 +0,0 @@
// 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 packet
import (
"bytes"
"crypto/rand"
"encoding/hex"
"io"
"io/ioutil"
"testing"
)
func TestSymmetricKeyEncrypted(t *testing.T) {
buf := readerFromHex(symmetricallyEncryptedHex)
packet, err := Read(buf)
if err != nil {
t.Errorf("failed to read SymmetricKeyEncrypted: %s", err)
return
}
ske, ok := packet.(*SymmetricKeyEncrypted)
if !ok {
t.Error("didn't find SymmetricKeyEncrypted packet")
return
}
err = ske.Decrypt([]byte("password"))
if err != nil {
t.Error(err)
return
}
packet, err = Read(buf)
if err != nil {
t.Errorf("failed to read SymmetricallyEncrypted: %s", err)
return
}
se, ok := packet.(*SymmetricallyEncrypted)
if !ok {
t.Error("didn't find SymmetricallyEncrypted packet")
return
}
r, err := se.Decrypt(ske.CipherFunc, ske.Key)
if err != nil {
t.Error(err)
return
}
contents, err := ioutil.ReadAll(r)
if err != nil && err != io.EOF {
t.Error(err)
return
}
expectedContents, _ := hex.DecodeString(symmetricallyEncryptedContentsHex)
if !bytes.Equal(expectedContents, contents) {
t.Errorf("bad contents got:%x want:%x", contents, expectedContents)
}
}
const symmetricallyEncryptedHex = "8c0d04030302371a0b38d884f02060c91cf97c9973b8e58e028e9501708ccfe618fb92afef7fa2d80ddadd93cf"
const symmetricallyEncryptedContentsHex = "cb1062004d14c4df636f6e74656e74732e0a"
func TestSerializeSymmetricKeyEncrypted(t *testing.T) {
buf := bytes.NewBuffer(nil)
passphrase := []byte("testing")
cipherFunc := CipherAES128
key, err := SerializeSymmetricKeyEncrypted(buf, rand.Reader, passphrase, cipherFunc)
if err != nil {
t.Errorf("failed to serialize: %s", err)
return
}
p, err := Read(buf)
if err != nil {
t.Errorf("failed to reparse: %s", err)
return
}
ske, ok := p.(*SymmetricKeyEncrypted)
if !ok {
t.Errorf("parsed a different packet type: %#v", p)
return
}
if !ske.Encrypted {
t.Errorf("SKE not encrypted but should be")
}
if ske.CipherFunc != cipherFunc {
t.Errorf("SKE cipher function is %d (expected %d)", ske.CipherFunc, cipherFunc)
}
err = ske.Decrypt(passphrase)
if err != nil {
t.Errorf("failed to decrypt reparsed SKE: %s", err)
return
}
if !bytes.Equal(key, ske.Key) {
t.Errorf("keys don't match after Decrpyt: %x (original) vs %x (parsed)", key, ske.Key)
}
}

View File

@ -1,289 +0,0 @@
// 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 packet
import (
"crypto/cipher"
"crypto/openpgp/errors"
"crypto/sha1"
"crypto/subtle"
"hash"
"io"
"strconv"
)
// SymmetricallyEncrypted represents a symmetrically encrypted byte string. The
// encrypted contents will consist of more OpenPGP packets. See RFC 4880,
// sections 5.7 and 5.13.
type SymmetricallyEncrypted struct {
MDC bool // true iff this is a type 18 packet and thus has an embedded MAC.
contents io.Reader
prefix []byte
}
const symmetricallyEncryptedVersion = 1
func (se *SymmetricallyEncrypted) parse(r io.Reader) error {
if se.MDC {
// See RFC 4880, section 5.13.
var buf [1]byte
_, err := readFull(r, buf[:])
if err != nil {
return err
}
if buf[0] != symmetricallyEncryptedVersion {
return errors.UnsupportedError("unknown SymmetricallyEncrypted version")
}
}
se.contents = r
return nil
}
// Decrypt returns a ReadCloser, from which the decrypted contents of the
// packet can be read. An incorrect key can, with high probability, be detected
// immediately and this will result in a KeyIncorrect error being returned.
func (se *SymmetricallyEncrypted) Decrypt(c CipherFunction, key []byte) (io.ReadCloser, error) {
keySize := c.KeySize()
if keySize == 0 {
return nil, errors.UnsupportedError("unknown cipher: " + strconv.Itoa(int(c)))
}
if len(key) != keySize {
return nil, errors.InvalidArgumentError("SymmetricallyEncrypted: incorrect key length")
}
if se.prefix == nil {
se.prefix = make([]byte, c.blockSize()+2)
_, err := readFull(se.contents, se.prefix)
if err != nil {
return nil, err
}
} else if len(se.prefix) != c.blockSize()+2 {
return nil, errors.InvalidArgumentError("can't try ciphers with different block lengths")
}
ocfbResync := cipher.OCFBResync
if se.MDC {
// MDC packets use a different form of OCFB mode.
ocfbResync = cipher.OCFBNoResync
}
s := cipher.NewOCFBDecrypter(c.new(key), se.prefix, ocfbResync)
if s == nil {
return nil, errors.KeyIncorrectError
}
plaintext := cipher.StreamReader{S: s, R: se.contents}
if se.MDC {
// MDC packets have an embedded hash that we need to check.
h := sha1.New()
h.Write(se.prefix)
return &seMDCReader{in: plaintext, h: h}, nil
}
// Otherwise, we just need to wrap plaintext so that it's a valid ReadCloser.
return seReader{plaintext}, nil
}
// seReader wraps an io.Reader with a no-op Close method.
type seReader struct {
in io.Reader
}
func (ser seReader) Read(buf []byte) (int, error) {
return ser.in.Read(buf)
}
func (ser seReader) Close() error {
return nil
}
const mdcTrailerSize = 1 /* tag byte */ + 1 /* length byte */ + sha1.Size
// An seMDCReader wraps an io.Reader, maintains a running hash and keeps hold
// of the most recent 22 bytes (mdcTrailerSize). Upon EOF, those bytes form an
// MDC packet containing a hash of the previous contents which is checked
// against the running hash. See RFC 4880, section 5.13.
type seMDCReader struct {
in io.Reader
h hash.Hash
trailer [mdcTrailerSize]byte
scratch [mdcTrailerSize]byte
trailerUsed int
error bool
eof bool
}
func (ser *seMDCReader) Read(buf []byte) (n int, err error) {
if ser.error {
err = io.ErrUnexpectedEOF
return
}
if ser.eof {
err = io.EOF
return
}
// If we haven't yet filled the trailer buffer then we must do that
// first.
for ser.trailerUsed < mdcTrailerSize {
n, err = ser.in.Read(ser.trailer[ser.trailerUsed:])
ser.trailerUsed += n
if err == io.EOF {
if ser.trailerUsed != mdcTrailerSize {
n = 0
err = io.ErrUnexpectedEOF
ser.error = true
return
}
ser.eof = true
n = 0
return
}
if err != nil {
n = 0
return
}
}
// If it's a short read then we read into a temporary buffer and shift
// the data into the caller's buffer.
if len(buf) <= mdcTrailerSize {
n, err = readFull(ser.in, ser.scratch[:len(buf)])
copy(buf, ser.trailer[:n])
ser.h.Write(buf[:n])
copy(ser.trailer[:], ser.trailer[n:])
copy(ser.trailer[mdcTrailerSize-n:], ser.scratch[:])
if n < len(buf) {
ser.eof = true
err = io.EOF
}
return
}
n, err = ser.in.Read(buf[mdcTrailerSize:])
copy(buf, ser.trailer[:])
ser.h.Write(buf[:n])
copy(ser.trailer[:], buf[n:])
if err == io.EOF {
ser.eof = true
}
return
}
// This is a new-format packet tag byte for a type 19 (MDC) packet.
const mdcPacketTagByte = byte(0x80) | 0x40 | 19
func (ser *seMDCReader) Close() error {
if ser.error {
return errors.SignatureError("error during reading")
}
for !ser.eof {
// We haven't seen EOF so we need to read to the end
var buf [1024]byte
_, err := ser.Read(buf[:])
if err == io.EOF {
break
}
if err != nil {
return errors.SignatureError("error during reading")
}
}
if ser.trailer[0] != mdcPacketTagByte || ser.trailer[1] != sha1.Size {
return errors.SignatureError("MDC packet not found")
}
ser.h.Write(ser.trailer[:2])
final := ser.h.Sum(nil)
if subtle.ConstantTimeCompare(final, ser.trailer[2:]) != 1 {
return errors.SignatureError("hash mismatch")
}
return nil
}
// An seMDCWriter writes through to an io.WriteCloser while maintains a running
// hash of the data written. On close, it emits an MDC packet containing the
// running hash.
type seMDCWriter struct {
w io.WriteCloser
h hash.Hash
}
func (w *seMDCWriter) Write(buf []byte) (n int, err error) {
w.h.Write(buf)
return w.w.Write(buf)
}
func (w *seMDCWriter) Close() (err error) {
var buf [mdcTrailerSize]byte
buf[0] = mdcPacketTagByte
buf[1] = sha1.Size
w.h.Write(buf[:2])
digest := w.h.Sum(nil)
copy(buf[2:], digest)
_, err = w.w.Write(buf[:])
if err != nil {
return
}
return w.w.Close()
}
// noOpCloser is like an ioutil.NopCloser, but for an io.Writer.
type noOpCloser struct {
w io.Writer
}
func (c noOpCloser) Write(data []byte) (n int, err error) {
return c.w.Write(data)
}
func (c noOpCloser) Close() error {
return nil
}
// SerializeSymmetricallyEncrypted serializes a symmetrically encrypted packet
// to w and returns a WriteCloser to which the to-be-encrypted packets can be
// written.
func SerializeSymmetricallyEncrypted(w io.Writer, rand io.Reader, c CipherFunction, key []byte) (contents io.WriteCloser, err error) {
if c.KeySize() != len(key) {
return nil, errors.InvalidArgumentError("SymmetricallyEncrypted.Serialize: bad key length")
}
writeCloser := noOpCloser{w}
ciphertext, err := serializeStreamHeader(writeCloser, packetTypeSymmetricallyEncryptedMDC)
if err != nil {
return
}
_, err = ciphertext.Write([]byte{symmetricallyEncryptedVersion})
if err != nil {
return
}
block := c.new(key)
blockSize := block.BlockSize()
iv := make([]byte, blockSize)
_, err = rand.Read(iv)
if err != nil {
return
}
s, prefix := cipher.NewOCFBEncrypter(block, iv, cipher.OCFBNoResync)
_, err = ciphertext.Write(prefix)
if err != nil {
return
}
plaintext := cipher.StreamWriter{S: s, W: ciphertext}
h := sha1.New()
h.Write(iv)
h.Write(iv[blockSize-2:])
contents = &seMDCWriter{w: plaintext, h: h}
return
}

View File

@ -1,124 +0,0 @@
// 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 packet
import (
"bytes"
"crypto/openpgp/errors"
"crypto/rand"
"crypto/sha1"
"encoding/hex"
"io"
"io/ioutil"
"testing"
)
// TestReader wraps a []byte and returns reads of a specific length.
type testReader struct {
data []byte
stride int
}
func (t *testReader) Read(buf []byte) (n int, err error) {
n = t.stride
if n > len(t.data) {
n = len(t.data)
}
if n > len(buf) {
n = len(buf)
}
copy(buf, t.data)
t.data = t.data[n:]
if len(t.data) == 0 {
err = io.EOF
}
return
}
func testMDCReader(t *testing.T) {
mdcPlaintext, _ := hex.DecodeString(mdcPlaintextHex)
for stride := 1; stride < len(mdcPlaintext)/2; stride++ {
r := &testReader{data: mdcPlaintext, stride: stride}
mdcReader := &seMDCReader{in: r, h: sha1.New()}
body, err := ioutil.ReadAll(mdcReader)
if err != nil {
t.Errorf("stride: %d, error: %s", stride, err)
continue
}
if !bytes.Equal(body, mdcPlaintext[:len(mdcPlaintext)-22]) {
t.Errorf("stride: %d: bad contents %x", stride, body)
continue
}
err = mdcReader.Close()
if err != nil {
t.Errorf("stride: %d, error on Close: %s", stride, err)
}
}
mdcPlaintext[15] ^= 80
r := &testReader{data: mdcPlaintext, stride: 2}
mdcReader := &seMDCReader{in: r, h: sha1.New()}
_, err := ioutil.ReadAll(mdcReader)
if err != nil {
t.Errorf("corruption test, error: %s", err)
return
}
err = mdcReader.Close()
if err == nil {
t.Error("corruption: no error")
} else if _, ok := err.(*errors.SignatureError); !ok {
t.Errorf("corruption: expected SignatureError, got: %s", err)
}
}
const mdcPlaintextHex = "a302789c3b2d93c4e0eb9aba22283539b3203335af44a134afb800c849cb4c4de10200aff40b45d31432c80cb384299a0655966d6939dfdeed1dddf980"
func TestSerialize(t *testing.T) {
buf := bytes.NewBuffer(nil)
c := CipherAES128
key := make([]byte, c.KeySize())
w, err := SerializeSymmetricallyEncrypted(buf, rand.Reader, c, key)
if err != nil {
t.Errorf("error from SerializeSymmetricallyEncrypted: %s", err)
return
}
contents := []byte("hello world\n")
w.Write(contents)
w.Close()
p, err := Read(buf)
if err != nil {
t.Errorf("error from Read: %s", err)
return
}
se, ok := p.(*SymmetricallyEncrypted)
if !ok {
t.Errorf("didn't read a *SymmetricallyEncrypted")
return
}
r, err := se.Decrypt(c, key)
if err != nil {
t.Errorf("error from Decrypt: %s", err)
return
}
contentsCopy := bytes.NewBuffer(nil)
_, err = io.Copy(contentsCopy, r)
if err != nil {
t.Errorf("error from io.Copy: %s", err)
return
}
if !bytes.Equal(contentsCopy.Bytes(), contents) {
t.Errorf("contents not equal got: %x want: %x", contentsCopy.Bytes(), contents)
}
}

View File

@ -1,160 +0,0 @@
// 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 packet
import (
"io"
"io/ioutil"
"strings"
)
// UserId contains text that is intended to represent the name and email
// address of the key holder. See RFC 4880, section 5.11. By convention, this
// takes the form "Full Name (Comment) <email@example.com>"
type UserId struct {
Id string // By convention, this takes the form "Full Name (Comment) <email@example.com>" which is split out in the fields below.
Name, Comment, Email string
}
func hasInvalidCharacters(s string) bool {
for _, c := range s {
switch c {
case '(', ')', '<', '>', 0:
return true
}
}
return false
}
// NewUserId returns a UserId or nil if any of the arguments contain invalid
// characters. The invalid characters are '\x00', '(', ')', '<' and '>'
func NewUserId(name, comment, email string) *UserId {
// RFC 4880 doesn't deal with the structure of userid strings; the
// name, comment and email form is just a convention. However, there's
// no convention about escaping the metacharacters and GPG just refuses
// to create user ids where, say, the name contains a '('. We mirror
// this behaviour.
if hasInvalidCharacters(name) || hasInvalidCharacters(comment) || hasInvalidCharacters(email) {
return nil
}
uid := new(UserId)
uid.Name, uid.Comment, uid.Email = name, comment, email
uid.Id = name
if len(comment) > 0 {
if len(uid.Id) > 0 {
uid.Id += " "
}
uid.Id += "("
uid.Id += comment
uid.Id += ")"
}
if len(email) > 0 {
if len(uid.Id) > 0 {
uid.Id += " "
}
uid.Id += "<"
uid.Id += email
uid.Id += ">"
}
return uid
}
func (uid *UserId) parse(r io.Reader) (err error) {
// RFC 4880, section 5.11
b, err := ioutil.ReadAll(r)
if err != nil {
return
}
uid.Id = string(b)
uid.Name, uid.Comment, uid.Email = parseUserId(uid.Id)
return
}
// Serialize marshals uid to w in the form of an OpenPGP packet, including
// header.
func (uid *UserId) Serialize(w io.Writer) error {
err := serializeHeader(w, packetTypeUserId, len(uid.Id))
if err != nil {
return err
}
_, err = w.Write([]byte(uid.Id))
return err
}
// parseUserId extracts the name, comment and email from a user id string that
// is formatted as "Full Name (Comment) <email@example.com>".
func parseUserId(id string) (name, comment, email string) {
var n, c, e struct {
start, end int
}
var state int
for offset, rune := range id {
switch state {
case 0:
// Entering name
n.start = offset
state = 1
fallthrough
case 1:
// In name
if rune == '(' {
state = 2
n.end = offset
} else if rune == '<' {
state = 5
n.end = offset
}
case 2:
// Entering comment
c.start = offset
state = 3
fallthrough
case 3:
// In comment
if rune == ')' {
state = 4
c.end = offset
}
case 4:
// Between comment and email
if rune == '<' {
state = 5
}
case 5:
// Entering email
e.start = offset
state = 6
fallthrough
case 6:
// In email
if rune == '>' {
state = 7
e.end = offset
}
default:
// After email
}
}
switch state {
case 1:
// ended in the name
n.end = len(id)
case 3:
// ended in comment
c.end = len(id)
case 6:
// ended in email
e.end = len(id)
}
name = strings.TrimSpace(id[n.start:n.end])
comment = strings.TrimSpace(id[c.start:c.end])
email = strings.TrimSpace(id[e.start:e.end])
return
}

View File

@ -1,87 +0,0 @@
// 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 packet
import (
"testing"
)
var userIdTests = []struct {
id string
name, comment, email string
}{
{"", "", "", ""},
{"John Smith", "John Smith", "", ""},
{"John Smith ()", "John Smith", "", ""},
{"John Smith () <>", "John Smith", "", ""},
{"(comment", "", "comment", ""},
{"(comment)", "", "comment", ""},
{"<email", "", "", "email"},
{"<email> sdfk", "", "", "email"},
{" John Smith ( Comment ) asdkflj < email > lksdfj", "John Smith", "Comment", "email"},
{" John Smith < email > lksdfj", "John Smith", "", "email"},
{"(<foo", "", "<foo", ""},
{"René Descartes (العربي)", "René Descartes", "العربي", ""},
}
func TestParseUserId(t *testing.T) {
for i, test := range userIdTests {
name, comment, email := parseUserId(test.id)
if name != test.name {
t.Errorf("%d: name mismatch got:%s want:%s", i, name, test.name)
}
if comment != test.comment {
t.Errorf("%d: comment mismatch got:%s want:%s", i, comment, test.comment)
}
if email != test.email {
t.Errorf("%d: email mismatch got:%s want:%s", i, email, test.email)
}
}
}
var newUserIdTests = []struct {
name, comment, email, id string
}{
{"foo", "", "", "foo"},
{"", "bar", "", "(bar)"},
{"", "", "baz", "<baz>"},
{"foo", "bar", "", "foo (bar)"},
{"foo", "", "baz", "foo <baz>"},
{"", "bar", "baz", "(bar) <baz>"},
{"foo", "bar", "baz", "foo (bar) <baz>"},
}
func TestNewUserId(t *testing.T) {
for i, test := range newUserIdTests {
uid := NewUserId(test.name, test.comment, test.email)
if uid == nil {
t.Errorf("#%d: returned nil", i)
continue
}
if uid.Id != test.id {
t.Errorf("#%d: got '%s', want '%s'", i, uid.Id, test.id)
}
}
}
var invalidNewUserIdTests = []struct {
name, comment, email string
}{
{"foo(", "", ""},
{"foo<", "", ""},
{"", "bar)", ""},
{"", "bar<", ""},
{"", "", "baz>"},
{"", "", "baz)"},
{"", "", "baz\x00"},
}
func TestNewUserIdWithInvalidInput(t *testing.T) {
for i, test := range invalidNewUserIdTests {
if uid := NewUserId(test.name, test.comment, test.email); uid != nil {
t.Errorf("#%d: returned non-nil value: %#v", i, uid)
}
}
}

View File

@ -1,414 +0,0 @@
// 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 openpgp implements high level operations on OpenPGP messages.
package openpgp
import (
"crypto"
"crypto/openpgp/armor"
"crypto/openpgp/errors"
"crypto/openpgp/packet"
_ "crypto/sha256"
"hash"
"io"
"strconv"
)
// SignatureType is the armor type for a PGP signature.
var SignatureType = "PGP SIGNATURE"
// readArmored reads an armored block with the given type.
func readArmored(r io.Reader, expectedType string) (body io.Reader, err error) {
block, err := armor.Decode(r)
if err != nil {
return
}
if block.Type != expectedType {
return nil, errors.InvalidArgumentError("expected '" + expectedType + "', got: " + block.Type)
}
return block.Body, nil
}
// MessageDetails contains the result of parsing an OpenPGP encrypted and/or
// signed message.
type MessageDetails struct {
IsEncrypted bool // true if the message was encrypted.
EncryptedToKeyIds []uint64 // the list of recipient key ids.
IsSymmetricallyEncrypted bool // true if a passphrase could have decrypted the message.
DecryptedWith Key // the private key used to decrypt the message, if any.
IsSigned bool // true if the message is signed.
SignedByKeyId uint64 // the key id of the signer, if any.
SignedBy *Key // the key of the signer, if available.
LiteralData *packet.LiteralData // the metadata of the contents
UnverifiedBody io.Reader // the contents of the message.
// If IsSigned is true and SignedBy is non-zero then the signature will
// be verified as UnverifiedBody is read. The signature cannot be
// checked until the whole of UnverifiedBody is read so UnverifiedBody
// must be consumed until EOF before the data can trusted. Even if a
// message isn't signed (or the signer is unknown) the data may contain
// an authentication code that is only checked once UnverifiedBody has
// been consumed. Once EOF has been seen, the following fields are
// valid. (An authentication code failure is reported as a
// SignatureError error when reading from UnverifiedBody.)
SignatureError error // nil if the signature is good.
Signature *packet.Signature // the signature packet itself.
decrypted io.ReadCloser
}
// A PromptFunction is used as a callback by functions that may need to decrypt
// a private key, or prompt for a passphrase. It is called with a list of
// acceptable, encrypted private keys and a boolean that indicates whether a
// passphrase is usable. It should either decrypt a private key or return a
// passphrase to try. If the decrypted private key or given passphrase isn't
// correct, the function will be called again, forever. Any error returned will
// be passed up.
type PromptFunction func(keys []Key, symmetric bool) ([]byte, error)
// A keyEnvelopePair is used to store a private key with the envelope that
// contains a symmetric key, encrypted with that key.
type keyEnvelopePair struct {
key Key
encryptedKey *packet.EncryptedKey
}
// ReadMessage parses an OpenPGP message that may be signed and/or encrypted.
// The given KeyRing should contain both public keys (for signature
// verification) and, possibly encrypted, private keys for decrypting.
func ReadMessage(r io.Reader, keyring KeyRing, prompt PromptFunction) (md *MessageDetails, err error) {
var p packet.Packet
var symKeys []*packet.SymmetricKeyEncrypted
var pubKeys []keyEnvelopePair
var se *packet.SymmetricallyEncrypted
packets := packet.NewReader(r)
md = new(MessageDetails)
md.IsEncrypted = true
// The message, if encrypted, starts with a number of packets
// containing an encrypted decryption key. The decryption key is either
// encrypted to a public key, or with a passphrase. This loop
// collects these packets.
ParsePackets:
for {
p, err = packets.Next()
if err != nil {
return nil, err
}
switch p := p.(type) {
case *packet.SymmetricKeyEncrypted:
// This packet contains the decryption key encrypted with a passphrase.
md.IsSymmetricallyEncrypted = true
symKeys = append(symKeys, p)
case *packet.EncryptedKey:
// This packet contains the decryption key encrypted to a public key.
md.EncryptedToKeyIds = append(md.EncryptedToKeyIds, p.KeyId)
switch p.Algo {
case packet.PubKeyAlgoRSA, packet.PubKeyAlgoRSAEncryptOnly, packet.PubKeyAlgoElGamal:
break
default:
continue
}
var keys []Key
if p.KeyId == 0 {
keys = keyring.DecryptionKeys()
} else {
keys = keyring.KeysById(p.KeyId)
}
for _, k := range keys {
pubKeys = append(pubKeys, keyEnvelopePair{k, p})
}
case *packet.SymmetricallyEncrypted:
se = p
break ParsePackets
case *packet.Compressed, *packet.LiteralData, *packet.OnePassSignature:
// This message isn't encrypted.
if len(symKeys) != 0 || len(pubKeys) != 0 {
return nil, errors.StructuralError("key material not followed by encrypted message")
}
packets.Unread(p)
return readSignedMessage(packets, nil, keyring)
}
}
var candidates []Key
var decrypted io.ReadCloser
// Now that we have the list of encrypted keys we need to decrypt at
// least one of them or, if we cannot, we need to call the prompt
// function so that it can decrypt a key or give us a passphrase.
FindKey:
for {
// See if any of the keys already have a private key available
candidates = candidates[:0]
candidateFingerprints := make(map[string]bool)
for _, pk := range pubKeys {
if pk.key.PrivateKey == nil {
continue
}
if !pk.key.PrivateKey.Encrypted {
if len(pk.encryptedKey.Key) == 0 {
pk.encryptedKey.Decrypt(pk.key.PrivateKey)
}
if len(pk.encryptedKey.Key) == 0 {
continue
}
decrypted, err = se.Decrypt(pk.encryptedKey.CipherFunc, pk.encryptedKey.Key)
if err != nil && err != errors.KeyIncorrectError {
return nil, err
}
if decrypted != nil {
md.DecryptedWith = pk.key
break FindKey
}
} else {
fpr := string(pk.key.PublicKey.Fingerprint[:])
if v := candidateFingerprints[fpr]; v {
continue
}
candidates = append(candidates, pk.key)
candidateFingerprints[fpr] = true
}
}
if len(candidates) == 0 && len(symKeys) == 0 {
return nil, errors.KeyIncorrectError
}
if prompt == nil {
return nil, errors.KeyIncorrectError
}
passphrase, err := prompt(candidates, len(symKeys) != 0)
if err != nil {
return nil, err
}
// Try the symmetric passphrase first
if len(symKeys) != 0 && passphrase != nil {
for _, s := range symKeys {
err = s.Decrypt(passphrase)
if err == nil && !s.Encrypted {
decrypted, err = se.Decrypt(s.CipherFunc, s.Key)
if err != nil && err != errors.KeyIncorrectError {
return nil, err
}
if decrypted != nil {
break FindKey
}
}
}
}
}
md.decrypted = decrypted
packets.Push(decrypted)
return readSignedMessage(packets, md, keyring)
}
// readSignedMessage reads a possibly signed message if mdin is non-zero then
// that structure is updated and returned. Otherwise a fresh MessageDetails is
// used.
func readSignedMessage(packets *packet.Reader, mdin *MessageDetails, keyring KeyRing) (md *MessageDetails, err error) {
if mdin == nil {
mdin = new(MessageDetails)
}
md = mdin
var p packet.Packet
var h hash.Hash
var wrappedHash hash.Hash
FindLiteralData:
for {
p, err = packets.Next()
if err != nil {
return nil, err
}
switch p := p.(type) {
case *packet.Compressed:
packets.Push(p.Body)
case *packet.OnePassSignature:
if !p.IsLast {
return nil, errors.UnsupportedError("nested signatures")
}
h, wrappedHash, err = hashForSignature(p.Hash, p.SigType)
if err != nil {
md = nil
return
}
md.IsSigned = true
md.SignedByKeyId = p.KeyId
keys := keyring.KeysById(p.KeyId)
for i, key := range keys {
if key.SelfSignature.FlagsValid && !key.SelfSignature.FlagSign {
continue
}
md.SignedBy = &keys[i]
break
}
case *packet.LiteralData:
md.LiteralData = p
break FindLiteralData
}
}
if md.SignedBy != nil {
md.UnverifiedBody = &signatureCheckReader{packets, h, wrappedHash, md}
} else if md.decrypted != nil {
md.UnverifiedBody = checkReader{md}
} else {
md.UnverifiedBody = md.LiteralData.Body
}
return md, nil
}
// hashForSignature returns a pair of hashes that can be used to verify a
// signature. The signature may specify that the contents of the signed message
// should be preprocessed (i.e. to normalize line endings). Thus this function
// returns two hashes. The second should be used to hash the message itself and
// performs any needed preprocessing.
func hashForSignature(hashId crypto.Hash, sigType packet.SignatureType) (hash.Hash, hash.Hash, error) {
h := hashId.New()
if h == nil {
return nil, nil, errors.UnsupportedError("hash not available: " + strconv.Itoa(int(hashId)))
}
switch sigType {
case packet.SigTypeBinary:
return h, h, nil
case packet.SigTypeText:
return h, NewCanonicalTextHash(h), nil
}
return nil, nil, errors.UnsupportedError("unsupported signature type: " + strconv.Itoa(int(sigType)))
}
// checkReader wraps an io.Reader from a LiteralData packet. When it sees EOF
// it closes the ReadCloser from any SymmetricallyEncrypted packet to trigger
// MDC checks.
type checkReader struct {
md *MessageDetails
}
func (cr checkReader) Read(buf []byte) (n int, err error) {
n, err = cr.md.LiteralData.Body.Read(buf)
if err == io.EOF {
mdcErr := cr.md.decrypted.Close()
if mdcErr != nil {
err = mdcErr
}
}
return
}
// signatureCheckReader wraps an io.Reader from a LiteralData packet and hashes
// the data as it is read. When it sees an EOF from the underlying io.Reader
// it parses and checks a trailing Signature packet and triggers any MDC checks.
type signatureCheckReader struct {
packets *packet.Reader
h, wrappedHash hash.Hash
md *MessageDetails
}
func (scr *signatureCheckReader) Read(buf []byte) (n int, err error) {
n, err = scr.md.LiteralData.Body.Read(buf)
scr.wrappedHash.Write(buf[:n])
if err == io.EOF {
var p packet.Packet
p, scr.md.SignatureError = scr.packets.Next()
if scr.md.SignatureError != nil {
return
}
var ok bool
if scr.md.Signature, ok = p.(*packet.Signature); !ok {
scr.md.SignatureError = errors.StructuralError("LiteralData not followed by Signature")
return
}
scr.md.SignatureError = scr.md.SignedBy.PublicKey.VerifySignature(scr.h, scr.md.Signature)
// The SymmetricallyEncrypted packet, if any, might have an
// unsigned hash of its own. In order to check this we need to
// close that Reader.
if scr.md.decrypted != nil {
mdcErr := scr.md.decrypted.Close()
if mdcErr != nil {
err = mdcErr
}
}
}
return
}
// CheckDetachedSignature takes a signed file and a detached signature and
// returns the signer if the signature is valid. If the signer isn't know,
// UnknownIssuerError is returned.
func CheckDetachedSignature(keyring KeyRing, signed, signature io.Reader) (signer *Entity, err error) {
p, err := packet.Read(signature)
if err != nil {
return
}
sig, ok := p.(*packet.Signature)
if !ok {
return nil, errors.StructuralError("non signature packet found")
}
if sig.IssuerKeyId == nil {
return nil, errors.StructuralError("signature doesn't have an issuer")
}
keys := keyring.KeysById(*sig.IssuerKeyId)
if len(keys) == 0 {
return nil, errors.UnknownIssuerError
}
h, wrappedHash, err := hashForSignature(sig.Hash, sig.SigType)
if err != nil {
return
}
_, err = io.Copy(wrappedHash, signed)
if err != nil && err != io.EOF {
return
}
for _, key := range keys {
if key.SelfSignature.FlagsValid && !key.SelfSignature.FlagSign {
continue
}
err = key.PublicKey.VerifySignature(h, sig)
if err == nil {
return key.Entity, nil
}
}
if err != nil {
return
}
return nil, errors.UnknownIssuerError
}
// CheckArmoredDetachedSignature performs the same actions as
// CheckDetachedSignature but expects the signature to be armored.
func CheckArmoredDetachedSignature(keyring KeyRing, signed, signature io.Reader) (signer *Entity, err error) {
body, err := readArmored(signature, SignatureType)
if err != nil {
return
}
return CheckDetachedSignature(keyring, signed, body)
}

File diff suppressed because one or more lines are too long

View File

@ -1,183 +0,0 @@
// 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 s2k implements the various OpenPGP string-to-key transforms as
// specified in RFC 4800 section 3.7.1.
package s2k
import (
"crypto"
"crypto/openpgp/errors"
"hash"
"io"
"strconv"
)
// Simple writes to out the result of computing the Simple S2K function (RFC
// 4880, section 3.7.1.1) using the given hash and input passphrase.
func Simple(out []byte, h hash.Hash, in []byte) {
Salted(out, h, in, nil)
}
var zero [1]byte
// Salted writes to out the result of computing the Salted S2K function (RFC
// 4880, section 3.7.1.2) using the given hash, input passphrase and salt.
func Salted(out []byte, h hash.Hash, in []byte, salt []byte) {
done := 0
var digest []byte
for i := 0; done < len(out); i++ {
h.Reset()
for j := 0; j < i; j++ {
h.Write(zero[:])
}
h.Write(salt)
h.Write(in)
digest = h.Sum(digest[:0])
n := copy(out[done:], digest)
done += n
}
}
// Iterated writes to out the result of computing the Iterated and Salted S2K
// function (RFC 4880, section 3.7.1.3) using the given hash, input passphrase,
// salt and iteration count.
func Iterated(out []byte, h hash.Hash, in []byte, salt []byte, count int) {
combined := make([]byte, len(in)+len(salt))
copy(combined, salt)
copy(combined[len(salt):], in)
if count < len(combined) {
count = len(combined)
}
done := 0
var digest []byte
for i := 0; done < len(out); i++ {
h.Reset()
for j := 0; j < i; j++ {
h.Write(zero[:])
}
written := 0
for written < count {
if written+len(combined) > count {
todo := count - written
h.Write(combined[:todo])
written = count
} else {
h.Write(combined)
written += len(combined)
}
}
digest = h.Sum(digest[:0])
n := copy(out[done:], digest)
done += n
}
}
// Parse reads a binary specification for a string-to-key transformation from r
// and returns a function which performs that transform.
func Parse(r io.Reader) (f func(out, in []byte), err error) {
var buf [9]byte
_, err = io.ReadFull(r, buf[:2])
if err != nil {
return
}
hash, ok := HashIdToHash(buf[1])
if !ok {
return nil, errors.UnsupportedError("hash for S2K function: " + strconv.Itoa(int(buf[1])))
}
h := hash.New()
if h == nil {
return nil, errors.UnsupportedError("hash not available: " + strconv.Itoa(int(hash)))
}
switch buf[0] {
case 1:
f := func(out, in []byte) {
Simple(out, h, in)
}
return f, nil
case 2:
_, err = io.ReadFull(r, buf[:8])
if err != nil {
return
}
f := func(out, in []byte) {
Salted(out, h, in, buf[:8])
}
return f, nil
case 3:
_, err = io.ReadFull(r, buf[:9])
if err != nil {
return
}
count := (16 + int(buf[8]&15)) << (uint32(buf[8]>>4) + 6)
f := func(out, in []byte) {
Iterated(out, h, in, buf[:8], count)
}
return f, nil
}
return nil, errors.UnsupportedError("S2K function")
}
// Serialize salts and stretches the given passphrase and writes the resulting
// key into key. It also serializes an S2K descriptor to w.
func Serialize(w io.Writer, key []byte, rand io.Reader, passphrase []byte) error {
var buf [11]byte
buf[0] = 3 /* iterated and salted */
buf[1], _ = HashToHashId(crypto.SHA1)
salt := buf[2:10]
if _, err := io.ReadFull(rand, salt); err != nil {
return err
}
const count = 65536 // this is the default in gpg
buf[10] = 96 // 65536 iterations
if _, err := w.Write(buf[:]); err != nil {
return err
}
Iterated(key, crypto.SHA1.New(), passphrase, salt, count)
return nil
}
// hashToHashIdMapping contains pairs relating OpenPGP's hash identifier with
// Go's crypto.Hash type. See RFC 4880, section 9.4.
var hashToHashIdMapping = []struct {
id byte
hash crypto.Hash
}{
{1, crypto.MD5},
{2, crypto.SHA1},
{3, crypto.RIPEMD160},
{8, crypto.SHA256},
{9, crypto.SHA384},
{10, crypto.SHA512},
{11, crypto.SHA224},
}
// HashIdToHash returns a crypto.Hash which corresponds to the given OpenPGP
// hash id.
func HashIdToHash(id byte) (h crypto.Hash, ok bool) {
for _, m := range hashToHashIdMapping {
if m.id == id {
return m.hash, true
}
}
return 0, false
}
// HashIdToHash returns an OpenPGP hash id which corresponds the given Hash.
func HashToHashId(h crypto.Hash) (id byte, ok bool) {
for _, m := range hashToHashIdMapping {
if m.hash == h {
return m.id, true
}
}
return 0, false
}

View File

@ -1,118 +0,0 @@
// 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 s2k
import (
"bytes"
"crypto/rand"
"crypto/sha1"
"encoding/hex"
"testing"
)
var saltedTests = []struct {
in, out string
}{
{"hello", "10295ac1"},
{"world", "ac587a5e"},
{"foo", "4dda8077"},
{"bar", "bd8aac6b9ea9cae04eae6a91c6133b58b5d9a61c14f355516ed9370456"},
{"x", "f1d3f289"},
{"xxxxxxxxxxxxxxxxxxxxxxx", "e00d7b45"},
}
func TestSalted(t *testing.T) {
h := sha1.New()
salt := [4]byte{1, 2, 3, 4}
for i, test := range saltedTests {
expected, _ := hex.DecodeString(test.out)
out := make([]byte, len(expected))
Salted(out, h, []byte(test.in), salt[:])
if !bytes.Equal(expected, out) {
t.Errorf("#%d, got: %x want: %x", i, out, expected)
}
}
}
var iteratedTests = []struct {
in, out string
}{
{"hello", "83126105"},
{"world", "6fa317f9"},
{"foo", "8fbc35b9"},
{"bar", "2af5a99b54f093789fd657f19bd245af7604d0f6ae06f66602a46a08ae"},
{"x", "5a684dfe"},
{"xxxxxxxxxxxxxxxxxxxxxxx", "18955174"},
}
func TestIterated(t *testing.T) {
h := sha1.New()
salt := [4]byte{4, 3, 2, 1}
for i, test := range iteratedTests {
expected, _ := hex.DecodeString(test.out)
out := make([]byte, len(expected))
Iterated(out, h, []byte(test.in), salt[:], 31)
if !bytes.Equal(expected, out) {
t.Errorf("#%d, got: %x want: %x", i, out, expected)
}
}
}
var parseTests = []struct {
spec, in, out string
}{
/* Simple with SHA1 */
{"0102", "hello", "aaf4c61d"},
/* Salted with SHA1 */
{"02020102030405060708", "hello", "f4f7d67e"},
/* Iterated with SHA1 */
{"03020102030405060708f1", "hello", "f2a57b7c"},
}
func TestParse(t *testing.T) {
for i, test := range parseTests {
spec, _ := hex.DecodeString(test.spec)
buf := bytes.NewBuffer(spec)
f, err := Parse(buf)
if err != nil {
t.Errorf("%d: Parse returned error: %s", i, err)
continue
}
expected, _ := hex.DecodeString(test.out)
out := make([]byte, len(expected))
f(out, []byte(test.in))
if !bytes.Equal(out, expected) {
t.Errorf("%d: output got: %x want: %x", i, out, expected)
}
if testing.Short() {
break
}
}
}
func TestSerialize(t *testing.T) {
buf := bytes.NewBuffer(nil)
key := make([]byte, 16)
passphrase := []byte("testing")
err := Serialize(buf, key, rand.Reader, passphrase)
if err != nil {
t.Errorf("failed to serialize: %s", err)
return
}
f, err := Parse(buf)
if err != nil {
t.Errorf("failed to reparse: %s", err)
return
}
key2 := make([]byte, len(key))
f(key2, passphrase)
if !bytes.Equal(key2, key) {
t.Errorf("keys don't match: %x (serialied) vs %x (parsed)", key, key2)
}
}

View File

@ -1,315 +0,0 @@
// 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 openpgp
import (
"crypto"
"crypto/openpgp/armor"
"crypto/openpgp/errors"
"crypto/openpgp/packet"
"crypto/openpgp/s2k"
"crypto/rand"
_ "crypto/sha256"
"hash"
"io"
"strconv"
"time"
)
// DetachSign signs message with the private key from signer (which must
// already have been decrypted) and writes the signature to w.
func DetachSign(w io.Writer, signer *Entity, message io.Reader) error {
return detachSign(w, signer, message, packet.SigTypeBinary)
}
// ArmoredDetachSign signs message with the private key from signer (which
// must already have been decrypted) and writes an armored signature to w.
func ArmoredDetachSign(w io.Writer, signer *Entity, message io.Reader) (err error) {
return armoredDetachSign(w, signer, message, packet.SigTypeBinary)
}
// DetachSignText signs message (after canonicalising the line endings) with
// the private key from signer (which must already have been decrypted) and
// writes the signature to w.
func DetachSignText(w io.Writer, signer *Entity, message io.Reader) error {
return detachSign(w, signer, message, packet.SigTypeText)
}
// ArmoredDetachSignText signs message (after canonicalising the line endings)
// with the private key from signer (which must already have been decrypted)
// and writes an armored signature to w.
func ArmoredDetachSignText(w io.Writer, signer *Entity, message io.Reader) error {
return armoredDetachSign(w, signer, message, packet.SigTypeText)
}
func armoredDetachSign(w io.Writer, signer *Entity, message io.Reader, sigType packet.SignatureType) (err error) {
out, err := armor.Encode(w, SignatureType, nil)
if err != nil {
return
}
err = detachSign(out, signer, message, sigType)
if err != nil {
return
}
return out.Close()
}
func detachSign(w io.Writer, signer *Entity, message io.Reader, sigType packet.SignatureType) (err error) {
if signer.PrivateKey == nil {
return errors.InvalidArgumentError("signing key doesn't have a private key")
}
if signer.PrivateKey.Encrypted {
return errors.InvalidArgumentError("signing key is encrypted")
}
sig := new(packet.Signature)
sig.SigType = sigType
sig.PubKeyAlgo = signer.PrivateKey.PubKeyAlgo
sig.Hash = crypto.SHA256
sig.CreationTime = time.Now()
sig.IssuerKeyId = &signer.PrivateKey.KeyId
h, wrappedHash, err := hashForSignature(sig.Hash, sig.SigType)
if err != nil {
return
}
io.Copy(wrappedHash, message)
err = sig.Sign(rand.Reader, h, signer.PrivateKey)
if err != nil {
return
}
return sig.Serialize(w)
}
// FileHints contains metadata about encrypted files. This metadata is, itself,
// encrypted.
type FileHints struct {
// IsBinary can be set to hint that the contents are binary data.
IsBinary bool
// FileName hints at the name of the file that should be written. It's
// truncated to 255 bytes if longer. It may be empty to suggest that the
// file should not be written to disk. It may be equal to "_CONSOLE" to
// suggest the data should not be written to disk.
FileName string
// ModTime contains the modification time of the file, or the zero time if not applicable.
ModTime time.Time
}
// SymmetricallyEncrypt acts like gpg -c: it encrypts a file with a passphrase.
// The resulting WriteCloser must be closed after the contents of the file have
// been written.
func SymmetricallyEncrypt(ciphertext io.Writer, passphrase []byte, hints *FileHints) (plaintext io.WriteCloser, err error) {
if hints == nil {
hints = &FileHints{}
}
key, err := packet.SerializeSymmetricKeyEncrypted(ciphertext, rand.Reader, passphrase, packet.CipherAES128)
if err != nil {
return
}
w, err := packet.SerializeSymmetricallyEncrypted(ciphertext, rand.Reader, packet.CipherAES128, key)
if err != nil {
return
}
var epochSeconds uint32
if !hints.ModTime.IsZero() {
epochSeconds = uint32(hints.ModTime.Unix())
}
return packet.SerializeLiteral(w, hints.IsBinary, hints.FileName, epochSeconds)
}
// intersectPreferences mutates and returns a prefix of a that contains only
// the values in the intersection of a and b. The order of a is preserved.
func intersectPreferences(a []uint8, b []uint8) (intersection []uint8) {
var j int
for _, v := range a {
for _, v2 := range b {
if v == v2 {
a[j] = v
j++
break
}
}
}
return a[:j]
}
func hashToHashId(h crypto.Hash) uint8 {
v, ok := s2k.HashToHashId(h)
if !ok {
panic("tried to convert unknown hash")
}
return v
}
// Encrypt encrypts a message to a number of recipients and, optionally, signs
// it. hints contains optional information, that is also encrypted, that aids
// the recipients in processing the message. The resulting WriteCloser must
// be closed after the contents of the file have been written.
func Encrypt(ciphertext io.Writer, to []*Entity, signed *Entity, hints *FileHints) (plaintext io.WriteCloser, err error) {
var signer *packet.PrivateKey
if signed != nil {
signer = signed.signingKey().PrivateKey
if signer == nil || signer.Encrypted {
return nil, errors.InvalidArgumentError("signing key must be decrypted")
}
}
// These are the possible ciphers that we'll use for the message.
candidateCiphers := []uint8{
uint8(packet.CipherAES128),
uint8(packet.CipherAES256),
uint8(packet.CipherCAST5),
}
// These are the possible hash functions that we'll use for the signature.
candidateHashes := []uint8{
hashToHashId(crypto.SHA256),
hashToHashId(crypto.SHA512),
hashToHashId(crypto.SHA1),
hashToHashId(crypto.RIPEMD160),
}
// In the event that a recipient doesn't specify any supported ciphers
// or hash functions, these are the ones that we assume that every
// implementation supports.
defaultCiphers := candidateCiphers[len(candidateCiphers)-1:]
defaultHashes := candidateHashes[len(candidateHashes)-1:]
encryptKeys := make([]Key, len(to))
for i := range to {
encryptKeys[i] = to[i].encryptionKey()
if encryptKeys[i].PublicKey == nil {
return nil, errors.InvalidArgumentError("cannot encrypt a message to key id " + strconv.FormatUint(to[i].PrimaryKey.KeyId, 16) + " because it has no encryption keys")
}
sig := to[i].primaryIdentity().SelfSignature
preferredSymmetric := sig.PreferredSymmetric
if len(preferredSymmetric) == 0 {
preferredSymmetric = defaultCiphers
}
preferredHashes := sig.PreferredHash
if len(preferredHashes) == 0 {
preferredHashes = defaultHashes
}
candidateCiphers = intersectPreferences(candidateCiphers, preferredSymmetric)
candidateHashes = intersectPreferences(candidateHashes, preferredHashes)
}
if len(candidateCiphers) == 0 || len(candidateHashes) == 0 {
return nil, errors.InvalidArgumentError("cannot encrypt because recipient set shares no common algorithms")
}
cipher := packet.CipherFunction(candidateCiphers[0])
hash, _ := s2k.HashIdToHash(candidateHashes[0])
symKey := make([]byte, cipher.KeySize())
if _, err := io.ReadFull(rand.Reader, symKey); err != nil {
return nil, err
}
for _, key := range encryptKeys {
if err := packet.SerializeEncryptedKey(ciphertext, rand.Reader, key.PublicKey, cipher, symKey); err != nil {
return nil, err
}
}
encryptedData, err := packet.SerializeSymmetricallyEncrypted(ciphertext, rand.Reader, cipher, symKey)
if err != nil {
return
}
if signer != nil {
ops := &packet.OnePassSignature{
SigType: packet.SigTypeBinary,
Hash: hash,
PubKeyAlgo: signer.PubKeyAlgo,
KeyId: signer.KeyId,
IsLast: true,
}
if err := ops.Serialize(encryptedData); err != nil {
return nil, err
}
}
if hints == nil {
hints = &FileHints{}
}
w := encryptedData
if signer != nil {
// If we need to write a signature packet after the literal
// data then we need to stop literalData from closing
// encryptedData.
w = noOpCloser{encryptedData}
}
var epochSeconds uint32
if !hints.ModTime.IsZero() {
epochSeconds = uint32(hints.ModTime.Unix())
}
literalData, err := packet.SerializeLiteral(w, hints.IsBinary, hints.FileName, epochSeconds)
if err != nil {
return nil, err
}
if signer != nil {
return signatureWriter{encryptedData, literalData, hash, hash.New(), signer}, nil
}
return literalData, nil
}
// signatureWriter hashes the contents of a message while passing it along to
// literalData. When closed, it closes literalData, writes a signature packet
// to encryptedData and then also closes encryptedData.
type signatureWriter struct {
encryptedData io.WriteCloser
literalData io.WriteCloser
hashType crypto.Hash
h hash.Hash
signer *packet.PrivateKey
}
func (s signatureWriter) Write(data []byte) (int, error) {
s.h.Write(data)
return s.literalData.Write(data)
}
func (s signatureWriter) Close() error {
sig := &packet.Signature{
SigType: packet.SigTypeBinary,
PubKeyAlgo: s.signer.PubKeyAlgo,
Hash: s.hashType,
CreationTime: time.Now(),
IssuerKeyId: &s.signer.KeyId,
}
if err := sig.Sign(rand.Reader, s.h, s.signer); err != nil {
return err
}
if err := s.literalData.Close(); err != nil {
return err
}
if err := sig.Serialize(s.encryptedData); err != nil {
return err
}
return s.encryptedData.Close()
}
// noOpCloser is like an ioutil.NopCloser, but for an io.Writer.
// TODO: we have two of these in OpenPGP packages alone. This probably needs
// to be promoted somewhere more common.
type noOpCloser struct {
w io.Writer
}
func (c noOpCloser) Write(data []byte) (n int, err error) {
return c.w.Write(data)
}
func (c noOpCloser) Close() error {
return nil
}

View File

@ -1,232 +0,0 @@
// 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 openpgp
import (
"bytes"
"crypto/rand"
"io"
"io/ioutil"
"testing"
"time"
)
func TestSignDetached(t *testing.T) {
kring, _ := ReadKeyRing(readerFromHex(testKeys1And2PrivateHex))
out := bytes.NewBuffer(nil)
message := bytes.NewBufferString(signedInput)
err := DetachSign(out, kring[0], message)
if err != nil {
t.Error(err)
}
testDetachedSignature(t, kring, out, signedInput, "check", testKey1KeyId)
}
func TestSignTextDetached(t *testing.T) {
kring, _ := ReadKeyRing(readerFromHex(testKeys1And2PrivateHex))
out := bytes.NewBuffer(nil)
message := bytes.NewBufferString(signedInput)
err := DetachSignText(out, kring[0], message)
if err != nil {
t.Error(err)
}
testDetachedSignature(t, kring, out, signedInput, "check", testKey1KeyId)
}
func TestSignDetachedDSA(t *testing.T) {
kring, _ := ReadKeyRing(readerFromHex(dsaTestKeyPrivateHex))
out := bytes.NewBuffer(nil)
message := bytes.NewBufferString(signedInput)
err := DetachSign(out, kring[0], message)
if err != nil {
t.Error(err)
}
testDetachedSignature(t, kring, out, signedInput, "check", testKey3KeyId)
}
func TestNewEntity(t *testing.T) {
if testing.Short() {
return
}
e, err := NewEntity(rand.Reader, time.Now(), "Test User", "test", "test@example.com")
if err != nil {
t.Errorf("failed to create entity: %s", err)
return
}
w := bytes.NewBuffer(nil)
if err := e.SerializePrivate(w); err != nil {
t.Errorf("failed to serialize entity: %s", err)
return
}
serialized := w.Bytes()
el, err := ReadKeyRing(w)
if err != nil {
t.Errorf("failed to reparse entity: %s", err)
return
}
if len(el) != 1 {
t.Errorf("wrong number of entities found, got %d, want 1", len(el))
}
w = bytes.NewBuffer(nil)
if err := e.SerializePrivate(w); err != nil {
t.Errorf("failed to serialize entity second time: %s", err)
return
}
if !bytes.Equal(w.Bytes(), serialized) {
t.Errorf("results differed")
}
}
func TestSymmetricEncryption(t *testing.T) {
buf := new(bytes.Buffer)
plaintext, err := SymmetricallyEncrypt(buf, []byte("testing"), nil)
if err != nil {
t.Errorf("error writing headers: %s", err)
return
}
message := []byte("hello world\n")
_, err = plaintext.Write(message)
if err != nil {
t.Errorf("error writing to plaintext writer: %s", err)
}
err = plaintext.Close()
if err != nil {
t.Errorf("error closing plaintext writer: %s", err)
}
md, err := ReadMessage(buf, nil, func(keys []Key, symmetric bool) ([]byte, error) {
return []byte("testing"), nil
})
if err != nil {
t.Errorf("error rereading message: %s", err)
}
messageBuf := bytes.NewBuffer(nil)
_, err = io.Copy(messageBuf, md.UnverifiedBody)
if err != nil {
t.Errorf("error rereading message: %s", err)
}
if !bytes.Equal(message, messageBuf.Bytes()) {
t.Errorf("recovered message incorrect got '%s', want '%s'", messageBuf.Bytes(), message)
}
}
var testEncryptionTests = []struct {
keyRingHex string
isSigned bool
}{
{
testKeys1And2PrivateHex,
false,
},
{
testKeys1And2PrivateHex,
true,
},
{
dsaElGamalTestKeysHex,
false,
},
{
dsaElGamalTestKeysHex,
true,
},
}
func TestEncryption(t *testing.T) {
for i, test := range testEncryptionTests {
kring, _ := ReadKeyRing(readerFromHex(test.keyRingHex))
passphrase := []byte("passphrase")
for _, entity := range kring {
if entity.PrivateKey != nil && entity.PrivateKey.Encrypted {
err := entity.PrivateKey.Decrypt(passphrase)
if err != nil {
t.Errorf("#%d: failed to decrypt key", i)
}
}
for _, subkey := range entity.Subkeys {
if subkey.PrivateKey != nil && subkey.PrivateKey.Encrypted {
err := subkey.PrivateKey.Decrypt(passphrase)
if err != nil {
t.Errorf("#%d: failed to decrypt subkey", i)
}
}
}
}
var signed *Entity
if test.isSigned {
signed = kring[0]
}
buf := new(bytes.Buffer)
w, err := Encrypt(buf, kring[:1], signed, nil /* no hints */ )
if err != nil {
t.Errorf("#%d: error in Encrypt: %s", i, err)
continue
}
const message = "testing"
_, err = w.Write([]byte(message))
if err != nil {
t.Errorf("#%d: error writing plaintext: %s", i, err)
continue
}
err = w.Close()
if err != nil {
t.Errorf("#%d: error closing WriteCloser: %s", i, err)
continue
}
md, err := ReadMessage(buf, kring, nil /* no prompt */ )
if err != nil {
t.Errorf("#%d: error reading message: %s", i, err)
continue
}
if test.isSigned {
expectedKeyId := kring[0].signingKey().PublicKey.KeyId
if md.SignedByKeyId != expectedKeyId {
t.Errorf("#%d: message signed by wrong key id, got: %d, want: %d", i, *md.SignedBy, expectedKeyId)
}
if md.SignedBy == nil {
t.Errorf("#%d: failed to find the signing Entity", i)
}
}
plaintext, err := ioutil.ReadAll(md.UnverifiedBody)
if err != nil {
t.Errorf("#%d: error reading encrypted contents: %s", i, err)
continue
}
expectedKeyId := kring[0].encryptionKey().PublicKey.KeyId
if len(md.EncryptedToKeyIds) != 1 || md.EncryptedToKeyIds[0] != expectedKeyId {
t.Errorf("#%d: expected message to be encrypted to %v, but got %#v", i, expectedKeyId, md.EncryptedToKeyIds)
}
if string(plaintext) != message {
t.Errorf("#%d: got: %s, want: %s", i, string(plaintext), message)
}
if test.isSigned {
if md.SignatureError != nil {
t.Errorf("#%d: signature error: %s", i, md.SignatureError)
}
if md.Signature == nil {
t.Error("signature missing")
}
}
}
}

View File

@ -1,120 +0,0 @@
// 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 ripemd160 implements the RIPEMD-160 hash algorithm.
package ripemd160
// RIPEMD-160 is designed by by Hans Dobbertin, Antoon Bosselaers, and Bart
// Preneel with specifications available at:
// http://homes.esat.kuleuven.be/~cosicart/pdf/AB-9601/AB-9601.pdf.
import (
"crypto"
"hash"
)
func init() {
crypto.RegisterHash(crypto.RIPEMD160, New)
}
// The size of the checksum in bytes.
const Size = 20
// The block size of the hash algorithm in bytes.
const BlockSize = 64
const (
_s0 = 0x67452301
_s1 = 0xefcdab89
_s2 = 0x98badcfe
_s3 = 0x10325476
_s4 = 0xc3d2e1f0
)
// digest represents the partial evaluation of a checksum.
type digest struct {
s [5]uint32 // running context
x [BlockSize]byte // temporary buffer
nx int // index into x
tc uint64 // total count of bytes processed
}
func (d *digest) Reset() {
d.s[0], d.s[1], d.s[2], d.s[3], d.s[4] = _s0, _s1, _s2, _s3, _s4
d.nx = 0
d.tc = 0
}
// New returns a new hash.Hash computing the checksum.
func New() hash.Hash {
result := new(digest)
result.Reset()
return result
}
func (d *digest) Size() int { return Size }
func (d *digest) BlockSize() int { return BlockSize }
func (d *digest) Write(p []byte) (nn int, err error) {
nn = len(p)
d.tc += uint64(nn)
if d.nx > 0 {
n := len(p)
if n > BlockSize-d.nx {
n = BlockSize - d.nx
}
for i := 0; i < n; i++ {
d.x[d.nx+i] = p[i]
}
d.nx += n
if d.nx == BlockSize {
_Block(d, d.x[0:])
d.nx = 0
}
p = p[n:]
}
n := _Block(d, p)
p = p[n:]
if len(p) > 0 {
d.nx = copy(d.x[:], p)
}
return
}
func (d0 *digest) Sum(in []byte) []byte {
// Make a copy of d0 so that caller can keep writing and summing.
d := *d0
// Padding. Add a 1 bit and 0 bits until 56 bytes mod 64.
tc := d.tc
var tmp [64]byte
tmp[0] = 0x80
if tc%64 < 56 {
d.Write(tmp[0 : 56-tc%64])
} else {
d.Write(tmp[0 : 64+56-tc%64])
}
// Length in bits.
tc <<= 3
for i := uint(0); i < 8; i++ {
tmp[i] = byte(tc >> (8 * i))
}
d.Write(tmp[0:8])
if d.nx != 0 {
panic("d.nx != 0")
}
var digest [Size]byte
for i, s := range d.s {
digest[i*4] = byte(s)
digest[i*4+1] = byte(s >> 8)
digest[i*4+2] = byte(s >> 16)
digest[i*4+3] = byte(s >> 24)
}
return append(in, digest[:]...)
}

View File

@ -1,64 +0,0 @@
// 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 ripemd160
// Test vectors are from:
// http://homes.esat.kuleuven.be/~bosselae/ripemd160.html
import (
"fmt"
"io"
"testing"
)
type mdTest struct {
out string
in string
}
var vectors = [...]mdTest{
{"9c1185a5c5e9fc54612808977ee8f548b2258d31", ""},
{"0bdc9d2d256b3ee9daae347be6f4dc835a467ffe", "a"},
{"8eb208f7e05d987a9b044a8e98c6b087f15a0bfc", "abc"},
{"5d0689ef49d2fae572b881b123a85ffa21595f36", "message digest"},
{"f71c27109c692c1b56bbdceb5b9d2865b3708dbc", "abcdefghijklmnopqrstuvwxyz"},
{"12a053384a9c0c88e405a06c27dcf49ada62eb2b", "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq"},
{"b0e20b6e3116640286ed3a87a5713079b21f5189", "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"},
{"9b752e45573d4b39f4dbd3323cab82bf63326bfb", "12345678901234567890123456789012345678901234567890123456789012345678901234567890"},
}
func TestVectors(t *testing.T) {
for i := 0; i < len(vectors); i++ {
tv := vectors[i]
md := New()
for j := 0; j < 3; j++ {
if j < 2 {
io.WriteString(md, tv.in)
} else {
io.WriteString(md, tv.in[0:len(tv.in)/2])
md.Sum(nil)
io.WriteString(md, tv.in[len(tv.in)/2:])
}
s := fmt.Sprintf("%x", md.Sum(nil))
if s != tv.out {
t.Fatalf("RIPEMD-160[%d](%s) = %s, expected %s", j, tv.in, s, tv.out)
}
md.Reset()
}
}
}
func TestMillionA(t *testing.T) {
md := New()
for i := 0; i < 100000; i++ {
io.WriteString(md, "aaaaaaaaaa")
}
out := "52783243c1697bdbe16d37f97f68f08325dc1528"
s := fmt.Sprintf("%x", md.Sum(nil))
if s != out {
t.Fatalf("RIPEMD-160 (1 million 'a') = %s, expected %s", s, out)
}
md.Reset()
}

View File

@ -1,161 +0,0 @@
// 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.
// RIPEMD-160 block step.
// In its own file so that a faster assembly or C version
// can be substituted easily.
package ripemd160
// work buffer indices and roll amounts for one line
var _n = [80]uint{
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
7, 4, 13, 1, 10, 6, 15, 3, 12, 0, 9, 5, 2, 14, 11, 8,
3, 10, 14, 4, 9, 15, 8, 1, 2, 7, 0, 6, 13, 11, 5, 12,
1, 9, 11, 10, 0, 8, 12, 4, 13, 3, 7, 15, 14, 5, 6, 2,
4, 0, 5, 9, 7, 12, 2, 10, 14, 1, 3, 8, 11, 6, 15, 13,
}
var _r = [80]uint{
11, 14, 15, 12, 5, 8, 7, 9, 11, 13, 14, 15, 6, 7, 9, 8,
7, 6, 8, 13, 11, 9, 7, 15, 7, 12, 15, 9, 11, 7, 13, 12,
11, 13, 6, 7, 14, 9, 13, 15, 14, 8, 13, 6, 5, 12, 7, 5,
11, 12, 14, 15, 14, 15, 9, 8, 9, 14, 5, 6, 8, 6, 5, 12,
9, 15, 5, 11, 6, 8, 13, 12, 5, 12, 13, 14, 11, 8, 5, 6,
}
// same for the other parallel one
var n_ = [80]uint{
5, 14, 7, 0, 9, 2, 11, 4, 13, 6, 15, 8, 1, 10, 3, 12,
6, 11, 3, 7, 0, 13, 5, 10, 14, 15, 8, 12, 4, 9, 1, 2,
15, 5, 1, 3, 7, 14, 6, 9, 11, 8, 12, 2, 10, 0, 4, 13,
8, 6, 4, 1, 3, 11, 15, 0, 5, 12, 2, 13, 9, 7, 10, 14,
12, 15, 10, 4, 1, 5, 8, 7, 6, 2, 13, 14, 0, 3, 9, 11,
}
var r_ = [80]uint{
8, 9, 9, 11, 13, 15, 15, 5, 7, 7, 8, 11, 14, 14, 12, 6,
9, 13, 15, 7, 12, 8, 9, 11, 7, 7, 12, 7, 6, 15, 13, 11,
9, 7, 15, 11, 8, 6, 6, 14, 12, 13, 5, 14, 13, 13, 7, 5,
15, 5, 8, 11, 14, 14, 6, 14, 6, 9, 12, 9, 12, 5, 15, 8,
8, 5, 12, 9, 12, 5, 14, 6, 8, 13, 6, 5, 15, 13, 11, 11,
}
func _Block(md *digest, p []byte) int {
n := 0
var x [16]uint32
var alpha, beta uint32
for len(p) >= BlockSize {
a, b, c, d, e := md.s[0], md.s[1], md.s[2], md.s[3], md.s[4]
aa, bb, cc, dd, ee := a, b, c, d, e
j := 0
for i := 0; i < 16; i++ {
x[i] = uint32(p[j]) | uint32(p[j+1])<<8 | uint32(p[j+2])<<16 | uint32(p[j+3])<<24
j += 4
}
// round 1
i := 0
for i < 16 {
alpha = a + (b ^ c ^ d) + x[_n[i]]
s := _r[i]
alpha = (alpha<<s | alpha>>(32-s)) + e
beta = c<<10 | c>>22
a, b, c, d, e = e, alpha, b, beta, d
// parallel line
alpha = aa + (bb ^ (cc | ^dd)) + x[n_[i]] + 0x50a28be6
s = r_[i]
alpha = (alpha<<s | alpha>>(32-s)) + ee
beta = cc<<10 | cc>>22
aa, bb, cc, dd, ee = ee, alpha, bb, beta, dd
i++
}
// round 2
for i < 32 {
alpha = a + (b&c | ^b&d) + x[_n[i]] + 0x5a827999
s := _r[i]
alpha = (alpha<<s | alpha>>(32-s)) + e
beta = c<<10 | c>>22
a, b, c, d, e = e, alpha, b, beta, d
// parallel line
alpha = aa + (bb&dd | cc&^dd) + x[n_[i]] + 0x5c4dd124
s = r_[i]
alpha = (alpha<<s | alpha>>(32-s)) + ee
beta = cc<<10 | cc>>22
aa, bb, cc, dd, ee = ee, alpha, bb, beta, dd
i++
}
// round 3
for i < 48 {
alpha = a + (b | ^c ^ d) + x[_n[i]] + 0x6ed9eba1
s := _r[i]
alpha = (alpha<<s | alpha>>(32-s)) + e
beta = c<<10 | c>>22
a, b, c, d, e = e, alpha, b, beta, d
// parallel line
alpha = aa + (bb | ^cc ^ dd) + x[n_[i]] + 0x6d703ef3
s = r_[i]
alpha = (alpha<<s | alpha>>(32-s)) + ee
beta = cc<<10 | cc>>22
aa, bb, cc, dd, ee = ee, alpha, bb, beta, dd
i++
}
// round 4
for i < 64 {
alpha = a + (b&d | c&^d) + x[_n[i]] + 0x8f1bbcdc
s := _r[i]
alpha = (alpha<<s | alpha>>(32-s)) + e
beta = c<<10 | c>>22
a, b, c, d, e = e, alpha, b, beta, d
// parallel line
alpha = aa + (bb&cc | ^bb&dd) + x[n_[i]] + 0x7a6d76e9
s = r_[i]
alpha = (alpha<<s | alpha>>(32-s)) + ee
beta = cc<<10 | cc>>22
aa, bb, cc, dd, ee = ee, alpha, bb, beta, dd
i++
}
// round 5
for i < 80 {
alpha = a + (b ^ (c | ^d)) + x[_n[i]] + 0xa953fd4e
s := _r[i]
alpha = (alpha<<s | alpha>>(32-s)) + e
beta = c<<10 | c>>22
a, b, c, d, e = e, alpha, b, beta, d
// parallel line
alpha = aa + (bb ^ cc ^ dd) + x[n_[i]]
s = r_[i]
alpha = (alpha<<s | alpha>>(32-s)) + ee
beta = cc<<10 | cc>>22
aa, bb, cc, dd, ee = ee, alpha, bb, beta, dd
i++
}
// combine results
dd += c + md.s[1]
md.s[1] = md.s[2] + d + ee
md.s[2] = md.s[3] + e + aa
md.s[3] = md.s[4] + a + bb
md.s[4] = md.s[0] + b + cc
md.s[0] = dd
p = p[BlockSize:]
n += BlockSize
}
return n
}

View File

@ -2,7 +2,7 @@
// 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.
// +build plan9 darwin/nocgo // +build plan9 darwin,!cgo
package tls package tls

View File

@ -1,355 +0,0 @@
// 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 twofish implements Bruce Schneier's Twofish encryption algorithm.
package twofish
// Twofish is defined in http://www.schneier.com/paper-twofish-paper.pdf [TWOFISH]
// This code is a port of the LibTom C implementation.
// See http://libtom.org/?page=features&newsitems=5&whatfile=crypt.
// LibTomCrypt is free for all purposes under the public domain.
// It was heavily inspired by the go blowfish package.
import "strconv"
// BlockSize is the constant block size of Twofish.
const BlockSize = 16
const mdsPolynomial = 0x169 // x^8 + x^6 + x^5 + x^3 + 1, see [TWOFISH] 4.2
const rsPolynomial = 0x14d // x^8 + x^6 + x^3 + x^2 + 1, see [TWOFISH] 4.3
// A Cipher is an instance of Twofish encryption using a particular key.
type Cipher struct {
s [4][256]uint32
k [40]uint32
}
type KeySizeError int
func (k KeySizeError) Error() string {
return "crypto/twofish: invalid key size " + strconv.Itoa(int(k))
}
// NewCipher creates and returns a Cipher.
// The key argument should be the Twofish key, 16, 24 or 32 bytes.
func NewCipher(key []byte) (*Cipher, error) {
keylen := len(key)
if keylen != 16 && keylen != 24 && keylen != 32 {
return nil, KeySizeError(keylen)
}
// k is the number of 64 bit words in key
k := keylen / 8
// Create the S[..] words
var S [4 * 4]byte
for i := 0; i < k; i++ {
// Computes [y0 y1 y2 y3] = rs . [x0 x1 x2 x3 x4 x5 x6 x7]
for j, rsRow := range rs {
for k, rsVal := range rsRow {
S[4*i+j] ^= gfMult(key[8*i+k], rsVal, rsPolynomial)
}
}
}
// Calculate subkeys
c := new(Cipher)
var tmp [4]byte
for i := byte(0); i < 20; i++ {
// A = h(p * 2x, Me)
for j := range tmp {
tmp[j] = 2 * i
}
A := h(tmp[:], key, 0)
// B = rolc(h(p * (2x + 1), Mo), 8)
for j := range tmp {
tmp[j] = 2*i + 1
}
B := h(tmp[:], key, 1)
B = rol(B, 8)
c.k[2*i] = A + B
// K[2i+1] = (A + 2B) <<< 9
c.k[2*i+1] = rol(2*B+A, 9)
}
// Calculate sboxes
switch k {
case 2:
for i := range c.s[0] {
c.s[0][i] = mdsColumnMult(sbox[1][sbox[0][sbox[0][byte(i)]^S[0]]^S[4]], 0)
c.s[1][i] = mdsColumnMult(sbox[0][sbox[0][sbox[1][byte(i)]^S[1]]^S[5]], 1)
c.s[2][i] = mdsColumnMult(sbox[1][sbox[1][sbox[0][byte(i)]^S[2]]^S[6]], 2)
c.s[3][i] = mdsColumnMult(sbox[0][sbox[1][sbox[1][byte(i)]^S[3]]^S[7]], 3)
}
case 3:
for i := range c.s[0] {
c.s[0][i] = mdsColumnMult(sbox[1][sbox[0][sbox[0][sbox[1][byte(i)]^S[0]]^S[4]]^S[8]], 0)
c.s[1][i] = mdsColumnMult(sbox[0][sbox[0][sbox[1][sbox[1][byte(i)]^S[1]]^S[5]]^S[9]], 1)
c.s[2][i] = mdsColumnMult(sbox[1][sbox[1][sbox[0][sbox[0][byte(i)]^S[2]]^S[6]]^S[10]], 2)
c.s[3][i] = mdsColumnMult(sbox[0][sbox[1][sbox[1][sbox[0][byte(i)]^S[3]]^S[7]]^S[11]], 3)
}
default:
for i := range c.s[0] {
c.s[0][i] = mdsColumnMult(sbox[1][sbox[0][sbox[0][sbox[1][sbox[1][byte(i)]^S[0]]^S[4]]^S[8]]^S[12]], 0)
c.s[1][i] = mdsColumnMult(sbox[0][sbox[0][sbox[1][sbox[1][sbox[0][byte(i)]^S[1]]^S[5]]^S[9]]^S[13]], 1)
c.s[2][i] = mdsColumnMult(sbox[1][sbox[1][sbox[0][sbox[0][sbox[0][byte(i)]^S[2]]^S[6]]^S[10]]^S[14]], 2)
c.s[3][i] = mdsColumnMult(sbox[0][sbox[1][sbox[1][sbox[0][sbox[1][byte(i)]^S[3]]^S[7]]^S[11]]^S[15]], 3)
}
}
return c, nil
}
// Reset zeros the key data, so that it will no longer appear in the process's
// memory.
func (c *Cipher) Reset() {
for i := range c.k {
c.k[i] = 0
}
for i := range c.s {
for j := 0; j < 256; j++ {
c.s[i][j] = 0
}
}
}
// BlockSize returns the Twofish block size, 16 bytes.
func (c *Cipher) BlockSize() int { return BlockSize }
// store32l stores src in dst in little-endian form.
func store32l(dst []byte, src uint32) {
dst[0] = byte(src)
dst[1] = byte(src >> 8)
dst[2] = byte(src >> 16)
dst[3] = byte(src >> 24)
return
}
// load32l reads a little-endian uint32 from src.
func load32l(src []byte) uint32 {
return uint32(src[0]) | uint32(src[1])<<8 | uint32(src[2])<<16 | uint32(src[3])<<24
}
// rol returns x after a left circular rotation of y bits.
func rol(x, y uint32) uint32 {
return (x << (y & 31)) | (x >> (32 - (y & 31)))
}
// ror returns x after a right circular rotation of y bits.
func ror(x, y uint32) uint32 {
return (x >> (y & 31)) | (x << (32 - (y & 31)))
}
// The RS matrix. See [TWOFISH] 4.3
var rs = [4][8]byte{
{0x01, 0xA4, 0x55, 0x87, 0x5A, 0x58, 0xDB, 0x9E},
{0xA4, 0x56, 0x82, 0xF3, 0x1E, 0xC6, 0x68, 0xE5},
{0x02, 0xA1, 0xFC, 0xC1, 0x47, 0xAE, 0x3D, 0x19},
{0xA4, 0x55, 0x87, 0x5A, 0x58, 0xDB, 0x9E, 0x03},
}
// sbox tables
var sbox = [2][256]byte{
{
0xa9, 0x67, 0xb3, 0xe8, 0x04, 0xfd, 0xa3, 0x76, 0x9a, 0x92, 0x80, 0x78, 0xe4, 0xdd, 0xd1, 0x38,
0x0d, 0xc6, 0x35, 0x98, 0x18, 0xf7, 0xec, 0x6c, 0x43, 0x75, 0x37, 0x26, 0xfa, 0x13, 0x94, 0x48,
0xf2, 0xd0, 0x8b, 0x30, 0x84, 0x54, 0xdf, 0x23, 0x19, 0x5b, 0x3d, 0x59, 0xf3, 0xae, 0xa2, 0x82,
0x63, 0x01, 0x83, 0x2e, 0xd9, 0x51, 0x9b, 0x7c, 0xa6, 0xeb, 0xa5, 0xbe, 0x16, 0x0c, 0xe3, 0x61,
0xc0, 0x8c, 0x3a, 0xf5, 0x73, 0x2c, 0x25, 0x0b, 0xbb, 0x4e, 0x89, 0x6b, 0x53, 0x6a, 0xb4, 0xf1,
0xe1, 0xe6, 0xbd, 0x45, 0xe2, 0xf4, 0xb6, 0x66, 0xcc, 0x95, 0x03, 0x56, 0xd4, 0x1c, 0x1e, 0xd7,
0xfb, 0xc3, 0x8e, 0xb5, 0xe9, 0xcf, 0xbf, 0xba, 0xea, 0x77, 0x39, 0xaf, 0x33, 0xc9, 0x62, 0x71,
0x81, 0x79, 0x09, 0xad, 0x24, 0xcd, 0xf9, 0xd8, 0xe5, 0xc5, 0xb9, 0x4d, 0x44, 0x08, 0x86, 0xe7,
0xa1, 0x1d, 0xaa, 0xed, 0x06, 0x70, 0xb2, 0xd2, 0x41, 0x7b, 0xa0, 0x11, 0x31, 0xc2, 0x27, 0x90,
0x20, 0xf6, 0x60, 0xff, 0x96, 0x5c, 0xb1, 0xab, 0x9e, 0x9c, 0x52, 0x1b, 0x5f, 0x93, 0x0a, 0xef,
0x91, 0x85, 0x49, 0xee, 0x2d, 0x4f, 0x8f, 0x3b, 0x47, 0x87, 0x6d, 0x46, 0xd6, 0x3e, 0x69, 0x64,
0x2a, 0xce, 0xcb, 0x2f, 0xfc, 0x97, 0x05, 0x7a, 0xac, 0x7f, 0xd5, 0x1a, 0x4b, 0x0e, 0xa7, 0x5a,
0x28, 0x14, 0x3f, 0x29, 0x88, 0x3c, 0x4c, 0x02, 0xb8, 0xda, 0xb0, 0x17, 0x55, 0x1f, 0x8a, 0x7d,
0x57, 0xc7, 0x8d, 0x74, 0xb7, 0xc4, 0x9f, 0x72, 0x7e, 0x15, 0x22, 0x12, 0x58, 0x07, 0x99, 0x34,
0x6e, 0x50, 0xde, 0x68, 0x65, 0xbc, 0xdb, 0xf8, 0xc8, 0xa8, 0x2b, 0x40, 0xdc, 0xfe, 0x32, 0xa4,
0xca, 0x10, 0x21, 0xf0, 0xd3, 0x5d, 0x0f, 0x00, 0x6f, 0x9d, 0x36, 0x42, 0x4a, 0x5e, 0xc1, 0xe0,
},
{
0x75, 0xf3, 0xc6, 0xf4, 0xdb, 0x7b, 0xfb, 0xc8, 0x4a, 0xd3, 0xe6, 0x6b, 0x45, 0x7d, 0xe8, 0x4b,
0xd6, 0x32, 0xd8, 0xfd, 0x37, 0x71, 0xf1, 0xe1, 0x30, 0x0f, 0xf8, 0x1b, 0x87, 0xfa, 0x06, 0x3f,
0x5e, 0xba, 0xae, 0x5b, 0x8a, 0x00, 0xbc, 0x9d, 0x6d, 0xc1, 0xb1, 0x0e, 0x80, 0x5d, 0xd2, 0xd5,
0xa0, 0x84, 0x07, 0x14, 0xb5, 0x90, 0x2c, 0xa3, 0xb2, 0x73, 0x4c, 0x54, 0x92, 0x74, 0x36, 0x51,
0x38, 0xb0, 0xbd, 0x5a, 0xfc, 0x60, 0x62, 0x96, 0x6c, 0x42, 0xf7, 0x10, 0x7c, 0x28, 0x27, 0x8c,
0x13, 0x95, 0x9c, 0xc7, 0x24, 0x46, 0x3b, 0x70, 0xca, 0xe3, 0x85, 0xcb, 0x11, 0xd0, 0x93, 0xb8,
0xa6, 0x83, 0x20, 0xff, 0x9f, 0x77, 0xc3, 0xcc, 0x03, 0x6f, 0x08, 0xbf, 0x40, 0xe7, 0x2b, 0xe2,
0x79, 0x0c, 0xaa, 0x82, 0x41, 0x3a, 0xea, 0xb9, 0xe4, 0x9a, 0xa4, 0x97, 0x7e, 0xda, 0x7a, 0x17,
0x66, 0x94, 0xa1, 0x1d, 0x3d, 0xf0, 0xde, 0xb3, 0x0b, 0x72, 0xa7, 0x1c, 0xef, 0xd1, 0x53, 0x3e,
0x8f, 0x33, 0x26, 0x5f, 0xec, 0x76, 0x2a, 0x49, 0x81, 0x88, 0xee, 0x21, 0xc4, 0x1a, 0xeb, 0xd9,
0xc5, 0x39, 0x99, 0xcd, 0xad, 0x31, 0x8b, 0x01, 0x18, 0x23, 0xdd, 0x1f, 0x4e, 0x2d, 0xf9, 0x48,
0x4f, 0xf2, 0x65, 0x8e, 0x78, 0x5c, 0x58, 0x19, 0x8d, 0xe5, 0x98, 0x57, 0x67, 0x7f, 0x05, 0x64,
0xaf, 0x63, 0xb6, 0xfe, 0xf5, 0xb7, 0x3c, 0xa5, 0xce, 0xe9, 0x68, 0x44, 0xe0, 0x4d, 0x43, 0x69,
0x29, 0x2e, 0xac, 0x15, 0x59, 0xa8, 0x0a, 0x9e, 0x6e, 0x47, 0xdf, 0x34, 0x35, 0x6a, 0xcf, 0xdc,
0x22, 0xc9, 0xc0, 0x9b, 0x89, 0xd4, 0xed, 0xab, 0x12, 0xa2, 0x0d, 0x52, 0xbb, 0x02, 0x2f, 0xa9,
0xd7, 0x61, 0x1e, 0xb4, 0x50, 0x04, 0xf6, 0xc2, 0x16, 0x25, 0x86, 0x56, 0x55, 0x09, 0xbe, 0x91,
},
}
// gfMult returns a·b in GF(2^8)/p
func gfMult(a, b byte, p uint32) byte {
B := [2]uint32{0, uint32(b)}
P := [2]uint32{0, p}
var result uint32
// branchless GF multiplier
for i := 0; i < 7; i++ {
result ^= B[a&1]
a >>= 1
B[1] = P[B[1]>>7] ^ (B[1] << 1)
}
result ^= B[a&1]
return byte(result)
}
// mdsColumnMult calculates y{col} where [y0 y1 y2 y3] = MDS · [x0]
func mdsColumnMult(in byte, col int) uint32 {
mul01 := in
mul5B := gfMult(in, 0x5B, mdsPolynomial)
mulEF := gfMult(in, 0xEF, mdsPolynomial)
switch col {
case 0:
return uint32(mul01) | uint32(mul5B)<<8 | uint32(mulEF)<<16 | uint32(mulEF)<<24
case 1:
return uint32(mulEF) | uint32(mulEF)<<8 | uint32(mul5B)<<16 | uint32(mul01)<<24
case 2:
return uint32(mul5B) | uint32(mulEF)<<8 | uint32(mul01)<<16 | uint32(mulEF)<<24
case 3:
return uint32(mul5B) | uint32(mul01)<<8 | uint32(mulEF)<<16 | uint32(mul5B)<<24
}
panic("unreachable")
}
// h implements the S-box generation function. See [TWOFISH] 4.3.5
func h(in, key []byte, offset int) uint32 {
var y [4]byte
for x := range y {
y[x] = in[x]
}
switch len(key) / 8 {
case 4:
y[0] = sbox[1][y[0]] ^ key[4*(6+offset)+0]
y[1] = sbox[0][y[1]] ^ key[4*(6+offset)+1]
y[2] = sbox[0][y[2]] ^ key[4*(6+offset)+2]
y[3] = sbox[1][y[3]] ^ key[4*(6+offset)+3]
fallthrough
case 3:
y[0] = sbox[1][y[0]] ^ key[4*(4+offset)+0]
y[1] = sbox[1][y[1]] ^ key[4*(4+offset)+1]
y[2] = sbox[0][y[2]] ^ key[4*(4+offset)+2]
y[3] = sbox[0][y[3]] ^ key[4*(4+offset)+3]
fallthrough
case 2:
y[0] = sbox[1][sbox[0][sbox[0][y[0]]^key[4*(2+offset)+0]]^key[4*(0+offset)+0]]
y[1] = sbox[0][sbox[0][sbox[1][y[1]]^key[4*(2+offset)+1]]^key[4*(0+offset)+1]]
y[2] = sbox[1][sbox[1][sbox[0][y[2]]^key[4*(2+offset)+2]]^key[4*(0+offset)+2]]
y[3] = sbox[0][sbox[1][sbox[1][y[3]]^key[4*(2+offset)+3]]^key[4*(0+offset)+3]]
}
// [y0 y1 y2 y3] = MDS . [x0 x1 x2 x3]
var mdsMult uint32
for i := range y {
mdsMult ^= mdsColumnMult(y[i], i)
}
return mdsMult
}
// Encrypt encrypts a 16-byte block from src to dst, which may overlap.
// 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) {
S1 := c.s[0]
S2 := c.s[1]
S3 := c.s[2]
S4 := c.s[3]
// Load input
ia := load32l(src[0:4])
ib := load32l(src[4:8])
ic := load32l(src[8:12])
id := load32l(src[12:16])
// Pre-whitening
ia ^= c.k[0]
ib ^= c.k[1]
ic ^= c.k[2]
id ^= c.k[3]
for i := 0; i < 8; i++ {
k := c.k[8+i*4 : 12+i*4]
t2 := S2[byte(ib)] ^ S3[byte(ib>>8)] ^ S4[byte(ib>>16)] ^ S1[byte(ib>>24)]
t1 := S1[byte(ia)] ^ S2[byte(ia>>8)] ^ S3[byte(ia>>16)] ^ S4[byte(ia>>24)] + t2
ic = ror(ic^(t1+k[0]), 1)
id = rol(id, 1) ^ (t2 + t1 + k[1])
t2 = S2[byte(id)] ^ S3[byte(id>>8)] ^ S4[byte(id>>16)] ^ S1[byte(id>>24)]
t1 = S1[byte(ic)] ^ S2[byte(ic>>8)] ^ S3[byte(ic>>16)] ^ S4[byte(ic>>24)] + t2
ia = ror(ia^(t1+k[2]), 1)
ib = rol(ib, 1) ^ (t2 + t1 + k[3])
}
// Output with "undo last swap"
ta := ic ^ c.k[4]
tb := id ^ c.k[5]
tc := ia ^ c.k[6]
td := ib ^ c.k[7]
store32l(dst[0:4], ta)
store32l(dst[4:8], tb)
store32l(dst[8:12], tc)
store32l(dst[12:16], td)
}
// Decrypt decrypts a 16-byte block from src to dst, which may overlap.
func (c *Cipher) Decrypt(dst, src []byte) {
S1 := c.s[0]
S2 := c.s[1]
S3 := c.s[2]
S4 := c.s[3]
// Load input
ta := load32l(src[0:4])
tb := load32l(src[4:8])
tc := load32l(src[8:12])
td := load32l(src[12:16])
// Undo undo final swap
ia := tc ^ c.k[6]
ib := td ^ c.k[7]
ic := ta ^ c.k[4]
id := tb ^ c.k[5]
for i := 8; i > 0; i-- {
k := c.k[4+i*4 : 8+i*4]
t2 := S2[byte(id)] ^ S3[byte(id>>8)] ^ S4[byte(id>>16)] ^ S1[byte(id>>24)]
t1 := S1[byte(ic)] ^ S2[byte(ic>>8)] ^ S3[byte(ic>>16)] ^ S4[byte(ic>>24)] + t2
ia = rol(ia, 1) ^ (t1 + k[2])
ib = ror(ib^(t2+t1+k[3]), 1)
t2 = S2[byte(ib)] ^ S3[byte(ib>>8)] ^ S4[byte(ib>>16)] ^ S1[byte(ib>>24)]
t1 = S1[byte(ia)] ^ S2[byte(ia>>8)] ^ S3[byte(ia>>16)] ^ S4[byte(ia>>24)] + t2
ic = rol(ic, 1) ^ (t1 + k[0])
id = ror(id^(t2+t1+k[1]), 1)
}
// Undo pre-whitening
ia ^= c.k[0]
ib ^= c.k[1]
ic ^= c.k[2]
id ^= c.k[3]
store32l(dst[0:4], ia)
store32l(dst[4:8], ib)
store32l(dst[8:12], ic)
store32l(dst[12:16], id)
}

View File

@ -1,129 +0,0 @@
// 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 twofish
import (
"bytes"
"testing"
)
var qbox = [2][4][16]byte{
{
{0x8, 0x1, 0x7, 0xD, 0x6, 0xF, 0x3, 0x2, 0x0, 0xB, 0x5, 0x9, 0xE, 0xC, 0xA, 0x4},
{0xE, 0xC, 0xB, 0x8, 0x1, 0x2, 0x3, 0x5, 0xF, 0x4, 0xA, 0x6, 0x7, 0x0, 0x9, 0xD},
{0xB, 0xA, 0x5, 0xE, 0x6, 0xD, 0x9, 0x0, 0xC, 0x8, 0xF, 0x3, 0x2, 0x4, 0x7, 0x1},
{0xD, 0x7, 0xF, 0x4, 0x1, 0x2, 0x6, 0xE, 0x9, 0xB, 0x3, 0x0, 0x8, 0x5, 0xC, 0xA},
},
{
{0x2, 0x8, 0xB, 0xD, 0xF, 0x7, 0x6, 0xE, 0x3, 0x1, 0x9, 0x4, 0x0, 0xA, 0xC, 0x5},
{0x1, 0xE, 0x2, 0xB, 0x4, 0xC, 0x3, 0x7, 0x6, 0xD, 0xA, 0x5, 0xF, 0x9, 0x0, 0x8},
{0x4, 0xC, 0x7, 0x5, 0x1, 0x6, 0x9, 0xA, 0x0, 0xE, 0xD, 0x8, 0x2, 0xB, 0x3, 0xF},
{0xB, 0x9, 0x5, 0x1, 0xC, 0x3, 0xD, 0xE, 0x6, 0x4, 0x7, 0xF, 0x2, 0x0, 0x8, 0xA},
},
}
// genSbox generates the variable sbox
func genSbox(qi int, x byte) byte {
a0, b0 := x/16, x%16
for i := 0; i < 2; i++ {
a1 := a0 ^ b0
b1 := (a0 ^ ((b0 << 3) | (b0 >> 1)) ^ (a0 << 3)) & 15
a0 = qbox[qi][2*i][a1]
b0 = qbox[qi][2*i+1][b1]
}
return (b0 << 4) + a0
}
func TestSbox(t *testing.T) {
for n := range sbox {
for m := range sbox[n] {
if genSbox(n, byte(m)) != sbox[n][m] {
t.Errorf("#%d|%d: sbox value = %d want %d", n, m, sbox[n][m], genSbox(n, byte(m)))
}
}
}
}
var testVectors = []struct {
key []byte
dec []byte
enc []byte
}{
// These tests are extracted from LibTom
{
[]byte{0x9F, 0x58, 0x9F, 0x5C, 0xF6, 0x12, 0x2C, 0x32, 0xB6, 0xBF, 0xEC, 0x2F, 0x2A, 0xE8, 0xC3, 0x5A},
[]byte{0xD4, 0x91, 0xDB, 0x16, 0xE7, 0xB1, 0xC3, 0x9E, 0x86, 0xCB, 0x08, 0x6B, 0x78, 0x9F, 0x54, 0x19},
[]byte{0x01, 0x9F, 0x98, 0x09, 0xDE, 0x17, 0x11, 0x85, 0x8F, 0xAA, 0xC3, 0xA3, 0xBA, 0x20, 0xFB, 0xC3},
},
{
[]byte{0x88, 0xB2, 0xB2, 0x70, 0x6B, 0x10, 0x5E, 0x36, 0xB4, 0x46, 0xBB, 0x6D, 0x73, 0x1A, 0x1E, 0x88,
0xEF, 0xA7, 0x1F, 0x78, 0x89, 0x65, 0xBD, 0x44},
[]byte{0x39, 0xDA, 0x69, 0xD6, 0xBA, 0x49, 0x97, 0xD5, 0x85, 0xB6, 0xDC, 0x07, 0x3C, 0xA3, 0x41, 0xB2},
[]byte{0x18, 0x2B, 0x02, 0xD8, 0x14, 0x97, 0xEA, 0x45, 0xF9, 0xDA, 0xAC, 0xDC, 0x29, 0x19, 0x3A, 0x65},
},
{
[]byte{0xD4, 0x3B, 0xB7, 0x55, 0x6E, 0xA3, 0x2E, 0x46, 0xF2, 0xA2, 0x82, 0xB7, 0xD4, 0x5B, 0x4E, 0x0D,
0x57, 0xFF, 0x73, 0x9D, 0x4D, 0xC9, 0x2C, 0x1B, 0xD7, 0xFC, 0x01, 0x70, 0x0C, 0xC8, 0x21, 0x6F},
[]byte{0x90, 0xAF, 0xE9, 0x1B, 0xB2, 0x88, 0x54, 0x4F, 0x2C, 0x32, 0xDC, 0x23, 0x9B, 0x26, 0x35, 0xE6},
[]byte{0x6C, 0xB4, 0x56, 0x1C, 0x40, 0xBF, 0x0A, 0x97, 0x05, 0x93, 0x1C, 0xB6, 0xD4, 0x08, 0xE7, 0xFA},
},
// These test are derived from http://www.schneier.com/code/ecb_ival.txt
{
[]byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
[]byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
[]byte{0x9F, 0x58, 0x9F, 0x5C, 0xF6, 0x12, 0x2C, 0x32, 0xB6, 0xBF, 0xEC, 0x2F, 0x2A, 0xE8, 0xC3, 0x5A},
},
{
[]byte{0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF, 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10,
0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77,
},
[]byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
[]byte{0xCF, 0xD1, 0xD2, 0xE5, 0xA9, 0xBE, 0x9C, 0xDF, 0x50, 0x1F, 0x13, 0xB8, 0x92, 0xBD, 0x22, 0x48},
},
{
[]byte{0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF, 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10,
0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF,
},
[]byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
[]byte{0x37, 0x52, 0x7B, 0xE0, 0x05, 0x23, 0x34, 0xB8, 0x9F, 0x0C, 0xFC, 0xCA, 0xE8, 0x7C, 0xFA, 0x20},
},
}
func TestCipher(t *testing.T) {
for n, tt := range testVectors {
// Test if the plaintext (dec) is encrypts to the given
// ciphertext (enc) using the given key. Test also if enc can
// be decrypted again into dec.
c, err := NewCipher(tt.key)
if err != nil {
t.Errorf("#%d: NewCipher: %v", n, err)
return
}
buf := make([]byte, 16)
c.Encrypt(buf, tt.dec)
if !bytes.Equal(buf, tt.enc) {
t.Errorf("#%d: encrypt = %x want %x", n, buf, tt.enc)
}
c.Decrypt(buf, tt.enc)
if !bytes.Equal(buf, tt.dec) {
t.Errorf("#%d: decrypt = %x want %x", n, buf, tt.dec)
}
// Test that 16 zero bytes, encrypted 1000 times then decrypted
// 1000 times results in zero bytes again.
zero := make([]byte, 16)
buf = make([]byte, 16)
for i := 0; i < 1000; i++ {
c.Encrypt(buf, buf)
}
for i := 0; i < 1000; i++ {
c.Decrypt(buf, buf)
}
if !bytes.Equal(buf, zero) {
t.Errorf("#%d: encrypt/decrypt 1000: have %x want %x", n, buf, zero)
}
}
}

View File

@ -1,66 +0,0 @@
// 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.
/*
Implementation adapted from Needham and Wheeler's paper:
http://www.cix.co.uk/~klockstone/xtea.pdf
A precalculated look up table is used during encryption/decryption for values that are based purely on the key.
*/
package xtea
// XTEA is based on 64 rounds.
const numRounds = 64
// blockToUint32 reads an 8 byte slice into two uint32s.
// The block is treated as big endian.
func blockToUint32(src []byte) (uint32, uint32) {
r0 := uint32(src[0])<<24 | uint32(src[1])<<16 | uint32(src[2])<<8 | uint32(src[3])
r1 := uint32(src[4])<<24 | uint32(src[5])<<16 | uint32(src[6])<<8 | uint32(src[7])
return r0, r1
}
// uint32ToBlock writes two uint32s into an 8 byte data block.
// Values are written as big endian.
func uint32ToBlock(v0, v1 uint32, dst []byte) {
dst[0] = byte(v0 >> 24)
dst[1] = byte(v0 >> 16)
dst[2] = byte(v0 >> 8)
dst[3] = byte(v0)
dst[4] = byte(v1 >> 24)
dst[5] = byte(v1 >> 16)
dst[6] = byte(v1 >> 8)
dst[7] = byte(v1 >> 0)
}
// encryptBlock encrypts a single 8 byte block using XTEA.
func encryptBlock(c *Cipher, dst, src []byte) {
v0, v1 := blockToUint32(src)
// Two rounds of XTEA applied per loop
for i := 0; i < numRounds; {
v0 += ((v1<<4 ^ v1>>5) + v1) ^ c.table[i]
i++
v1 += ((v0<<4 ^ v0>>5) + v0) ^ c.table[i]
i++
}
uint32ToBlock(v0, v1, dst)
}
// decryptBlock decrypt a single 8 byte block using XTEA.
func decryptBlock(c *Cipher, dst, src []byte) {
v0, v1 := blockToUint32(src)
// Two rounds of XTEA applied per loop
for i := numRounds; i > 0; {
i--
v1 -= ((v0<<4 ^ v0>>5) + v0) ^ c.table[i]
i--
v0 -= ((v1<<4 ^ v1>>5) + v1) ^ c.table[i]
}
uint32ToBlock(v0, v1, dst)
}

View File

@ -1,89 +0,0 @@
// 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 xtea implements XTEA encryption, as defined in Needham and Wheeler's
// 1997 technical report, "Tea extensions."
package xtea
// For details, see http://www.cix.co.uk/~klockstone/xtea.pdf
import "strconv"
// The XTEA block size in bytes.
const BlockSize = 8
// A Cipher is an instance of an XTEA cipher using a particular key.
// table contains a series of precalculated values that are used each round.
type Cipher struct {
table [64]uint32
}
type KeySizeError int
func (k KeySizeError) Error() string {
return "crypto/xtea: invalid key size " + strconv.Itoa(int(k))
}
// NewCipher creates and returns a new Cipher.
// The key argument should be the XTEA key.
// XTEA only supports 128 bit (16 byte) keys.
func NewCipher(key []byte) (*Cipher, error) {
k := len(key)
switch k {
default:
return nil, KeySizeError(k)
case 16:
break
}
c := new(Cipher)
initCipher(c, key)
return c, nil
}
// BlockSize returns the XTEA block size, 8 bytes.
// It is necessary to satisfy the Block interface in the
// package "crypto/cipher".
func (c *Cipher) BlockSize() int { return BlockSize }
// Encrypt encrypts the 8 byte buffer src using the key 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, dst, src) }
// Decrypt decrypts the 8 byte buffer src using the key k and stores the result in dst.
func (c *Cipher) Decrypt(dst, src []byte) { decryptBlock(c, dst, src) }
// Reset zeros the table, so that it will no longer appear in the process's memory.
func (c *Cipher) Reset() {
for i := 0; i < len(c.table); i++ {
c.table[i] = 0
}
}
// initCipher initializes the cipher context by creating a look up table
// of precalculated values that are based on the key.
func initCipher(c *Cipher, key []byte) {
// Load the key into four uint32s
var k [4]uint32
for i := 0; i < len(k); i++ {
j := i << 2 // Multiply by 4
k[i] = uint32(key[j+0])<<24 | uint32(key[j+1])<<16 | uint32(key[j+2])<<8 | uint32(key[j+3])
}
// Precalculate the table
const delta = 0x9E3779B9
var sum uint32 = 0
// Two rounds of XTEA applied per loop
for i := 0; i < numRounds; {
c.table[i] = sum + k[sum&3]
i++
sum += delta
c.table[i] = sum + k[(sum>>11)&3]
i++
}
}

View File

@ -1,246 +0,0 @@
// 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 xtea
import (
"testing"
)
// A sample test key for when we just want to initialize a cipher
var testKey = []byte{0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF}
// Test that the block size for XTEA is correct
func TestBlocksize(t *testing.T) {
if BlockSize != 8 {
t.Errorf("BlockSize constant - expected 8, got %d", BlockSize)
return
}
c, err := NewCipher(testKey)
if err != nil {
t.Errorf("NewCipher(%d bytes) = %s", len(testKey), err)
return
}
result := c.BlockSize()
if result != 8 {
t.Errorf("BlockSize function - expected 8, got %d", result)
return
}
}
// A series of test values to confirm that the Cipher.table array was initialized correctly
var testTable = []uint32{
0x00112233, 0x6B1568B8, 0xE28CE030, 0xC5089E2D, 0xC5089E2D, 0x1EFBD3A2, 0xA7845C2A, 0x78EF0917,
0x78EF0917, 0x172682D0, 0x5B6AC714, 0x822AC955, 0x3DE68511, 0xDC1DFECA, 0x2062430E, 0x3611343F,
0xF1CCEFFB, 0x900469B4, 0xD448ADF8, 0x2E3BE36D, 0xB6C46BF5, 0x994029F2, 0x994029F2, 0xF3335F67,
0x6AAAD6DF, 0x4D2694DC, 0x4D2694DC, 0xEB5E0E95, 0x2FA252D9, 0x4551440A, 0x121E10D6, 0xB0558A8F,
0xE388BDC3, 0x0A48C004, 0xC6047BC0, 0x643BF579, 0xA88039BD, 0x02736F32, 0x8AFBF7BA, 0x5C66A4A7,
0x5C66A4A7, 0xC76AEB2C, 0x3EE262A4, 0x215E20A1, 0x215E20A1, 0x7B515616, 0x03D9DE9E, 0x1988CFCF,
0xD5448B8B, 0x737C0544, 0xB7C04988, 0xDE804BC9, 0x9A3C0785, 0x3873813E, 0x7CB7C582, 0xD6AAFAF7,
0x4E22726F, 0x309E306C, 0x309E306C, 0x8A9165E1, 0x1319EE69, 0xF595AC66, 0xF595AC66, 0x4F88E1DB,
}
// Test that the cipher context is initialized correctly
func TestCipherInit(t *testing.T) {
c, err := NewCipher(testKey)
if err != nil {
t.Errorf("NewCipher(%d bytes) = %s", len(testKey), err)
return
}
for i := 0; i < len(c.table); i++ {
if c.table[i] != testTable[i] {
t.Errorf("NewCipher() failed to initialize Cipher.table[%d] correctly. Expected %08X, got %08X", i, testTable[i], c.table[i])
break
}
}
}
// Test that invalid key sizes return an error
func TestInvalidKeySize(t *testing.T) {
// Test a long key
key := []byte{
0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF,
0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF,
}
_, err := NewCipher(key)
if err == nil {
t.Errorf("Invalid key size %d didn't result in an error.", len(key))
}
// Test a short key
key = []byte{0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77}
_, err = NewCipher(key)
if err == nil {
t.Errorf("Invalid key size %d didn't result in an error.", len(key))
}
}
// Test that we can correctly decode some bytes we have encoded
func TestEncodeDecode(t *testing.T) {
original := []byte{0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF}
input := original
output := make([]byte, BlockSize)
c, err := NewCipher(testKey)
if err != nil {
t.Errorf("NewCipher(%d bytes) = %s", len(testKey), err)
return
}
// Encrypt the input block
c.Encrypt(output, input)
// Check that the output does not match the input
differs := false
for i := 0; i < len(input); i++ {
if output[i] != input[i] {
differs = true
break
}
}
if differs == false {
t.Error("Cipher.Encrypt: Failed to encrypt the input block.")
return
}
// Decrypt the block we just encrypted
input = output
output = make([]byte, BlockSize)
c.Decrypt(output, input)
// Check that the output from decrypt matches our initial input
for i := 0; i < len(input); i++ {
if output[i] != original[i] {
t.Errorf("Decrypted byte %d differed. Expected %02X, got %02X\n", i, original[i], output[i])
return
}
}
}
// Test Vectors
type CryptTest struct {
key []byte
plainText []byte
cipherText []byte
}
var CryptTests = []CryptTest{
// These were sourced from http://www.freemedialibrary.com/index.php/XTEA_test_vectors
{
[]byte{0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f},
[]byte{0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48},
[]byte{0x49, 0x7d, 0xf3, 0xd0, 0x72, 0x61, 0x2c, 0xb5},
},
{
[]byte{0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f},
[]byte{0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41},
[]byte{0xe7, 0x8f, 0x2d, 0x13, 0x74, 0x43, 0x41, 0xd8},
},
{
[]byte{0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f},
[]byte{0x5a, 0x5b, 0x6e, 0x27, 0x89, 0x48, 0xd7, 0x7f},
[]byte{0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41},
},
{
[]byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
[]byte{0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48},
[]byte{0xa0, 0x39, 0x05, 0x89, 0xf8, 0xb8, 0xef, 0xa5},
},
{
[]byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
[]byte{0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41},
[]byte{0xed, 0x23, 0x37, 0x5a, 0x82, 0x1a, 0x8c, 0x2d},
},
{
[]byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
[]byte{0x70, 0xe1, 0x22, 0x5d, 0x6e, 0x4e, 0x76, 0x55},
[]byte{0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41},
},
// These vectors are from http://wiki.secondlife.com/wiki/XTEA_Strong_Encryption_Implementation#Bouncy_Castle_C.23_API
{
[]byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
[]byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
[]byte{0xDE, 0xE9, 0xD4, 0xD8, 0xF7, 0x13, 0x1E, 0xD9},
},
{
[]byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
[]byte{0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08},
[]byte{0x06, 0x5C, 0x1B, 0x89, 0x75, 0xC6, 0xA8, 0x16},
},
{
[]byte{0x01, 0x23, 0x45, 0x67, 0x12, 0x34, 0x56, 0x78, 0x23, 0x45, 0x67, 0x89, 0x34, 0x56, 0x78, 0x9A},
[]byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
[]byte{0x1F, 0xF9, 0xA0, 0x26, 0x1A, 0xC6, 0x42, 0x64},
},
{
[]byte{0x01, 0x23, 0x45, 0x67, 0x12, 0x34, 0x56, 0x78, 0x23, 0x45, 0x67, 0x89, 0x34, 0x56, 0x78, 0x9A},
[]byte{0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08},
[]byte{0x8C, 0x67, 0x15, 0x5B, 0x2E, 0xF9, 0x1E, 0xAD},
},
}
// Test encryption
func TestCipherEncrypt(t *testing.T) {
for i, tt := range CryptTests {
c, err := NewCipher(tt.key)
if err != nil {
t.Errorf("NewCipher(%d bytes), vector %d = %s", len(tt.key), i, err)
continue
}
out := make([]byte, len(tt.plainText))
c.Encrypt(out, tt.plainText)
for j := 0; j < len(out); j++ {
if out[j] != tt.cipherText[j] {
t.Errorf("Cipher.Encrypt %d: out[%d] = %02X, expected %02X", i, j, out[j], tt.cipherText[j])
break
}
}
}
}
// Test decryption
func TestCipherDecrypt(t *testing.T) {
for i, tt := range CryptTests {
c, err := NewCipher(tt.key)
if err != nil {
t.Errorf("NewCipher(%d bytes), vector %d = %s", len(tt.key), i, err)
continue
}
out := make([]byte, len(tt.cipherText))
c.Decrypt(out, tt.cipherText)
for j := 0; j < len(out); j++ {
if out[j] != tt.plainText[j] {
t.Errorf("Cipher.Decrypt %d: out[%d] = %02X, expected %02X", i, j, out[j], tt.plainText[j])
break
}
}
}
}
// Test resetting the cipher context
func TestReset(t *testing.T) {
c, err := NewCipher(testKey)
if err != nil {
t.Errorf("NewCipher(%d bytes) = %s", len(testKey), err)
return
}
c.Reset()
for i := 0; i < len(c.table); i++ {
if c.table[i] != 0 {
t.Errorf("Cipher.Reset: Failed to clear Cipher.table[%d]. expected 0, got %08X", i, c.table[i])
return
}
}
}

View File

@ -40,6 +40,9 @@ func convertAssign(dest, src interface{}) error {
case *string: case *string:
*d = s *d = s
return nil return nil
case *[]byte:
*d = []byte(s)
return nil
} }
case []byte: case []byte:
switch d := dest.(type) { switch d := dest.(type) {
@ -50,6 +53,12 @@ func convertAssign(dest, src interface{}) error {
*d = s *d = s
return nil return nil
} }
case nil:
switch d := dest.(type) {
case *[]byte:
*d = nil
return nil
}
} }
var sv reflect.Value var sv reflect.Value

View File

@ -585,12 +585,26 @@ func converterForType(typ string) driver.ValueConverter {
switch typ { switch typ {
case "bool": case "bool":
return driver.Bool return driver.Bool
case "nullbool":
return driver.Null{driver.Bool}
case "int32": case "int32":
return driver.Int32 return driver.Int32
case "string": case "string":
return driver.NotNull{driver.String} return driver.NotNull{driver.String}
case "nullstring": case "nullstring":
return driver.Null{driver.String} return driver.Null{driver.String}
case "int64":
// TODO(coopernurse): add type-specific converter
return driver.NotNull{driver.DefaultParameterConverter}
case "nullint64":
// TODO(coopernurse): add type-specific converter
return driver.Null{driver.DefaultParameterConverter}
case "float64":
// TODO(coopernurse): add type-specific converter
return driver.NotNull{driver.DefaultParameterConverter}
case "nullfloat64":
// TODO(coopernurse): add type-specific converter
return driver.Null{driver.DefaultParameterConverter}
case "datetime": case "datetime":
return driver.DefaultParameterConverter return driver.DefaultParameterConverter
} }

View File

@ -47,7 +47,6 @@ type RawBytes []byte
// // NULL value // // NULL value
// } // }
// //
// TODO(bradfitz): add other types.
type NullString struct { type NullString struct {
String string String string
Valid bool // Valid is true if String is not NULL Valid bool // Valid is true if String is not NULL
@ -71,6 +70,84 @@ func (ns NullString) SubsetValue() (interface{}, error) {
return ns.String, nil return ns.String, nil
} }
// NullInt64 represents an int64 that may be null.
// NullInt64 implements the ScannerInto interface so
// it can be used as a scan destination, similar to NullString.
type NullInt64 struct {
Int64 int64
Valid bool // Valid is true if Int64 is not NULL
}
// ScanInto implements the ScannerInto interface.
func (n *NullInt64) ScanInto(value interface{}) error {
if value == nil {
n.Int64, n.Valid = 0, false
return nil
}
n.Valid = true
return convertAssign(&n.Int64, value)
}
// SubsetValue implements the driver SubsetValuer interface.
func (n NullInt64) SubsetValue() (interface{}, error) {
if !n.Valid {
return nil, nil
}
return n.Int64, nil
}
// NullFloat64 represents a float64 that may be null.
// NullFloat64 implements the ScannerInto interface so
// it can be used as a scan destination, similar to NullString.
type NullFloat64 struct {
Float64 float64
Valid bool // Valid is true if Float64 is not NULL
}
// ScanInto implements the ScannerInto interface.
func (n *NullFloat64) ScanInto(value interface{}) error {
if value == nil {
n.Float64, n.Valid = 0, false
return nil
}
n.Valid = true
return convertAssign(&n.Float64, value)
}
// SubsetValue implements the driver SubsetValuer interface.
func (n NullFloat64) SubsetValue() (interface{}, error) {
if !n.Valid {
return nil, nil
}
return n.Float64, nil
}
// NullBool represents a bool that may be null.
// NullBool implements the ScannerInto interface so
// it can be used as a scan destination, similar to NullString.
type NullBool struct {
Bool bool
Valid bool // Valid is true if Bool is not NULL
}
// ScanInto implements the ScannerInto interface.
func (n *NullBool) ScanInto(value interface{}) error {
if value == nil {
n.Bool, n.Valid = false, false
return nil
}
n.Valid = true
return convertAssign(&n.Bool, value)
}
// SubsetValue implements the driver SubsetValuer interface.
func (n NullBool) SubsetValue() (interface{}, error) {
if !n.Valid {
return nil, nil
}
return n.Bool, nil
}
// ScannerInto is an interface used by Scan. // ScannerInto is an interface used by Scan.
type ScannerInto interface { type ScannerInto interface {
// ScanInto assigns a value from a database driver. // ScanInto assigns a value from a database driver.
@ -479,8 +556,11 @@ func (tx *Tx) Query(query string, args ...interface{}) (*Rows, error) {
if err != nil { if err != nil {
return nil, err return nil, err
} }
defer stmt.Close() rows, err := stmt.Query(args...)
return stmt.Query(args...) if err == nil {
rows.closeStmt = stmt
}
return rows, err
} }
// QueryRow executes a query that is expected to return at most one row. // QueryRow executes a query that is expected to return at most one row.
@ -824,6 +904,12 @@ func (rs *Rows) Scan(dest ...interface{}) error {
if !ok { if !ok {
continue continue
} }
if *b == nil {
// If the []byte is now nil (for a NULL value),
// don't fall through to below which would
// turn it into a non-nil 0-length byte slice
continue
}
if _, ok = dp.(*RawBytes); ok { if _, ok = dp.(*RawBytes); ok {
continue continue
} }
@ -865,17 +951,10 @@ func (r *Row) Scan(dest ...interface{}) error {
if r.err != nil { if r.err != nil {
return r.err return r.err
} }
defer r.rows.Close()
if !r.rows.Next() {
return ErrNoRows
}
err := r.rows.Scan(dest...)
if err != nil {
return err
}
// TODO(bradfitz): for now we need to defensively clone all // TODO(bradfitz): for now we need to defensively clone all
// []byte that the driver returned, since we're about to close // []byte that the driver returned (not permitting
// *RawBytes in Rows.Scan), since we're about to close
// the Rows in our defer, when we return from this function. // the Rows in our defer, when we return from this function.
// the contract with the driver.Next(...) interface is that it // the contract with the driver.Next(...) interface is that it
// can return slices into read-only temporary memory that's // can return slices into read-only temporary memory that's
@ -890,14 +969,17 @@ func (r *Row) Scan(dest ...interface{}) error {
if _, ok := dp.(*RawBytes); ok { if _, ok := dp.(*RawBytes); ok {
return errors.New("sql: RawBytes isn't allowed on Row.Scan") return errors.New("sql: RawBytes isn't allowed on Row.Scan")
} }
b, ok := dp.(*[]byte)
if !ok {
continue
} }
clone := make([]byte, len(*b))
copy(clone, *b) defer r.rows.Close()
*b = clone if !r.rows.Next() {
return ErrNoRows
} }
err := r.rows.Scan(dest...)
if err != nil {
return err
}
return nil return nil
} }

View File

@ -5,6 +5,7 @@
package sql package sql
import ( import (
"fmt"
"reflect" "reflect"
"strings" "strings"
"testing" "testing"
@ -310,6 +311,40 @@ func TestTxStmt(t *testing.T) {
} }
} }
// Issue: http://golang.org/issue/2784
// This test didn't fail before because we got luckly with the fakedb driver.
// It was failing, and now not, in github.com/bradfitz/go-sql-test
func TestTxQuery(t *testing.T) {
db := newTestDB(t, "")
defer closeDB(t, db)
exec(t, db, "CREATE|t1|name=string,age=int32,dead=bool")
exec(t, db, "INSERT|t1|name=Alice")
tx, err := db.Begin()
if err != nil {
t.Fatal(err)
}
defer tx.Rollback()
r, err := tx.Query("SELECT|t1|name|")
if err != nil {
t.Fatal(err)
}
if !r.Next() {
if r.Err() != nil {
t.Fatal(r.Err())
}
t.Fatal("expected one row")
}
var x string
err = r.Scan(&x)
if err != nil {
t.Fatal(err)
}
}
// Tests fix for issue 2542, that we release a lock when querying on // Tests fix for issue 2542, that we release a lock when querying on
// a closed connection. // a closed connection.
func TestIssue2542Deadlock(t *testing.T) { func TestIssue2542Deadlock(t *testing.T) {
@ -323,6 +358,34 @@ func TestIssue2542Deadlock(t *testing.T) {
} }
} }
// Tests fix for issue 2788, that we bind nil to a []byte if the
// value in the column is sql null
func TestNullByteSlice(t *testing.T) {
db := newTestDB(t, "")
defer closeDB(t, db)
exec(t, db, "CREATE|t|id=int32,name=nullstring")
exec(t, db, "INSERT|t|id=10,name=?", nil)
var name []byte
err := db.QueryRow("SELECT|t|name|id=?", 10).Scan(&name)
if err != nil {
t.Fatal(err)
}
if name != nil {
t.Fatalf("name []byte should be nil for null column value, got: %#v", name)
}
exec(t, db, "INSERT|t|id=11,name=?", "bob")
err = db.QueryRow("SELECT|t|name|id=?", 11).Scan(&name)
if err != nil {
t.Fatal(err)
}
if string(name) != "bob" {
t.Fatalf("name []byte should be bob, got: %q", string(name))
}
}
func TestQueryRowClosingStmt(t *testing.T) { func TestQueryRowClosingStmt(t *testing.T) {
db := newTestDB(t, "people") db := newTestDB(t, "people")
defer closeDB(t, db) defer closeDB(t, db)
@ -341,16 +404,96 @@ func TestQueryRowClosingStmt(t *testing.T) {
} }
} }
type nullTestRow struct {
nullParam interface{}
notNullParam interface{}
scanNullVal interface{}
}
type nullTestSpec struct {
nullType string
notNullType string
rows [6]nullTestRow
}
func TestNullStringParam(t *testing.T) { func TestNullStringParam(t *testing.T) {
spec := nullTestSpec{"nullstring", "string", [6]nullTestRow{
nullTestRow{NullString{"aqua", true}, "", NullString{"aqua", true}},
nullTestRow{NullString{"brown", false}, "", NullString{"", false}},
nullTestRow{"chartreuse", "", NullString{"chartreuse", true}},
nullTestRow{NullString{"darkred", true}, "", NullString{"darkred", true}},
nullTestRow{NullString{"eel", false}, "", NullString{"", false}},
nullTestRow{"foo", NullString{"black", false}, nil},
}}
nullTestRun(t, spec)
}
func TestNullInt64Param(t *testing.T) {
spec := nullTestSpec{"nullint64", "int64", [6]nullTestRow{
nullTestRow{NullInt64{31, true}, 1, NullInt64{31, true}},
nullTestRow{NullInt64{-22, false}, 1, NullInt64{0, false}},
nullTestRow{22, 1, NullInt64{22, true}},
nullTestRow{NullInt64{33, true}, 1, NullInt64{33, true}},
nullTestRow{NullInt64{222, false}, 1, NullInt64{0, false}},
nullTestRow{0, NullInt64{31, false}, nil},
}}
nullTestRun(t, spec)
}
func TestNullFloat64Param(t *testing.T) {
spec := nullTestSpec{"nullfloat64", "float64", [6]nullTestRow{
nullTestRow{NullFloat64{31.2, true}, 1, NullFloat64{31.2, true}},
nullTestRow{NullFloat64{13.1, false}, 1, NullFloat64{0, false}},
nullTestRow{-22.9, 1, NullFloat64{-22.9, true}},
nullTestRow{NullFloat64{33.81, true}, 1, NullFloat64{33.81, true}},
nullTestRow{NullFloat64{222, false}, 1, NullFloat64{0, false}},
nullTestRow{10, NullFloat64{31.2, false}, nil},
}}
nullTestRun(t, spec)
}
func TestNullBoolParam(t *testing.T) {
spec := nullTestSpec{"nullbool", "bool", [6]nullTestRow{
nullTestRow{NullBool{false, true}, true, NullBool{false, true}},
nullTestRow{NullBool{true, false}, false, NullBool{false, false}},
nullTestRow{true, true, NullBool{true, true}},
nullTestRow{NullBool{true, true}, false, NullBool{true, true}},
nullTestRow{NullBool{true, false}, true, NullBool{false, false}},
nullTestRow{true, NullBool{true, false}, nil},
}}
nullTestRun(t, spec)
}
func nullTestRun(t *testing.T, spec nullTestSpec) {
db := newTestDB(t, "") db := newTestDB(t, "")
defer closeDB(t, db) defer closeDB(t, db)
exec(t, db, "CREATE|t|id=int32,name=string,favcolor=nullstring") exec(t, db, fmt.Sprintf("CREATE|t|id=int32,name=string,nullf=%s,notnullf=%s", spec.nullType, spec.notNullType))
// Inserts with db.Exec: // Inserts with db.Exec:
exec(t, db, "INSERT|t|id=?,name=?,favcolor=?", 1, "alice", NullString{"aqua", true}) exec(t, db, "INSERT|t|id=?,name=?,nullf=?,notnullf=?", 1, "alice", spec.rows[0].nullParam, spec.rows[0].notNullParam)
exec(t, db, "INSERT|t|id=?,name=?,favcolor=?", 2, "bob", NullString{"brown", false}) exec(t, db, "INSERT|t|id=?,name=?,nullf=?,notnullf=?", 2, "bob", spec.rows[1].nullParam, spec.rows[1].notNullParam)
_, err := db.Exec("INSERT|t|id=?,name=?,favcolor=?", 999, nil, nil) // Inserts with a prepared statement:
stmt, err := db.Prepare("INSERT|t|id=?,name=?,nullf=?,notnullf=?")
if err != nil {
t.Fatalf("prepare: %v", err)
}
if _, err := stmt.Exec(3, "chris", spec.rows[2].nullParam, spec.rows[2].notNullParam); err != nil {
t.Errorf("exec insert chris: %v", err)
}
if _, err := stmt.Exec(4, "dave", spec.rows[3].nullParam, spec.rows[3].notNullParam); err != nil {
t.Errorf("exec insert dave: %v", err)
}
if _, err := stmt.Exec(5, "eleanor", spec.rows[4].nullParam, spec.rows[4].notNullParam); err != nil {
t.Errorf("exec insert eleanor: %v", err)
}
// Can't put null val into non-null col
if _, err := stmt.Exec(6, "bob", spec.rows[5].nullParam, spec.rows[5].notNullParam); err == nil {
t.Errorf("expected error inserting nil val with prepared statement Exec")
}
_, err = db.Exec("INSERT|t|id=?,name=?,nullf=?", 999, nil, nil)
if err == nil { if err == nil {
// TODO: this test fails, but it's just because // TODO: this test fails, but it's just because
// fakeConn implements the optional Execer interface, // fakeConn implements the optional Execer interface,
@ -360,45 +503,17 @@ func TestNullStringParam(t *testing.T) {
// t.Errorf("expected error inserting nil name with Exec") // t.Errorf("expected error inserting nil name with Exec")
} }
// Inserts with a prepared statement: paramtype := reflect.TypeOf(spec.rows[0].nullParam)
stmt, err := db.Prepare("INSERT|t|id=?,name=?,favcolor=?") bindVal := reflect.New(paramtype).Interface()
if err != nil {
t.Fatalf("prepare: %v", err)
}
if _, err := stmt.Exec(3, "chris", "chartreuse"); err != nil {
t.Errorf("exec insert chris: %v", err)
}
if _, err := stmt.Exec(4, "dave", NullString{"darkred", true}); err != nil {
t.Errorf("exec insert dave: %v", err)
}
if _, err := stmt.Exec(5, "eleanor", NullString{"eel", false}); err != nil {
t.Errorf("exec insert dave: %v", err)
}
// Can't put null name into non-nullstring column, for i := 0; i < 5; i++ {
if _, err := stmt.Exec(5, NullString{"", false}, nil); err == nil { id := i + 1
t.Errorf("expected error inserting nil name with prepared statement Exec") if err := db.QueryRow("SELECT|t|nullf|id=?", id).Scan(bindVal); err != nil {
}
type nameColor struct {
name string
favColor NullString
}
wantMap := map[int]nameColor{
1: nameColor{"alice", NullString{"aqua", true}},
2: nameColor{"bob", NullString{"", false}},
3: nameColor{"chris", NullString{"chartreuse", true}},
4: nameColor{"dave", NullString{"darkred", true}},
5: nameColor{"eleanor", NullString{"", false}},
}
for id, want := range wantMap {
var got nameColor
if err := db.QueryRow("SELECT|t|name,favcolor|id=?", id).Scan(&got.name, &got.favColor); err != nil {
t.Errorf("id=%d Scan: %v", id, err) t.Errorf("id=%d Scan: %v", id, err)
} }
if got != want { bindValDeref := reflect.ValueOf(bindVal).Elem().Interface()
t.Errorf("id=%d got %#v, want %#v", id, got, want) if !reflect.DeepEqual(bindValDeref, spec.rows[i].scanNullVal) {
t.Errorf("id=%d got %#v, want %#v", id, bindValDeref, spec.rows[i].scanNullVal)
} }
} }
} }

View File

@ -37,6 +37,7 @@ const (
) )
// PutUvarint encodes a uint64 into buf and returns the number of bytes written. // PutUvarint encodes a uint64 into buf and returns the number of bytes written.
// If the buffer is too small, PutUvarint will panic.
func PutUvarint(buf []byte, x uint64) int { func PutUvarint(buf []byte, x uint64) int {
i := 0 i := 0
for x >= 0x80 { for x >= 0x80 {
@ -73,6 +74,7 @@ func Uvarint(buf []byte) (uint64, int) {
} }
// PutVarint encodes an int64 into buf and returns the number of bytes written. // PutVarint encodes an int64 into buf and returns the number of bytes written.
// If the buffer is too small, PutVarint will panic.
func PutVarint(buf []byte, x int64) int { func PutVarint(buf []byte, x int64) int {
ux := uint64(x) << 1 ux := uint64(x) << 1
if x < 0 { if x < 0 {
@ -98,14 +100,6 @@ func Varint(buf []byte) (int64, int) {
return x, n return x, n
} }
// WriteUvarint encodes x and writes the result to w.
func WriteUvarint(w io.Writer, x uint64) error {
var buf [MaxVarintLen64]byte
n := PutUvarint(buf[:], x)
_, err := w.Write(buf[0:n])
return err
}
var overflow = errors.New("binary: varint overflows a 64-bit integer") var overflow = errors.New("binary: varint overflows a 64-bit integer")
// ReadUvarint reads an encoded unsigned integer from r and returns it as a uint64. // ReadUvarint reads an encoded unsigned integer from r and returns it as a uint64.
@ -129,15 +123,6 @@ func ReadUvarint(r io.ByteReader) (uint64, error) {
panic("unreachable") panic("unreachable")
} }
// WriteVarint encodes x and writes the result to w.
func WriteVarint(w io.Writer, x int64) error {
ux := uint64(x) << 1
if x < 0 {
ux = ^ux
}
return WriteUvarint(w, ux)
}
// ReadVarint reads an encoded unsigned integer from r and returns it as a uint64. // ReadVarint reads an encoded unsigned integer from r and returns it as a uint64.
func ReadVarint(r io.ByteReader) (int64, error) { func ReadVarint(r io.ByteReader) (int64, error) {
ux, err := ReadUvarint(r) // ok to continue in presence of error ux, err := ReadUvarint(r) // ok to continue in presence of error

View File

@ -25,9 +25,9 @@ func TestConstants(t *testing.T) {
} }
func testVarint(t *testing.T, x int64) { func testVarint(t *testing.T, x int64) {
buf1 := make([]byte, MaxVarintLen64) buf := make([]byte, MaxVarintLen64)
n := PutVarint(buf1[:], x) n := PutVarint(buf, x)
y, m := Varint(buf1[0:n]) y, m := Varint(buf[0:n])
if x != y { if x != y {
t.Errorf("Varint(%d): got %d", x, y) t.Errorf("Varint(%d): got %d", x, y)
} }
@ -35,15 +35,7 @@ func testVarint(t *testing.T, x int64) {
t.Errorf("Varint(%d): got n = %d; want %d", x, m, n) t.Errorf("Varint(%d): got n = %d; want %d", x, m, n)
} }
var buf2 bytes.Buffer y, err := ReadVarint(bytes.NewBuffer(buf))
err := WriteVarint(&buf2, x)
if err != nil {
t.Errorf("WriteVarint(%d): %s", x, err)
}
if n != buf2.Len() {
t.Errorf("WriteVarint(%d): got n = %d; want %d", x, buf2.Len(), n)
}
y, err = ReadVarint(&buf2)
if err != nil { if err != nil {
t.Errorf("ReadVarint(%d): %s", x, err) t.Errorf("ReadVarint(%d): %s", x, err)
} }
@ -53,9 +45,9 @@ func testVarint(t *testing.T, x int64) {
} }
func testUvarint(t *testing.T, x uint64) { func testUvarint(t *testing.T, x uint64) {
buf1 := make([]byte, MaxVarintLen64) buf := make([]byte, MaxVarintLen64)
n := PutUvarint(buf1[:], x) n := PutUvarint(buf, x)
y, m := Uvarint(buf1[0:n]) y, m := Uvarint(buf[0:n])
if x != y { if x != y {
t.Errorf("Uvarint(%d): got %d", x, y) t.Errorf("Uvarint(%d): got %d", x, y)
} }
@ -63,15 +55,7 @@ func testUvarint(t *testing.T, x uint64) {
t.Errorf("Uvarint(%d): got n = %d; want %d", x, m, n) t.Errorf("Uvarint(%d): got n = %d; want %d", x, m, n)
} }
var buf2 bytes.Buffer y, err := ReadUvarint(bytes.NewBuffer(buf))
err := WriteUvarint(&buf2, x)
if err != nil {
t.Errorf("WriteUvarint(%d): %s", x, err)
}
if n != buf2.Len() {
t.Errorf("WriteUvarint(%d): got n = %d; want %d", x, buf2.Len(), n)
}
y, err = ReadUvarint(&buf2)
if err != nil { if err != nil {
t.Errorf("ReadUvarint(%d): %s", x, err) t.Errorf("ReadUvarint(%d): %s", x, err)
} }

View File

@ -1,276 +0,0 @@
// 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 git85 implements the radix 85 data encoding
// used in the Git version control system.
package git85
import (
"bytes"
"io"
"strconv"
)
type CorruptInputError int64
func (e CorruptInputError) Error() string {
return "illegal git85 data at input byte " + strconv.FormatInt(int64(e), 10)
}
const encode = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz!#$%&()*+-;<=>?@^_`{|}~"
// The decodings are 1+ the actual value, so that the
// default zero value can be used to mean "not valid".
var decode = [256]uint8{
'0': 1, 2, 3, 4, 5, 6, 7, 8, 9, 10,
'A': 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23,
24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36,
'a': 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49,
50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62,
'!': 63,
'#': 64, 65, 66, 67,
'(': 68, 69, 70, 71,
'-': 72,
';': 73,
'<': 74, 75, 76, 77,
'@': 78,
'^': 79, 80, 81,
'{': 82, 83, 84, 85,
}
// Encode encodes src into EncodedLen(len(src))
// bytes of dst. As a convenience, it returns the number
// of bytes written to dst, but this value is always EncodedLen(len(src)).
// Encode implements the radix 85 encoding used in the
// Git version control tool.
//
// The encoding splits src into chunks of at most 52 bytes
// and encodes each chunk on its own line.
func Encode(dst, src []byte) int {
ndst := 0
for len(src) > 0 {
n := len(src)
if n > 52 {
n = 52
}
if n <= 27 {
dst[ndst] = byte('A' + n - 1)
} else {
dst[ndst] = byte('a' + n - 26 - 1)
}
ndst++
for i := 0; i < n; i += 4 {
var v uint32
for j := 0; j < 4 && i+j < n; j++ {
v |= uint32(src[i+j]) << uint(24-j*8)
}
for j := 4; j >= 0; j-- {
dst[ndst+j] = encode[v%85]
v /= 85
}
ndst += 5
}
dst[ndst] = '\n'
ndst++
src = src[n:]
}
return ndst
}
// EncodedLen returns the length of an encoding of n source bytes.
func EncodedLen(n int) int {
if n == 0 {
return 0
}
// 5 bytes per 4 bytes of input, rounded up.
// 2 extra bytes for each line of 52 src bytes, rounded up.
return (n+3)/4*5 + (n+51)/52*2
}
var newline = []byte{'\n'}
// Decode decodes src into at most MaxDecodedLen(len(src))
// bytes, returning the actual number of bytes written to dst.
//
// If Decode encounters invalid input, it returns a CorruptInputError.
//
func Decode(dst, src []byte) (n int, err error) {
ndst := 0
nsrc := 0
for nsrc < len(src) {
var l int
switch ch := int(src[nsrc]); {
case 'A' <= ch && ch <= 'Z':
l = ch - 'A' + 1
case 'a' <= ch && ch <= 'z':
l = ch - 'a' + 26 + 1
default:
return ndst, CorruptInputError(nsrc)
}
if nsrc+1+l > len(src) {
return ndst, CorruptInputError(nsrc)
}
el := (l + 3) / 4 * 5 // encoded len
if nsrc+1+el+1 > len(src) || src[nsrc+1+el] != '\n' {
return ndst, CorruptInputError(nsrc)
}
line := src[nsrc+1 : nsrc+1+el]
for i := 0; i < el; i += 5 {
var v uint32
for j := 0; j < 5; j++ {
ch := decode[line[i+j]]
if ch == 0 {
return ndst, CorruptInputError(nsrc + 1 + i + j)
}
v = v*85 + uint32(ch-1)
}
for j := 0; j < 4; j++ {
dst[ndst] = byte(v >> 24)
v <<= 8
ndst++
}
}
// Last fragment may have run too far (but there was room in dst).
// Back up.
if l%4 != 0 {
ndst -= 4 - l%4
}
nsrc += 1 + el + 1
}
return ndst, nil
}
func MaxDecodedLen(n int) int { return n / 5 * 4 }
// NewEncoder returns a new Git base85 stream encoder. Data written to
// the returned writer will be encoded and then written to w.
// The Git encoding operates on 52-byte blocks; when finished
// writing, the caller must Close the returned encoder to flush any
// partially written blocks.
func NewEncoder(w io.Writer) io.WriteCloser { return &encoder{w: w} }
type encoder struct {
w io.Writer
err error
buf [52]byte
nbuf int
out [1024]byte
nout int
}
func (e *encoder) Write(p []byte) (n int, err error) {
if e.err != nil {
return 0, e.err
}
// Leading fringe.
if e.nbuf > 0 {
var i int
for i = 0; i < len(p) && e.nbuf < 52; i++ {
e.buf[e.nbuf] = p[i]
e.nbuf++
}
n += i
p = p[i:]
if e.nbuf < 52 {
return
}
nout := Encode(e.out[0:], e.buf[0:])
if _, e.err = e.w.Write(e.out[0:nout]); e.err != nil {
return n, e.err
}
e.nbuf = 0
}
// Large interior chunks.
for len(p) >= 52 {
nn := len(e.out) / (1 + 52/4*5 + 1) * 52
if nn > len(p) {
nn = len(p) / 52 * 52
}
if nn > 0 {
nout := Encode(e.out[0:], p[0:nn])
if _, e.err = e.w.Write(e.out[0:nout]); e.err != nil {
return n, e.err
}
}
n += nn
p = p[nn:]
}
// Trailing fringe.
for i := 0; i < len(p); i++ {
e.buf[i] = p[i]
}
e.nbuf = len(p)
n += len(p)
return
}
func (e *encoder) Close() error {
// If there's anything left in the buffer, flush it out
if e.err == nil && e.nbuf > 0 {
nout := Encode(e.out[0:], e.buf[0:e.nbuf])
e.nbuf = 0
_, e.err = e.w.Write(e.out[0:nout])
}
return e.err
}
// NewDecoder returns a new Git base85 stream decoder.
func NewDecoder(r io.Reader) io.Reader { return &decoder{r: r} }
type decoder struct {
r io.Reader
err error
readErr error
buf [1024]byte
nbuf int
out []byte
outbuf [1024]byte
off int64
}
func (d *decoder) Read(p []byte) (n int, err error) {
if len(p) == 0 {
return 0, nil
}
for {
// Copy leftover output from last decode.
if len(d.out) > 0 {
n = copy(p, d.out)
d.out = d.out[n:]
return
}
// Out of decoded output. Check errors.
if d.err != nil {
return 0, d.err
}
if d.readErr != nil {
d.err = d.readErr
return 0, d.err
}
// Read and decode more input.
var nn int
nn, d.readErr = d.r.Read(d.buf[d.nbuf:])
d.nbuf += nn
// Send complete lines to Decode.
nl := bytes.LastIndex(d.buf[0:d.nbuf], newline)
if nl < 0 {
continue
}
nn, d.err = Decode(d.outbuf[0:], d.buf[0:nl+1])
if e, ok := d.err.(CorruptInputError); ok {
d.err = CorruptInputError(int64(e) + d.off)
}
d.out = d.outbuf[0:nn]
d.nbuf = copy(d.buf[0:], d.buf[nl+1:d.nbuf])
d.off += int64(nl + 1)
}
panic("unreachable")
}

View File

@ -1,194 +0,0 @@
// 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 git85
import (
"bytes"
"io"
"io/ioutil"
"testing"
)
type testpair struct {
decoded, encoded string
}
func testEqual(t *testing.T, msg string, args ...interface{}) bool {
if args[len(args)-2] != args[len(args)-1] {
t.Errorf(msg, args...)
return false
}
return true
}
func TestGitTable(t *testing.T) {
var saw [256]bool
for i, c := range encode {
if decode[c] != uint8(i+1) {
t.Errorf("decode['%c'] = %d, want %d", c, decode[c], i+1)
}
saw[c] = true
}
for i, b := range saw {
if !b && decode[i] != 0 {
t.Errorf("decode[%d] = %d, want 0", i, decode[i])
}
}
}
var gitPairs = []testpair{
// Wikipedia example, adapted.
{
"Man is distinguished, not only by his reason, but by this singular passion from " +
"other animals, which is a lust of the mind, that by a perseverance of delight in " +
"the continued and indefatigable generation of knowledge, exceeds the short " +
"vehemence of any carnal pleasure.",
"zO<`^zX>%ZCX>)XGZfA9Ab7*B`EFf-gbRchTY<VDJc_3(Mb0BhMVRLV8EFfZabRc4R\n" +
"zAarPHb0BkRZfA9DVR9gFVRLh7Z*CxFa&K)QZ**v7av))DX>DO_b1WctXlY|;AZc?T\n" +
"zVIXXEb95kYW*~HEWgu;7Ze%PVbZB98AYyqSVIXj2a&u*NWpZI|V`U(3W*}r`Y-wj`\n" +
"zbRcPNAarPDAY*TCbZKsNWn>^>Ze$>7Ze(R<VRUI{VPb4$AZKN6WpZJ3X>V>IZ)PBC\n" +
"zZf|#NWn^b%EFfigV`XJzb0BnRWgv5CZ*p`Xc4cT~ZDnp_Wgu^6AYpEKAY);2ZeeU7\n" +
"IaBO8^b9HiME&u=k\n",
},
}
var gitBigtest = gitPairs[len(gitPairs)-1]
func TestEncode(t *testing.T) {
for _, p := range gitPairs {
buf := make([]byte, EncodedLen(len(p.decoded)))
n := Encode(buf, []byte(p.decoded))
if n != len(buf) {
t.Errorf("EncodedLen does not agree with Encode")
}
buf = buf[0:n]
testEqual(t, "Encode(%q) = %q, want %q", p.decoded, string(buf), p.encoded)
}
}
func TestEncoder(t *testing.T) {
for _, p := range gitPairs {
bb := &bytes.Buffer{}
encoder := NewEncoder(bb)
encoder.Write([]byte(p.decoded))
encoder.Close()
testEqual(t, "Encode(%q) = %q, want %q", p.decoded, bb.String(), p.encoded)
}
}
func TestEncoderBuffering(t *testing.T) {
input := []byte(gitBigtest.decoded)
for bs := 1; bs <= 12; bs++ {
bb := &bytes.Buffer{}
encoder := NewEncoder(bb)
for pos := 0; pos < len(input); pos += bs {
end := pos + bs
if end > len(input) {
end = len(input)
}
n, err := encoder.Write(input[pos:end])
testEqual(t, "Write(%q) gave error %v, want %v", input[pos:end], err, error(nil))
testEqual(t, "Write(%q) gave length %v, want %v", input[pos:end], n, end-pos)
}
err := encoder.Close()
testEqual(t, "Close gave error %v, want %v", err, error(nil))
testEqual(t, "Encoding/%d of %q = %q, want %q", bs, gitBigtest.decoded, bb.String(), gitBigtest.encoded)
}
}
func TestDecode(t *testing.T) {
for _, p := range gitPairs {
dbuf := make([]byte, 4*len(p.encoded))
ndst, err := Decode(dbuf, []byte(p.encoded))
testEqual(t, "Decode(%q) = error %v, want %v", p.encoded, err, error(nil))
testEqual(t, "Decode(%q) = ndst %v, want %v", p.encoded, ndst, len(p.decoded))
testEqual(t, "Decode(%q) = %q, want %q", p.encoded, string(dbuf[0:ndst]), p.decoded)
}
}
func TestDecoder(t *testing.T) {
for _, p := range gitPairs {
decoder := NewDecoder(bytes.NewBufferString(p.encoded))
dbuf, err := ioutil.ReadAll(decoder)
if err != nil {
t.Fatal("Read failed", err)
}
testEqual(t, "Read from %q = length %v, want %v", p.encoded, len(dbuf), len(p.decoded))
testEqual(t, "Decoding of %q = %q, want %q", p.encoded, string(dbuf), p.decoded)
if err != nil {
testEqual(t, "Read from %q = %v, want %v", p.encoded, err, io.EOF)
}
}
}
func TestDecoderBuffering(t *testing.T) {
for bs := 1; bs <= 12; bs++ {
decoder := NewDecoder(bytes.NewBufferString(gitBigtest.encoded))
buf := make([]byte, len(gitBigtest.decoded)+12)
var total int
for total = 0; total < len(gitBigtest.decoded); {
n, err := decoder.Read(buf[total : total+bs])
testEqual(t, "Read from %q at pos %d = %d, %v, want _, %v", gitBigtest.encoded, total, n, err, error(nil))
total += n
}
testEqual(t, "Decoding/%d of %q = %q, want %q", bs, gitBigtest.encoded, string(buf[0:total]), gitBigtest.decoded)
}
}
func TestDecodeCorrupt(t *testing.T) {
type corrupt struct {
e string
p int
}
examples := []corrupt{
{"v", 0},
{"!z!!!!!!!!!", 0},
}
for _, e := range examples {
dbuf := make([]byte, 2*len(e.e))
_, err := Decode(dbuf, []byte(e.e))
switch err := err.(type) {
case CorruptInputError:
testEqual(t, "Corruption in %q at offset %v, want %v", e.e, int(err), e.p)
default:
t.Error("Decoder failed to detect corruption in", e)
}
}
}
func TestGitBig(t *testing.T) {
n := 3*1000 + 1
raw := make([]byte, n)
const alpha = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
for i := 0; i < n; i++ {
raw[i] = alpha[i%len(alpha)]
}
encoded := new(bytes.Buffer)
w := NewEncoder(encoded)
nn, err := w.Write(raw)
if nn != n || err != nil {
t.Fatalf("Encoder.Write(raw) = %d, %v want %d, nil", nn, err, n)
}
err = w.Close()
if err != nil {
t.Fatalf("Encoder.Close() = %v want nil", err)
}
decoded, err := ioutil.ReadAll(NewDecoder(encoded))
if err != nil {
t.Fatalf("ioutil.ReadAll(NewDecoder(...)): %v", err)
}
if !bytes.Equal(raw, decoded) {
var i int
for i = 0; i < len(decoded) && i < len(raw); i++ {
if decoded[i] != raw[i] {
break
}
}
t.Errorf("Decode(Encode(%d-byte string)) failed at offset %d", n, i)
}
}

View File

@ -2,6 +2,9 @@
// 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.
// Delete the next line to include this file in the gob package.
// +build ignore
package gob package gob
// This file is not normally included in the gob package. Used only for debugging the package itself. // This file is not normally included in the gob package. Used only for debugging the package itself.

View File

@ -75,7 +75,9 @@ func (dec *Decoder) recvMessage() bool {
dec.err = err dec.err = err
return false return false
} }
if nbytes >= 1<<31 { // Upper limit of 1GB, allowing room to grow a little without overflow.
// TODO: We might want more control over this limit.
if nbytes >= 1<<30 {
dec.err = errBadCount dec.err = errBadCount
return false return false
} }

View File

@ -547,7 +547,6 @@ func (a isZeroBugArray) GobEncode() (b []byte, e error) {
} }
func (a *isZeroBugArray) GobDecode(data []byte) error { func (a *isZeroBugArray) GobDecode(data []byte) error {
println("DECODE")
if len(data) != len(a) { if len(data) != len(a) {
return io.EOF return io.EOF
} }

View File

@ -15,26 +15,13 @@ import (
) )
const ( const (
// A generic XML header suitable for use with the output of Marshal and // A generic XML header suitable for use with the output of Marshal.
// MarshalIndent. This is not automatically added to any output of this // This is not automatically added to any output of this package,
// package, it is provided as a convenience. // it is provided as a convenience.
Header = `<?xml version="1.0" encoding="UTF-8"?>` + "\n" Header = `<?xml version="1.0" encoding="UTF-8"?>` + "\n"
) )
// A Marshaler can produce well-formatted XML representing its internal state. // Marshal returns the XML encoding of v.
// It is used by both Marshal and MarshalIndent.
type Marshaler interface {
MarshalXML() ([]byte, error)
}
type printer struct {
*bufio.Writer
}
// Marshal writes an XML-formatted representation of v to w.
//
// If v implements Marshaler, then Marshal calls its MarshalXML method.
// Otherwise, Marshal uses the following procedure to create the XML.
// //
// Marshal handles an array or slice by marshalling each of the elements. // Marshal handles an array or slice by marshalling each of the elements.
// Marshal handles a pointer by marshalling the value it points at or, if the // Marshal handles a pointer by marshalling the value it points at or, if the
@ -53,6 +40,7 @@ type printer struct {
// The XML element for a struct contains marshalled elements for each of the // The XML element for a struct contains marshalled elements for each of the
// exported fields of the struct, with these exceptions: // exported fields of the struct, with these exceptions:
// - the XMLName field, described above, is omitted. // - the XMLName field, described above, is omitted.
// - a field with tag "-" is omitted.
// - a field with tag "name,attr" becomes an attribute with // - a field with tag "name,attr" becomes an attribute with
// the given name in the XML element. // the given name in the XML element.
// - a field with tag ",attr" becomes an attribute with the // - a field with tag ",attr" becomes an attribute with the
@ -77,7 +65,7 @@ type printer struct {
// Age int `xml:"person>age"` // Age int `xml:"person>age"`
// } // }
// //
// xml.Marshal(w, &Result{Id: 13, FirstName: "John", LastName: "Doe", Age: 42}) // xml.Marshal(&Result{Id: 13, FirstName: "John", LastName: "Doe", Age: 42})
// //
// would be marshalled as: // would be marshalled as:
// //
@ -92,13 +80,38 @@ type printer struct {
// </result> // </result>
// //
// Marshal will return an error if asked to marshal a channel, function, or map. // Marshal will return an error if asked to marshal a channel, function, or map.
func Marshal(w io.Writer, v interface{}) (err error) { func Marshal(v interface{}) ([]byte, error) {
p := &printer{bufio.NewWriter(w)} var b bytes.Buffer
err = p.marshalValue(reflect.ValueOf(v), nil) if err := NewEncoder(&b).Encode(v); err != nil {
p.Flush() return nil, err
}
return b.Bytes(), nil
}
// An Encoder writes XML data to an output stream.
type Encoder struct {
printer
}
// NewEncoder returns a new encoder that writes to w.
func NewEncoder(w io.Writer) *Encoder {
return &Encoder{printer{bufio.NewWriter(w)}}
}
// Encode writes the XML encoding of v to the stream.
//
// See the documentation for Marshal for details about the conversion
// of Go values to XML.
func (enc *Encoder) Encode(v interface{}) error {
err := enc.marshalValue(reflect.ValueOf(v), nil)
enc.Flush()
return err return err
} }
type printer struct {
*bufio.Writer
}
func (p *printer) marshalValue(val reflect.Value, finfo *fieldInfo) error { func (p *printer) marshalValue(val reflect.Value, finfo *fieldInfo) error {
if !val.IsValid() { if !val.IsValid() {
return nil return nil
@ -107,18 +120,6 @@ func (p *printer) marshalValue(val reflect.Value, finfo *fieldInfo) error {
kind := val.Kind() kind := val.Kind()
typ := val.Type() typ := val.Type()
// Try Marshaler
if typ.NumMethod() > 0 {
if marshaler, ok := val.Interface().(Marshaler); ok {
bytes, err := marshaler.MarshalXML()
if err != nil {
return err
}
p.Write(bytes)
return nil
}
}
// Drill into pointers/interfaces // Drill into pointers/interfaces
if kind == reflect.Ptr || kind == reflect.Interface { if kind == reflect.Ptr || kind == reflect.Interface {
if val.IsNil() { if val.IsNil() {
@ -181,23 +182,43 @@ func (p *printer) marshalValue(val reflect.Value, finfo *fieldInfo) error {
if finfo.flags&fAttr == 0 { if finfo.flags&fAttr == 0 {
continue continue
} }
var str string fv := val.FieldByIndex(finfo.idx)
if fv := val.FieldByIndex(finfo.idx); fv.Kind() == reflect.String { switch fv.Kind() {
str = fv.String() case reflect.String, reflect.Array, reflect.Slice:
} else { // TODO: Should we really do this once ,omitempty is in?
str = fmt.Sprint(fv.Interface()) if fv.Len() == 0 {
continue
}
} }
if str != "" {
p.WriteByte(' ') p.WriteByte(' ')
p.WriteString(finfo.name) p.WriteString(finfo.name)
p.WriteString(`="`) p.WriteString(`="`)
Escape(p, []byte(str)) if err := p.marshalSimple(fv.Type(), fv); err != nil {
p.WriteByte('"') return err
} }
p.WriteByte('"')
} }
p.WriteByte('>') p.WriteByte('>')
switch k := val.Kind(); k { if val.Kind() == reflect.Struct {
err = p.marshalStruct(tinfo, val)
} else {
err = p.marshalSimple(typ, val)
}
if err != nil {
return err
}
p.WriteByte('<')
p.WriteByte('/')
p.WriteString(name)
p.WriteByte('>')
return nil
}
func (p *printer) marshalSimple(typ reflect.Type, val reflect.Value) error {
switch val.Kind() {
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
p.WriteString(strconv.FormatInt(val.Int(), 10)) p.WriteString(strconv.FormatInt(val.Int(), 10))
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
@ -205,6 +226,7 @@ func (p *printer) marshalValue(val reflect.Value, finfo *fieldInfo) error {
case reflect.Float32, reflect.Float64: case reflect.Float32, reflect.Float64:
p.WriteString(strconv.FormatFloat(val.Float(), 'g', -1, 64)) p.WriteString(strconv.FormatFloat(val.Float(), 'g', -1, 64))
case reflect.String: case reflect.String:
// TODO: Add EscapeString.
Escape(p, []byte(val.String())) Escape(p, []byte(val.String()))
case reflect.Bool: case reflect.Bool:
p.WriteString(strconv.FormatBool(val.Bool())) p.WriteString(strconv.FormatBool(val.Bool()))
@ -217,21 +239,10 @@ func (p *printer) marshalValue(val reflect.Value, finfo *fieldInfo) error {
Escape(p, bytes) Escape(p, bytes)
case reflect.Slice: case reflect.Slice:
// will be []byte // will be []byte
bytes := val.Interface().([]byte) Escape(p, val.Bytes())
Escape(p, bytes)
case reflect.Struct:
if err := p.marshalStruct(tinfo, val); err != nil {
return err
}
default: default:
return &UnsupportedTypeError{typ} return &UnsupportedTypeError{typ}
} }
p.WriteByte('<')
p.WriteByte('/')
p.WriteString(name)
p.WriteByte('>')
return nil return nil
} }
@ -358,7 +369,7 @@ func (s *parentStack) push(parents []string) {
s.stack = append(s.stack, parents...) s.stack = append(s.stack, parents...)
} }
// A MarshalXMLError is returned when Marshal or MarshalIndent encounter a type // A MarshalXMLError is returned when Marshal encounters a type
// that cannot be converted into XML. // that cannot be converted into XML.
type UnsupportedTypeError struct { type UnsupportedTypeError struct {
Type reflect.Type Type reflect.Type

View File

@ -5,7 +5,6 @@
package xml package xml
import ( import (
"bytes"
"reflect" "reflect"
"strconv" "strconv"
"strings" "strings"
@ -35,12 +34,6 @@ type Ship struct {
secret string secret string
} }
type RawXML string
func (rx RawXML) MarshalXML() ([]byte, error) {
return []byte(rx), nil
}
type NamedType string type NamedType string
type Port struct { type Port struct {
@ -184,6 +177,22 @@ type RecurseB struct {
B string B string
} }
type PresenceTest struct {
Exists *struct{}
}
type IgnoreTest struct {
PublicSecret string `xml:"-"`
}
type MyBytes []byte
type Data struct {
Bytes []byte
Attr []byte `xml:",attr"`
Custom MyBytes
}
type Plain struct { type Plain struct {
V interface{} V interface{}
} }
@ -225,6 +234,44 @@ var marshalTests = []struct {
{Value: &Plain{[]int{1, 2, 3}}, ExpectXML: `<Plain><V>1</V><V>2</V><V>3</V></Plain>`}, {Value: &Plain{[]int{1, 2, 3}}, ExpectXML: `<Plain><V>1</V><V>2</V><V>3</V></Plain>`},
{Value: &Plain{[3]int{1, 2, 3}}, ExpectXML: `<Plain><V>1</V><V>2</V><V>3</V></Plain>`}, {Value: &Plain{[3]int{1, 2, 3}}, ExpectXML: `<Plain><V>1</V><V>2</V><V>3</V></Plain>`},
// A pointer to struct{} may be used to test for an element's presence.
{
Value: &PresenceTest{new(struct{})},
ExpectXML: `<PresenceTest><Exists></Exists></PresenceTest>`,
},
{
Value: &PresenceTest{},
ExpectXML: `<PresenceTest></PresenceTest>`,
},
// A pointer to struct{} may be used to test for an element's presence.
{
Value: &PresenceTest{new(struct{})},
ExpectXML: `<PresenceTest><Exists></Exists></PresenceTest>`,
},
{
Value: &PresenceTest{},
ExpectXML: `<PresenceTest></PresenceTest>`,
},
// A []byte field is only nil if the element was not found.
{
Value: &Data{},
ExpectXML: `<Data></Data>`,
UnmarshalOnly: true,
},
{
Value: &Data{Bytes: []byte{}, Custom: MyBytes{}, Attr: []byte{}},
ExpectXML: `<Data Attr=""><Bytes></Bytes><Custom></Custom></Data>`,
UnmarshalOnly: true,
},
// Check that []byte works, including named []byte types.
{
Value: &Data{Bytes: []byte("ab"), Custom: MyBytes("cd"), Attr: []byte{'v'}},
ExpectXML: `<Data Attr="v"><Bytes>ab</Bytes><Custom>cd</Custom></Data>`,
},
// Test innerxml // Test innerxml
{ {
Value: &SecretAgent{ Value: &SecretAgent{
@ -245,13 +292,6 @@ var marshalTests = []struct {
UnmarshalOnly: true, UnmarshalOnly: true,
}, },
// Test marshaller interface
{
Value: RawXML("</>"),
ExpectXML: `</>`,
MarshalOnly: true,
},
// Test structs // Test structs
{Value: &Port{Type: "ssl", Number: "443"}, ExpectXML: `<port type="ssl">443</port>`}, {Value: &Port{Type: "ssl", Number: "443"}, ExpectXML: `<port type="ssl">443</port>`},
{Value: &Port{Number: "443"}, ExpectXML: `<port>443</port>`}, {Value: &Port{Number: "443"}, ExpectXML: `<port>443</port>`},
@ -542,6 +582,22 @@ var marshalTests = []struct {
}, },
ExpectXML: `<RecurseA><A>a1</A><B><A><A>a2</A></A><B>b1</B></B></RecurseA>`, ExpectXML: `<RecurseA><A>a1</A><B><A><A>a2</A></A><B>b1</B></B></RecurseA>`,
}, },
// Test ignoring fields via "-" tag
{
ExpectXML: `<IgnoreTest></IgnoreTest>`,
Value: &IgnoreTest{},
},
{
ExpectXML: `<IgnoreTest></IgnoreTest>`,
Value: &IgnoreTest{PublicSecret: "can't tell"},
MarshalOnly: true,
},
{
ExpectXML: `<IgnoreTest><PublicSecret>ignore me</PublicSecret></IgnoreTest>`,
Value: &IgnoreTest{},
UnmarshalOnly: true,
},
} }
func TestMarshal(t *testing.T) { func TestMarshal(t *testing.T) {
@ -549,13 +605,12 @@ func TestMarshal(t *testing.T) {
if test.UnmarshalOnly { if test.UnmarshalOnly {
continue continue
} }
buf := bytes.NewBuffer(nil) data, err := Marshal(test.Value)
err := Marshal(buf, test.Value)
if err != nil { if err != nil {
t.Errorf("#%d: Error: %s", idx, err) t.Errorf("#%d: Error: %s", idx, err)
continue continue
} }
if got, want := buf.String(), test.ExpectXML; got != want { if got, want := string(data), test.ExpectXML; got != want {
if strings.Contains(want, "\n") { if strings.Contains(want, "\n") {
t.Errorf("#%d: marshal(%#v):\nHAVE:\n%s\nWANT:\n%s", idx, test.Value, got, want) t.Errorf("#%d: marshal(%#v):\nHAVE:\n%s\nWANT:\n%s", idx, test.Value, got, want)
} else { } else {
@ -596,8 +651,7 @@ var marshalErrorTests = []struct {
func TestMarshalErrors(t *testing.T) { func TestMarshalErrors(t *testing.T) {
for idx, test := range marshalErrorTests { for idx, test := range marshalErrorTests {
buf := bytes.NewBuffer(nil) _, err := Marshal(test.Value)
err := Marshal(buf, test.Value)
if err == nil || err.Error() != test.Err { if err == nil || err.Error() != test.Err {
t.Errorf("#%d: marshal(%#v) = [error] %v, want %v", idx, test.Value, err, test.Err) t.Errorf("#%d: marshal(%#v) = [error] %v, want %v", idx, test.Value, err, test.Err)
} }
@ -621,8 +675,7 @@ func TestUnmarshal(t *testing.T) {
vt := reflect.TypeOf(test.Value) vt := reflect.TypeOf(test.Value)
dest := reflect.New(vt.Elem()).Interface() dest := reflect.New(vt.Elem()).Interface()
buffer := bytes.NewBufferString(test.ExpectXML) err := Unmarshal([]byte(test.ExpectXML), dest)
err := Unmarshal(buffer, dest)
switch fix := dest.(type) { switch fix := dest.(type) {
case *Feed: case *Feed:
@ -641,17 +694,14 @@ func TestUnmarshal(t *testing.T) {
} }
func BenchmarkMarshal(b *testing.B) { func BenchmarkMarshal(b *testing.B) {
buf := bytes.NewBuffer(nil)
for i := 0; i < b.N; i++ { for i := 0; i < b.N; i++ {
Marshal(buf, atomValue) Marshal(atomValue)
buf.Truncate(0)
} }
} }
func BenchmarkUnmarshal(b *testing.B) { func BenchmarkUnmarshal(b *testing.B) {
xml := []byte(atomXml) xml := []byte(atomXml)
for i := 0; i < b.N; i++ { for i := 0; i < b.N; i++ {
buffer := bytes.NewBuffer(xml) Unmarshal(xml, &Feed{})
Unmarshal(buffer, &Feed{})
} }
} }

View File

@ -7,7 +7,6 @@ package xml
import ( import (
"bytes" "bytes"
"errors" "errors"
"io"
"reflect" "reflect"
"strconv" "strconv"
"strings" "strings"
@ -20,10 +19,10 @@ import (
// See package json for a textual representation more suitable // See package json for a textual representation more suitable
// to data structures. // to data structures.
// Unmarshal parses an XML element from r and uses the // Unmarshal parses the XML-encoded data and stores the result in
// reflect library to fill in an arbitrary struct, slice, or string // the value pointed to by v, which must be an arbitrary struct,
// pointed at by val. Well-formed data that does not fit // slice, or string. Well-formed data that does not fit into v is
// into val is discarded. // discarded.
// //
// For example, given these definitions: // For example, given these definitions:
// //
@ -59,7 +58,7 @@ import (
// <address>123 Main Street</address> // <address>123 Main Street</address>
// </result> // </result>
// //
// via Unmarshal(r, &result) is equivalent to assigning // via Unmarshal(data, &result) is equivalent to assigning
// //
// r = Result{ // r = Result{
// xml.Name{Local: "result"}, // xml.Name{Local: "result"},
@ -78,8 +77,9 @@ import (
// field tag. // field tag.
// //
// Because Unmarshal uses the reflect package, it can only assign // Because Unmarshal uses the reflect package, it can only assign
// to exported (upper case) fields. Unmarshal uses a case-insensitive // to exported (upper case) fields. Unmarshal uses a case-sensitive
// comparison to match XML element names to struct field names. // comparison to match XML element names to tag values and struct
// field names.
// //
// Unmarshal maps an XML element to a struct using the following rules. // Unmarshal maps an XML element to a struct using the following rules.
// In the rules, the tag of a field refers to the value associated with the // In the rules, the tag of a field refers to the value associated with the
@ -132,9 +132,11 @@ import (
// of the above rules and the struct has a field with tag ",any", // of the above rules and the struct has a field with tag ",any",
// unmarshal maps the sub-element to that struct field. // unmarshal maps the sub-element to that struct field.
// //
// * A struct field with tag "-" is never unmarshalled into.
//
// Unmarshal maps an XML element to a string or []byte by saving the // Unmarshal maps an XML element to a string or []byte by saving the
// concatenation of that element's character data in the string or // concatenation of that element's character data in the string or
// []byte. // []byte. The saved []byte is never nil.
// //
// Unmarshal maps an attribute value to a string or []byte by saving // Unmarshal maps an attribute value to a string or []byte by saving
// the value in the string or slice. // the value in the string or slice.
@ -156,18 +158,26 @@ import (
// Unmarshal maps an XML element to a pointer by setting the pointer // Unmarshal maps an XML element to a pointer by setting the pointer
// to a freshly allocated value and then mapping the element to that value. // to a freshly allocated value and then mapping the element to that value.
// //
func Unmarshal(r io.Reader, val interface{}) error { func Unmarshal(data []byte, v interface{}) error {
v := reflect.ValueOf(val) return NewDecoder(bytes.NewBuffer(data)).Decode(v)
if v.Kind() != reflect.Ptr { }
// Decode works like xml.Unmarshal, except it reads the decoder
// stream to find the start element.
func (d *Decoder) Decode(v interface{}) error {
return d.DecodeElement(v, nil)
}
// DecodeElement works like xml.Unmarshal except that it takes
// a pointer to the start XML element to decode into v.
// It is useful when a client reads some raw XML tokens itself
// but also wants to defer to Unmarshal for some elements.
func (d *Decoder) DecodeElement(v interface{}, start *StartElement) error {
val := reflect.ValueOf(v)
if val.Kind() != reflect.Ptr {
return errors.New("non-pointer passed to Unmarshal") return errors.New("non-pointer passed to Unmarshal")
} }
p := NewParser(r) return d.unmarshal(val.Elem(), start)
elem := v.Elem()
err := p.unmarshal(elem, nil)
if err != nil {
return err
}
return nil
} }
// An UnmarshalError represents an error in the unmarshalling process. // An UnmarshalError represents an error in the unmarshalling process.
@ -175,22 +185,8 @@ type UnmarshalError string
func (e UnmarshalError) Error() string { return string(e) } func (e UnmarshalError) Error() string { return string(e) }
// The Parser's Unmarshal method is like xml.Unmarshal
// except that it can be passed a pointer to the initial start element,
// useful when a client reads some raw XML tokens itself
// but also defers to Unmarshal for some elements.
// Passing a nil start element indicates that Unmarshal should
// read the token stream to find the start element.
func (p *Parser) Unmarshal(val interface{}, start *StartElement) error {
v := reflect.ValueOf(val)
if v.Kind() != reflect.Ptr {
return errors.New("non-pointer passed to Unmarshal")
}
return p.unmarshal(v.Elem(), start)
}
// Unmarshal a single XML element into val. // Unmarshal a single XML element into val.
func (p *Parser) unmarshal(val reflect.Value, start *StartElement) error { func (p *Decoder) unmarshal(val reflect.Value, start *StartElement) error {
// Find start element if we need it. // Find start element if we need it.
if start == nil { if start == nil {
for { for {
@ -309,14 +305,12 @@ func (p *Parser) unmarshal(val reflect.Value, start *StartElement) error {
case fAttr: case fAttr:
strv := sv.FieldByIndex(finfo.idx) strv := sv.FieldByIndex(finfo.idx)
// Look for attribute. // Look for attribute.
val := ""
for _, a := range start.Attr { for _, a := range start.Attr {
if a.Name.Local == finfo.name { if a.Name.Local == finfo.name {
val = a.Value copyValue(strv, []byte(a.Value))
break break
} }
} }
copyValue(strv, []byte(val))
case fCharData: case fCharData:
if !saveData.IsValid() { if !saveData.IsValid() {
@ -473,7 +467,11 @@ func copyValue(dst reflect.Value, src []byte) (err error) {
case reflect.String: case reflect.String:
t.SetString(string(src)) t.SetString(string(src))
case reflect.Slice: case reflect.Slice:
t.Set(reflect.ValueOf(src)) if len(src) == 0 {
// non-nil to flag presence
src = []byte{}
}
t.SetBytes(src)
} }
return nil return nil
} }
@ -481,9 +479,9 @@ func copyValue(dst reflect.Value, src []byte) (err error) {
// unmarshalPath walks down an XML structure looking for wanted // unmarshalPath walks down an XML structure looking for wanted
// paths, and calls unmarshal on them. // paths, and calls unmarshal on them.
// The consumed result tells whether XML elements have been consumed // The consumed result tells whether XML elements have been consumed
// from the Parser until start's matching end element, or if it's // from the Decoder until start's matching end element, or if it's
// still untouched because start is uninteresting for sv's fields. // still untouched because start is uninteresting for sv's fields.
func (p *Parser) unmarshalPath(tinfo *typeInfo, sv reflect.Value, parents []string, start *StartElement) (consumed bool, err error) { func (p *Decoder) unmarshalPath(tinfo *typeInfo, sv reflect.Value, parents []string, start *StartElement) (consumed bool, err error) {
recurse := false recurse := false
Loop: Loop:
for i := range tinfo.fields { for i := range tinfo.fields {
@ -547,7 +545,7 @@ Loop:
// Read tokens until we find the end element. // Read tokens until we find the end element.
// Token is taking care of making sure the // Token is taking care of making sure the
// end element matches the start element we saw. // end element matches the start element we saw.
func (p *Parser) Skip() error { func (p *Decoder) Skip() error {
for { for {
tok, err := p.Token() tok, err := p.Token()
if err != nil { if err != nil {

View File

@ -6,7 +6,6 @@ package xml
import ( import (
"reflect" "reflect"
"strings"
"testing" "testing"
) )
@ -14,7 +13,7 @@ import (
func TestUnmarshalFeed(t *testing.T) { func TestUnmarshalFeed(t *testing.T) {
var f Feed var f Feed
if err := Unmarshal(strings.NewReader(atomFeedString), &f); err != nil { if err := Unmarshal([]byte(atomFeedString), &f); err != nil {
t.Fatalf("Unmarshal: %s", err) t.Fatalf("Unmarshal: %s", err)
} }
if !reflect.DeepEqual(f, atomFeed) { if !reflect.DeepEqual(f, atomFeed) {
@ -281,7 +280,7 @@ var pathTests = []interface{}{
func TestUnmarshalPaths(t *testing.T) { func TestUnmarshalPaths(t *testing.T) {
for _, pt := range pathTests { for _, pt := range pathTests {
v := reflect.New(reflect.TypeOf(pt).Elem()).Interface() v := reflect.New(reflect.TypeOf(pt).Elem()).Interface()
if err := Unmarshal(strings.NewReader(pathTestString), v); err != nil { if err := Unmarshal([]byte(pathTestString), v); err != nil {
t.Fatalf("Unmarshal: %s", err) t.Fatalf("Unmarshal: %s", err)
} }
if !reflect.DeepEqual(v, pt) { if !reflect.DeepEqual(v, pt) {
@ -331,7 +330,7 @@ var badPathTests = []struct {
func TestUnmarshalBadPaths(t *testing.T) { func TestUnmarshalBadPaths(t *testing.T) {
for _, tt := range badPathTests { for _, tt := range badPathTests {
err := Unmarshal(strings.NewReader(pathTestString), tt.v) err := Unmarshal([]byte(pathTestString), tt.v)
if !reflect.DeepEqual(err, tt.e) { if !reflect.DeepEqual(err, tt.e) {
t.Fatalf("Unmarshal with %#v didn't fail properly:\nhave %#v,\nwant %#v", tt.v, err, tt.e) t.Fatalf("Unmarshal with %#v didn't fail properly:\nhave %#v,\nwant %#v", tt.v, err, tt.e)
} }
@ -350,7 +349,7 @@ type TestThree struct {
func TestUnmarshalWithoutNameType(t *testing.T) { func TestUnmarshalWithoutNameType(t *testing.T) {
var x TestThree var x TestThree
if err := Unmarshal(strings.NewReader(withoutNameTypeData), &x); err != nil { if err := Unmarshal([]byte(withoutNameTypeData), &x); err != nil {
t.Fatalf("Unmarshal: %s", err) t.Fatalf("Unmarshal: %s", err)
} }
if x.Attr != OK { if x.Attr != OK {

View File

@ -37,7 +37,6 @@ const (
fAny fAny
// TODO: // TODO:
//fIgnore
//fOmitEmpty //fOmitEmpty
fMode = fElement | fAttr | fCharData | fInnerXml | fComment | fAny fMode = fElement | fAttr | fCharData | fInnerXml | fComment | fAny
@ -62,7 +61,7 @@ func getTypeInfo(typ reflect.Type) (*typeInfo, error) {
n := typ.NumField() n := typ.NumField()
for i := 0; i < n; i++ { for i := 0; i < n; i++ {
f := typ.Field(i) f := typ.Field(i)
if f.PkgPath != "" { if f.PkgPath != "" || f.Tag.Get("xml") == "-" {
continue // Private field continue // Private field
} }

View File

@ -36,7 +36,7 @@ func (e *SyntaxError) Error() string {
// A Name represents an XML name (Local) annotated // A Name represents an XML name (Local) annotated
// with a name space identifier (Space). // with a name space identifier (Space).
// In tokens returned by Parser.Token, the Space identifier // In tokens returned by Decoder.Token, the Space identifier
// is given as a canonical URL, not the short prefix used // is given as a canonical URL, not the short prefix used
// in the document being parsed. // in the document being parsed.
type Name struct { type Name struct {
@ -124,9 +124,9 @@ func CopyToken(t Token) Token {
return t return t
} }
// A Parser represents an XML parser reading a particular input stream. // A Decoder represents an XML parser reading a particular input stream.
// The parser assumes that its input is encoded in UTF-8. // The parser assumes that its input is encoded in UTF-8.
type Parser struct { type Decoder struct {
// Strict defaults to true, enforcing the requirements // Strict defaults to true, enforcing the requirements
// of the XML specification. // of the XML specification.
// If set to false, the parser allows input containing common // If set to false, the parser allows input containing common
@ -139,9 +139,9 @@ type Parser struct {
// //
// Setting: // Setting:
// //
// p.Strict = false; // d.Strict = false;
// p.AutoClose = HTMLAutoClose; // d.AutoClose = HTMLAutoClose;
// p.Entity = HTMLEntity // d.Entity = HTMLEntity
// //
// creates a parser that can handle typical HTML. // creates a parser that can handle typical HTML.
Strict bool Strict bool
@ -184,16 +184,16 @@ type Parser struct {
tmp [32]byte tmp [32]byte
} }
// NewParser creates a new XML parser reading from r. // NewDecoder creates a new XML parser reading from r.
func NewParser(r io.Reader) *Parser { func NewDecoder(r io.Reader) *Decoder {
p := &Parser{ d := &Decoder{
ns: make(map[string]string), ns: make(map[string]string),
nextByte: -1, nextByte: -1,
line: 1, line: 1,
Strict: true, Strict: true,
} }
p.switchToReader(r) d.switchToReader(r)
return p return d
} }
// Token returns the next XML token in the input stream. // Token returns the next XML token in the input stream.
@ -218,17 +218,17 @@ func NewParser(r io.Reader) *Parser {
// set to the URL identifying its name space when known. // set to the URL identifying its name space when known.
// If Token encounters an unrecognized name space prefix, // If Token encounters an unrecognized name space prefix,
// it uses the prefix as the Space rather than report an error. // it uses the prefix as the Space rather than report an error.
func (p *Parser) Token() (t Token, err error) { func (d *Decoder) Token() (t Token, err error) {
if p.nextToken != nil { if d.nextToken != nil {
t = p.nextToken t = d.nextToken
p.nextToken = nil d.nextToken = nil
} else if t, err = p.RawToken(); err != nil { } else if t, err = d.RawToken(); err != nil {
return return
} }
if !p.Strict { if !d.Strict {
if t1, ok := p.autoClose(t); ok { if t1, ok := d.autoClose(t); ok {
p.nextToken = t d.nextToken = t
t = t1 t = t1
} }
} }
@ -240,29 +240,29 @@ func (p *Parser) Token() (t Token, err error) {
// the translations first. // the translations first.
for _, a := range t1.Attr { for _, a := range t1.Attr {
if a.Name.Space == "xmlns" { if a.Name.Space == "xmlns" {
v, ok := p.ns[a.Name.Local] v, ok := d.ns[a.Name.Local]
p.pushNs(a.Name.Local, v, ok) d.pushNs(a.Name.Local, v, ok)
p.ns[a.Name.Local] = a.Value d.ns[a.Name.Local] = a.Value
} }
if a.Name.Space == "" && a.Name.Local == "xmlns" { if a.Name.Space == "" && a.Name.Local == "xmlns" {
// Default space for untagged names // Default space for untagged names
v, ok := p.ns[""] v, ok := d.ns[""]
p.pushNs("", v, ok) d.pushNs("", v, ok)
p.ns[""] = a.Value d.ns[""] = a.Value
} }
} }
p.translate(&t1.Name, true) d.translate(&t1.Name, true)
for i := range t1.Attr { for i := range t1.Attr {
p.translate(&t1.Attr[i].Name, false) d.translate(&t1.Attr[i].Name, false)
} }
p.pushElement(t1.Name) d.pushElement(t1.Name)
t = t1 t = t1
case EndElement: case EndElement:
p.translate(&t1.Name, true) d.translate(&t1.Name, true)
if !p.popElement(&t1) { if !d.popElement(&t1) {
return nil, p.err return nil, d.err
} }
t = t1 t = t1
} }
@ -272,7 +272,7 @@ func (p *Parser) Token() (t Token, err error) {
// Apply name space translation to name n. // Apply name space translation to name n.
// The default name space (for Space=="") // The default name space (for Space=="")
// applies only to element names, not to attribute names. // applies only to element names, not to attribute names.
func (p *Parser) translate(n *Name, isElementName bool) { func (d *Decoder) translate(n *Name, isElementName bool) {
switch { switch {
case n.Space == "xmlns": case n.Space == "xmlns":
return return
@ -281,20 +281,20 @@ func (p *Parser) translate(n *Name, isElementName bool) {
case n.Space == "" && n.Local == "xmlns": case n.Space == "" && n.Local == "xmlns":
return return
} }
if v, ok := p.ns[n.Space]; ok { if v, ok := d.ns[n.Space]; ok {
n.Space = v n.Space = v
} }
} }
func (p *Parser) switchToReader(r io.Reader) { func (d *Decoder) switchToReader(r io.Reader) {
// Get efficient byte at a time reader. // Get efficient byte at a time reader.
// Assume that if reader has its own // Assume that if reader has its own
// ReadByte, it's efficient enough. // ReadByte, it's efficient enough.
// Otherwise, use bufio. // Otherwise, use bufio.
if rb, ok := r.(io.ByteReader); ok { if rb, ok := r.(io.ByteReader); ok {
p.r = rb d.r = rb
} else { } else {
p.r = bufio.NewReader(r) d.r = bufio.NewReader(r)
} }
} }
@ -314,47 +314,47 @@ const (
stkNs stkNs
) )
func (p *Parser) push(kind int) *stack { func (d *Decoder) push(kind int) *stack {
s := p.free s := d.free
if s != nil { if s != nil {
p.free = s.next d.free = s.next
} else { } else {
s = new(stack) s = new(stack)
} }
s.next = p.stk s.next = d.stk
s.kind = kind s.kind = kind
p.stk = s d.stk = s
return s return s
} }
func (p *Parser) pop() *stack { func (d *Decoder) pop() *stack {
s := p.stk s := d.stk
if s != nil { if s != nil {
p.stk = s.next d.stk = s.next
s.next = p.free s.next = d.free
p.free = s d.free = s
} }
return s return s
} }
// Record that we are starting an element with the given name. // Record that we are starting an element with the given name.
func (p *Parser) pushElement(name Name) { func (d *Decoder) pushElement(name Name) {
s := p.push(stkStart) s := d.push(stkStart)
s.name = name s.name = name
} }
// Record that we are changing the value of ns[local]. // Record that we are changing the value of ns[local].
// The old value is url, ok. // The old value is url, ok.
func (p *Parser) pushNs(local string, url string, ok bool) { func (d *Decoder) pushNs(local string, url string, ok bool) {
s := p.push(stkNs) s := d.push(stkNs)
s.name.Local = local s.name.Local = local
s.name.Space = url s.name.Space = url
s.ok = ok s.ok = ok
} }
// Creates a SyntaxError with the current line number. // Creates a SyntaxError with the current line number.
func (p *Parser) syntaxError(msg string) error { func (d *Decoder) syntaxError(msg string) error {
return &SyntaxError{Msg: msg, Line: p.line} return &SyntaxError{Msg: msg, Line: d.line}
} }
// Record that we are ending an element with the given name. // Record that we are ending an element with the given name.
@ -363,36 +363,36 @@ func (p *Parser) syntaxError(msg string) error {
// After popping the element, apply any undo records from // After popping the element, apply any undo records from
// the stack to restore the name translations that existed // the stack to restore the name translations that existed
// before we saw this element. // before we saw this element.
func (p *Parser) popElement(t *EndElement) bool { func (d *Decoder) popElement(t *EndElement) bool {
s := p.pop() s := d.pop()
name := t.Name name := t.Name
switch { switch {
case s == nil || s.kind != stkStart: case s == nil || s.kind != stkStart:
p.err = p.syntaxError("unexpected end element </" + name.Local + ">") d.err = d.syntaxError("unexpected end element </" + name.Local + ">")
return false return false
case s.name.Local != name.Local: case s.name.Local != name.Local:
if !p.Strict { if !d.Strict {
p.needClose = true d.needClose = true
p.toClose = t.Name d.toClose = t.Name
t.Name = s.name t.Name = s.name
return true return true
} }
p.err = p.syntaxError("element <" + s.name.Local + "> closed by </" + name.Local + ">") d.err = d.syntaxError("element <" + s.name.Local + "> closed by </" + name.Local + ">")
return false return false
case s.name.Space != name.Space: case s.name.Space != name.Space:
p.err = p.syntaxError("element <" + s.name.Local + "> in space " + s.name.Space + d.err = d.syntaxError("element <" + s.name.Local + "> in space " + s.name.Space +
"closed by </" + name.Local + "> in space " + name.Space) "closed by </" + name.Local + "> in space " + name.Space)
return false return false
} }
// Pop stack until a Start is on the top, undoing the // Pop stack until a Start is on the top, undoing the
// translations that were associated with the element we just closed. // translations that were associated with the element we just closed.
for p.stk != nil && p.stk.kind != stkStart { for d.stk != nil && d.stk.kind != stkStart {
s := p.pop() s := d.pop()
if s.ok { if s.ok {
p.ns[s.name.Local] = s.name.Space d.ns[s.name.Local] = s.name.Space
} else { } else {
delete(p.ns, s.name.Local) delete(d.ns, s.name.Local)
} }
} }
@ -401,17 +401,17 @@ func (p *Parser) popElement(t *EndElement) bool {
// If the top element on the stack is autoclosing and // If the top element on the stack is autoclosing and
// t is not the end tag, invent the end tag. // t is not the end tag, invent the end tag.
func (p *Parser) autoClose(t Token) (Token, bool) { func (d *Decoder) autoClose(t Token) (Token, bool) {
if p.stk == nil || p.stk.kind != stkStart { if d.stk == nil || d.stk.kind != stkStart {
return nil, false return nil, false
} }
name := strings.ToLower(p.stk.name.Local) name := strings.ToLower(d.stk.name.Local)
for _, s := range p.AutoClose { for _, s := range d.AutoClose {
if strings.ToLower(s) == name { if strings.ToLower(s) == name {
// This one should be auto closed if t doesn't close it. // This one should be auto closed if t doesn't close it.
et, ok := t.(EndElement) et, ok := t.(EndElement)
if !ok || et.Name.Local != name { if !ok || et.Name.Local != name {
return EndElement{p.stk.name}, true return EndElement{d.stk.name}, true
} }
break break
} }
@ -422,53 +422,53 @@ func (p *Parser) autoClose(t Token) (Token, bool) {
// RawToken is like Token but does not verify that // RawToken is like Token but does not verify that
// start and end elements match and does not translate // start and end elements match and does not translate
// name space prefixes to their corresponding URLs. // name space prefixes to their corresponding URLs.
func (p *Parser) RawToken() (Token, error) { func (d *Decoder) RawToken() (Token, error) {
if p.err != nil { if d.err != nil {
return nil, p.err return nil, d.err
} }
if p.needClose { if d.needClose {
// The last element we read was self-closing and // The last element we read was self-closing and
// we returned just the StartElement half. // we returned just the StartElement half.
// Return the EndElement half now. // Return the EndElement half now.
p.needClose = false d.needClose = false
return EndElement{p.toClose}, nil return EndElement{d.toClose}, nil
} }
b, ok := p.getc() b, ok := d.getc()
if !ok { if !ok {
return nil, p.err return nil, d.err
} }
if b != '<' { if b != '<' {
// Text section. // Text section.
p.ungetc(b) d.ungetc(b)
data := p.text(-1, false) data := d.text(-1, false)
if data == nil { if data == nil {
return nil, p.err return nil, d.err
} }
return CharData(data), nil return CharData(data), nil
} }
if b, ok = p.mustgetc(); !ok { if b, ok = d.mustgetc(); !ok {
return nil, p.err return nil, d.err
} }
switch b { switch b {
case '/': case '/':
// </: End element // </: End element
var name Name var name Name
if name, ok = p.nsname(); !ok { if name, ok = d.nsname(); !ok {
if p.err == nil { if d.err == nil {
p.err = p.syntaxError("expected element name after </") d.err = d.syntaxError("expected element name after </")
} }
return nil, p.err return nil, d.err
} }
p.space() d.space()
if b, ok = p.mustgetc(); !ok { if b, ok = d.mustgetc(); !ok {
return nil, p.err return nil, d.err
} }
if b != '>' { if b != '>' {
p.err = p.syntaxError("invalid characters between </" + name.Local + " and >") d.err = d.syntaxError("invalid characters between </" + name.Local + " and >")
return nil, p.err return nil, d.err
} }
return EndElement{name}, nil return EndElement{name}, nil
@ -477,95 +477,95 @@ func (p *Parser) RawToken() (Token, error) {
// TODO(rsc): Should parse the <?xml declaration to make sure // TODO(rsc): Should parse the <?xml declaration to make sure
// the version is 1.0 and the encoding is UTF-8. // the version is 1.0 and the encoding is UTF-8.
var target string var target string
if target, ok = p.name(); !ok { if target, ok = d.name(); !ok {
if p.err == nil { if d.err == nil {
p.err = p.syntaxError("expected target name after <?") d.err = d.syntaxError("expected target name after <?")
} }
return nil, p.err return nil, d.err
} }
p.space() d.space()
p.buf.Reset() d.buf.Reset()
var b0 byte var b0 byte
for { for {
if b, ok = p.mustgetc(); !ok { if b, ok = d.mustgetc(); !ok {
return nil, p.err return nil, d.err
} }
p.buf.WriteByte(b) d.buf.WriteByte(b)
if b0 == '?' && b == '>' { if b0 == '?' && b == '>' {
break break
} }
b0 = b b0 = b
} }
data := p.buf.Bytes() data := d.buf.Bytes()
data = data[0 : len(data)-2] // chop ?> data = data[0 : len(data)-2] // chop ?>
if target == "xml" { if target == "xml" {
enc := procInstEncoding(string(data)) enc := procInstEncoding(string(data))
if enc != "" && enc != "utf-8" && enc != "UTF-8" { if enc != "" && enc != "utf-8" && enc != "UTF-8" {
if p.CharsetReader == nil { if d.CharsetReader == nil {
p.err = fmt.Errorf("xml: encoding %q declared but Parser.CharsetReader is nil", enc) d.err = fmt.Errorf("xml: encoding %q declared but Decoder.CharsetReader is nil", enc)
return nil, p.err return nil, d.err
} }
newr, err := p.CharsetReader(enc, p.r.(io.Reader)) newr, err := d.CharsetReader(enc, d.r.(io.Reader))
if err != nil { if err != nil {
p.err = fmt.Errorf("xml: opening charset %q: %v", enc, err) d.err = fmt.Errorf("xml: opening charset %q: %v", enc, err)
return nil, p.err return nil, d.err
} }
if newr == nil { if newr == nil {
panic("CharsetReader returned a nil Reader for charset " + enc) panic("CharsetReader returned a nil Reader for charset " + enc)
} }
p.switchToReader(newr) d.switchToReader(newr)
} }
} }
return ProcInst{target, data}, nil return ProcInst{target, data}, nil
case '!': case '!':
// <!: Maybe comment, maybe CDATA. // <!: Maybe comment, maybe CDATA.
if b, ok = p.mustgetc(); !ok { if b, ok = d.mustgetc(); !ok {
return nil, p.err return nil, d.err
} }
switch b { switch b {
case '-': // <!- case '-': // <!-
// Probably <!-- for a comment. // Probably <!-- for a comment.
if b, ok = p.mustgetc(); !ok { if b, ok = d.mustgetc(); !ok {
return nil, p.err return nil, d.err
} }
if b != '-' { if b != '-' {
p.err = p.syntaxError("invalid sequence <!- not part of <!--") d.err = d.syntaxError("invalid sequence <!- not part of <!--")
return nil, p.err return nil, d.err
} }
// Look for terminator. // Look for terminator.
p.buf.Reset() d.buf.Reset()
var b0, b1 byte var b0, b1 byte
for { for {
if b, ok = p.mustgetc(); !ok { if b, ok = d.mustgetc(); !ok {
return nil, p.err return nil, d.err
} }
p.buf.WriteByte(b) d.buf.WriteByte(b)
if b0 == '-' && b1 == '-' && b == '>' { if b0 == '-' && b1 == '-' && b == '>' {
break break
} }
b0, b1 = b1, b b0, b1 = b1, b
} }
data := p.buf.Bytes() data := d.buf.Bytes()
data = data[0 : len(data)-3] // chop --> data = data[0 : len(data)-3] // chop -->
return Comment(data), nil return Comment(data), nil
case '[': // <![ case '[': // <![
// Probably <![CDATA[. // Probably <![CDATA[.
for i := 0; i < 6; i++ { for i := 0; i < 6; i++ {
if b, ok = p.mustgetc(); !ok { if b, ok = d.mustgetc(); !ok {
return nil, p.err return nil, d.err
} }
if b != "CDATA["[i] { if b != "CDATA["[i] {
p.err = p.syntaxError("invalid <![ sequence") d.err = d.syntaxError("invalid <![ sequence")
return nil, p.err return nil, d.err
} }
} }
// Have <![CDATA[. Read text until ]]>. // Have <![CDATA[. Read text until ]]>.
data := p.text(-1, true) data := d.text(-1, true)
if data == nil { if data == nil {
return nil, p.err return nil, d.err
} }
return CharData(data), nil return CharData(data), nil
} }
@ -573,18 +573,18 @@ func (p *Parser) RawToken() (Token, error) {
// Probably a directive: <!DOCTYPE ...>, <!ENTITY ...>, etc. // Probably a directive: <!DOCTYPE ...>, <!ENTITY ...>, etc.
// We don't care, but accumulate for caller. Quoted angle // We don't care, but accumulate for caller. Quoted angle
// brackets do not count for nesting. // brackets do not count for nesting.
p.buf.Reset() d.buf.Reset()
p.buf.WriteByte(b) d.buf.WriteByte(b)
inquote := uint8(0) inquote := uint8(0)
depth := 0 depth := 0
for { for {
if b, ok = p.mustgetc(); !ok { if b, ok = d.mustgetc(); !ok {
return nil, p.err return nil, d.err
} }
if inquote == 0 && b == '>' && depth == 0 { if inquote == 0 && b == '>' && depth == 0 {
break break
} }
p.buf.WriteByte(b) d.buf.WriteByte(b)
switch { switch {
case b == inquote: case b == inquote:
inquote = 0 inquote = 0
@ -602,45 +602,45 @@ func (p *Parser) RawToken() (Token, error) {
depth++ depth++
} }
} }
return Directive(p.buf.Bytes()), nil return Directive(d.buf.Bytes()), nil
} }
// Must be an open element like <a href="foo"> // Must be an open element like <a href="foo">
p.ungetc(b) d.ungetc(b)
var ( var (
name Name name Name
empty bool empty bool
attr []Attr attr []Attr
) )
if name, ok = p.nsname(); !ok { if name, ok = d.nsname(); !ok {
if p.err == nil { if d.err == nil {
p.err = p.syntaxError("expected element name after <") d.err = d.syntaxError("expected element name after <")
} }
return nil, p.err return nil, d.err
} }
attr = make([]Attr, 0, 4) attr = make([]Attr, 0, 4)
for { for {
p.space() d.space()
if b, ok = p.mustgetc(); !ok { if b, ok = d.mustgetc(); !ok {
return nil, p.err return nil, d.err
} }
if b == '/' { if b == '/' {
empty = true empty = true
if b, ok = p.mustgetc(); !ok { if b, ok = d.mustgetc(); !ok {
return nil, p.err return nil, d.err
} }
if b != '>' { if b != '>' {
p.err = p.syntaxError("expected /> in element") d.err = d.syntaxError("expected /> in element")
return nil, p.err return nil, d.err
} }
break break
} }
if b == '>' { if b == '>' {
break break
} }
p.ungetc(b) d.ungetc(b)
n := len(attr) n := len(attr)
if n >= cap(attr) { if n >= cap(attr) {
@ -650,85 +650,85 @@ func (p *Parser) RawToken() (Token, error) {
} }
attr = attr[0 : n+1] attr = attr[0 : n+1]
a := &attr[n] a := &attr[n]
if a.Name, ok = p.nsname(); !ok { if a.Name, ok = d.nsname(); !ok {
if p.err == nil { if d.err == nil {
p.err = p.syntaxError("expected attribute name in element") d.err = d.syntaxError("expected attribute name in element")
} }
return nil, p.err return nil, d.err
} }
p.space() d.space()
if b, ok = p.mustgetc(); !ok { if b, ok = d.mustgetc(); !ok {
return nil, p.err return nil, d.err
} }
if b != '=' { if b != '=' {
if p.Strict { if d.Strict {
p.err = p.syntaxError("attribute name without = in element") d.err = d.syntaxError("attribute name without = in element")
return nil, p.err return nil, d.err
} else { } else {
p.ungetc(b) d.ungetc(b)
a.Value = a.Name.Local a.Value = a.Name.Local
} }
} else { } else {
p.space() d.space()
data := p.attrval() data := d.attrval()
if data == nil { if data == nil {
return nil, p.err return nil, d.err
} }
a.Value = string(data) a.Value = string(data)
} }
} }
if empty { if empty {
p.needClose = true d.needClose = true
p.toClose = name d.toClose = name
} }
return StartElement{name, attr}, nil return StartElement{name, attr}, nil
} }
func (p *Parser) attrval() []byte { func (d *Decoder) attrval() []byte {
b, ok := p.mustgetc() b, ok := d.mustgetc()
if !ok { if !ok {
return nil return nil
} }
// Handle quoted attribute values // Handle quoted attribute values
if b == '"' || b == '\'' { if b == '"' || b == '\'' {
return p.text(int(b), false) return d.text(int(b), false)
} }
// Handle unquoted attribute values for strict parsers // Handle unquoted attribute values for strict parsers
if p.Strict { if d.Strict {
p.err = p.syntaxError("unquoted or missing attribute value in element") d.err = d.syntaxError("unquoted or missing attribute value in element")
return nil return nil
} }
// Handle unquoted attribute values for unstrict parsers // Handle unquoted attribute values for unstrict parsers
p.ungetc(b) d.ungetc(b)
p.buf.Reset() d.buf.Reset()
for { for {
b, ok = p.mustgetc() b, ok = d.mustgetc()
if !ok { if !ok {
return nil return nil
} }
// http://www.w3.org/TR/REC-html40/intro/sgmltut.html#h-3.2.2 // http://www.w3.org/TR/REC-html40/intro/sgmltut.html#h-3.2.2
if 'a' <= b && b <= 'z' || 'A' <= b && b <= 'Z' || if 'a' <= b && b <= 'z' || 'A' <= b && b <= 'Z' ||
'0' <= b && b <= '9' || b == '_' || b == ':' || b == '-' { '0' <= b && b <= '9' || b == '_' || b == ':' || b == '-' {
p.buf.WriteByte(b) d.buf.WriteByte(b)
} else { } else {
p.ungetc(b) d.ungetc(b)
break break
} }
} }
return p.buf.Bytes() return d.buf.Bytes()
} }
// Skip spaces if any // Skip spaces if any
func (p *Parser) space() { func (d *Decoder) space() {
for { for {
b, ok := p.getc() b, ok := d.getc()
if !ok { if !ok {
return return
} }
switch b { switch b {
case ' ', '\r', '\n', '\t': case ' ', '\r', '\n', '\t':
default: default:
p.ungetc(b) d.ungetc(b)
return return
} }
} }
@ -736,35 +736,35 @@ func (p *Parser) space() {
// Read a single byte. // Read a single byte.
// If there is no byte to read, return ok==false // If there is no byte to read, return ok==false
// and leave the error in p.err. // and leave the error in d.err.
// Maintain line number. // Maintain line number.
func (p *Parser) getc() (b byte, ok bool) { func (d *Decoder) getc() (b byte, ok bool) {
if p.err != nil { if d.err != nil {
return 0, false return 0, false
} }
if p.nextByte >= 0 { if d.nextByte >= 0 {
b = byte(p.nextByte) b = byte(d.nextByte)
p.nextByte = -1 d.nextByte = -1
} else { } else {
b, p.err = p.r.ReadByte() b, d.err = d.r.ReadByte()
if p.err != nil { if d.err != nil {
return 0, false return 0, false
} }
if p.saved != nil { if d.saved != nil {
p.saved.WriteByte(b) d.saved.WriteByte(b)
} }
} }
if b == '\n' { if b == '\n' {
p.line++ d.line++
} }
return b, true return b, true
} }
// Return saved offset. // Return saved offset.
// If we did ungetc (nextByte >= 0), have to back up one. // If we did ungetc (nextByte >= 0), have to back up one.
func (p *Parser) savedOffset() int { func (d *Decoder) savedOffset() int {
n := p.saved.Len() n := d.saved.Len()
if p.nextByte >= 0 { if d.nextByte >= 0 {
n-- n--
} }
return n return n
@ -772,23 +772,23 @@ func (p *Parser) savedOffset() int {
// Must read a single byte. // Must read a single byte.
// If there is no byte to read, // If there is no byte to read,
// set p.err to SyntaxError("unexpected EOF") // set d.err to SyntaxError("unexpected EOF")
// and return ok==false // and return ok==false
func (p *Parser) mustgetc() (b byte, ok bool) { func (d *Decoder) mustgetc() (b byte, ok bool) {
if b, ok = p.getc(); !ok { if b, ok = d.getc(); !ok {
if p.err == io.EOF { if d.err == io.EOF {
p.err = p.syntaxError("unexpected EOF") d.err = d.syntaxError("unexpected EOF")
} }
} }
return return
} }
// Unread a single byte. // Unread a single byte.
func (p *Parser) ungetc(b byte) { func (d *Decoder) ungetc(b byte) {
if b == '\n' { if b == '\n' {
p.line-- d.line--
} }
p.nextByte = int(b) d.nextByte = int(b)
} }
var entity = map[string]int{ var entity = map[string]int{
@ -802,18 +802,18 @@ var entity = map[string]int{
// Read plain text section (XML calls it character data). // Read plain text section (XML calls it character data).
// If quote >= 0, we are in a quoted string and need to find the matching quote. // If quote >= 0, we are in a quoted string and need to find the matching quote.
// If cdata == true, we are in a <![CDATA[ section and need to find ]]>. // If cdata == true, we are in a <![CDATA[ section and need to find ]]>.
// On failure return nil and leave the error in p.err. // On failure return nil and leave the error in d.err.
func (p *Parser) text(quote int, cdata bool) []byte { func (d *Decoder) text(quote int, cdata bool) []byte {
var b0, b1 byte var b0, b1 byte
var trunc int var trunc int
p.buf.Reset() d.buf.Reset()
Input: Input:
for { for {
b, ok := p.getc() b, ok := d.getc()
if !ok { if !ok {
if cdata { if cdata {
if p.err == io.EOF { if d.err == io.EOF {
p.err = p.syntaxError("unexpected EOF in CDATA section") d.err = d.syntaxError("unexpected EOF in CDATA section")
} }
return nil return nil
} }
@ -827,17 +827,17 @@ Input:
trunc = 2 trunc = 2
break Input break Input
} }
p.err = p.syntaxError("unescaped ]]> not in CDATA section") d.err = d.syntaxError("unescaped ]]> not in CDATA section")
return nil return nil
} }
// Stop reading text if we see a <. // Stop reading text if we see a <.
if b == '<' && !cdata { if b == '<' && !cdata {
if quote >= 0 { if quote >= 0 {
p.err = p.syntaxError("unescaped < inside quoted string") d.err = d.syntaxError("unescaped < inside quoted string")
return nil return nil
} }
p.ungetc('<') d.ungetc('<')
break Input break Input
} }
if quote >= 0 && b == byte(quote) { if quote >= 0 && b == byte(quote) {
@ -850,16 +850,16 @@ Input:
// Parsers are required to recognize lt, gt, amp, apos, and quot // Parsers are required to recognize lt, gt, amp, apos, and quot
// even if they have not been declared. That's all we allow. // even if they have not been declared. That's all we allow.
var i int var i int
for i = 0; i < len(p.tmp); i++ { for i = 0; i < len(d.tmp); i++ {
var ok bool var ok bool
p.tmp[i], ok = p.getc() d.tmp[i], ok = d.getc()
if !ok { if !ok {
if p.err == io.EOF { if d.err == io.EOF {
p.err = p.syntaxError("unexpected EOF") d.err = d.syntaxError("unexpected EOF")
} }
return nil return nil
} }
c := p.tmp[i] c := d.tmp[i]
if c == ';' { if c == ';' {
break break
} }
@ -869,18 +869,18 @@ Input:
c == '_' || c == '#' { c == '_' || c == '#' {
continue continue
} }
p.ungetc(c) d.ungetc(c)
break break
} }
s := string(p.tmp[0:i]) s := string(d.tmp[0:i])
if i >= len(p.tmp) { if i >= len(d.tmp) {
if !p.Strict { if !d.Strict {
b0, b1 = 0, 0 b0, b1 = 0, 0
p.buf.WriteByte('&') d.buf.WriteByte('&')
p.buf.Write(p.tmp[0:i]) d.buf.Write(d.tmp[0:i])
continue Input continue Input
} }
p.err = p.syntaxError("character entity expression &" + s + "... too long") d.err = d.syntaxError("character entity expression &" + s + "... too long")
return nil return nil
} }
var haveText bool var haveText bool
@ -901,28 +901,28 @@ Input:
if r, ok := entity[s]; ok { if r, ok := entity[s]; ok {
text = string(r) text = string(r)
haveText = true haveText = true
} else if p.Entity != nil { } else if d.Entity != nil {
text, haveText = p.Entity[s] text, haveText = d.Entity[s]
} }
} }
if !haveText { if !haveText {
if !p.Strict { if !d.Strict {
b0, b1 = 0, 0 b0, b1 = 0, 0
p.buf.WriteByte('&') d.buf.WriteByte('&')
p.buf.Write(p.tmp[0:i]) d.buf.Write(d.tmp[0:i])
continue Input continue Input
} }
p.err = p.syntaxError("invalid character entity &" + s + ";") d.err = d.syntaxError("invalid character entity &" + s + ";")
return nil return nil
} }
p.buf.Write([]byte(text)) d.buf.Write([]byte(text))
b0, b1 = 0, 0 b0, b1 = 0, 0
continue Input continue Input
} }
p.buf.WriteByte(b) d.buf.WriteByte(b)
b0, b1 = b1, b b0, b1 = b1, b
} }
data := p.buf.Bytes() data := d.buf.Bytes()
data = data[0 : len(data)-trunc] data = data[0 : len(data)-trunc]
// Inspect each rune for being a disallowed character. // Inspect each rune for being a disallowed character.
@ -930,12 +930,12 @@ Input:
for len(buf) > 0 { for len(buf) > 0 {
r, size := utf8.DecodeRune(buf) r, size := utf8.DecodeRune(buf)
if r == utf8.RuneError && size == 1 { if r == utf8.RuneError && size == 1 {
p.err = p.syntaxError("invalid UTF-8") d.err = d.syntaxError("invalid UTF-8")
return nil return nil
} }
buf = buf[size:] buf = buf[size:]
if !isInCharacterRange(r) { if !isInCharacterRange(r) {
p.err = p.syntaxError(fmt.Sprintf("illegal character code %U", r)) d.err = d.syntaxError(fmt.Sprintf("illegal character code %U", r))
return nil return nil
} }
} }
@ -970,8 +970,8 @@ func isInCharacterRange(r rune) (inrange bool) {
// Get name space name: name with a : stuck in the middle. // Get name space name: name with a : stuck in the middle.
// The part before the : is the name space identifier. // The part before the : is the name space identifier.
func (p *Parser) nsname() (name Name, ok bool) { func (d *Decoder) nsname() (name Name, ok bool) {
s, ok := p.name() s, ok := d.name()
if !ok { if !ok {
return return
} }
@ -986,37 +986,37 @@ func (p *Parser) nsname() (name Name, ok bool) {
} }
// Get name: /first(first|second)*/ // Get name: /first(first|second)*/
// Do not set p.err if the name is missing (unless unexpected EOF is received): // Do not set d.err if the name is missing (unless unexpected EOF is received):
// let the caller provide better context. // let the caller provide better context.
func (p *Parser) name() (s string, ok bool) { func (d *Decoder) name() (s string, ok bool) {
var b byte var b byte
if b, ok = p.mustgetc(); !ok { if b, ok = d.mustgetc(); !ok {
return return
} }
// As a first approximation, we gather the bytes [A-Za-z_:.-\x80-\xFF]* // As a first approximation, we gather the bytes [A-Za-z_:.-\x80-\xFF]*
if b < utf8.RuneSelf && !isNameByte(b) { if b < utf8.RuneSelf && !isNameByte(b) {
p.ungetc(b) d.ungetc(b)
return "", false return "", false
} }
p.buf.Reset() d.buf.Reset()
p.buf.WriteByte(b) d.buf.WriteByte(b)
for { for {
if b, ok = p.mustgetc(); !ok { if b, ok = d.mustgetc(); !ok {
return return
} }
if b < utf8.RuneSelf && !isNameByte(b) { if b < utf8.RuneSelf && !isNameByte(b) {
p.ungetc(b) d.ungetc(b)
break break
} }
p.buf.WriteByte(b) d.buf.WriteByte(b)
} }
// Then we check the characters. // Then we check the characters.
s = p.buf.String() s = d.buf.String()
for i, c := range s { for i, c := range s {
if !unicode.Is(first, c) && (i == 0 || !unicode.Is(second, c)) { if !unicode.Is(first, c) && (i == 0 || !unicode.Is(second, c)) {
p.err = p.syntaxError("invalid XML name: " + s) d.err = d.syntaxError("invalid XML name: " + s)
return "", false return "", false
} }
} }

View File

@ -5,7 +5,6 @@
package xml package xml
import ( import (
"bytes"
"io" "io"
"reflect" "reflect"
"strings" "strings"
@ -155,8 +154,8 @@ var xmlInput = []string{
} }
func TestRawToken(t *testing.T) { func TestRawToken(t *testing.T) {
p := NewParser(strings.NewReader(testInput)) d := NewDecoder(strings.NewReader(testInput))
testRawToken(t, p, rawTokens) testRawToken(t, d, rawTokens)
} }
type downCaser struct { type downCaser struct {
@ -179,27 +178,27 @@ func (d *downCaser) Read(p []byte) (int, error) {
func TestRawTokenAltEncoding(t *testing.T) { func TestRawTokenAltEncoding(t *testing.T) {
sawEncoding := "" sawEncoding := ""
p := NewParser(strings.NewReader(testInputAltEncoding)) d := NewDecoder(strings.NewReader(testInputAltEncoding))
p.CharsetReader = func(charset string, input io.Reader) (io.Reader, error) { d.CharsetReader = func(charset string, input io.Reader) (io.Reader, error) {
sawEncoding = charset sawEncoding = charset
if charset != "x-testing-uppercase" { if charset != "x-testing-uppercase" {
t.Fatalf("unexpected charset %q", charset) t.Fatalf("unexpected charset %q", charset)
} }
return &downCaser{t, input.(io.ByteReader)}, nil return &downCaser{t, input.(io.ByteReader)}, nil
} }
testRawToken(t, p, rawTokensAltEncoding) testRawToken(t, d, rawTokensAltEncoding)
} }
func TestRawTokenAltEncodingNoConverter(t *testing.T) { func TestRawTokenAltEncodingNoConverter(t *testing.T) {
p := NewParser(strings.NewReader(testInputAltEncoding)) d := NewDecoder(strings.NewReader(testInputAltEncoding))
token, err := p.RawToken() token, err := d.RawToken()
if token == nil { if token == nil {
t.Fatalf("expected a token on first RawToken call") t.Fatalf("expected a token on first RawToken call")
} }
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
token, err = p.RawToken() token, err = d.RawToken()
if token != nil { if token != nil {
t.Errorf("expected a nil token; got %#v", token) t.Errorf("expected a nil token; got %#v", token)
} }
@ -213,9 +212,9 @@ func TestRawTokenAltEncodingNoConverter(t *testing.T) {
} }
} }
func testRawToken(t *testing.T, p *Parser, rawTokens []Token) { func testRawToken(t *testing.T, d *Decoder, rawTokens []Token) {
for i, want := range rawTokens { for i, want := range rawTokens {
have, err := p.RawToken() have, err := d.RawToken()
if err != nil { if err != nil {
t.Fatalf("token %d: unexpected error: %s", i, err) t.Fatalf("token %d: unexpected error: %s", i, err)
} }
@ -258,10 +257,10 @@ var nestedDirectivesTokens = []Token{
} }
func TestNestedDirectives(t *testing.T) { func TestNestedDirectives(t *testing.T) {
p := NewParser(strings.NewReader(nestedDirectivesInput)) d := NewDecoder(strings.NewReader(nestedDirectivesInput))
for i, want := range nestedDirectivesTokens { for i, want := range nestedDirectivesTokens {
have, err := p.Token() have, err := d.Token()
if err != nil { if err != nil {
t.Fatalf("token %d: unexpected error: %s", i, err) t.Fatalf("token %d: unexpected error: %s", i, err)
} }
@ -272,10 +271,10 @@ func TestNestedDirectives(t *testing.T) {
} }
func TestToken(t *testing.T) { func TestToken(t *testing.T) {
p := NewParser(strings.NewReader(testInput)) d := NewDecoder(strings.NewReader(testInput))
for i, want := range cookedTokens { for i, want := range cookedTokens {
have, err := p.Token() have, err := d.Token()
if err != nil { if err != nil {
t.Fatalf("token %d: unexpected error: %s", i, err) t.Fatalf("token %d: unexpected error: %s", i, err)
} }
@ -287,9 +286,9 @@ func TestToken(t *testing.T) {
func TestSyntax(t *testing.T) { func TestSyntax(t *testing.T) {
for i := range xmlInput { for i := range xmlInput {
p := NewParser(strings.NewReader(xmlInput[i])) d := NewDecoder(strings.NewReader(xmlInput[i]))
var err error var err error
for _, err = p.Token(); err == nil; _, err = p.Token() { for _, err = d.Token(); err == nil; _, err = d.Token() {
} }
if _, ok := err.(*SyntaxError); !ok { if _, ok := err.(*SyntaxError); !ok {
t.Fatalf(`xmlInput "%s": expected SyntaxError not received`, xmlInput[i]) t.Fatalf(`xmlInput "%s": expected SyntaxError not received`, xmlInput[i])
@ -368,8 +367,7 @@ const testScalarsInput = `<allscalars>
func TestAllScalars(t *testing.T) { func TestAllScalars(t *testing.T) {
var a allScalars var a allScalars
buf := bytes.NewBufferString(testScalarsInput) err := Unmarshal([]byte(testScalarsInput), &a)
err := Unmarshal(buf, &a)
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
@ -386,8 +384,7 @@ type item struct {
func TestIssue569(t *testing.T) { func TestIssue569(t *testing.T) {
data := `<item><Field_a>abcd</Field_a></item>` data := `<item><Field_a>abcd</Field_a></item>`
var i item var i item
buf := bytes.NewBufferString(data) err := Unmarshal([]byte(data), &i)
err := Unmarshal(buf, &i)
if err != nil || i.Field_a != "abcd" { if err != nil || i.Field_a != "abcd" {
t.Fatal("Expecting abcd") t.Fatal("Expecting abcd")
@ -396,9 +393,9 @@ func TestIssue569(t *testing.T) {
func TestUnquotedAttrs(t *testing.T) { func TestUnquotedAttrs(t *testing.T) {
data := "<tag attr=azAZ09:-_\t>" data := "<tag attr=azAZ09:-_\t>"
p := NewParser(strings.NewReader(data)) d := NewDecoder(strings.NewReader(data))
p.Strict = false d.Strict = false
token, err := p.Token() token, err := d.Token()
if _, ok := err.(*SyntaxError); ok { if _, ok := err.(*SyntaxError); ok {
t.Errorf("Unexpected error: %v", err) t.Errorf("Unexpected error: %v", err)
} }
@ -422,9 +419,9 @@ func TestValuelessAttrs(t *testing.T) {
{"<input checked />", "input", "checked"}, {"<input checked />", "input", "checked"},
} }
for _, test := range tests { for _, test := range tests {
p := NewParser(strings.NewReader(test[0])) d := NewDecoder(strings.NewReader(test[0]))
p.Strict = false d.Strict = false
token, err := p.Token() token, err := d.Token()
if _, ok := err.(*SyntaxError); ok { if _, ok := err.(*SyntaxError); ok {
t.Errorf("Unexpected error: %v", err) t.Errorf("Unexpected error: %v", err)
} }
@ -472,9 +469,9 @@ func TestCopyTokenStartElement(t *testing.T) {
func TestSyntaxErrorLineNum(t *testing.T) { func TestSyntaxErrorLineNum(t *testing.T) {
testInput := "<P>Foo<P>\n\n<P>Bar</>\n" testInput := "<P>Foo<P>\n\n<P>Bar</>\n"
p := NewParser(strings.NewReader(testInput)) d := NewDecoder(strings.NewReader(testInput))
var err error var err error
for _, err = p.Token(); err == nil; _, err = p.Token() { for _, err = d.Token(); err == nil; _, err = d.Token() {
} }
synerr, ok := err.(*SyntaxError) synerr, ok := err.(*SyntaxError)
if !ok { if !ok {
@ -487,41 +484,41 @@ func TestSyntaxErrorLineNum(t *testing.T) {
func TestTrailingRawToken(t *testing.T) { func TestTrailingRawToken(t *testing.T) {
input := `<FOO></FOO> ` input := `<FOO></FOO> `
p := NewParser(strings.NewReader(input)) d := NewDecoder(strings.NewReader(input))
var err error var err error
for _, err = p.RawToken(); err == nil; _, err = p.RawToken() { for _, err = d.RawToken(); err == nil; _, err = d.RawToken() {
} }
if err != io.EOF { if err != io.EOF {
t.Fatalf("p.RawToken() = _, %v, want _, io.EOF", err) t.Fatalf("d.RawToken() = _, %v, want _, io.EOF", err)
} }
} }
func TestTrailingToken(t *testing.T) { func TestTrailingToken(t *testing.T) {
input := `<FOO></FOO> ` input := `<FOO></FOO> `
p := NewParser(strings.NewReader(input)) d := NewDecoder(strings.NewReader(input))
var err error var err error
for _, err = p.Token(); err == nil; _, err = p.Token() { for _, err = d.Token(); err == nil; _, err = d.Token() {
} }
if err != io.EOF { if err != io.EOF {
t.Fatalf("p.Token() = _, %v, want _, io.EOF", err) t.Fatalf("d.Token() = _, %v, want _, io.EOF", err)
} }
} }
func TestEntityInsideCDATA(t *testing.T) { func TestEntityInsideCDATA(t *testing.T) {
input := `<test><![CDATA[ &val=foo ]]></test>` input := `<test><![CDATA[ &val=foo ]]></test>`
p := NewParser(strings.NewReader(input)) d := NewDecoder(strings.NewReader(input))
var err error var err error
for _, err = p.Token(); err == nil; _, err = p.Token() { for _, err = d.Token(); err == nil; _, err = d.Token() {
} }
if err != io.EOF { if err != io.EOF {
t.Fatalf("p.Token() = _, %v, want _, io.EOF", err) t.Fatalf("d.Token() = _, %v, want _, io.EOF", err)
} }
} }
// The last three tests (respectively one for characters in attribute // The last three tests (respectively one for characters in attribute
// names and two for character entities) pass not because of code // names and two for character entities) pass not because of code
// changed for issue 1259, but instead pass with the given messages // changed for issue 1259, but instead pass with the given messages
// from other parts of xml.Parser. I provide these to note the // from other parts of xml.Decoder. I provide these to note the
// current behavior of situations where one might think that character // current behavior of situations where one might think that character
// range checking would detect the error, but it does not in fact. // range checking would detect the error, but it does not in fact.
@ -541,15 +538,15 @@ var characterTests = []struct {
func TestDisallowedCharacters(t *testing.T) { func TestDisallowedCharacters(t *testing.T) {
for i, tt := range characterTests { for i, tt := range characterTests {
p := NewParser(strings.NewReader(tt.in)) d := NewDecoder(strings.NewReader(tt.in))
var err error var err error
for err == nil { for err == nil {
_, err = p.Token() _, err = d.Token()
} }
synerr, ok := err.(*SyntaxError) synerr, ok := err.(*SyntaxError)
if !ok { if !ok {
t.Fatalf("input %d p.Token() = _, %v, want _, *SyntaxError", i, err) t.Fatalf("input %d d.Token() = _, %v, want _, *SyntaxError", i, err)
} }
if synerr.Msg != tt.err { if synerr.Msg != tt.err {
t.Fatalf("input %d synerr.Msg wrong: want '%s', got '%s'", i, tt.err, synerr.Msg) t.Fatalf("input %d synerr.Msg wrong: want '%s', got '%s'", i, tt.err, synerr.Msg)

View File

@ -11,6 +11,7 @@ import (
"fmt" "fmt"
"go/scanner" "go/scanner"
"go/token" "go/token"
"io"
"io/ioutil" "io/ioutil"
"os" "os"
"path/filepath" "path/filepath"
@ -76,34 +77,46 @@ func main() {
flag.Parse() flag.Parse()
var ( var (
filename string name string
src []byte r io.Reader
err error
) )
switch flag.NArg() { switch flag.NArg() {
case 0: case 0:
filename = "<stdin>" name, r = "<stdin>", os.Stdin
src, err = ioutil.ReadAll(os.Stdin)
case 1: case 1:
filename = flag.Arg(0) name = flag.Arg(0)
src, err = ioutil.ReadFile(filename)
default: default:
usage() usage()
} }
if err != nil {
if err := verify(name, *start, r); err != nil {
report(err) report(err)
} }
}
if filepath.Ext(filename) == ".html" || bytes.Index(src, open) >= 0 { func verify(name, start string, r io.Reader) error {
if r == nil {
f, err := os.Open(name)
if err != nil {
return err
}
defer f.Close()
r = f
}
src, err := ioutil.ReadAll(r)
if err != nil {
return err
}
if filepath.Ext(name) == ".html" || bytes.Index(src, open) >= 0 {
src = extractEBNF(src) src = extractEBNF(src)
} }
grammar, err := ebnf.Parse(filename, bytes.NewBuffer(src)) grammar, err := ebnf.Parse(name, bytes.NewBuffer(src))
if err != nil { if err != nil {
report(err) return err
} }
if err = ebnf.Verify(grammar, *start); err != nil { return ebnf.Verify(grammar, start)
report(err)
}
} }

Some files were not shown because too many files have changed in this diff Show More