1// Package passvault manages the vault containing user records on
2// disk. It contains usernames and associated passwords which are
3// stored hashed (with salt) using scrypt.
4//
5// Copyright (c) 2013 CloudFlare, Inc.
6package passvault
7
8import (
9	"bytes"
10	"crypto/aes"
11	"crypto/ecdsa"
12	"crypto/elliptic"
13	"crypto/rand"
14	"crypto/rsa"
15	"crypto/sha1"
16	"crypto/x509"
17	"encoding/binary"
18	"encoding/json"
19	"errors"
20	"io/ioutil"
21	"math/big"
22	mrand "math/rand"
23	"os"
24
25	"github.com/cloudflare/redoctober/ecdh"
26	"github.com/cloudflare/redoctober/padding"
27	"github.com/cloudflare/redoctober/symcrypt"
28	"golang.org/x/crypto/scrypt"
29)
30
31// Constants for record type
32const (
33	RSARecord = "RSA"
34	ECCRecord = "ECC"
35)
36
37var DefaultRecordType = RSARecord
38
39// Constants for scrypt
40const (
41	KEYLENGTH = 16    // 16-byte output from scrypt
42	N         = 16384 // Cost parameter
43	R         = 8     // Block size
44	P         = 1     // Parallelization factor
45
46	DEFAULT_VERSION = 1
47)
48
49type ECPublicKey struct {
50	Curve *elliptic.CurveParams
51	X, Y  *big.Int
52}
53
54// toECDSA takes the internal ECPublicKey and returns an equivalent
55// an ecdsa.PublicKey
56func (pk *ECPublicKey) toECDSA() *ecdsa.PublicKey {
57	ecdsaPub := new(ecdsa.PublicKey)
58	ecdsaPub.Curve = pk.Curve
59	ecdsaPub.X = pk.X
60	ecdsaPub.Y = pk.Y
61
62	return ecdsaPub
63}
64
65// PasswordRecord is the structure used to store password and key
66// material for a single user name. It is written and read from
67// storage in JSON format.
68type PasswordRecord struct {
69	Type           string
70	PasswordSalt   []byte
71	HashedPassword []byte
72	KeySalt        []byte
73	RSAKey         struct {
74		RSAExp      []byte
75		RSAExpIV    []byte
76		RSAPrimeP   []byte
77		RSAPrimePIV []byte
78		RSAPrimeQ   []byte
79		RSAPrimeQIV []byte
80		RSAPublic   rsa.PublicKey
81	}
82	ECKey struct {
83		ECPriv   []byte
84		ECPrivIV []byte
85		ECPublic ECPublicKey
86	}
87	AltNames map[string]string
88	Admin    bool
89}
90
91// Records is the structure used to read and write a JSON file
92// containing the contents of a password vault
93type Records struct {
94	Version   int
95	VaultId   int
96	HmacKey   []byte
97	Passwords map[string]PasswordRecord
98
99	localPath string // Path of current vault
100}
101
102// Summary is a minmial account summary.
103type Summary struct {
104	Admin bool
105	Type  string
106}
107
108func init() {
109	// seed math.random from crypto.random
110	seedBytes, _ := symcrypt.MakeRandom(8)
111	seedBuf := bytes.NewBuffer(seedBytes)
112	n64, _ := binary.ReadVarint(seedBuf)
113	mrand.Seed(n64)
114}
115
116// hashPassword takes a password and derives a scrypt salted and hashed
117// version
118func hashPassword(password string, salt []byte) ([]byte, error) {
119	return scrypt.Key([]byte(password), salt, N, R, P, KEYLENGTH)
120}
121
122// encryptRSARecord takes an RSA private key and encrypts it with
123// a password key
124func encryptRSARecord(newRec *PasswordRecord, rsaPriv *rsa.PrivateKey, passKey []byte) (err error) {
125	if newRec.RSAKey.RSAExpIV, err = symcrypt.MakeRandom(16); err != nil {
126		return
127	}
128
129	paddedExponent := padding.AddPadding(rsaPriv.D.Bytes())
130	if newRec.RSAKey.RSAExp, err = symcrypt.EncryptCBC(paddedExponent, newRec.RSAKey.RSAExpIV, passKey); err != nil {
131		return
132	}
133
134	if newRec.RSAKey.RSAPrimePIV, err = symcrypt.MakeRandom(16); err != nil {
135		return
136	}
137
138	paddedPrimeP := padding.AddPadding(rsaPriv.Primes[0].Bytes())
139	if newRec.RSAKey.RSAPrimeP, err = symcrypt.EncryptCBC(paddedPrimeP, newRec.RSAKey.RSAPrimePIV, passKey); err != nil {
140		return
141	}
142
143	if newRec.RSAKey.RSAPrimeQIV, err = symcrypt.MakeRandom(16); err != nil {
144		return
145	}
146
147	paddedPrimeQ := padding.AddPadding(rsaPriv.Primes[1].Bytes())
148	newRec.RSAKey.RSAPrimeQ, err = symcrypt.EncryptCBC(paddedPrimeQ, newRec.RSAKey.RSAPrimeQIV, passKey)
149	return
150}
151
152// encryptECCRecord takes an ECDSA private key and encrypts it with
153// a password key.
154func encryptECCRecord(newRec *PasswordRecord, ecPriv *ecdsa.PrivateKey, passKey []byte) (err error) {
155	ecX509, err := x509.MarshalECPrivateKey(ecPriv)
156	if err != nil {
157		return
158	}
159
160	if newRec.ECKey.ECPrivIV, err = symcrypt.MakeRandom(16); err != nil {
161		return
162	}
163
164	paddedX509 := padding.AddPadding(ecX509)
165	newRec.ECKey.ECPriv, err = symcrypt.EncryptCBC(paddedX509, newRec.ECKey.ECPrivIV, passKey)
166	return
167}
168
169// createPasswordRec creates a new record from a username and password
170func createPasswordRec(password string, admin bool, userType string) (newRec PasswordRecord, err error) {
171	newRec.Type = userType
172
173	if newRec.PasswordSalt, err = symcrypt.MakeRandom(16); err != nil {
174		return
175	}
176
177	if newRec.HashedPassword, err = hashPassword(password, newRec.PasswordSalt); err != nil {
178		return
179	}
180
181	if newRec.KeySalt, err = symcrypt.MakeRandom(16); err != nil {
182		return
183	}
184
185	passKey, err := derivePasswordKey(password, newRec.KeySalt)
186	if err != nil {
187		return
188	}
189
190	newRec.AltNames = make(map[string]string)
191
192	// generate a key pair
193	switch userType {
194	case RSARecord:
195		var rsaPriv *rsa.PrivateKey
196		rsaPriv, err = rsa.GenerateKey(rand.Reader, 2048)
197		if err != nil {
198			return
199		}
200		// encrypt RSA key with password key
201		if err = encryptRSARecord(&newRec, rsaPriv, passKey); err != nil {
202			return
203		}
204		newRec.RSAKey.RSAPublic = rsaPriv.PublicKey
205	case ECCRecord:
206		var ecPriv *ecdsa.PrivateKey
207		ecPriv, err = ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
208		if err != nil {
209			return
210		}
211		// encrypt ECDSA key with password key
212		if err = encryptECCRecord(&newRec, ecPriv, passKey); err != nil {
213			return
214		}
215		newRec.ECKey.ECPublic.Curve = ecPriv.PublicKey.Curve.Params()
216		newRec.ECKey.ECPublic.X = ecPriv.PublicKey.X
217		newRec.ECKey.ECPublic.Y = ecPriv.PublicKey.Y
218	default:
219		err = errors.New("Unknown record type")
220	}
221
222	newRec.Admin = admin
223
224	return
225}
226
227// derivePasswordKey generates a key from a password (and salt) using
228// scrypt
229func derivePasswordKey(password string, keySalt []byte) ([]byte, error) {
230	return scrypt.Key([]byte(password), keySalt, N, R, P, KEYLENGTH)
231}
232
233// decryptECB decrypts bytes using a key in AES ECB mode.
234func decryptECB(data, key []byte) (decryptedData []byte, err error) {
235	aesCrypt, err := aes.NewCipher(key)
236	if err != nil {
237		return
238	}
239
240	decryptedData = make([]byte, len(data))
241	aesCrypt.Decrypt(decryptedData, data)
242
243	return
244}
245
246// encryptECB encrypts bytes using a key in AES ECB mode.
247func encryptECB(data, key []byte) (encryptedData []byte, err error) {
248	aesCrypt, err := aes.NewCipher(key)
249	if err != nil {
250		return
251	}
252
253	encryptedData = make([]byte, len(data))
254	aesCrypt.Encrypt(encryptedData, data)
255
256	return
257}
258
259// InitFrom reads the record from disk and initialize global context.
260func InitFrom(path string) (records Records, err error) {
261	var jsonDiskRecord []byte
262
263	if path != "memory" {
264		jsonDiskRecord, err = ioutil.ReadFile(path)
265
266		// It's OK for the file to be missing, we'll create it later if
267		// anything is added.
268
269		if err != nil && !os.IsNotExist(err) {
270			return
271		}
272	}
273
274	// Initialized so that we can determine later if anything was read
275	// from the file.
276
277	records.Version = 0
278	if len(jsonDiskRecord) != 0 {
279		if err = json.Unmarshal(jsonDiskRecord, &records); err != nil {
280			return
281		}
282	}
283
284	err = errors.New("Format error")
285	for k, rec := range records.Passwords {
286
287		if rec.AltNames == nil {
288			rec.AltNames = make(map[string]string)
289			records.Passwords[k] = rec
290		}
291		if len(rec.PasswordSalt) != 16 {
292			return
293		}
294		if len(rec.HashedPassword) != 16 {
295			return
296		}
297		if len(rec.KeySalt) != 16 {
298			return
299		}
300		if rec.Type == RSARecord {
301			if len(rec.RSAKey.RSAExp) == 0 || len(rec.RSAKey.RSAExp)%16 != 0 {
302				return
303			}
304			if len(rec.RSAKey.RSAPrimeP) == 0 || len(rec.RSAKey.RSAPrimeP)%16 != 0 {
305				return
306			}
307			if len(rec.RSAKey.RSAPrimeQ) == 0 || len(rec.RSAKey.RSAPrimeQ)%16 != 0 {
308				return
309			}
310			if len(rec.RSAKey.RSAExpIV) != 16 {
311				return
312			}
313			if len(rec.RSAKey.RSAPrimePIV) != 16 {
314				return
315			}
316			if len(rec.RSAKey.RSAPrimeQIV) != 16 {
317				return
318			}
319		}
320		if rec.Type == ECCRecord {
321			if len(rec.ECKey.ECPriv) == 0 || len(rec.ECKey.ECPriv)%16 != 0 {
322				return
323			}
324			if len(rec.ECKey.ECPrivIV) != 16 {
325				return
326			}
327		}
328	}
329
330	// If the Version field is 0 then it indicates that nothing was
331	// read from the file and so it needs to be initialized.
332
333	if records.Version == 0 {
334		records.Version = DEFAULT_VERSION
335		records.VaultId = int(mrand.Int31())
336		records.HmacKey, err = symcrypt.MakeRandom(16)
337		if err != nil {
338			return
339		}
340		records.Passwords = make(map[string]PasswordRecord)
341	}
342
343	records.localPath = path
344
345	err = nil
346	return
347}
348
349// WriteRecordsToDisk saves the current state of the records to disk.
350func (records *Records) WriteRecordsToDisk() error {
351	if records.localPath == "memory" {
352		return nil
353	}
354
355	jsonDiskRecord, err := json.Marshal(records)
356	if err != nil {
357		return err
358	}
359	return ioutil.WriteFile(records.localPath, jsonDiskRecord, 0644)
360}
361
362// AddNewRecord adds a new record for a given username and password.
363func (records *Records) AddNewRecord(name, password string, admin bool, userType string) (PasswordRecord, error) {
364	pr, err := createPasswordRec(password, admin, userType)
365	if err != nil {
366		return pr, err
367	}
368	records.SetRecord(pr, name)
369	return pr, records.WriteRecordsToDisk()
370}
371
372// ChangePassword changes the password for a given user.
373func (records *Records) ChangePassword(name, password, newPassword, hipchatName string) (err error) {
374	pr, ok := records.GetRecord(name)
375
376	if !ok {
377		err = errors.New("Record not present")
378		return
379	}
380
381	if len(hipchatName) != 0 {
382		pr.AltNames["HipchatName"] = hipchatName
383	}
384
385	if len(newPassword) == 0 {
386		records.SetRecord(pr, name)
387		return records.WriteRecordsToDisk()
388	}
389
390	var keySalt []byte
391	if keySalt, err = symcrypt.MakeRandom(16); err != nil {
392		return
393	}
394	newPassKey, err := derivePasswordKey(newPassword, keySalt)
395	if err != nil {
396		return
397	}
398
399	// decrypt with old password and re-encrypt original key with new password
400	if pr.Type == RSARecord {
401		var rsaKey rsa.PrivateKey
402		rsaKey, err = pr.GetKeyRSA(password)
403		if err != nil {
404			return
405		}
406
407		// encrypt RSA key with password key
408		err = encryptRSARecord(&pr, &rsaKey, newPassKey)
409		if err != nil {
410			return
411		}
412	} else if pr.Type == ECCRecord {
413		var ecKey *ecdsa.PrivateKey
414		ecKey, err = pr.GetKeyECC(password)
415		if err != nil {
416			return
417		}
418
419		// encrypt ECDSA key with password key
420		err = encryptECCRecord(&pr, ecKey, newPassKey)
421		if err != nil {
422			return
423		}
424	} else {
425		err = errors.New("Unknown record type")
426		return
427	}
428
429	// add the password salt and hash
430	if pr.PasswordSalt, err = symcrypt.MakeRandom(16); err != nil {
431		return
432	}
433	if pr.HashedPassword, err = hashPassword(newPassword, pr.PasswordSalt); err != nil {
434		return
435	}
436
437	pr.KeySalt = keySalt
438
439	records.SetRecord(pr, name)
440
441	return records.WriteRecordsToDisk()
442}
443
444// DeleteRecord deletes a given record.
445func (records *Records) DeleteRecord(name string) error {
446	if _, ok := records.GetRecord(name); ok {
447		delete(records.Passwords, name)
448		return records.WriteRecordsToDisk()
449	}
450	return errors.New("Record missing")
451}
452
453// RevokeRecord removes admin status from a record.
454func (records *Records) RevokeRecord(name string) error {
455	if rec, ok := records.GetRecord(name); ok {
456		rec.Admin = false
457		records.SetRecord(rec, name)
458		return records.WriteRecordsToDisk()
459	}
460	return errors.New("Record missing")
461}
462
463// MakeAdmin adds admin status to a given record.
464func (records *Records) MakeAdmin(name string) error {
465	if rec, ok := records.GetRecord(name); ok {
466		rec.Admin = true
467		records.SetRecord(rec, name)
468		return records.WriteRecordsToDisk()
469	}
470	return errors.New("Record missing")
471}
472
473// SetRecord puts a record into the global status.
474func (records *Records) SetRecord(pr PasswordRecord, name string) {
475	records.Passwords[name] = pr
476}
477
478// GetRecord returns a record given a name.
479func (records *Records) GetRecord(name string) (PasswordRecord, bool) {
480	dpr, found := records.Passwords[name]
481	return dpr, found
482}
483
484// GetVaultID returns the id of the current vault.
485func (records *Records) GetVaultID() (id int, err error) {
486	return records.VaultId, nil
487}
488
489// GetHMACKey returns the hmac key of the current vault.
490func (records *Records) GetHMACKey() (key []byte, err error) {
491	return records.HmacKey, nil
492}
493
494// NumRecords returns the number of records in the vault.
495func (records *Records) NumRecords() int {
496	return len(records.Passwords)
497}
498
499// GetSummary returns a summary of the records on disk.
500func (records *Records) GetSummary() (summary map[string]Summary) {
501	summary = make(map[string]Summary)
502	for name, pass := range records.Passwords {
503		summary[name] = Summary{pass.Admin, pass.Type}
504	}
505	return
506}
507
508// IsAdmin returns the admin status of the PasswordRecord.
509func (pr *PasswordRecord) IsAdmin() bool {
510	return pr.Admin
511}
512
513// GetType returns the type status of the PasswordRecord.
514func (pr *PasswordRecord) GetType() string {
515	return pr.Type
516}
517
518// EncryptKey encrypts a 16-byte key with the RSA or EC key of the record.
519func (pr *PasswordRecord) EncryptKey(in []byte) (out []byte, err error) {
520	if pr.Type == RSARecord {
521		return rsa.EncryptOAEP(sha1.New(), rand.Reader, &pr.RSAKey.RSAPublic, in, nil)
522	} else if pr.Type == ECCRecord {
523		return ecdh.Encrypt(pr.ECKey.ECPublic.toECDSA(), in)
524	} else {
525		return nil, errors.New("Invalid function for record type")
526	}
527}
528
529// GetKeyRSAPub returns the RSA public key of the record.
530func (pr *PasswordRecord) GetKeyRSAPub() (out *rsa.PublicKey, err error) {
531	if pr.Type != RSARecord {
532		return out, errors.New("Invalid function for record type")
533	}
534	return &pr.RSAKey.RSAPublic, err
535}
536
537// GetKeyECCPub returns the ECDSA public key out of the record.
538func (pr *PasswordRecord) GetKeyECCPub() (out *ecdsa.PublicKey, err error) {
539	if pr.Type != ECCRecord {
540		return out, errors.New("Invalid function for record type")
541	}
542	return pr.ECKey.ECPublic.toECDSA(), err
543}
544
545// GetKeyECC returns the ECDSA private key of the record given the correct password.
546func (pr *PasswordRecord) GetKeyECC(password string) (key *ecdsa.PrivateKey, err error) {
547	if pr.Type != ECCRecord {
548		return key, errors.New("Invalid function for record type")
549	}
550
551	if err = pr.ValidatePassword(password); err != nil {
552		return
553	}
554
555	passKey, err := derivePasswordKey(password, pr.KeySalt)
556	if err != nil {
557		return
558	}
559
560	x509Padded, err := symcrypt.DecryptCBC(pr.ECKey.ECPriv, pr.ECKey.ECPrivIV, passKey)
561	if err != nil {
562		return
563	}
564
565	ecX509, err := padding.RemovePadding(x509Padded)
566	if err != nil {
567		return
568	}
569	return x509.ParseECPrivateKey(ecX509)
570}
571
572// GetKeyRSA returns the RSA private key of the record given the correct password.
573func (pr *PasswordRecord) GetKeyRSA(password string) (key rsa.PrivateKey, err error) {
574	if pr.Type != RSARecord {
575		return key, errors.New("Invalid function for record type")
576	}
577
578	err = pr.ValidatePassword(password)
579	if err != nil {
580		return
581	}
582
583	passKey, err := derivePasswordKey(password, pr.KeySalt)
584	if err != nil {
585		return
586	}
587
588	rsaExponentPadded, err := symcrypt.DecryptCBC(pr.RSAKey.RSAExp, pr.RSAKey.RSAExpIV, passKey)
589	if err != nil {
590		return
591	}
592	rsaExponent, err := padding.RemovePadding(rsaExponentPadded)
593	if err != nil {
594		return
595	}
596
597	rsaPrimePPadded, err := symcrypt.DecryptCBC(pr.RSAKey.RSAPrimeP, pr.RSAKey.RSAPrimePIV, passKey)
598	if err != nil {
599		return
600	}
601	rsaPrimeP, err := padding.RemovePadding(rsaPrimePPadded)
602	if err != nil {
603		return
604	}
605
606	rsaPrimeQPadded, err := symcrypt.DecryptCBC(pr.RSAKey.RSAPrimeQ, pr.RSAKey.RSAPrimeQIV, passKey)
607	if err != nil {
608		return
609	}
610	rsaPrimeQ, err := padding.RemovePadding(rsaPrimeQPadded)
611	if err != nil {
612		return
613	}
614
615	key.PublicKey = pr.RSAKey.RSAPublic
616	key.D = big.NewInt(0).SetBytes(rsaExponent)
617	key.Primes = []*big.Int{big.NewInt(0), big.NewInt(0)}
618	key.Primes[0].SetBytes(rsaPrimeP)
619	key.Primes[1].SetBytes(rsaPrimeQ)
620
621	err = key.Validate()
622	if err != nil {
623		return
624	}
625
626	return
627}
628func (records *Records) GetAltNameFromName(alt, name string) (altName string, found bool) {
629	if passwordRecord, ok := records.Passwords[name]; ok {
630		if altName, ok := passwordRecord.AltNames[alt]; ok {
631			return altName, true
632		}
633	}
634	return "", false
635}
636func (r *Records) GetAltNamesFromName(alt string, names []string) map[string]string {
637	altNames := make(map[string]string)
638	for _, name := range names {
639		altName, found := r.GetAltNameFromName(alt, name)
640		if !found {
641			altName = name
642		}
643		altNames[name] = altName
644	}
645	return altNames
646
647}
648
649// ValidatePassword returns an error if the password is incorrect.
650func (pr *PasswordRecord) ValidatePassword(password string) error {
651	h, err := hashPassword(password, pr.PasswordSalt)
652	if err != nil {
653		return err
654	}
655
656	if bytes.Compare(h, pr.HashedPassword) != 0 {
657		return errors.New("Wrong Password")
658	}
659	return nil
660}
661