| // 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 cipher |
| |
| type ocfbEncrypter struct { |
| b 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 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. 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 |
| } |
| |
| 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 Block |
| fre []byte |
| outUsed int |
| } |
| |
| // 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. 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 |
| } |
| |
| 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 |
| } |
| 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++ |
| } |
| } |