Commit fc5c1f0a authored by Adam Langley's avatar Adam Langley

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
parent 31ccf196
...@@ -12,11 +12,21 @@ type ocfbEncrypter struct { ...@@ -12,11 +12,21 @@ type ocfbEncrypter struct {
outUsed int 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 // NewOCFBEncrypter returns a Stream which encrypts data with OpenPGP's cipher
// feedback mode using the given Block, and an initial amount of ciphertext. // 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 // randData must be random bytes and be the same length as the Block's block
// size. // size. Resync determines if the "resynchronization step" from RFC 4880, 13.9
func NewOCFBEncrypter(block Block, randData []byte) (Stream, []byte) { // 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() blockSize := block.BlockSize()
if len(randData) != blockSize { if len(randData) != blockSize {
return nil, nil return nil, nil
...@@ -38,7 +48,13 @@ func NewOCFBEncrypter(block Block, randData []byte) (Stream, []byte) { ...@@ -38,7 +48,13 @@ func NewOCFBEncrypter(block Block, randData []byte) (Stream, []byte) {
prefix[blockSize] = x.fre[0] ^ randData[blockSize-2] prefix[blockSize] = x.fre[0] ^ randData[blockSize-2]
prefix[blockSize+1] = x.fre[1] ^ randData[blockSize-1] prefix[blockSize+1] = x.fre[1] ^ randData[blockSize-1]
if resync {
block.Encrypt(x.fre, prefix[2:]) block.Encrypt(x.fre, prefix[2:])
} else {
x.fre[0] = prefix[blockSize]
x.fre[1] = prefix[blockSize+1]
x.outUsed = 2
}
return x, prefix return x, prefix
} }
...@@ -64,8 +80,10 @@ type ocfbDecrypter struct { ...@@ -64,8 +80,10 @@ type ocfbDecrypter struct {
// NewOCFBDecrypter returns a Stream which decrypts data with OpenPGP's cipher // NewOCFBDecrypter returns a Stream which decrypts data with OpenPGP's cipher
// feedback mode using the given Block. Prefix must be the first blockSize + 2 // 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 // bytes of the ciphertext, where blockSize is the Block's block size. If an
// incorrect key is detected then nil is returned. // incorrect key is detected then nil is returned. Resync determines if the
func NewOCFBDecrypter(block Block, prefix []byte) Stream { // "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() blockSize := block.BlockSize()
if len(prefix) != blockSize+2 { if len(prefix) != blockSize+2 {
return nil return nil
...@@ -93,7 +111,13 @@ func NewOCFBDecrypter(block Block, prefix []byte) Stream { ...@@ -93,7 +111,13 @@ func NewOCFBDecrypter(block Block, prefix []byte) Stream {
return nil return nil
} }
if resync {
block.Encrypt(x.fre, prefix[2:]) block.Encrypt(x.fre, prefix[2:])
} else {
x.fre[0] = prefix[blockSize]
x.fre[1] = prefix[blockSize+1]
x.outUsed = 2
}
return x return x
} }
......
...@@ -11,29 +11,34 @@ import ( ...@@ -11,29 +11,34 @@ import (
"testing" "testing"
) )
func TestOCFB(t *testing.T) { func testOCFB(t *testing.T, resync OCFBResyncOption) {
block, err := aes.NewCipher(commonKey128) block, err := aes.NewCipher(commonKey128)
if err != nil { if err != nil {
t.Error(err) t.Error(err)
return 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()) randData := make([]byte, block.BlockSize())
rand.Reader.Read(randData) rand.Reader.Read(randData)
ocfb, prefix := NewOCFBEncrypter(block, randData) ocfb, prefix := NewOCFBEncrypter(block, randData, resync)
ciphertext := make([]byte, len(plaintext)) ciphertext := make([]byte, len(plaintext))
ocfb.XORKeyStream(ciphertext, plaintext) ocfb.XORKeyStream(ciphertext, plaintext)
ocfbdec := NewOCFBDecrypter(block, prefix) ocfbdec := NewOCFBDecrypter(block, prefix, resync)
if ocfbdec == nil { if ocfbdec == nil {
t.Error("NewOCFBDecrypter failed") t.Error("NewOCFBDecrypter failed (resync: %t)", resync)
return return
} }
plaintextCopy := make([]byte, len(plaintext)) plaintextCopy := make([]byte, len(plaintext))
ocfbdec.XORKeyStream(plaintextCopy, ciphertext) ocfbdec.XORKeyStream(plaintextCopy, ciphertext)
if !bytes.Equal(plaintextCopy, plaintext) { 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)
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment