@@ -106,6 +106,8 @@ func (p PrivateKey) Equal(x crypto.PrivateKey) bool {
106
106
//
107
107
// For password-protected private keys refer to [EncryptKey].
108
108
func (p PrivateKey ) MarshalText () ([]byte , error ) {
109
+ // A non-encrypted private key has the same format as an encrypted one.
110
+ // However, the salt, and auth. tag are set to all zero.
109
111
var b [privateKeySize ]byte
110
112
111
113
binary .LittleEndian .PutUint16 (b [:], EdDSA )
@@ -115,6 +117,8 @@ func (p PrivateKey) MarshalText() ([]byte, error) {
115
117
binary .LittleEndian .PutUint64 (b [54 :], p .id )
116
118
copy (b [62 :], p .bytes [:])
117
119
120
+ // It seems odd that the comment says: "encrypted secret key".
121
+ // However, the original C implementation behaves like this.
118
122
const comment = "untrusted comment: minisign encrypted secret key\n "
119
123
encodedBytes := make ([]byte , len (comment )+ base64 .StdEncoding .EncodedLen (len (b )))
120
124
copy (encodedBytes , []byte (comment ))
@@ -140,7 +144,7 @@ func (p *PrivateKey) UnmarshalText(text []byte) error {
140
144
}
141
145
142
146
var (
143
- empty [32 ]byte
147
+ empty [32 ]byte // For checking that the salt/tag are empty
144
148
145
149
kType = binary .LittleEndian .Uint16 (b )
146
150
kdf = binary .LittleEndian .Uint16 (b [2 :])
@@ -149,7 +153,7 @@ func (p *PrivateKey) UnmarshalText(text []byte) error {
149
153
scryptOps = binary .LittleEndian .Uint64 (b [38 :])
150
154
scryptMem = binary .LittleEndian .Uint64 (b [46 :])
151
155
key = b [54 :126 ]
152
- checksum = b [126 :privateKeySize ]
156
+ tag = b [126 :privateKeySize ]
153
157
)
154
158
if kType != EdDSA {
155
159
return fmt .Errorf ("minisign: invalid private key: invalid key type '%d'" , kType )
@@ -163,7 +167,7 @@ func (p *PrivateKey) UnmarshalText(text []byte) error {
163
167
if hType != algorithmBlake2b {
164
168
return fmt .Errorf ("minisign: invalid private key: invalid hash type '%d'" , hType )
165
169
}
166
- if ! bytes .Equal (salt [:] , empty [:]) {
170
+ if ! bytes .Equal (salt , empty [:]) {
167
171
return errors .New ("minisign: invalid private key: salt is not empty" )
168
172
}
169
173
if scryptOps != 0 {
@@ -172,11 +176,11 @@ func (p *PrivateKey) UnmarshalText(text []byte) error {
172
176
if scryptMem != 0 {
173
177
return errors .New ("minisign: invalid private key: scrypt mem parameter is not zero" )
174
178
}
175
- if ! bytes .Equal (checksum , empty [:]) {
179
+ if ! bytes .Equal (tag , empty [:]) {
176
180
return errors .New ("minisign: invalid private key: salt is not empty" )
177
181
}
178
182
179
- p .id = binary .LittleEndian .Uint64 (key [: 8 ] )
183
+ p .id = binary .LittleEndian .Uint64 (key )
180
184
copy (p .bytes [:], key [8 :])
181
185
return nil
182
186
}
@@ -235,10 +239,7 @@ func IsEncrypted(privateKey []byte) bool {
235
239
}
236
240
bytes = bytes [:n ]
237
241
238
- if len (bytes ) != privateKeySize {
239
- return false
240
- }
241
- return binary .LittleEndian .Uint16 (bytes [2 :4 ]) == algorithmScrypt
242
+ return len (bytes ) >= 4 && binary .LittleEndian .Uint16 (bytes [2 :]) == algorithmScrypt
242
243
}
243
244
244
245
var errDecrypt = errors .New ("minisign: decryption failed" )
@@ -247,47 +248,50 @@ var errDecrypt = errors.New("minisign: decryption failed")
247
248
// the given password.
248
249
func DecryptKey (password string , privateKey []byte ) (PrivateKey , error ) {
249
250
privateKey = trimUntrustedComment (privateKey )
250
- bytes := make ([]byte , base64 .StdEncoding .DecodedLen (len (privateKey )))
251
- n , err := base64 .StdEncoding .Decode (bytes , privateKey )
251
+ b := make ([]byte , base64 .StdEncoding .DecodedLen (len (privateKey )))
252
+ n , err := base64 .StdEncoding .Decode (b , privateKey )
252
253
if err != nil {
253
254
return PrivateKey {}, err
254
255
}
255
- bytes = bytes [:n ]
256
+ b = b [:n ]
256
257
257
- if len (bytes ) != privateKeySize {
258
+ if len (b ) != privateKeySize {
258
259
return PrivateKey {}, errDecrypt
259
260
}
260
- if a := binary .LittleEndian .Uint16 (bytes [:2 ]); a != EdDSA {
261
+ var (
262
+ kType = binary .LittleEndian .Uint16 (b )
263
+ kdf = binary .LittleEndian .Uint16 (b [2 :])
264
+ hType = binary .LittleEndian .Uint16 (b [4 :])
265
+ salt = b [6 :38 ]
266
+ scryptOps = binary .LittleEndian .Uint64 (b [38 :])
267
+ scryptMem = binary .LittleEndian .Uint64 (b [46 :])
268
+ ciphertext = b [54 :]
269
+ )
270
+ if kType != EdDSA {
261
271
return PrivateKey {}, errDecrypt
262
272
}
263
- if a := binary . LittleEndian . Uint16 ( bytes [ 2 : 4 ]); a != algorithmScrypt {
273
+ if kdf != algorithmScrypt {
264
274
return PrivateKey {}, errDecrypt
265
275
}
266
- if a := binary . LittleEndian . Uint16 ( bytes [ 4 : 6 ]); a != algorithmBlake2b {
276
+ if hType != algorithmBlake2b {
267
277
return PrivateKey {}, errDecrypt
268
278
}
269
-
270
- var (
271
- scryptOps = binary .LittleEndian .Uint64 (bytes [38 :46 ])
272
- scryptMem = binary .LittleEndian .Uint64 (bytes [46 :54 ])
273
- )
274
279
if scryptOps > scryptOpsLimit {
275
280
return PrivateKey {}, errDecrypt
276
281
}
277
282
if scryptMem > scryptMemLimit {
278
283
return PrivateKey {}, errDecrypt
279
284
}
280
- var salt [32 ]byte
281
- copy (salt [:], bytes [6 :38 ])
282
- privateKeyBytes , err := decryptKey (password , salt [:], scryptOps , scryptMem , bytes [54 :])
285
+
286
+ plaintext , err := decryptKey (password , salt , scryptOps , scryptMem , ciphertext )
283
287
if err != nil {
284
288
return PrivateKey {}, err
285
289
}
286
290
287
291
key := PrivateKey {
288
- id : binary .LittleEndian .Uint64 (privateKeyBytes [: 8 ] ),
292
+ id : binary .LittleEndian .Uint64 (plaintext ),
289
293
}
290
- copy (key .bytes [:], privateKeyBytes [8 :])
294
+ copy (key .bytes [:], plaintext [8 :])
291
295
return key , nil
292
296
}
293
297
@@ -368,7 +372,7 @@ func decryptKey(password string, salt []byte, ops, mem uint64, ciphertext []byte
368
372
binary .LittleEndian .PutUint16 (message [:2 ], EdDSA )
369
373
copy (message [2 :], privateKeyBytes )
370
374
371
- if sum := blake2b .Sum256 (message [:]); subtle .ConstantTimeCompare (sum [:], checksum [:] ) != 1 {
375
+ if sum := blake2b .Sum256 (message [:]); subtle .ConstantTimeCompare (sum [:], checksum ) != 1 {
372
376
return nil , errDecrypt
373
377
}
374
378
return privateKeyBytes , nil
0 commit comments