main
Raw Download raw file
  1// Copyright 2010 The Go Authors. All rights reserved.
  2// Use of this source code is governed by a BSD-style
  3// license that can be found in the LICENSE file.
  4
  5// OpenPGP CFB Mode. http://tools.ietf.org/html/rfc4880#section-13.9
  6
  7package packet
  8
  9import (
 10	"crypto/cipher"
 11)
 12
 13type ocfbEncrypter struct {
 14	b       cipher.Block
 15	fre     []byte
 16	outUsed int
 17}
 18
 19// An OCFBResyncOption determines if the "resynchronization step" of OCFB is
 20// performed.
 21type OCFBResyncOption bool
 22
 23const (
 24	OCFBResync   OCFBResyncOption = true
 25	OCFBNoResync OCFBResyncOption = false
 26)
 27
 28// NewOCFBEncrypter returns a cipher.Stream which encrypts data with OpenPGP's
 29// cipher feedback mode using the given cipher.Block, and an initial amount of
 30// ciphertext.  randData must be random bytes and be the same length as the
 31// cipher.Block's block size. Resync determines if the "resynchronization step"
 32// from RFC 4880, 13.9 step 7 is performed. Different parts of OpenPGP vary on
 33// this point.
 34func NewOCFBEncrypter(block cipher.Block, randData []byte, resync OCFBResyncOption) (cipher.Stream, []byte) {
 35	blockSize := block.BlockSize()
 36	if len(randData) != blockSize {
 37		return nil, nil
 38	}
 39
 40	x := &ocfbEncrypter{
 41		b:       block,
 42		fre:     make([]byte, blockSize),
 43		outUsed: 0,
 44	}
 45	prefix := make([]byte, blockSize+2)
 46
 47	block.Encrypt(x.fre, x.fre)
 48	for i := 0; i < blockSize; i++ {
 49		prefix[i] = randData[i] ^ x.fre[i]
 50	}
 51
 52	block.Encrypt(x.fre, prefix[:blockSize])
 53	prefix[blockSize] = x.fre[0] ^ randData[blockSize-2]
 54	prefix[blockSize+1] = x.fre[1] ^ randData[blockSize-1]
 55
 56	if resync {
 57		block.Encrypt(x.fre, prefix[2:])
 58	} else {
 59		x.fre[0] = prefix[blockSize]
 60		x.fre[1] = prefix[blockSize+1]
 61		x.outUsed = 2
 62	}
 63	return x, prefix
 64}
 65
 66func (x *ocfbEncrypter) XORKeyStream(dst, src []byte) {
 67	for i := 0; i < len(src); i++ {
 68		if x.outUsed == len(x.fre) {
 69			x.b.Encrypt(x.fre, x.fre)
 70			x.outUsed = 0
 71		}
 72
 73		x.fre[x.outUsed] ^= src[i]
 74		dst[i] = x.fre[x.outUsed]
 75		x.outUsed++
 76	}
 77}
 78
 79type ocfbDecrypter struct {
 80	b       cipher.Block
 81	fre     []byte
 82	outUsed int
 83}
 84
 85// NewOCFBDecrypter returns a cipher.Stream which decrypts data with OpenPGP's
 86// cipher feedback mode using the given cipher.Block. Prefix must be the first
 87// blockSize + 2 bytes of the ciphertext, where blockSize is the cipher.Block's
 88// block size. On successful exit, blockSize+2 bytes of decrypted data are written into
 89// prefix. Resync determines if the "resynchronization step" from RFC 4880,
 90// 13.9 step 7 is performed. Different parts of OpenPGP vary on this point.
 91func NewOCFBDecrypter(block cipher.Block, prefix []byte, resync OCFBResyncOption) cipher.Stream {
 92	blockSize := block.BlockSize()
 93	if len(prefix) != blockSize+2 {
 94		return nil
 95	}
 96
 97	x := &ocfbDecrypter{
 98		b:       block,
 99		fre:     make([]byte, blockSize),
100		outUsed: 0,
101	}
102	prefixCopy := make([]byte, len(prefix))
103	copy(prefixCopy, prefix)
104
105	block.Encrypt(x.fre, x.fre)
106	for i := 0; i < blockSize; i++ {
107		prefixCopy[i] ^= x.fre[i]
108	}
109
110	block.Encrypt(x.fre, prefix[:blockSize])
111	prefixCopy[blockSize] ^= x.fre[0]
112	prefixCopy[blockSize+1] ^= x.fre[1]
113
114	if resync {
115		block.Encrypt(x.fre, prefix[2:])
116	} else {
117		x.fre[0] = prefix[blockSize]
118		x.fre[1] = prefix[blockSize+1]
119		x.outUsed = 2
120	}
121	copy(prefix, prefixCopy)
122	return x
123}
124
125func (x *ocfbDecrypter) XORKeyStream(dst, src []byte) {
126	for i := 0; i < len(src); i++ {
127		if x.outUsed == len(x.fre) {
128			x.b.Encrypt(x.fre, x.fre)
129			x.outUsed = 0
130		}
131
132		c := src[i]
133		dst[i] = x.fre[x.outUsed] ^ src[i]
134		x.fre[x.outUsed] = c
135		x.outUsed++
136	}
137}