@@ -19,7 +19,8 @@ type SessionKey struct {
19
19
// Algo defines the symmetric encryption algorithm used with this key.
20
20
// Only present if the key was not parsed from a v6 packet.
21
21
Algo string
22
- // v6 is a flag to indicate that the session key was parsed from a v6 PKESK or SKESK packet
22
+ // v6 is a flag to indicate that the session key is capable
23
+ // to be used in v6 PKESK or SKESK, and SEIPDv2 packets
23
24
v6 bool
24
25
}
25
26
@@ -66,8 +67,8 @@ func (cr checkReader) Read(buf []byte) (int, error) {
66
67
// with this SessionKey.
67
68
// Not supported in go-mobile clients use sk.GetCipherFuncInt instead.
68
69
func (sk * SessionKey ) GetCipherFunc () (packet.CipherFunction , error ) {
69
- if sk .v6 {
70
- return 0 , errors .New ("gopenpgp: no cipher function available for a v6 session key" )
70
+ if ! sk .hasAlgorithm () {
71
+ return 0 , errors .New ("gopenpgp: no cipher function available for the session key" )
71
72
}
72
73
cf , ok := symKeyAlgos [sk .Algo ]
73
74
if ! ok {
@@ -89,6 +90,11 @@ func (sk *SessionKey) GetBase64Key() string {
89
90
return base64 .StdEncoding .EncodeToString (sk .Key )
90
91
}
91
92
93
+ // IsV6 indicates if the session key can be used with SEIPDv2, PKESKv6/SKESKv6.
94
+ func (sk * SessionKey ) IsV6 () bool {
95
+ return sk .v6
96
+ }
97
+
92
98
// RandomToken generates a random token with the specified key size.
93
99
func RandomToken (size int ) ([]byte , error ) {
94
100
config := & packet.Config {DefaultCipher : packet .CipherAES256 }
@@ -118,13 +124,61 @@ func GenerateSessionKeyAlgo(algo string) (sk *SessionKey, err error) {
118
124
return sk , nil
119
125
}
120
126
121
- // GenerateSessionKey generates a random key for the default cipher.
122
- func generateSessionKey (config * packet.Config ) (* SessionKey , error ) {
123
- cf , ok := algosToSymKey [config .DefaultCipher ]
127
+ // GenerateSessionKey generates a random key.
128
+ // Considers the cipher and aead preferences in recipients and hiddenRecipients for
129
+ // session key generation.
130
+ func generateSessionKey (config * packet.Config , recipients * KeyRing , hiddenRecipients * KeyRing ) (* SessionKey , error ) {
131
+ candidateCiphers := []uint8 {
132
+ uint8 (packet .CipherAES256 ),
133
+ uint8 (packet .CipherAES128 ),
134
+ }
135
+
136
+ currentTime := config .Now ()
137
+ aeadSupport := config .AEADConfig != nil
138
+ for _ , e := range append (recipients .getEntities (), hiddenRecipients .getEntities ()... ) {
139
+ primarySelfSignature , _ := e .PrimarySelfSignature (currentTime , config )
140
+ if primarySelfSignature == nil {
141
+ continue
142
+ }
143
+
144
+ if ! primarySelfSignature .SEIPDv2 {
145
+ aeadSupport = false
146
+ }
147
+
148
+ candidateCiphers = intersectPreferences (candidateCiphers , primarySelfSignature .PreferredSymmetric )
149
+ }
150
+
151
+ if len (candidateCiphers ) == 0 {
152
+ candidateCiphers = []uint8 {uint8 (packet .CipherAES128 )}
153
+ }
154
+ cipher := packet .CipherFunction (candidateCiphers [0 ])
155
+
156
+ // If the cipher specified by config is a candidate, we'll use that.
157
+ configuredCipher := config .Cipher ()
158
+ for _ , c := range candidateCiphers {
159
+ cipherFunc := packet .CipherFunction (c )
160
+ if cipherFunc == configuredCipher {
161
+ cipher = cipherFunc
162
+ break
163
+ }
164
+ }
165
+
166
+ algo , ok := algosToSymKey [cipher ]
124
167
if ! ok {
125
168
return nil , errors .New ("gopenpgp: unsupported cipher function" )
126
169
}
127
- return GenerateSessionKeyAlgo (cf )
170
+
171
+ r , err := RandomToken (cipher .KeySize ())
172
+ if err != nil {
173
+ return nil , err
174
+ }
175
+
176
+ sk := & SessionKey {
177
+ Key : r ,
178
+ Algo : algo ,
179
+ v6 : aeadSupport ,
180
+ }
181
+ return sk , nil
128
182
}
129
183
130
184
// NewSessionKeyFromToken creates a SessionKey struct with the given token and algorithm.
@@ -136,6 +190,16 @@ func NewSessionKeyFromToken(token []byte, algo string) *SessionKey {
136
190
}
137
191
}
138
192
193
+ // NewSessionKeyFromTokenWithAead creates a SessionKey struct with the given token and algorithm,
194
+ // If aead is set to true, the key is used with v6 PKESK or SKESK, and SEIPDv2 packets.
195
+ func NewSessionKeyFromTokenWithAead (token []byte , algo string , aead bool ) * SessionKey {
196
+ return & SessionKey {
197
+ Key : clone (token ),
198
+ Algo : algo ,
199
+ v6 : aead ,
200
+ }
201
+ }
202
+
139
203
func newSessionKeyFromEncrypted (ek * packet.EncryptedKey ) (* SessionKey , error ) {
140
204
var algo string
141
205
for k , v := range symKeyAlgos {
@@ -178,6 +242,10 @@ func (sk *SessionKey) checkSize() error {
178
242
return nil
179
243
}
180
244
245
+ func (sk * SessionKey ) hasAlgorithm () bool {
246
+ return sk .Algo != ""
247
+ }
248
+
181
249
func getAlgo (cipher packet.CipherFunction ) string {
182
250
algo := ""
183
251
for k , v := range symKeyAlgos {
@@ -188,3 +256,17 @@ func getAlgo(cipher packet.CipherFunction) string {
188
256
}
189
257
return algo
190
258
}
259
+
260
+ func intersectPreferences (a []uint8 , b []uint8 ) (intersection []uint8 ) {
261
+ var currentIndex int
262
+ for _ , valueFirst := range a {
263
+ for _ , valueSecond := range b {
264
+ if valueFirst == valueSecond {
265
+ a [currentIndex ] = valueFirst
266
+ currentIndex ++
267
+ break
268
+ }
269
+ }
270
+ }
271
+ return a [:currentIndex ]
272
+ }
0 commit comments