فهرست منبع

openpgp/packet: move OCFB code here.

The code has been moved from crypto/cipher in CL 5629044.

R=rsc
CC=golang-dev
https://golang.org/cl/5627045
Adam Langley 14 سال پیش
والد
کامیت
a1e605a210
3فایلهای تغییر یافته به همراه193 افزوده شده و 4 حذف شده
  1. 143 0
      openpgp/packet/ocfb.go
  2. 46 0
      openpgp/packet/ocfb_test.go
  3. 4 4
      openpgp/packet/symmetrically_encrypted.go

+ 143 - 0
openpgp/packet/ocfb.go

@@ -0,0 +1,143 @@
+// 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.
+
+// OpenPGP CFB Mode. http://tools.ietf.org/html/rfc4880#section-13.9
+
+package packet
+
+import (
+	"crypto/cipher"
+)
+
+type ocfbEncrypter struct {
+	b       cipher.Block
+	fre     []byte
+	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 cipher.Stream which encrypts data with OpenPGP's
+// cipher feedback mode using the given cipher.Block, and an initial amount of
+// ciphertext.  randData must be random bytes and be the same length as the
+// cipher.Block's block 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 cipher.Block, randData []byte, resync OCFBResyncOption) (cipher.Stream, []byte) {
+	blockSize := block.BlockSize()
+	if len(randData) != blockSize {
+		return nil, nil
+	}
+
+	x := &ocfbEncrypter{
+		b:       block,
+		fre:     make([]byte, blockSize),
+		outUsed: 0,
+	}
+	prefix := make([]byte, blockSize+2)
+
+	block.Encrypt(x.fre, x.fre)
+	for i := 0; i < blockSize; i++ {
+		prefix[i] = randData[i] ^ x.fre[i]
+	}
+
+	block.Encrypt(x.fre, prefix[:blockSize])
+	prefix[blockSize] = x.fre[0] ^ randData[blockSize-2]
+	prefix[blockSize+1] = x.fre[1] ^ randData[blockSize-1]
+
+	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
+}
+
+func (x *ocfbEncrypter) XORKeyStream(dst, src []byte) {
+	for i := 0; i < len(src); i++ {
+		if x.outUsed == len(x.fre) {
+			x.b.Encrypt(x.fre, x.fre)
+			x.outUsed = 0
+		}
+
+		x.fre[x.outUsed] ^= src[i]
+		dst[i] = x.fre[x.outUsed]
+		x.outUsed++
+	}
+}
+
+type ocfbDecrypter struct {
+	b       cipher.Block
+	fre     []byte
+	outUsed int
+}
+
+// NewOCFBDecrypter returns a cipher.Stream which decrypts data with OpenPGP's
+// cipher feedback mode using the given cipher.Block. Prefix must be the first
+// blockSize + 2 bytes of the ciphertext, where blockSize is the cipher.Block's
+// block size. If an incorrect key is detected then nil is returned. On
+// successful exit, blockSize+2 bytes of decrypted data are written into
+// prefix. 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 cipher.Block, prefix []byte, resync OCFBResyncOption) cipher.Stream {
+	blockSize := block.BlockSize()
+	if len(prefix) != blockSize+2 {
+		return nil
+	}
+
+	x := &ocfbDecrypter{
+		b:       block,
+		fre:     make([]byte, blockSize),
+		outUsed: 0,
+	}
+	prefixCopy := make([]byte, len(prefix))
+	copy(prefixCopy, prefix)
+
+	block.Encrypt(x.fre, x.fre)
+	for i := 0; i < blockSize; i++ {
+		prefixCopy[i] ^= x.fre[i]
+	}
+
+	block.Encrypt(x.fre, prefix[:blockSize])
+	prefixCopy[blockSize] ^= x.fre[0]
+	prefixCopy[blockSize+1] ^= x.fre[1]
+
+	if prefixCopy[blockSize-2] != prefixCopy[blockSize] ||
+		prefixCopy[blockSize-1] != prefixCopy[blockSize+1] {
+		return nil
+	}
+
+	if resync {
+		block.Encrypt(x.fre, prefix[2:])
+	} else {
+		x.fre[0] = prefix[blockSize]
+		x.fre[1] = prefix[blockSize+1]
+		x.outUsed = 2
+	}
+	copy(prefix, prefixCopy)
+	return x
+}
+
+func (x *ocfbDecrypter) XORKeyStream(dst, src []byte) {
+	for i := 0; i < len(src); i++ {
+		if x.outUsed == len(x.fre) {
+			x.b.Encrypt(x.fre, x.fre)
+			x.outUsed = 0
+		}
+
+		c := src[i]
+		dst[i] = x.fre[x.outUsed] ^ src[i]
+		x.fre[x.outUsed] = c
+		x.outUsed++
+	}
+}

+ 46 - 0
openpgp/packet/ocfb_test.go

@@ -0,0 +1,46 @@
+// 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 packet
+
+import (
+	"bytes"
+	"crypto/aes"
+	"crypto/rand"
+	"testing"
+)
+
+var commonKey128 = []byte{0x2b, 0x7e, 0x15, 0x16, 0x28, 0xae, 0xd2, 0xa6, 0xab, 0xf7, 0x15, 0x88, 0x09, 0xcf, 0x4f, 0x3c}
+
+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, which is long enough to span several blocks.")
+	randData := make([]byte, block.BlockSize())
+	rand.Reader.Read(randData)
+	ocfb, prefix := NewOCFBEncrypter(block, randData, resync)
+	ciphertext := make([]byte, len(plaintext))
+	ocfb.XORKeyStream(ciphertext, plaintext)
+
+	ocfbdec := NewOCFBDecrypter(block, prefix, resync)
+	if ocfbdec == nil {
+		t.Errorf("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 (resync: %t)", plaintextCopy, plaintext, resync)
+	}
+}
+
+func TestOCFB(t *testing.T) {
+	testOCFB(t, OCFBNoResync)
+	testOCFB(t, OCFBResync)
+}

+ 4 - 4
openpgp/packet/symmetrically_encrypted.go

@@ -63,13 +63,13 @@ func (se *SymmetricallyEncrypted) Decrypt(c CipherFunction, key []byte) (io.Read
 		return nil, errors.InvalidArgumentError("can't try ciphers with different block lengths")
 	}
 
-	ocfbResync := cipher.OCFBResync
+	ocfbResync := OCFBResync
 	if se.MDC {
 		// MDC packets use a different form of OCFB mode.
-		ocfbResync = cipher.OCFBNoResync
+		ocfbResync = OCFBNoResync
 	}
 
-	s := cipher.NewOCFBDecrypter(c.new(key), se.prefix, ocfbResync)
+	s := NewOCFBDecrypter(c.new(key), se.prefix, ocfbResync)
 	if s == nil {
 		return nil, errors.ErrKeyIncorrect
 	}
@@ -274,7 +274,7 @@ func SerializeSymmetricallyEncrypted(w io.Writer, rand io.Reader, c CipherFuncti
 	if err != nil {
 		return
 	}
-	s, prefix := cipher.NewOCFBEncrypter(block, iv, cipher.OCFBNoResync)
+	s, prefix := NewOCFBEncrypter(block, iv, OCFBNoResync)
 	_, err = ciphertext.Write(prefix)
 	if err != nil {
 		return