]>
Commit | Line | Data |
---|---|---|
c680a8e1 RS |
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 | ||
7 | package packet | |
8 | ||
9 | import ( | |
10 | "crypto/cipher" | |
11 | ) | |
12 | ||
13 | type 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. | |
21 | type OCFBResyncOption bool | |
22 | ||
23 | const ( | |
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. | |
34 | func 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 | ||
66 | func (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 | ||
79 | type 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. If an incorrect key is detected then nil is returned. On | |
89 | // successful exit, blockSize+2 bytes of decrypted data are written into | |
90 | // prefix. Resync determines if the "resynchronization step" from RFC 4880, | |
91 | // 13.9 step 7 is performed. Different parts of OpenPGP vary on this point. | |
92 | func NewOCFBDecrypter(block cipher.Block, prefix []byte, resync OCFBResyncOption) cipher.Stream { | |
93 | blockSize := block.BlockSize() | |
94 | if len(prefix) != blockSize+2 { | |
95 | return nil | |
96 | } | |
97 | ||
98 | x := &ocfbDecrypter{ | |
99 | b: block, | |
100 | fre: make([]byte, blockSize), | |
101 | outUsed: 0, | |
102 | } | |
103 | prefixCopy := make([]byte, len(prefix)) | |
104 | copy(prefixCopy, prefix) | |
105 | ||
106 | block.Encrypt(x.fre, x.fre) | |
107 | for i := 0; i < blockSize; i++ { | |
108 | prefixCopy[i] ^= x.fre[i] | |
109 | } | |
110 | ||
111 | block.Encrypt(x.fre, prefix[:blockSize]) | |
112 | prefixCopy[blockSize] ^= x.fre[0] | |
113 | prefixCopy[blockSize+1] ^= x.fre[1] | |
114 | ||
115 | if prefixCopy[blockSize-2] != prefixCopy[blockSize] || | |
116 | prefixCopy[blockSize-1] != prefixCopy[blockSize+1] { | |
117 | return nil | |
118 | } | |
119 | ||
120 | if resync { | |
121 | block.Encrypt(x.fre, prefix[2:]) | |
122 | } else { | |
123 | x.fre[0] = prefix[blockSize] | |
124 | x.fre[1] = prefix[blockSize+1] | |
125 | x.outUsed = 2 | |
126 | } | |
127 | copy(prefix, prefixCopy) | |
128 | return x | |
129 | } | |
130 | ||
131 | func (x *ocfbDecrypter) XORKeyStream(dst, src []byte) { | |
132 | for i := 0; i < len(src); i++ { | |
133 | if x.outUsed == len(x.fre) { | |
134 | x.b.Encrypt(x.fre, x.fre) | |
135 | x.outUsed = 0 | |
136 | } | |
137 | ||
138 | c := src[i] | |
139 | dst[i] = x.fre[x.outUsed] ^ src[i] | |
140 | x.fre[x.outUsed] = c | |
141 | x.outUsed++ | |
142 | } | |
143 | } |