From fc5c1f0a181dd620bfc3c48d93e6b2fcba234c7c Mon Sep 17 00:00:00 2001 From: Adam Langley Date: Thu, 3 Feb 2011 09:17:42 -0500 Subject: [PATCH] crypto/cipher: add resync open to OCFB mode. OpenPGP changed its OCFB mode for more modern packets (for example, the MDC symmetrically encrypted packet). This change adds a bool to determine which mode is used. R=bradfitzgo, r, rsc CC=golang-dev https://golang.org/cl/4126041 --- src/pkg/crypto/cipher/ocfb.go | 36 +++++++++++++++++++++++++----- src/pkg/crypto/cipher/ocfb_test.go | 17 +++++++++----- 2 files changed, 41 insertions(+), 12 deletions(-) diff --git a/src/pkg/crypto/cipher/ocfb.go b/src/pkg/crypto/cipher/ocfb.go index 43cb5a5310..b2d8775911 100644 --- a/src/pkg/crypto/cipher/ocfb.go +++ b/src/pkg/crypto/cipher/ocfb.go @@ -12,11 +12,21 @@ type ocfbEncrypter struct { outUsed int } +// An OCFBResyncOption determines if the "resynchronization step" of OCFB is +// performed. +type OCFBResyncOption bool + +const ( + OCFBResync OCFBResyncOption = true + OCFBNoResync OCFBResyncOption = false +) + // NewOCFBEncrypter returns a Stream which encrypts data with OpenPGP's cipher // feedback mode using the given Block, and an initial amount of ciphertext. // randData must be random bytes and be the same length as the Block's block -// size. -func NewOCFBEncrypter(block Block, randData []byte) (Stream, []byte) { +// size. Resync determines if the "resynchronization step" from RFC 4880, 13.9 +// step 7 is performed. Different parts of OpenPGP vary on this point. +func NewOCFBEncrypter(block Block, randData []byte, resync OCFBResyncOption) (Stream, []byte) { blockSize := block.BlockSize() if len(randData) != blockSize { return nil, nil @@ -38,7 +48,13 @@ func NewOCFBEncrypter(block Block, randData []byte) (Stream, []byte) { prefix[blockSize] = x.fre[0] ^ randData[blockSize-2] prefix[blockSize+1] = x.fre[1] ^ randData[blockSize-1] - block.Encrypt(x.fre, prefix[2:]) + if resync { + block.Encrypt(x.fre, prefix[2:]) + } else { + x.fre[0] = prefix[blockSize] + x.fre[1] = prefix[blockSize+1] + x.outUsed = 2 + } return x, prefix } @@ -64,8 +80,10 @@ type ocfbDecrypter struct { // NewOCFBDecrypter returns a Stream which decrypts data with OpenPGP's cipher // feedback mode using the given Block. Prefix must be the first blockSize + 2 // bytes of the ciphertext, where blockSize is the Block's block size. If an -// incorrect key is detected then nil is returned. -func NewOCFBDecrypter(block Block, prefix []byte) Stream { +// incorrect key is detected then nil is returned. Resync determines if the +// "resynchronization step" from RFC 4880, 13.9 step 7 is performed. Different +// parts of OpenPGP vary on this point. +func NewOCFBDecrypter(block Block, prefix []byte, resync OCFBResyncOption) Stream { blockSize := block.BlockSize() if len(prefix) != blockSize+2 { return nil @@ -93,7 +111,13 @@ func NewOCFBDecrypter(block Block, prefix []byte) Stream { return nil } - block.Encrypt(x.fre, prefix[2:]) + if resync { + block.Encrypt(x.fre, prefix[2:]) + } else { + x.fre[0] = prefix[blockSize] + x.fre[1] = prefix[blockSize+1] + x.outUsed = 2 + } return x } diff --git a/src/pkg/crypto/cipher/ocfb_test.go b/src/pkg/crypto/cipher/ocfb_test.go index 289bb7c91e..7aae27bec9 100644 --- a/src/pkg/crypto/cipher/ocfb_test.go +++ b/src/pkg/crypto/cipher/ocfb_test.go @@ -11,29 +11,34 @@ import ( "testing" ) -func TestOCFB(t *testing.T) { +func testOCFB(t *testing.T, resync OCFBResyncOption) { block, err := aes.NewCipher(commonKey128) if err != nil { t.Error(err) return } - plaintext := []byte("this is the plaintext") + plaintext := []byte("this is the plaintext, which is long enough to span several blocks.") randData := make([]byte, block.BlockSize()) rand.Reader.Read(randData) - ocfb, prefix := NewOCFBEncrypter(block, randData) + ocfb, prefix := NewOCFBEncrypter(block, randData, resync) ciphertext := make([]byte, len(plaintext)) ocfb.XORKeyStream(ciphertext, plaintext) - ocfbdec := NewOCFBDecrypter(block, prefix) + ocfbdec := NewOCFBDecrypter(block, prefix, resync) if ocfbdec == nil { - t.Error("NewOCFBDecrypter failed") + t.Error("NewOCFBDecrypter failed (resync: %t)", resync) return } plaintextCopy := make([]byte, len(plaintext)) ocfbdec.XORKeyStream(plaintextCopy, ciphertext) if !bytes.Equal(plaintextCopy, plaintext) { - t.Errorf("got: %x, want: %x", plaintextCopy, plaintext) + t.Errorf("got: %x, want: %x (resync: %t)", plaintextCopy, plaintext, resync) } } + +func TestOCFB(t *testing.T) { + testOCFB(t, OCFBNoResync) + testOCFB(t, OCFBResync) +} -- 2.50.0