1// Copyright 2015 Keybase, Inc. All rights reserved. Use of
2// this source code is governed by the included BSD license.
3
4package libkb
5
6import (
7	"bytes"
8	"crypto/hmac"
9	"crypto/rand"
10	"crypto/sha256"
11	"encoding/base64"
12	"fmt"
13	"io"
14
15	"github.com/keybase/client/go/kbcrypto"
16	keybase1 "github.com/keybase/client/go/protocol/keybase1"
17	"github.com/keybase/go-crypto/ed25519"
18	"golang.org/x/crypto/nacl/box"
19)
20
21type NaclEncryptionInfo struct {
22	Ciphertext     []byte            `codec:"ciphertext"`
23	EncryptionType kbcrypto.AlgoType `codec:"enc_type"`
24	Nonce          []byte            `codec:"nonce"`
25	Receiver       []byte            `codec:"receiver_key"`
26	Sender         []byte            `codec:"sender_key"`
27}
28
29const NaclDHKeysize = 32
30
31// TODO: Ideally, ed25519 would expose how many random bytes it needs.
32const NaclSigningKeySecretSize = 32
33
34// TODO: Ideally, box would expose how many random bytes it needs.
35const NaclDHKeySecretSize = 32
36
37// Todo: Ideally, box would specify nonce size
38const NaclDHNonceSize = 24
39
40const NaclSecretBoxKeySize = 32
41
42type NaclSigningKeyPair struct {
43	Public  kbcrypto.NaclSigningKeyPublic
44	Private *kbcrypto.NaclSigningKeyPrivate
45}
46
47var _ GenericKey = NaclSigningKeyPair{}
48
49type NaclDHKeyPublic [NaclDHKeysize]byte
50type NaclDHKeyPrivate [NaclDHKeysize]byte
51
52type NaclDHKeyPair struct {
53	Public  NaclDHKeyPublic
54	Private *NaclDHKeyPrivate
55}
56
57func (k NaclDHKeyPair) Clone() (ret NaclDHKeyPair) {
58	ret.Public = k.Public
59	if k.Private != nil {
60		tmp := *k.Private
61		ret.Private = &tmp
62	}
63	return ret
64}
65
66var _ GenericKey = NaclDHKeyPair{}
67
68type NaclSecretBoxKey [NaclSecretBoxKeySize]byte
69
70func (k NaclSecretBoxKey) IsZero() bool {
71	var z NaclSecretBoxKey
72	return hmac.Equal(k[:], z[:])
73}
74
75func importNaclHex(s string, typ byte, bodyLen int) (ret []byte, err error) {
76	kid := keybase1.KIDFromString(s)
77	return importNaclKid(kid.ToBytes(), typ, bodyLen)
78}
79
80func importNaclKid(bkid []byte, typ byte, bodyLen int) (ret []byte, err error) {
81	l := len(bkid)
82	if l != bodyLen+3 {
83		err = kbcrypto.BadKeyError{Msg: fmt.Sprintf("Wrong length; wanted %d, got %d", bodyLen+3, l)}
84		return
85	}
86
87	if bkid[0] != byte(kbcrypto.KeybaseKIDV1) || bkid[l-1] != byte(kbcrypto.IDSuffixKID) || bkid[1] != typ {
88		err = kbcrypto.BadKeyError{Msg: "bad header or trailer bytes"}
89		return
90	}
91	ret = bkid[2:(l - 1)]
92	return
93}
94
95func BinaryKIDToRawNaCl(k keybase1.BinaryKID) (ret []byte, err error) {
96	return importNaclKid([]byte(k), byte(kbcrypto.KIDNaclDH), NaclDHKeysize)
97}
98
99func ImportNaclSigningKeyPairFromBytes(pub []byte, priv []byte) (ret NaclSigningKeyPair, err error) {
100	var body []byte
101	if body, err = importNaclKid(pub, byte(kbcrypto.KIDNaclEddsa), ed25519.PublicKeySize); err != nil {
102		return
103	}
104	copy(ret.Public[:], body)
105	if priv == nil {
106	} else if len(priv) != ed25519.PrivateKeySize {
107		err = kbcrypto.BadKeyError{Msg: "Secret key was wrong size"}
108	} else {
109		ret.Private = &kbcrypto.NaclSigningKeyPrivate{}
110		copy(ret.Private[:], priv)
111	}
112	return
113}
114
115func ImportKeypairFromKID(k keybase1.KID) (key GenericKey, err error) {
116	kid := k.ToBytes()
117	l := len(kid)
118	if l < 3 {
119		err = kbcrypto.BadKeyError{Msg: "KID was way too short"}
120		return
121	}
122	if kid[0] != byte(kbcrypto.KeybaseKIDV1) || kid[l-1] != byte(kbcrypto.IDSuffixKID) {
123		err = kbcrypto.BadKeyError{Msg: "bad header or trailer found"}
124		return
125	}
126	raw := kid[2:(l - 1)]
127	switch kid[1] {
128	case byte(kbcrypto.KIDNaclEddsa):
129		if len(raw) != ed25519.PublicKeySize {
130			err = kbcrypto.BadKeyError{Msg: "Bad EdDSA key size"}
131		} else {
132			tmp := NaclSigningKeyPair{}
133			copy(tmp.Public[:], raw)
134			key = tmp
135		}
136	case byte(kbcrypto.KIDNaclDH):
137		if len(raw) != NaclDHKeysize {
138			err = kbcrypto.BadKeyError{Msg: "Bad DH key size"}
139		} else {
140			tmp := NaclDHKeyPair{}
141			copy(tmp.Public[:], raw)
142			key = tmp
143		}
144	default:
145		err = kbcrypto.BadKeyError{Msg: fmt.Sprintf("Bad key prefix: %d", kid[1])}
146	}
147	return
148}
149
150func ImportDHKeypairFromKID(k keybase1.KID) (*NaclDHKeyPair, error) {
151	genericKey, err := ImportKeypairFromKID(k)
152	if err != nil {
153		return nil, err
154	}
155	naclKey, ok := genericKey.(NaclDHKeyPair)
156	if !ok {
157		return nil, fmt.Errorf("expected NaclDHKeyPair, got %T", genericKey)
158	}
159	return &naclKey, nil
160}
161
162func ImportNaclSigningKeyPairFromHex(s string) (ret NaclSigningKeyPair, err error) {
163	var body []byte
164	if body, err = importNaclHex(s, byte(kbcrypto.KIDNaclEddsa), ed25519.PublicKeySize); err != nil {
165		return
166	}
167	copy(ret.Public[:], body)
168	return
169}
170
171func ImportNaclDHKeyPairFromBytes(pub []byte, priv []byte) (ret NaclDHKeyPair, err error) {
172	var body []byte
173	if body, err = importNaclKid(pub, byte(kbcrypto.KIDNaclDH), NaclDHKeysize); err != nil {
174		return
175	}
176	copy(ret.Public[:], body)
177	if priv == nil {
178	} else if len(priv) != NaclDHKeysize {
179		err = kbcrypto.BadKeyError{Msg: "Secret key was wrong size"}
180	} else {
181		ret.Private = &NaclDHKeyPrivate{}
182		copy(ret.Private[:], priv)
183	}
184	return
185}
186
187func ImportNaclDHKeyPairFromHex(s string) (ret NaclDHKeyPair, err error) {
188	var body []byte
189	if body, err = importNaclHex(s, byte(kbcrypto.KIDNaclDH), NaclDHKeysize); err != nil {
190		return
191	}
192	copy(ret.Public[:], body)
193	return
194}
195
196func (k NaclDHKeyPublic) GetKID() keybase1.KID {
197	return k.GetBinaryKID().ToKID()
198}
199
200func (k NaclDHKeyPublic) GetBinaryKID() keybase1.BinaryKID {
201	prefix := []byte{
202		byte(kbcrypto.KeybaseKIDV1),
203		byte(kbcrypto.KIDNaclDH),
204	}
205	suffix := byte(kbcrypto.IDSuffixKID)
206	out := append(prefix, k[:]...)
207	out = append(out, suffix)
208	return keybase1.BinaryKID(out)
209}
210
211func (k NaclDHKeyPair) GetFingerprintP() *PGPFingerprint {
212	return nil
213}
214
215func (k NaclDHKeyPair) GetAlgoType() kbcrypto.AlgoType {
216	return kbcrypto.KIDNaclDH
217}
218
219func (k NaclSigningKeyPair) GetAlgoType() kbcrypto.AlgoType {
220	return kbcrypto.KIDNaclEddsa
221}
222
223func (k NaclSigningKeyPair) GetKID() (ret keybase1.KID) {
224	return k.Public.GetKID()
225}
226
227func (k NaclSigningKeyPair) GetBinaryKID() (ret keybase1.BinaryKID) {
228	return k.Public.GetBinaryKID()
229}
230
231func (k NaclSigningKeyPair) ToShortIDString() string {
232	return k.Public.GetKID().ToShortIDString()
233}
234
235func (k NaclDHKeyPair) ToShortIDString() string {
236	return k.Public.GetKID().ToShortIDString()
237}
238
239func (k NaclSigningKeyPair) VerboseDescription() string {
240	return fmt.Sprintf("255-bit EdDSA signing key (%s)", k.ToShortIDString())
241}
242func (k NaclDHKeyPair) VerboseDescription() string {
243	return fmt.Sprintf("255-bit Curve25519 DH key (%s)", k.ToShortIDString())
244}
245
246func (k NaclSigningKeyPair) GetFingerprintP() *PGPFingerprint {
247	return nil
248}
249
250func (k NaclDHKeyPair) GetKID() keybase1.KID {
251	return k.Public.GetKID()
252}
253func (k NaclDHKeyPair) GetBinaryKID() (ret keybase1.BinaryKID) {
254	return k.Public.GetBinaryKID()
255}
256
257func (k NaclSigningKeyPair) CheckSecretKey() error {
258	if k.Private == nil {
259		return NoSecretKeyError{}
260	}
261	return nil
262}
263
264func (k NaclSigningKeyPair) HasSecretKey() bool {
265	return k.Private != nil
266}
267
268func (k NaclSigningKeyPair) Encode() (string, error) {
269	return k.GetKID().String(), nil
270}
271
272func (k NaclDHKeyPair) Encode() (string, error) {
273	return k.GetKID().String(), nil
274}
275
276func (k NaclDHKeyPair) CheckSecretKey() error {
277	if k.Private == nil {
278		return NoSecretKeyError{}
279	}
280	return nil
281}
282
283func (k NaclDHKeyPair) HasSecretKey() bool {
284	return k.Private != nil
285}
286
287func (k NaclSigningKeyPair) CanSign() bool { return k.Private != nil }
288func (k NaclDHKeyPair) CanSign() bool      { return false }
289
290func (k NaclSigningKeyPair) Sign(msg []byte) (kbcrypto.NaclSigInfo, error) {
291	if k.Private == nil {
292		return kbcrypto.NaclSigInfo{}, NoSecretKeyError{}
293	}
294
295	return k.Private.SignInfoV0(msg, k.Public), nil
296}
297
298func (k NaclSigningKeyPair) SecretSymmetricKey(reason EncryptionReason) (NaclSecretBoxKey, error) {
299	return NaclSecretBoxKey{}, KeyCannotEncryptError{}
300}
301
302const encryptionReasonMinLength = 8
303
304type EncryptionReason string
305
306func (r EncryptionReason) Bytes() []byte {
307	return []byte(r)
308}
309
310func (k NaclSigningKeyPair) SignV2(msg []byte, prefix kbcrypto.SignaturePrefix) (kbcrypto.NaclSigInfo, error) {
311	if k.Private == nil {
312		return kbcrypto.NaclSigInfo{}, NoSecretKeyError{}
313	}
314
315	return k.Private.SignInfoV2(msg, k.Public, prefix)
316}
317
318func (k NaclSigningKeyPair) SignToString(msg []byte) (string, keybase1.SigIDBase, error) {
319	return k.Private.SignToStringV0(msg, k.Public)
320}
321
322func (k NaclSigningKeyPair) VerifyStringAndExtract(ctx VerifyContext, sig string) (msg []byte, id keybase1.SigIDBase, err error) {
323	var keyInSignature *kbcrypto.NaclSigningKeyPublic
324	var fullSigBody []byte
325	keyInSignature, msg, fullSigBody, err = kbcrypto.NaclVerifyAndExtract(sig)
326	if err != nil {
327		return nil, id, err
328	}
329
330	kidInSig := keyInSignature.GetKID()
331	kidWanted := k.GetKID()
332	if kidWanted.NotEqual(kidInSig) {
333		err = WrongKidError{kidInSig, kidWanted}
334		return nil, id, err
335	}
336
337	id = kbcrypto.ComputeSigIDFromSigBody(fullSigBody)
338	return msg, id, nil
339}
340
341func (k NaclSigningKeyPair) VerifyString(ctx VerifyContext, sig string, msg []byte) (id keybase1.SigIDBase, err error) {
342	var keyInSignature *kbcrypto.NaclSigningKeyPublic
343	var fullSigBody []byte
344	keyInSignature, fullSigBody, err = kbcrypto.NaclVerifyWithPayload(sig, msg)
345	if err != nil {
346		return id, err
347	}
348	kidInSig := keyInSignature.GetKID()
349	kidWanted := k.GetKID()
350	if kidWanted.NotEqual(kidInSig) {
351		err = WrongKidError{kidInSig, kidWanted}
352		return id, err
353	}
354
355	id = kbcrypto.ComputeSigIDFromSigBody(fullSigBody)
356	return id, nil
357}
358
359func (k NaclDHKeyPair) SignToString(msg []byte) (sig string, id keybase1.SigIDBase, err error) {
360	err = KeyCannotSignError{}
361	return
362}
363
364func (k NaclDHKeyPair) VerifyStringAndExtract(ctx VerifyContext, sig string) (msg []byte, id keybase1.SigIDBase, err error) {
365	err = KeyCannotVerifyError{}
366	return
367}
368
369func (k NaclDHKeyPair) VerifyString(ctx VerifyContext, sig string, msg []byte) (id keybase1.SigIDBase, err error) {
370	err = KeyCannotVerifyError{}
371	return
372}
373
374func EncryptionKIDToPublicKeyBytes(bk []byte) ([]byte, error) {
375	if len(bk) != 3+NaclDHKeysize {
376		return []byte{}, fmt.Errorf("invalid DH encryption key kbcrypto.KID (wrong length)")
377	}
378	if bk[0] != byte(kbcrypto.KeybaseKIDV1) || bk[1] != byte(kbcrypto.KIDNaclDH) || bk[len(bk)-1] != byte(kbcrypto.IDSuffixKID) {
379		return []byte{}, fmt.Errorf("invalid DH encryption key kbcrypto.KID (wrong type)")
380	}
381	return bk[2 : len(bk)-1], nil
382}
383
384func (k NaclSigningKeyPair) ExportPublicAndPrivate() (RawPublicKey, RawPrivateKey, error) {
385	return RawPublicKey(k.GetKID().ToBytes()), RawPrivateKey(k.Private[:]), nil
386}
387
388func (k NaclDHKeyPair) ExportPublicAndPrivate() (RawPublicKey, RawPrivateKey, error) {
389	return RawPublicKey(k.GetKID().ToBytes()), RawPrivateKey(k.Private[:]), nil
390}
391
392func makeNaclSigningKeyPair(reader io.Reader) (NaclSigningKeyPair, error) {
393	publicKey, privateKey, err := ed25519.GenerateKey(reader)
394	if err != nil {
395		return NaclSigningKeyPair{}, err
396	}
397
398	var publicArray kbcrypto.NaclSigningKeyPublic
399	var privateArray kbcrypto.NaclSigningKeyPrivate
400
401	copy(publicArray[:], publicKey)
402	copy(privateArray[:], privateKey)
403
404	return NaclSigningKeyPair{
405		Public:  publicArray,
406		Private: &privateArray,
407	}, nil
408}
409
410// MakeNaclSigningKeyPairFromSecret makes a signing key pair given a
411// secret. Of course, the security of depends entirely on the
412// randomness of the bytes in the secret.
413func MakeNaclSigningKeyPairFromSecret(secret [NaclSigningKeySecretSize]byte) (NaclSigningKeyPair, error) {
414	r := bytes.NewReader(secret[:])
415
416	kp, err := makeNaclSigningKeyPair(r)
417	if err != nil {
418		return NaclSigningKeyPair{}, err
419	}
420
421	if r.Len() > 0 {
422		return NaclSigningKeyPair{}, fmt.Errorf("Did not use %d secret byte(s)", r.Len())
423	}
424
425	return kp, err
426}
427
428func MakeNaclSigningKeyPairFromSecretBytes(secret []byte) (NaclSigningKeyPair, error) {
429	if len(secret) != NaclSigningKeySecretSize {
430		return NaclSigningKeyPair{}, fmt.Errorf("Bad NaCl signing key size: %d", len(secret))
431	}
432	var fixed [NaclSigningKeySecretSize]byte
433	copy(fixed[:], secret)
434	return MakeNaclSigningKeyPairFromSecret(fixed)
435}
436
437func GenerateNaclSigningKeyPair() (NaclSigningKeyPair, error) {
438	return makeNaclSigningKeyPair(rand.Reader)
439}
440
441func makeNaclDHKeyPair(reader io.Reader) (NaclDHKeyPair, error) {
442	pub, priv, err := box.GenerateKey(reader)
443	if err != nil {
444		return NaclDHKeyPair{}, err
445	}
446	return NaclDHKeyPair{
447		Public:  *pub,
448		Private: (*NaclDHKeyPrivate)(priv),
449	}, nil
450}
451
452func MakeNaclDHKeyPairFromSecretBytes(secret []byte) (NaclDHKeyPair, error) {
453	if len(secret) != NaclDHKeySecretSize {
454		return NaclDHKeyPair{}, fmt.Errorf("Bad NaCl DH key size: %d", len(secret))
455	}
456	var fixed [NaclDHKeySecretSize]byte
457	copy(fixed[:], secret)
458	return MakeNaclDHKeyPairFromSecret(fixed)
459}
460
461// MakeNaclDHKeyPairFromSecret makes a DH key pair given a secret. Of
462// course, the security of depends entirely on the randomness of the
463// bytes in the secret.
464func MakeNaclDHKeyPairFromSecret(secret [NaclDHKeySecretSize]byte) (NaclDHKeyPair, error) {
465	r := bytes.NewReader(secret[:])
466
467	kp, err := makeNaclDHKeyPair(r)
468	if err != nil {
469		return NaclDHKeyPair{}, err
470	}
471
472	if r.Len() > 0 {
473		return NaclDHKeyPair{}, fmt.Errorf("Did not use %d secret byte(s)", r.Len())
474	}
475
476	return kp, err
477}
478
479func GenerateNaclDHKeyPair() (NaclDHKeyPair, error) {
480	return makeNaclDHKeyPair(rand.Reader)
481}
482
483func GenerateNaclSigningKeyPairFromSeed(seed [ed25519.SeedSize]byte) (NaclSigningKeyPair, error) {
484	return makeNaclSigningKeyPair(bytes.NewReader(seed[:]))
485}
486
487func KbOpenSig(armored string) ([]byte, error) {
488	return base64.StdEncoding.DecodeString(armored)
489}
490
491func SigExtractKbPayloadAndKID(armored string) (payload []byte, kid keybase1.KID, sigID keybase1.SigIDBase, err error) {
492	var byt []byte
493	var sig kbcrypto.NaclSigInfo
494
495	if byt, err = KbOpenSig(armored); err != nil {
496		return nil, kid, sigID, err
497	}
498
499	if sig, err = kbcrypto.DecodeNaclSigInfoPacket(byt); err != nil {
500		return nil, kid, sigID, err
501	}
502	sigID = kbcrypto.ComputeSigIDFromSigBody(byt)
503	kid = sig.Kid.ToKID()
504	payload = sig.Payload
505	return payload, kid, sigID, nil
506}
507
508func SigAssertKbPayload(armored string, expected []byte) (sigID keybase1.SigIDBase, err error) {
509	var payload []byte
510	nilSigID := keybase1.SigIDBase("")
511	payload, _, sigID, err = SigExtractKbPayloadAndKID(armored)
512	if err != nil {
513		return nilSigID, err
514	}
515	if !FastByteArrayEq(expected, payload) {
516		return nilSigID, BadSigError{"wrong payload"}
517	}
518	return sigID, nil
519}
520
521// EncryptToString fails for this type of key.
522func (k NaclSigningKeyPair) EncryptToString(plaintext []byte, sender GenericKey) (ciphertext string, err error) {
523	err = KeyCannotEncryptError{}
524	return
525}
526
527// DecryptFromString fails for this type of key.
528func (k NaclSigningKeyPair) DecryptFromString(ciphertext string) (msg []byte, sender keybase1.KID, err error) {
529	err = KeyCannotDecryptError{}
530	return
531}
532
533// CanEncrypt always returns false for a signing key pair.
534func (k NaclSigningKeyPair) CanEncrypt() bool { return false }
535
536// CanDecrypt always returns false for a signing key pair.
537func (k NaclSigningKeyPair) CanDecrypt() bool { return false }
538
539// CanEncrypt always returns true for an encryption key pair.
540func (k NaclDHKeyPair) CanEncrypt() bool { return true }
541
542// CanDecrypt returns true if there's a private key available
543func (k NaclDHKeyPair) CanDecrypt() bool { return k.Private != nil }
544
545func (k NaclDHKeyPair) IsNil() bool {
546	var empty NaclDHKeyPublic
547	return bytes.Equal(k.Public[:], empty[:])
548}
549
550func (k NaclSigningKeyPair) IsNil() bool {
551	var empty kbcrypto.NaclSigningKeyPublic
552	return bytes.Equal(k.Public[:], empty[:])
553}
554
555// Encrypt a message to the key `k` from the given `sender`. If sender is nil, an ephemeral
556// keypair will be invented
557func (k NaclDHKeyPair) Encrypt(msg []byte, sender *NaclDHKeyPair) (*NaclEncryptionInfo, error) {
558	if sender == nil {
559		if tmp, err := GenerateNaclDHKeyPair(); err == nil {
560			sender = &tmp
561		} else {
562			return nil, err
563		}
564	} else if sender.Private == nil {
565		return nil, NoSecretKeyError{}
566	}
567
568	var nonce [NaclDHNonceSize]byte
569	if nRead, err := rand.Read(nonce[:]); err != nil {
570		return nil, err
571	} else if nRead != NaclDHNonceSize {
572		return nil, fmt.Errorf("Short random read: %d", nRead)
573	}
574
575	var ctext []byte
576	ctext = box.Seal(ctext, msg, &nonce, ((*[32]byte)(&k.Public)), ((*[32]byte)(sender.Private)))
577	ret := &NaclEncryptionInfo{
578		Ciphertext:     ctext,
579		EncryptionType: kbcrypto.KIDNaclDH,
580		Nonce:          nonce[:],
581		Receiver:       k.GetKID().ToBytes(),
582		Sender:         sender.GetKID().ToBytes(),
583	}
584
585	return ret, nil
586}
587
588// EncryptToString encrypts the plaintext using DiffieHelman; the this object is
589// the receiver, and the passed sender is optional.  If not provided, we'll make
590// up an ephemeral key.
591func (k NaclDHKeyPair) EncryptToString(plaintext []byte, sender GenericKey) (string, error) {
592	var senderDh *NaclDHKeyPair
593	if sender != nil {
594		var ok bool
595		if senderDh, ok = sender.(*NaclDHKeyPair); !ok {
596			return "", NoSecretKeyError{}
597		}
598	}
599
600	info, err := k.Encrypt(plaintext, senderDh)
601	if err != nil {
602		return "", err
603	}
604
605	return kbcrypto.EncodePacketToArmoredString(info)
606}
607
608func (k NaclDHKeyPair) SecretSymmetricKey(reason EncryptionReason) (NaclSecretBoxKey, error) {
609	if !k.CanDecrypt() {
610		return NaclSecretBoxKey{}, NoSecretKeyError{}
611	}
612
613	return deriveSymmetricKeyFromAsymmetric(*k.Private, reason)
614}
615
616// Derive a symmetric key using HMAC(k, reason).
617// Suitable for deriving from an asymmetric encryption key.
618// For deriving from a shared encryption key, this output is too close
619// to something that might be used as a public authenticator.
620func deriveSymmetricKeyFromAsymmetric(inKey NaclDHKeyPrivate, reason EncryptionReason) (NaclSecretBoxKey, error) {
621	var outKey = [32]byte{}
622	if len(reason) < encryptionReasonMinLength {
623		return outKey, KeyGenError{Msg: "reason must be at least 8 bytes"}
624	}
625
626	mac := hmac.New(sha256.New, inKey[:])
627	_, err := mac.Write(reason.Bytes())
628	if err != nil {
629		return outKey, err
630	}
631	out := mac.Sum(nil)
632
633	if copy(outKey[:], out) != len(outKey) {
634		return outKey, KeyGenError{Msg: "derived key of wrong size"}
635	}
636
637	return outKey, nil
638}
639
640// Derive a symmetric key.
641// Uses HMAC(key=reason, data=key)
642// Note the message and data are swapped as inputs to HMAC because that is less
643// likely to be accidentally used for another purpose such as authentication.
644func DeriveSymmetricKey(inKey NaclSecretBoxKey, reason EncryptionReason) (NaclSecretBoxKey, error) {
645	var outKey = [32]byte{}
646	if len(reason) < encryptionReasonMinLength {
647		return outKey, KeyGenError{Msg: "reason must be at least 8 bytes"}
648	}
649
650	mac := hmac.New(sha256.New, []byte(reason))
651	_, err := mac.Write(inKey[:])
652	if err != nil {
653		return outKey, err
654	}
655	out := mac.Sum(nil)
656
657	if copy(outKey[:], out) != len(outKey) {
658		return outKey, KeyGenError{Msg: "derived key of wrong size"}
659	}
660
661	return outKey, nil
662}
663
664// Derive a key from another.
665// Uses HMAC(key=key, data=reason)
666// Not to be confused with DeriveSymmetricKey which has hmac inputs swapped.
667// This one makes sense for derivation from secrets used only to derive from.
668func DeriveFromSecret(inKey [32]byte, reason DeriveReason) (outKey [32]byte, err error) {
669	if len(reason) < 8 {
670		return outKey, KeyGenError{Msg: "reason must be at least 8 bytes"}
671	}
672
673	mac := hmac.New(sha256.New, inKey[:])
674	_, err = mac.Write([]byte(reason))
675	if err != nil {
676		return outKey, err
677	}
678	out := mac.Sum(nil)
679
680	if copy(outKey[:], out) != len(outKey) {
681		return outKey, KeyGenError{Msg: "derived key of wrong size"}
682	}
683
684	return outKey, nil
685}
686
687func (k *NaclEncryptionInfo) GetTagAndVersion() (kbcrypto.PacketTag, kbcrypto.PacketVersion) {
688	return kbcrypto.TagEncryption, kbcrypto.KeybasePacketV1
689}
690
691// DecryptFromString decrypts the output of EncryptToString above,
692// and returns the kbcrypto.KID of the other end.
693func (k NaclDHKeyPair) DecryptFromString(ciphertext string) (msg []byte, sender keybase1.KID, err error) {
694	var nei NaclEncryptionInfo
695
696	if nei, err = DecodeArmoredNaclEncryptionInfoPacket(ciphertext); err != nil {
697		return
698	}
699
700	return k.Decrypt(&nei)
701}
702
703// Decrypt a NaclEncryptionInfo packet, and on success return the plaintext
704// and the kbcrypto.KID of the sender (which might be an ephemeral key).
705func (k NaclDHKeyPair) Decrypt(nei *NaclEncryptionInfo) (plaintext []byte, sender keybase1.KID, err error) {
706	if k.Private == nil {
707		err = NoSecretKeyError{}
708		return
709	}
710	if nei.EncryptionType != kbcrypto.KIDNaclDH {
711		err = DecryptBadPacketTypeError{}
712		return
713	}
714	var nonce [NaclDHNonceSize]byte
715	if len(nei.Nonce) != NaclDHNonceSize {
716		err = DecryptBadNonceError{}
717		return
718	}
719	copy(nonce[:], nei.Nonce)
720
721	var gk GenericKey
722	if gk, err = ImportKeypairFromKID(keybase1.KIDFromSlice(nei.Sender)); err != nil {
723		return
724	}
725
726	var senderDH NaclDHKeyPair
727	var ok bool
728	if senderDH, ok = gk.(NaclDHKeyPair); !ok {
729		err = DecryptBadSenderError{}
730		return
731	}
732
733	rkid := keybase1.KIDFromSlice(nei.Receiver)
734	if k.GetKID().NotEqual(rkid) {
735		err = DecryptWrongReceiverError{}
736		return
737	}
738
739	if plaintext, ok = box.Open(plaintext, nei.Ciphertext, &nonce,
740		((*[32]byte)(&senderDH.Public)), ((*[32]byte)(k.Private))); !ok {
741		err = DecryptOpenError{}
742		return
743	}
744	sender = senderDH.GetKID()
745	return
746}
747
748func GeneratePerUserKeySeed() (res PerUserKeySeed, err error) {
749	bs, err := RandBytes(32)
750	if err != nil {
751		return res, err
752	}
753	seed := PerUserKeySeed(MakeByte32(bs))
754	return seed, nil
755}
756
757func RandomNaclDHNonce() (nonce [NaclDHNonceSize]byte, err error) {
758	nRead, err := rand.Read(nonce[:])
759	if err != nil {
760		return nonce, err
761	}
762	if nRead != NaclDHNonceSize {
763		return nonce, fmt.Errorf("Short random read: %d", nRead)
764	}
765	return nonce, nil
766}
767