main
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}