mirror of
https://github.com/golang/go
synced 2024-11-22 01:34:41 -07:00
crypto/openpgp/packet: four more packet types.
R=bradfitzgo CC=golang-dev https://golang.org/cl/4156044
This commit is contained in:
parent
239ef63bf2
commit
9fe490ee38
53
src/pkg/crypto/openpgp/packet/literal.go
Normal file
53
src/pkg/crypto/openpgp/packet/literal.go
Normal file
@ -0,0 +1,53 @@
|
|||||||
|
// 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"
|
||||||
|
"os"
|
||||||
|
)
|
||||||
|
|
||||||
|
// LiteralData represents an encrypted file. See RFC 4880, section 5.9.
|
||||||
|
type LiteralData struct {
|
||||||
|
IsBinary bool
|
||||||
|
FileName string
|
||||||
|
Time uint32 // Unix epoc time. Either creation time or modification time. 0 means undefined.
|
||||||
|
Body io.Reader
|
||||||
|
}
|
||||||
|
|
||||||
|
// ForEyesOnly return 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 os.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
|
||||||
|
}
|
49
src/pkg/crypto/openpgp/packet/one_pass_signature.go
Normal file
49
src/pkg/crypto/openpgp/packet/one_pass_signature.go
Normal file
@ -0,0 +1,49 @@
|
|||||||
|
// 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/error"
|
||||||
|
"crypto/openpgp/s2k"
|
||||||
|
"encoding/binary"
|
||||||
|
"io"
|
||||||
|
"os"
|
||||||
|
"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
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ops *OnePassSignature) parse(r io.Reader) (err os.Error) {
|
||||||
|
var buf [13]byte
|
||||||
|
|
||||||
|
_, err = readFull(r, buf[:])
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if buf[0] != 3 {
|
||||||
|
err = error.UnsupportedError("one-pass-signature packet version " + strconv.Itoa(int(buf[0])))
|
||||||
|
}
|
||||||
|
|
||||||
|
var ok bool
|
||||||
|
ops.Hash, ok = s2k.HashIdToHash(buf[2])
|
||||||
|
if !ok {
|
||||||
|
return error.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
|
||||||
|
}
|
102
src/pkg/crypto/openpgp/packet/symmetric_key_encrypted.go
Normal file
102
src/pkg/crypto/openpgp/packet/symmetric_key_encrypted.go
Normal file
@ -0,0 +1,102 @@
|
|||||||
|
// 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/error"
|
||||||
|
"crypto/openpgp/s2k"
|
||||||
|
"io"
|
||||||
|
"os"
|
||||||
|
"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
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ske *SymmetricKeyEncrypted) parse(r io.Reader) (err os.Error) {
|
||||||
|
// RFC 4880, section 5.3.
|
||||||
|
var buf [2]byte
|
||||||
|
_, err = readFull(r, buf[:])
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if buf[0] != 4 {
|
||||||
|
return error.UnsupportedError("SymmetricKeyEncrypted version")
|
||||||
|
}
|
||||||
|
ske.CipherFunc = CipherFunction(buf[1])
|
||||||
|
|
||||||
|
if ske.CipherFunc.keySize() == 0 {
|
||||||
|
return error.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 error.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) os.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 error.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 error.StructuralError("length of decrypted key not a multiple of block size")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ske.Encrypted = false
|
||||||
|
return nil
|
||||||
|
}
|
@ -0,0 +1,62 @@
|
|||||||
|
// 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/ioutil"
|
||||||
|
"os"
|
||||||
|
"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 != os.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"
|
206
src/pkg/crypto/openpgp/packet/symmetrically_encrypted.go
Normal file
206
src/pkg/crypto/openpgp/packet/symmetrically_encrypted.go
Normal file
@ -0,0 +1,206 @@
|
|||||||
|
// 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/error"
|
||||||
|
"crypto/sha1"
|
||||||
|
"crypto/subtle"
|
||||||
|
"hash"
|
||||||
|
"io"
|
||||||
|
"os"
|
||||||
|
"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
|
||||||
|
}
|
||||||
|
|
||||||
|
func (se *SymmetricallyEncrypted) parse(r io.Reader) os.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] != 1 {
|
||||||
|
return error.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, os.Error) {
|
||||||
|
keySize := c.keySize()
|
||||||
|
if keySize == 0 {
|
||||||
|
return nil, error.UnsupportedError("unknown cipher: " + strconv.Itoa(int(c)))
|
||||||
|
}
|
||||||
|
if len(key) != keySize {
|
||||||
|
return nil, error.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, error.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, error.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, os.Error) {
|
||||||
|
return ser.in.Read(buf)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ser seReader) Close() os.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 os.Error) {
|
||||||
|
if ser.error {
|
||||||
|
err = io.ErrUnexpectedEOF
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if ser.eof {
|
||||||
|
err = os.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 == os.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 = os.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 == os.EOF {
|
||||||
|
ser.eof = true
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ser *seMDCReader) Close() os.Error {
|
||||||
|
if ser.error {
|
||||||
|
return error.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 == os.EOF {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
if err != nil {
|
||||||
|
return error.SignatureError("error during reading")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// This is a new-format packet tag byte for a type 19 (MDC) packet.
|
||||||
|
const mdcPacketTagByte = byte(0x80) | 0x40 | 19
|
||||||
|
if ser.trailer[0] != mdcPacketTagByte || ser.trailer[1] != sha1.Size {
|
||||||
|
return error.SignatureError("MDC packet not found")
|
||||||
|
}
|
||||||
|
ser.h.Write(ser.trailer[:2])
|
||||||
|
|
||||||
|
final := ser.h.Sum()
|
||||||
|
if subtle.ConstantTimeCompare(final, ser.trailer[2:]) == 1 {
|
||||||
|
return error.SignatureError("hash mismatch")
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
@ -0,0 +1,78 @@
|
|||||||
|
// 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/error"
|
||||||
|
"crypto/sha1"
|
||||||
|
"encoding/hex"
|
||||||
|
"io/ioutil"
|
||||||
|
"os"
|
||||||
|
"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 os.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 = os.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", 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.(*error.SignatureError); !ok {
|
||||||
|
t.Errorf("corruption: expected SignatureError, got: %s", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const mdcPlaintextHex = "a302789c3b2d93c4e0eb9aba22283539b3203335af44a134afb800c849cb4c4de10200aff40b45d31432c80cb384299a0655966d6939dfdeed1dddf980"
|
Loading…
Reference in New Issue
Block a user