You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
144 lines
3.6 KiB
144 lines
3.6 KiB
8 years ago
|
// 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++
|
||
|
}
|
||
|
}
|