| // 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++ |
| } |
| } |